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