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