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