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