Home | History | Annotate | Download | only in avct
      1 /******************************************************************************
      2  *
      3  *  Copyright 2003-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 AVCTP module interfaces to L2CAP
     22  *
     23  ******************************************************************************/
     24 
     25 #include <string.h>
     26 #include "avct_api.h"
     27 #include "avct_int.h"
     28 #include "bt_target.h"
     29 #include "bt_types.h"
     30 #include "bt_utils.h"
     31 #include "l2c_api.h"
     32 #include "l2cdefs.h"
     33 #include "osi/include/osi.h"
     34 
     35 /* Configuration flags. */
     36 #define AVCT_L2C_CFG_IND_DONE (1 << 0)
     37 #define AVCT_L2C_CFG_CFM_DONE (1 << 1)
     38 
     39 /* callback function declarations */
     40 void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
     41                                 uint16_t psm, uint8_t id);
     42 void avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result);
     43 void avct_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
     44 void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
     45 void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
     46 void avct_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result);
     47 void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested);
     48 void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf);
     49 
     50 /* L2CAP callback function structure */
     51 const tL2CAP_APPL_INFO avct_l2c_appl = {avct_l2c_connect_ind_cback,
     52                                         avct_l2c_connect_cfm_cback,
     53                                         NULL,
     54                                         avct_l2c_config_ind_cback,
     55                                         avct_l2c_config_cfm_cback,
     56                                         avct_l2c_disconnect_ind_cback,
     57                                         avct_l2c_disconnect_cfm_cback,
     58                                         NULL,
     59                                         avct_l2c_data_ind_cback,
     60                                         avct_l2c_congestion_ind_cback,
     61                                         NULL, /* tL2CA_TX_COMPLETE_CB */
     62                                         NULL /* tL2CA_CREDITS_RECEIVED_CB */};
     63 
     64 /*******************************************************************************
     65  *
     66  * Function         avct_l2c_is_passive
     67  *
     68  * Description      check is the CCB associated with the given LCB was created
     69  *                  as passive
     70  *
     71  * Returns          true, if the given LCB is created as AVCT_PASSIVE
     72  *
     73  ******************************************************************************/
     74 static bool avct_l2c_is_passive(tAVCT_LCB* p_lcb) {
     75   bool is_passive = false;
     76   tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
     77   int i;
     78 
     79   for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
     80     if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
     81       AVCT_TRACE_DEBUG("avct_l2c_is_ct control:x%x", p_ccb->cc.control);
     82       if (p_ccb->cc.control & AVCT_PASSIVE) {
     83         is_passive = true;
     84         break;
     85       }
     86     }
     87   }
     88   return is_passive;
     89 }
     90 
     91 /*******************************************************************************
     92  *
     93  * Function         avct_l2c_connect_ind_cback
     94  *
     95  * Description      This is the L2CAP connect indication callback function.
     96  *
     97  *
     98  * Returns          void
     99  *
    100  ******************************************************************************/
    101 void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
    102                                 UNUSED_ATTR uint16_t psm, uint8_t id) {
    103   tAVCT_LCB* p_lcb;
    104   uint16_t result = L2CAP_CONN_OK;
    105   tL2CAP_CFG_INFO cfg;
    106 
    107   /* do we already have a channel for this peer? */
    108   p_lcb = avct_lcb_by_bd(bd_addr);
    109   if (p_lcb == NULL) {
    110     /* no, allocate lcb */
    111     p_lcb = avct_lcb_alloc(bd_addr);
    112     if (p_lcb == NULL) {
    113       /* no ccb available, reject L2CAP connection */
    114       result = L2CAP_CONN_NO_RESOURCES;
    115     }
    116   }
    117   /* else we already have a channel for this peer */
    118   else {
    119     if (!avct_l2c_is_passive(p_lcb) || (p_lcb->ch_state == AVCT_CH_OPEN)) {
    120       /* this LCB included CT role - reject */
    121       result = L2CAP_CONN_NO_RESOURCES;
    122     } else {
    123       /* TG role only - accept the connection from CT. move the channel ID to
    124        * the conflict list */
    125       p_lcb->conflict_lcid = p_lcb->ch_lcid;
    126       AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback conflict_lcid:0x%x",
    127                        p_lcb->conflict_lcid);
    128     }
    129   }
    130 
    131   if (p_lcb) {
    132     AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback: 0x%x, res: %d, ch_state: %d",
    133                      lcid, result, p_lcb->ch_state);
    134   }
    135   /* Send L2CAP connect rsp */
    136   L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
    137 
    138   /* if result ok, proceed with connection */
    139   if (result == L2CAP_CONN_OK) {
    140     /* store LCID */
    141     p_lcb->ch_lcid = lcid;
    142 
    143     /* transition to configuration state */
    144     p_lcb->ch_state = AVCT_CH_CFG;
    145 
    146     /* Send L2CAP config req */
    147     memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
    148     cfg.mtu_present = true;
    149     cfg.mtu = avct_cb.mtu;
    150     L2CA_ConfigReq(lcid, &cfg);
    151     AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
    152   }
    153 
    154   if (p_lcb) AVCT_TRACE_DEBUG("ch_state cni: %d ", p_lcb->ch_state);
    155 }
    156 
    157 /*******************************************************************************
    158  *
    159  * Function         avct_l2c_connect_cfm_cback
    160  *
    161  * Description      This is the L2CAP connect confirm callback function.
    162  *
    163  *
    164  * Returns          void
    165  *
    166  ******************************************************************************/
    167 void avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result) {
    168   tAVCT_LCB* p_lcb;
    169   tL2CAP_CFG_INFO cfg;
    170 
    171   /* look up lcb for this channel */
    172   p_lcb = avct_lcb_by_lcid(lcid);
    173   if (p_lcb != NULL) {
    174     AVCT_TRACE_DEBUG(
    175         "avct_l2c_connect_cfm_cback lcid:0x%x result: %d ch_state: %d, "
    176         "conflict_lcid:0x%x",
    177         lcid, result, p_lcb->ch_state, p_lcb->conflict_lcid);
    178     /* if in correct state */
    179     if (p_lcb->ch_state == AVCT_CH_CONN) {
    180       /* if result successful */
    181       if (result == L2CAP_CONN_OK) {
    182         /* set channel state */
    183         p_lcb->ch_state = AVCT_CH_CFG;
    184 
    185         /* Send L2CAP config req */
    186         memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
    187         cfg.mtu_present = true;
    188         cfg.mtu = avct_cb.mtu;
    189         L2CA_ConfigReq(lcid, &cfg);
    190         AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
    191       }
    192       /* else failure */
    193       else {
    194         AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback conflict_lcid:0x%x",
    195                          p_lcb->conflict_lcid);
    196         if (p_lcb->conflict_lcid == lcid) {
    197           p_lcb->conflict_lcid = 0;
    198         } else {
    199           tAVCT_LCB_EVT avct_lcb_evt;
    200           avct_lcb_evt.result = result;
    201           avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt);
    202         }
    203       }
    204     } else if (p_lcb->conflict_lcid == lcid) {
    205       /* we must be in AVCT_CH_CFG state for the ch_lcid channel */
    206       AVCT_TRACE_DEBUG(
    207           "avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x",
    208           p_lcb->ch_state, p_lcb->conflict_lcid);
    209       if (result == L2CAP_CONN_OK) {
    210         /* just in case the peer also accepts our connection - Send L2CAP
    211          * disconnect req */
    212         L2CA_DisconnectReq(lcid);
    213       }
    214       p_lcb->conflict_lcid = 0;
    215     }
    216     AVCT_TRACE_DEBUG("ch_state cnc: %d ", p_lcb->ch_state);
    217   }
    218 }
    219 
    220 /*******************************************************************************
    221  *
    222  * Function         avct_l2c_config_cfm_cback
    223  *
    224  * Description      This is the L2CAP config confirm callback function.
    225  *
    226  *
    227  * Returns          void
    228  *
    229  ******************************************************************************/
    230 void avct_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
    231   tAVCT_LCB* p_lcb;
    232 
    233   /* look up lcb for this channel */
    234   p_lcb = avct_lcb_by_lcid(lcid);
    235   if (p_lcb != NULL) {
    236     AVCT_TRACE_DEBUG("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d, res: %d",
    237                      lcid, p_lcb->ch_state, p_cfg->result);
    238     /* if in correct state */
    239     if (p_lcb->ch_state == AVCT_CH_CFG) {
    240       /* if result successful */
    241       if (p_cfg->result == L2CAP_CFG_OK) {
    242         /* update flags */
    243         p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
    244 
    245         /* if configuration complete */
    246         if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) {
    247           p_lcb->ch_state = AVCT_CH_OPEN;
    248           avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
    249         }
    250       }
    251       /* else failure */
    252       else {
    253         AVCT_TRACE_DEBUG(
    254             "ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ",
    255             p_lcb->ch_state);
    256         /* store result value */
    257         p_lcb->ch_result = p_cfg->result;
    258 
    259         /* Send L2CAP disconnect req */
    260         L2CA_DisconnectReq(lcid);
    261       }
    262     }
    263     AVCT_TRACE_DEBUG("ch_state cfc: %d ", p_lcb->ch_state);
    264   }
    265 }
    266 
    267 /*******************************************************************************
    268  *
    269  * Function         avct_l2c_config_ind_cback
    270  *
    271  * Description      This is the L2CAP config indication callback function.
    272  *
    273  *
    274  * Returns          void
    275  *
    276  ******************************************************************************/
    277 void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
    278   tAVCT_LCB* p_lcb;
    279 
    280   /* look up lcb for this channel */
    281   p_lcb = avct_lcb_by_lcid(lcid);
    282   if (p_lcb != NULL) {
    283     AVCT_TRACE_DEBUG("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid,
    284                      p_lcb->ch_state);
    285     /* store the mtu in tbl */
    286     if (p_cfg->mtu_present) {
    287       p_lcb->peer_mtu = p_cfg->mtu;
    288     } else {
    289       p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
    290     }
    291 
    292     /* send L2CAP configure response */
    293     memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
    294     p_cfg->result = L2CAP_CFG_OK;
    295     L2CA_ConfigRsp(lcid, p_cfg);
    296 
    297     /* if first config ind */
    298     if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0) {
    299       /* update flags */
    300       p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
    301 
    302       /* if configuration complete */
    303       if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE) {
    304         p_lcb->ch_state = AVCT_CH_OPEN;
    305         avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
    306       }
    307     }
    308     AVCT_TRACE_DEBUG("ch_state cfi: %d ", p_lcb->ch_state);
    309   }
    310 }
    311 
    312 /*******************************************************************************
    313  *
    314  * Function         avct_l2c_disconnect_ind_cback
    315  *
    316  * Description      This is the L2CAP disconnect indication callback function.
    317  *
    318  *
    319  * Returns          void
    320  *
    321  ******************************************************************************/
    322 void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
    323   tAVCT_LCB* p_lcb;
    324   uint16_t result = AVCT_RESULT_FAIL;
    325 
    326   /* look up lcb for this channel */
    327   p_lcb = avct_lcb_by_lcid(lcid);
    328   if (p_lcb != NULL) {
    329     AVCT_TRACE_DEBUG("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid,
    330                      p_lcb->ch_state);
    331     if (ack_needed) {
    332       /* send L2CAP disconnect response */
    333       L2CA_DisconnectRsp(lcid);
    334     }
    335 
    336     tAVCT_LCB_EVT avct_lcb_evt;
    337     avct_lcb_evt.result = result;
    338     avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt);
    339     AVCT_TRACE_DEBUG("ch_state di: %d ", p_lcb->ch_state);
    340   }
    341 }
    342 
    343 /*******************************************************************************
    344  *
    345  * Function         avct_l2c_disconnect_cfm_cback
    346  *
    347  * Description      This is the L2CAP disconnect confirm callback function.
    348  *
    349  *
    350  * Returns          void
    351  *
    352  ******************************************************************************/
    353 void avct_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result) {
    354   tAVCT_LCB* p_lcb;
    355   uint16_t res;
    356 
    357   /* look up lcb for this channel */
    358   p_lcb = avct_lcb_by_lcid(lcid);
    359   if (p_lcb != NULL) {
    360     AVCT_TRACE_DEBUG(
    361         "avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d", lcid,
    362         p_lcb->ch_state, result);
    363     /* result value may be previously stored */
    364     res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
    365     p_lcb->ch_result = 0;
    366 
    367     tAVCT_LCB_EVT avct_lcb_evt;
    368     avct_lcb_evt.result = res;
    369     avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt);
    370     AVCT_TRACE_DEBUG("ch_state dc: %d ", p_lcb->ch_state);
    371   }
    372 }
    373 
    374 /*******************************************************************************
    375  *
    376  * Function         avct_l2c_congestion_ind_cback
    377  *
    378  * Description      This is the L2CAP congestion indication callback function.
    379  *
    380  *
    381  * Returns          void
    382  *
    383  ******************************************************************************/
    384 void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested) {
    385   tAVCT_LCB* p_lcb;
    386 
    387   AVCT_TRACE_DEBUG("avct_l2c_congestion_ind_cback: 0x%x", lcid);
    388   /* look up lcb for this channel */
    389   p_lcb = avct_lcb_by_lcid(lcid);
    390   if (p_lcb != NULL) {
    391     tAVCT_LCB_EVT avct_lcb_evt;
    392     avct_lcb_evt.cong = is_congested;
    393     avct_lcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, &avct_lcb_evt);
    394   }
    395 }
    396 
    397 /*******************************************************************************
    398  *
    399  * Function         avct_l2c_data_ind_cback
    400  *
    401  * Description      This is the L2CAP data indication callback function.
    402  *
    403  *
    404  * Returns          void
    405  *
    406  ******************************************************************************/
    407 void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
    408   tAVCT_LCB* p_lcb;
    409 
    410   AVCT_TRACE_DEBUG("avct_l2c_data_ind_cback: 0x%x", lcid);
    411   /* look up lcb for this channel */
    412   p_lcb = avct_lcb_by_lcid(lcid);
    413   if (p_lcb != NULL) {
    414     avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT*)&p_buf);
    415   } else /* prevent buffer leak */
    416   {
    417     AVCT_TRACE_WARNING("ERROR -> avct_l2c_data_ind_cback drop buffer");
    418     osi_free(p_buf);
    419   }
    420 }
    421