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