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