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