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