• 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 <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