1 /****************************************************************************** 2 * 3 * Copyright 2002-2012 Broadcom Corporation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19 /****************************************************************************** 20 * 21 * This module contains the AVDTP adaption layer. 22 * 23 ******************************************************************************/ 24 25 #include <base/logging.h> 26 #include <string.h> 27 28 #include "avdt_api.h" 29 #include "avdt_int.h" 30 #include "avdtc_api.h" 31 #include "bt_target.h" 32 #include "bt_types.h" 33 #include "bt_utils.h" 34 #include "l2c_api.h" 35 #include "l2cdefs.h" 36 #include "osi/include/osi.h" 37 38 AvdtpScb* AvdtpAdaptationLayer::LookupAvdtpScb( 39 const AvdtpTransportChannel& tc) { 40 if (tc.ccb_idx >= AVDT_NUM_LINKS) { 41 AVDT_TRACE_ERROR("%s: AvdtpScb entry not found: invalid ccb_idx:%d", 42 __func__, tc.ccb_idx); 43 return nullptr; 44 } 45 if (tc.tcid >= AVDT_NUM_RT_TBL) { 46 AVDT_TRACE_ERROR("%s: AvdtpScb entry not found: invalid tcid:%d", __func__, 47 tc.tcid); 48 return nullptr; 49 } 50 const AvdtpRoutingEntry& re = rt_tbl[tc.ccb_idx][tc.tcid]; 51 AVDT_TRACE_DEBUG("%s: ccb_idx:%d tcid:%d scb_hdl:%d", __func__, tc.ccb_idx, 52 tc.tcid, re.scb_hdl); 53 return avdt_scb_by_hdl(re.scb_hdl); 54 } 55 56 /******************************************************************************* 57 * 58 * Function avdt_ad_type_to_tcid 59 * 60 * Description Derives the TCID from the channel type and SCB. 61 * 62 * 63 * Returns TCID value. 64 * 65 ******************************************************************************/ 66 uint8_t avdt_ad_type_to_tcid(uint8_t type, AvdtpScb* p_scb) { 67 if (type == AVDT_CHAN_SIG) { 68 return 0; 69 } 70 // The SCB Handle is unique in the [1, AVDT_NUM_LINKS * AVDT_NUM_SEPS] 71 // range. The scb_idx computed here is the SCB index for the corresponding 72 // SEP, and it is in the range [0, AVDT_NUM_SEPS) for a particular link. 73 uint8_t scb_idx = (avdt_scb_to_hdl(p_scb) - 1) % AVDT_NUM_LINKS; 74 // There are AVDT_CHAN_NUM_TYPES channel types per SEP. Here we compute 75 // the type index (TCID) from the SEP index and the type itself. 76 uint8_t tcid = (scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type; 77 AVDT_TRACE_DEBUG("%s: type:%d, tcid: %d", __func__, type, tcid); 78 return tcid; 79 } 80 81 /******************************************************************************* 82 * 83 * Function avdt_ad_tcid_to_type 84 * 85 * Description Derives the channel type from the TCID. 86 * 87 * 88 * Returns Channel type value. 89 * 90 ******************************************************************************/ 91 static uint8_t avdt_ad_tcid_to_type(uint8_t tcid) { 92 uint8_t type; 93 94 if (tcid == 0) { 95 type = AVDT_CHAN_SIG; 96 } else { 97 /* tcid translates to type based on number of channels, as follows: 98 ** only media channel : tcid=1,2,3,4,5,6... type=1,1,1,1,1,1... 99 ** media and report : tcid=1,2,3,4,5,6... type=1,2,1,2,1,2... 100 ** media, report, recov : tcid=1,2,3,4,5,6... type=1,2,3,1,2,3... 101 */ 102 type = ((tcid + AVDT_CHAN_NUM_TYPES - 2) % (AVDT_CHAN_NUM_TYPES - 1)) + 1; 103 } 104 AVDT_TRACE_DEBUG("tcid: %d, type: %d", tcid, type); 105 return type; 106 } 107 108 /******************************************************************************* 109 * 110 * Function avdt_ad_init 111 * 112 * Description Initialize adaption layer. 113 * 114 * 115 * Returns Nothing. 116 * 117 ******************************************************************************/ 118 void avdt_ad_init(void) { 119 int i; 120 AvdtpTransportChannel* p_tbl = avdtp_cb.ad.tc_tbl; 121 avdtp_cb.ad.Reset(); 122 123 /* make sure the peer_mtu is a valid value */ 124 for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) { 125 p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; 126 } 127 } 128 129 /******************************************************************************* 130 * 131 * Function avdt_ad_tc_tbl_by_st 132 * 133 * Description Find adaption layer transport channel table entry matching 134 * the given state. 135 * 136 * 137 * Returns Pointer to matching entry. For control channel it returns 138 * the matching entry. For media or other it returns the 139 * first matching entry (there could be more than one). 140 * 141 ******************************************************************************/ 142 AvdtpTransportChannel* avdt_ad_tc_tbl_by_st(uint8_t type, AvdtpCcb* p_ccb, 143 uint8_t state) { 144 int i; 145 AvdtpTransportChannel* p_tbl = avdtp_cb.ad.tc_tbl; 146 uint8_t ccb_idx; 147 148 if (p_ccb == NULL) { 149 /* resending security req */ 150 for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) { 151 /* must be AVDT_CHAN_SIG - tcid always zero */ 152 if ((p_tbl->tcid == 0) && (p_tbl->state == state)) { 153 break; 154 } 155 } 156 } else { 157 ccb_idx = avdt_ccb_to_idx(p_ccb); 158 159 for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) { 160 if (type == AVDT_CHAN_SIG) { 161 /* if control channel, tcid always zero */ 162 if ((p_tbl->tcid == 0) && (p_tbl->ccb_idx == ccb_idx) && 163 (p_tbl->state == state)) { 164 break; 165 } 166 } else { 167 /* if other channel, tcid is always > zero */ 168 if ((p_tbl->tcid > 0) && (p_tbl->ccb_idx == ccb_idx) && 169 (p_tbl->state == state)) { 170 break; 171 } 172 } 173 } 174 } 175 176 /* if nothing found return null */ 177 if (i == AVDT_NUM_TC_TBL) { 178 p_tbl = NULL; 179 } 180 181 return p_tbl; 182 } 183 184 /******************************************************************************* 185 * 186 * Function avdt_ad_tc_tbl_by_lcid 187 * 188 * Description Find adaption layer transport channel table entry by LCID. 189 * 190 * 191 * Returns Pointer to entry. 192 * 193 ******************************************************************************/ 194 AvdtpTransportChannel* avdt_ad_tc_tbl_by_lcid(uint16_t lcid) { 195 uint8_t idx; 196 197 idx = avdtp_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID]; 198 199 if (idx < AVDT_NUM_TC_TBL) { 200 return &avdtp_cb.ad.tc_tbl[idx]; 201 } else { 202 return NULL; 203 } 204 } 205 206 /******************************************************************************* 207 * 208 * Function avdt_ad_tc_tbl_by_type 209 * 210 * Description This function retrieves the transport channel table entry 211 * for a particular channel. 212 * 213 * 214 * Returns Pointer to transport channel table entry. 215 * 216 ******************************************************************************/ 217 AvdtpTransportChannel* avdt_ad_tc_tbl_by_type(uint8_t type, AvdtpCcb* p_ccb, 218 AvdtpScb* p_scb) { 219 uint8_t tcid; 220 int i; 221 AvdtpTransportChannel* p_tbl = avdtp_cb.ad.tc_tbl; 222 uint8_t ccb_idx = avdt_ccb_to_idx(p_ccb); 223 224 /* get tcid from type, scb */ 225 tcid = avdt_ad_type_to_tcid(type, p_scb); 226 227 for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) { 228 if ((p_tbl->tcid == tcid) && (p_tbl->ccb_idx == ccb_idx)) { 229 break; 230 } 231 } 232 233 CHECK(i != AVDT_NUM_TC_TBL); 234 235 return p_tbl; 236 } 237 238 /******************************************************************************* 239 * 240 * Function avdt_ad_tc_tbl_alloc 241 * 242 * Description Allocate an entry in the traffic channel table. 243 * 244 * 245 * Returns Pointer to entry. 246 * 247 ******************************************************************************/ 248 AvdtpTransportChannel* avdt_ad_tc_tbl_alloc(AvdtpCcb* p_ccb) { 249 int i; 250 AvdtpTransportChannel* p_tbl = avdtp_cb.ad.tc_tbl; 251 252 /* find next free entry in tc table */ 253 for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) { 254 if (p_tbl->state == AVDT_AD_ST_UNUSED) { 255 break; 256 } 257 } 258 259 /* sanity check */ 260 CHECK(i != AVDT_NUM_TC_TBL); 261 262 /* initialize entry */ 263 p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; 264 p_tbl->cfg_flags = 0; 265 p_tbl->ccb_idx = avdt_ccb_to_idx(p_ccb); 266 p_tbl->state = AVDT_AD_ST_IDLE; 267 return p_tbl; 268 } 269 270 /******************************************************************************* 271 * 272 * Function avdt_ad_tc_tbl_to_idx 273 * 274 * Description Convert a transport channel table entry to an index. 275 * 276 * 277 * Returns Index value. 278 * 279 ******************************************************************************/ 280 uint8_t avdt_ad_tc_tbl_to_idx(AvdtpTransportChannel* p_tbl) { 281 AVDT_TRACE_DEBUG("avdt_ad_tc_tbl_to_idx: %d", (p_tbl - avdtp_cb.ad.tc_tbl)); 282 /* use array arithmetic to determine index */ 283 return (uint8_t)(p_tbl - avdtp_cb.ad.tc_tbl); 284 } 285 286 /******************************************************************************* 287 * 288 * Function avdt_ad_tc_close_ind 289 * 290 * Description This function is called by the L2CAP interface when the 291 * L2CAP channel is closed. It looks up the CCB or SCB for 292 * the channel and sends it a close event. The reason 293 * parameter is the same value passed by the L2CAP 294 * callback function. 295 * 296 * 297 * Returns Nothing. 298 * 299 ******************************************************************************/ 300 void avdt_ad_tc_close_ind(AvdtpTransportChannel* p_tbl, 301 UNUSED_ATTR uint16_t reason) { 302 AvdtpCcb* p_ccb; 303 AvdtpScb* p_scb; 304 tAVDT_SCB_TC_CLOSE close; 305 306 close.old_tc_state = p_tbl->state; 307 /* clear avdt_ad_tc_tbl entry */ 308 p_tbl->state = AVDT_AD_ST_UNUSED; 309 p_tbl->cfg_flags = 0; 310 p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; 311 312 AVDT_TRACE_DEBUG("%s: tcid: %d, old: %d", __func__, p_tbl->tcid, 313 close.old_tc_state); 314 /* if signaling channel, notify ccb that channel open */ 315 if (p_tbl->tcid == 0) { 316 p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx); 317 avdt_ccb_event(p_ccb, AVDT_CCB_LL_CLOSE_EVT, NULL); 318 return; 319 } 320 /* if media or other channel, notify scb that channel close */ 321 /* look up scb in stream routing table by ccb, tcid */ 322 p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl); 323 if (p_scb == nullptr) { 324 AVDT_TRACE_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d", 325 __func__, p_tbl->ccb_idx, p_tbl->tcid); 326 return; 327 } 328 close.tcid = p_tbl->tcid; 329 close.type = avdt_ad_tcid_to_type(p_tbl->tcid); 330 tAVDT_SCB_EVT avdt_scb_evt; 331 avdt_scb_evt.close = close; 332 avdt_scb_event(p_scb, AVDT_SCB_TC_CLOSE_EVT, &avdt_scb_evt); 333 } 334 335 /******************************************************************************* 336 * 337 * Function avdt_ad_tc_open_ind 338 * 339 * Description This function is called by the L2CAP interface when 340 * the L2CAP channel is opened. It looks up the CCB or SCB 341 * for the channel and sends it an open event. 342 * 343 * 344 * Returns Nothing. 345 * 346 ******************************************************************************/ 347 void avdt_ad_tc_open_ind(AvdtpTransportChannel* p_tbl) { 348 AvdtpCcb* p_ccb; 349 AvdtpScb* p_scb; 350 tAVDT_OPEN open; 351 tAVDT_EVT_HDR evt; 352 353 AVDT_TRACE_DEBUG("%s: p_tbl:%p state:%d ccb_idx:%d tcid:%d scb_hdl:%d", 354 __func__, p_tbl, p_tbl->state, p_tbl->ccb_idx, p_tbl->tcid, 355 avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl); 356 357 p_tbl->state = AVDT_AD_ST_OPEN; 358 359 /* if signaling channel, notify ccb that channel open */ 360 if (p_tbl->tcid == 0) { 361 /* set the signal channel to use high priority within the ACL link */ 362 L2CA_SetTxPriority(avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][AVDT_CHAN_SIG].lcid, 363 L2CAP_CHNL_PRIORITY_HIGH); 364 365 p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx); 366 /* use err_param to indicate the role of connection. 367 * AVDT_ACP, if ACP */ 368 evt.err_param = AVDT_INT; 369 if (p_tbl->cfg_flags & AVDT_L2C_CFG_CONN_ACP) { 370 evt.err_param = AVDT_ACP; 371 } 372 tAVDT_CCB_EVT avdt_ccb_evt; 373 avdt_ccb_evt.msg.hdr = evt; 374 avdt_ccb_event(p_ccb, AVDT_CCB_LL_OPEN_EVT, &avdt_ccb_evt); 375 return; 376 } 377 /* if media or other channel, notify scb that channel open */ 378 /* look up scb in stream routing table by ccb, tcid */ 379 p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl); 380 if (p_scb == nullptr) { 381 AVDT_TRACE_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d", 382 __func__, p_tbl->ccb_idx, p_tbl->tcid); 383 return; 384 } 385 /* put lcid in event data */ 386 open.peer_mtu = p_tbl->peer_mtu; 387 open.lcid = avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].lcid; 388 open.hdr.err_code = avdt_ad_tcid_to_type(p_tbl->tcid); 389 tAVDT_SCB_EVT avdt_scb_evt; 390 avdt_scb_evt.open = open; 391 avdt_scb_event(p_scb, AVDT_SCB_TC_OPEN_EVT, &avdt_scb_evt); 392 } 393 394 /******************************************************************************* 395 * 396 * Function avdt_ad_tc_cong_ind 397 * 398 * Description This function is called by the L2CAP interface layer when 399 * L2CAP calls the congestion callback. It looks up the CCB 400 * or SCB for the channel and sends it a congestion event. 401 * The is_congested parameter is the same value passed by 402 * the L2CAP callback function. 403 * 404 * 405 * Returns Nothing. 406 * 407 ******************************************************************************/ 408 void avdt_ad_tc_cong_ind(AvdtpTransportChannel* p_tbl, bool is_congested) { 409 AvdtpCcb* p_ccb; 410 AvdtpScb* p_scb; 411 412 /* if signaling channel, notify ccb of congestion */ 413 if (p_tbl->tcid == 0) { 414 p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx); 415 tAVDT_CCB_EVT avdt_ccb_evt; 416 avdt_ccb_evt.llcong = is_congested; 417 avdt_ccb_event(p_ccb, AVDT_CCB_LL_CONG_EVT, &avdt_ccb_evt); 418 return; 419 } 420 /* if media or other channel, notify scb that channel open */ 421 /* look up scb in stream routing table by ccb, tcid */ 422 p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl); 423 if (p_scb == nullptr) { 424 AVDT_TRACE_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d", 425 __func__, p_tbl->ccb_idx, p_tbl->tcid); 426 return; 427 } 428 tAVDT_SCB_EVT avdt_scb_evt; 429 avdt_scb_evt.llcong = is_congested; 430 avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, &avdt_scb_evt); 431 } 432 433 /******************************************************************************* 434 * 435 * Function avdt_ad_tc_data_ind 436 * 437 * Description This function is called by the L2CAP interface layer when 438 * incoming data is received from L2CAP. It looks up the CCB 439 * or SCB for the channel and routes the data accordingly. 440 * 441 * 442 * Returns Nothing. 443 * 444 ******************************************************************************/ 445 void avdt_ad_tc_data_ind(AvdtpTransportChannel* p_tbl, BT_HDR* p_buf) { 446 AvdtpCcb* p_ccb; 447 AvdtpScb* p_scb; 448 449 /* store type (media, recovery, reporting) */ 450 p_buf->layer_specific = avdt_ad_tcid_to_type(p_tbl->tcid); 451 452 /* if signaling channel, handle control message */ 453 if (p_tbl->tcid == 0) { 454 p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx); 455 avdt_msg_ind(p_ccb, p_buf); 456 return; 457 } 458 /* if media or other channel, send event to scb */ 459 p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl); 460 if (p_scb == nullptr) { 461 AVDT_TRACE_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d", 462 __func__, p_tbl->ccb_idx, p_tbl->tcid); 463 osi_free(p_buf); 464 AVDT_TRACE_ERROR("%s: buffer freed", __func__); 465 return; 466 } 467 avdt_scb_event(p_scb, AVDT_SCB_TC_DATA_EVT, (tAVDT_SCB_EVT*)&p_buf); 468 } 469 470 /******************************************************************************* 471 * 472 * Function avdt_ad_write_req 473 * 474 * Description This function is called by a CCB or SCB to send data to a 475 * transport channel. It looks up the LCID of the channel 476 * based on the type, CCB, and SCB (if present). Then it 477 * passes the data to L2CA_DataWrite(). 478 * 479 * 480 * Returns AVDT_AD_SUCCESS, if data accepted 481 * AVDT_AD_CONGESTED, if data accepted and the channel is 482 * congested 483 * AVDT_AD_FAILED, if error 484 * 485 ******************************************************************************/ 486 uint8_t avdt_ad_write_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb, 487 BT_HDR* p_buf) { 488 uint8_t tcid; 489 490 /* get tcid from type, scb */ 491 tcid = avdt_ad_type_to_tcid(type, p_scb); 492 493 return L2CA_DataWrite(avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid, 494 p_buf); 495 } 496 497 /******************************************************************************* 498 * 499 * Function avdt_ad_open_req 500 * 501 * Description This function is called by a CCB or SCB to open a transport 502 * channel. This function allocates and initializes a 503 * transport channel table entry. The channel can be opened 504 * in two roles: as an initiator or acceptor. When opened 505 * as an initiator the function will start an L2CAP connection. 506 * When opened as an acceptor the function simply configures 507 * the table entry to listen for an incoming channel. 508 * 509 * 510 * Returns Nothing. 511 * 512 ******************************************************************************/ 513 void avdt_ad_open_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb, 514 uint8_t role) { 515 AvdtpTransportChannel* p_tbl; 516 uint16_t lcid; 517 518 p_tbl = avdt_ad_tc_tbl_alloc(p_ccb); 519 if (p_tbl == NULL) { 520 AVDT_TRACE_ERROR("avdt_ad_open_req: Cannot allocate p_tbl"); 521 return; 522 } 523 524 p_tbl->tcid = avdt_ad_type_to_tcid(type, p_scb); 525 AVDT_TRACE_DEBUG("avdt_ad_open_req: type: %d, role: %d, tcid:%d", type, role, 526 p_tbl->tcid); 527 528 if (type == AVDT_CHAN_SIG) { 529 /* if signaling, get mtu from registration control block */ 530 p_tbl->my_mtu = avdtp_cb.rcb.ctrl_mtu; 531 p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO; 532 } else { 533 /* otherwise get mtu from scb */ 534 p_tbl->my_mtu = p_scb->stream_config.mtu; 535 p_tbl->my_flush_to = p_scb->stream_config.flush_to; 536 537 /* also set scb_hdl in rt_tbl */ 538 avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].scb_hdl = 539 avdt_scb_to_hdl(p_scb); 540 AVDT_TRACE_DEBUG("avdtp_cb.ad.rt_tbl[%d][%d].scb_hdl = %d", 541 avdt_ccb_to_idx(p_ccb), p_tbl->tcid, 542 avdt_scb_to_hdl(p_scb)); 543 } 544 545 /* if we're acceptor, we're done; just sit back and listen */ 546 if (role == AVDT_ACP) { 547 p_tbl->state = AVDT_AD_ST_ACP; 548 } 549 /* else we're inititator, start the L2CAP connection */ 550 else { 551 p_tbl->state = AVDT_AD_ST_CONN; 552 553 /* call l2cap connect req */ 554 lcid = L2CA_ConnectReq(AVDT_PSM, p_ccb->peer_addr); 555 if (lcid != 0) { 556 /* if connect req ok, store tcid in lcid table */ 557 avdtp_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = 558 avdt_ad_tc_tbl_to_idx(p_tbl); 559 AVDT_TRACE_DEBUG("avdtp_cb.ad.lcid_tbl[%d] = %d", 560 (lcid - L2CAP_BASE_APPL_CID), 561 avdt_ad_tc_tbl_to_idx(p_tbl)); 562 563 avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid; 564 AVDT_TRACE_DEBUG("avdtp_cb.ad.rt_tbl[%d][%d].lcid = 0x%x", 565 avdt_ccb_to_idx(p_ccb), p_tbl->tcid, lcid); 566 } else { 567 /* if connect req failed, call avdt_ad_tc_close_ind() */ 568 avdt_ad_tc_close_ind(p_tbl, 0); 569 } 570 } 571 } 572 573 /******************************************************************************* 574 * 575 * Function avdt_ad_close_req 576 * 577 * Description This function is called by a CCB or SCB to close a 578 * transport channel. The function looks up the LCID for the 579 * channel and calls L2CA_DisconnectReq(). 580 * 581 * 582 * Returns Nothing. 583 * 584 ******************************************************************************/ 585 void avdt_ad_close_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb) { 586 uint8_t tcid; 587 AvdtpTransportChannel* p_tbl; 588 589 p_tbl = avdt_ad_tc_tbl_by_type(type, p_ccb, p_scb); 590 AVDT_TRACE_DEBUG("avdt_ad_close_req state: %d", p_tbl->state); 591 592 switch (p_tbl->state) { 593 case AVDT_AD_ST_UNUSED: 594 /* probably for reporting */ 595 break; 596 case AVDT_AD_ST_ACP: 597 /* if we're listening on this channel, send ourselves a close ind */ 598 avdt_ad_tc_close_ind(p_tbl, 0); 599 break; 600 default: 601 /* get tcid from type, scb */ 602 tcid = avdt_ad_type_to_tcid(type, p_scb); 603 604 /* call l2cap disconnect req */ 605 L2CA_DisconnectReq(avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid); 606 } 607 } 608