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