Home | History | Annotate | Download | only in avdt
      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 AVDTP adaption layer module interfaces to L2CAP
     22  *
     23  ******************************************************************************/
     24 
     25 #include <string.h>
     26 #include "bt_types.h"
     27 #include "bt_target.h"
     28 #include "bt_utils.h"
     29 #include "avdt_api.h"
     30 #include "avdtc_api.h"
     31 #include "avdt_int.h"
     32 #include "l2c_api.h"
     33 #include "l2cdefs.h"
     34 #include "btm_api.h"
     35 #include "btm_int.h"
     36 #include "device/include/interop.h"
     37 
     38 /* callback function declarations */
     39 void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
     40 void avdt_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
     41 void avdt_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
     42 void avdt_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
     43 void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
     44 void avdt_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
     45 void avdt_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
     46 void avdt_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
     47 
     48 /* L2CAP callback function structure */
     49 const tL2CAP_APPL_INFO avdt_l2c_appl = {
     50     avdt_l2c_connect_ind_cback,
     51     avdt_l2c_connect_cfm_cback,
     52     NULL,
     53     avdt_l2c_config_ind_cback,
     54     avdt_l2c_config_cfm_cback,
     55     avdt_l2c_disconnect_ind_cback,
     56     avdt_l2c_disconnect_cfm_cback,
     57     NULL,
     58     avdt_l2c_data_ind_cback,
     59     avdt_l2c_congestion_ind_cback,
     60     NULL                /* tL2CA_TX_COMPLETE_CB */
     61 };
     62 
     63 /*******************************************************************************
     64 **
     65 ** Function         avdt_sec_check_complete_term
     66 **
     67 ** Description      The function called when Security Manager finishes
     68 **                  verification of the service side connection
     69 **
     70 ** Returns          void
     71 **
     72 *******************************************************************************/
     73 static void avdt_sec_check_complete_term (BD_ADDR bd_addr, tBT_TRANSPORT transport,
     74                                                  void *p_ref_data, UINT8 res)
     75 {
     76     tAVDT_CCB       *p_ccb = NULL;
     77     tL2CAP_CFG_INFO cfg;
     78     tAVDT_TC_TBL    *p_tbl;
     79     UNUSED(p_ref_data);
     80 
     81     AVDT_TRACE_DEBUG("avdt_sec_check_complete_term res: %d", res);
     82     if (!bd_addr)
     83     {
     84         AVDT_TRACE_WARNING("avdt_sec_check_complete_term: NULL BD_ADDR");
     85         return;
     86 
     87     }
     88     p_ccb = avdt_ccb_by_bd(bd_addr);
     89 
     90     p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_ACP);
     91     if (p_tbl == NULL)
     92         return;
     93 
     94     if (res == BTM_SUCCESS)
     95     {
     96         /* Send response to the L2CAP layer. */
     97         L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK, L2CAP_CONN_OK);
     98 
     99         /* store idx in LCID table, store LCID in routing table */
    100         avdt_cb.ad.lcid_tbl[p_tbl->lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
    101         avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = p_tbl->lcid;
    102 
    103         /* transition to configuration state */
    104         p_tbl->state = AVDT_AD_ST_CFG;
    105 
    106         /* Send L2CAP config req */
    107         memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
    108         cfg.mtu_present = TRUE;
    109         cfg.mtu = p_tbl->my_mtu;
    110         cfg.flush_to_present = TRUE;
    111         cfg.flush_to = p_tbl->my_flush_to;
    112         L2CA_ConfigReq(p_tbl->lcid, &cfg);
    113     }
    114     else
    115     {
    116         L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
    117         avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
    118     }
    119 }
    120 
    121 /*******************************************************************************
    122 **
    123 ** Function         avdt_sec_check_complete_orig
    124 **
    125 ** Description      The function called when Security Manager finishes
    126 **                  verification of the service side connection
    127 **
    128 ** Returns          void
    129 **
    130 *******************************************************************************/
    131 static void avdt_sec_check_complete_orig (BD_ADDR bd_addr, tBT_TRANSPORT trasnport,
    132                                                 void *p_ref_data, UINT8 res)
    133 {
    134     tAVDT_CCB       *p_ccb = NULL;
    135     tL2CAP_CFG_INFO cfg;
    136     tAVDT_TC_TBL    *p_tbl;
    137     UNUSED(p_ref_data);
    138 
    139     AVDT_TRACE_DEBUG("avdt_sec_check_complete_orig res: %d", res);
    140     if (bd_addr)
    141         p_ccb = avdt_ccb_by_bd(bd_addr);
    142     p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_INT);
    143     if(p_tbl == NULL)
    144         return;
    145 
    146     if( res == BTM_SUCCESS )
    147     {
    148         /* set channel state */
    149         p_tbl->state = AVDT_AD_ST_CFG;
    150 
    151         /* Send L2CAP config req */
    152         memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
    153         cfg.mtu_present = TRUE;
    154         cfg.mtu = p_tbl->my_mtu;
    155         cfg.flush_to_present = TRUE;
    156         cfg.flush_to = p_tbl->my_flush_to;
    157         L2CA_ConfigReq(p_tbl->lcid, &cfg);
    158     }
    159     else
    160     {
    161         L2CA_DisconnectReq (p_tbl->lcid);
    162         avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
    163     }
    164 }
    165 /*******************************************************************************
    166 **
    167 ** Function         avdt_l2c_connect_ind_cback
    168 **
    169 ** Description      This is the L2CAP connect indication callback function.
    170 **
    171 **
    172 ** Returns          void
    173 **
    174 *******************************************************************************/
    175 void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
    176 {
    177     tAVDT_CCB       *p_ccb;
    178     tAVDT_TC_TBL    *p_tbl = NULL;
    179     UINT16          result;
    180     tL2CAP_CFG_INFO cfg;
    181     tBTM_STATUS rc;
    182     UNUSED(psm);
    183 
    184     /* do we already have a control channel for this peer? */
    185     if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
    186     {
    187         /* no, allocate ccb */
    188         if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
    189         {
    190             /* no ccb available, reject L2CAP connection */
    191             result = L2CAP_CONN_NO_RESOURCES;
    192         }
    193         else
    194         {
    195             /* allocate and set up entry; first channel is always signaling */
    196             p_tbl = avdt_ad_tc_tbl_alloc(p_ccb);
    197             p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
    198             p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
    199             p_tbl->tcid = AVDT_CHAN_SIG;
    200             p_tbl->lcid = lcid;
    201             p_tbl->id   = id;
    202             p_tbl->state = AVDT_AD_ST_SEC_ACP;
    203             p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_ACP;
    204 
    205             if (interop_match_addr(INTEROP_2MBPS_LINK_ONLY, (const bt_bdaddr_t *)&bd_addr)) {
    206                 // Disable 3DH packets for AVDT ACL to improve sensitivity on HS
    207                 tACL_CONN *p_acl_cb = btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR);
    208                 btm_set_packet_types(p_acl_cb, (btm_cb.btm_acl_pkt_types_supported |
    209                                                 HCI_PKT_TYPES_MASK_NO_3_DH1 |
    210                                                 HCI_PKT_TYPES_MASK_NO_3_DH3 |
    211                                                 HCI_PKT_TYPES_MASK_NO_3_DH5));
    212             }
    213 
    214             /* Check the security */
    215             rc = btm_sec_mx_access_request (bd_addr, AVDT_PSM,
    216                 FALSE, BTM_SEC_PROTO_AVDT,
    217                 AVDT_CHAN_SIG,
    218                 &avdt_sec_check_complete_term, NULL);
    219             if(rc == BTM_CMD_STARTED)
    220             {
    221                 L2CA_ConnectRsp (p_ccb->peer_addr, p_tbl->id, lcid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
    222             }
    223             return;
    224         }
    225     }
    226     /* deal with simultaneous control channel connect case */
    227     else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_CONN)) != NULL)
    228     {
    229         /* reject their connection */
    230         result = L2CAP_CONN_NO_RESOURCES;
    231     }
    232     /* this must be a traffic channel; are we accepting a traffic channel
    233     ** for this ccb?
    234     */
    235     else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_MEDIA, p_ccb, AVDT_AD_ST_ACP)) != NULL)
    236     {
    237         /* yes; proceed with connection */
    238         result = L2CAP_CONN_OK;
    239     }
    240 #if AVDT_REPORTING == TRUE
    241     /* this must be a reporting channel; are we accepting a reporting channel
    242     ** for this ccb?
    243     */
    244     else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_REPORT, p_ccb, AVDT_AD_ST_ACP)) != NULL)
    245     {
    246         /* yes; proceed with connection */
    247         result = L2CAP_CONN_OK;
    248     }
    249 #endif
    250     /* else we're not listening for traffic channel; reject */
    251     else
    252     {
    253         result = L2CAP_CONN_NO_PSM;
    254     }
    255 
    256     /* Send L2CAP connect rsp */
    257     L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
    258 
    259     /* if result ok, proceed with connection */
    260     if (result == L2CAP_CONN_OK)
    261     {
    262         /* store idx in LCID table, store LCID in routing table */
    263         avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
    264         avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
    265 
    266         /* transition to configuration state */
    267         p_tbl->state = AVDT_AD_ST_CFG;
    268 
    269         /* Send L2CAP config req */
    270         memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
    271         cfg.mtu_present = TRUE;
    272         cfg.mtu = p_tbl->my_mtu;
    273         cfg.flush_to_present = TRUE;
    274         cfg.flush_to = p_tbl->my_flush_to;
    275         L2CA_ConfigReq(lcid, &cfg);
    276     }
    277 }
    278 
    279 /*******************************************************************************
    280 **
    281 ** Function         avdt_l2c_connect_cfm_cback
    282 **
    283 ** Description      This is the L2CAP connect confirm callback function.
    284 **
    285 **
    286 ** Returns          void
    287 **
    288 *******************************************************************************/
    289 void avdt_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
    290 {
    291     tAVDT_TC_TBL    *p_tbl;
    292     tL2CAP_CFG_INFO cfg;
    293     tAVDT_CCB *p_ccb;
    294 
    295     AVDT_TRACE_DEBUG("avdt_l2c_connect_cfm_cback lcid: %d, result: %d",
    296         lcid, result);
    297     /* look up info for this channel */
    298     if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
    299     {
    300         /* if in correct state */
    301         if (p_tbl->state == AVDT_AD_ST_CONN)
    302         {
    303             /* if result successful */
    304             if (result == L2CAP_CONN_OK)
    305             {
    306                 if(p_tbl->tcid != AVDT_CHAN_SIG)
    307                 {
    308                     /* set channel state */
    309                     p_tbl->state = AVDT_AD_ST_CFG;
    310 
    311                     /* Send L2CAP config req */
    312                     memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
    313                     cfg.mtu_present = TRUE;
    314                     cfg.mtu = p_tbl->my_mtu;
    315                     cfg.flush_to_present = TRUE;
    316                     cfg.flush_to = p_tbl->my_flush_to;
    317                     L2CA_ConfigReq(lcid, &cfg);
    318                 }
    319                 else
    320                 {
    321                     p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
    322                     if(p_ccb == NULL)
    323                     {
    324                         result = L2CAP_CONN_NO_RESOURCES;
    325                     }
    326                     else
    327                     {
    328                         /* set channel state */
    329                         p_tbl->state = AVDT_AD_ST_SEC_INT;
    330                         p_tbl->lcid = lcid;
    331                         p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_INT;
    332 
    333                         if (interop_match_addr(INTEROP_2MBPS_LINK_ONLY, (const bt_bdaddr_t *) &p_ccb->peer_addr)) {
    334                             // Disable 3DH packets for AVDT ACL to improve sensitivity on HS
    335                             tACL_CONN *p_acl_cb = btm_bda_to_acl(p_ccb->peer_addr, BT_TRANSPORT_BR_EDR);
    336                             btm_set_packet_types(p_acl_cb, (btm_cb.btm_acl_pkt_types_supported |
    337                                                             HCI_PKT_TYPES_MASK_NO_3_DH1 |
    338                                                             HCI_PKT_TYPES_MASK_NO_3_DH3 |
    339                                                             HCI_PKT_TYPES_MASK_NO_3_DH5));
    340                         }
    341 
    342                         /* Check the security */
    343                         btm_sec_mx_access_request (p_ccb->peer_addr, AVDT_PSM,
    344                             TRUE, BTM_SEC_PROTO_AVDT,
    345                             AVDT_CHAN_SIG,
    346                             &avdt_sec_check_complete_orig, NULL);
    347                     }
    348                 }
    349             }
    350 
    351             /* failure; notify adaption that channel closed */
    352             if (result != L2CAP_CONN_OK)
    353             {
    354                 avdt_ad_tc_close_ind(p_tbl, result);
    355             }
    356         }
    357     }
    358 }
    359 
    360 /*******************************************************************************
    361 **
    362 ** Function         avdt_l2c_config_cfm_cback
    363 **
    364 ** Description      This is the L2CAP config confirm callback function.
    365 **
    366 **
    367 ** Returns          void
    368 **
    369 *******************************************************************************/
    370 void avdt_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
    371 {
    372     tAVDT_TC_TBL    *p_tbl;
    373 
    374     /* look up info for this channel */
    375     if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
    376     {
    377         p_tbl->lcid = lcid;
    378 
    379         /* if in correct state */
    380         if (p_tbl->state == AVDT_AD_ST_CFG)
    381         {
    382             /* if result successful */
    383             if (p_cfg->result == L2CAP_CONN_OK)
    384             {
    385                 /* update cfg_flags */
    386                 p_tbl->cfg_flags |= AVDT_L2C_CFG_CFM_DONE;
    387 
    388                 /* if configuration complete */
    389                 if (p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE)
    390                 {
    391                     avdt_ad_tc_open_ind(p_tbl);
    392                 }
    393             }
    394             /* else failure */
    395             else
    396             {
    397                 /* Send L2CAP disconnect req */
    398                 L2CA_DisconnectReq(lcid);
    399             }
    400         }
    401     }
    402 }
    403 
    404 /*******************************************************************************
    405 **
    406 ** Function         avdt_l2c_config_ind_cback
    407 **
    408 ** Description      This is the L2CAP config indication callback function.
    409 **
    410 **
    411 ** Returns          void
    412 **
    413 *******************************************************************************/
    414 void avdt_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
    415 {
    416     tAVDT_TC_TBL    *p_tbl;
    417 
    418     /* look up info for this channel */
    419     if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
    420     {
    421         /* store the mtu in tbl */
    422         if (p_cfg->mtu_present)
    423         {
    424             p_tbl->peer_mtu = p_cfg->mtu;
    425         }
    426         else
    427         {
    428             p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
    429         }
    430         AVDT_TRACE_DEBUG("peer_mtu: %d, lcid: x%x",p_tbl->peer_mtu, lcid);
    431 
    432         /* send L2CAP configure response */
    433         memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
    434         p_cfg->result = L2CAP_CFG_OK;
    435         L2CA_ConfigRsp(lcid, p_cfg);
    436 
    437         /* if first config ind */
    438         if ((p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE) == 0)
    439         {
    440             /* update cfg_flags */
    441             p_tbl->cfg_flags |= AVDT_L2C_CFG_IND_DONE;
    442 
    443             /* if configuration complete */
    444             if (p_tbl->cfg_flags & AVDT_L2C_CFG_CFM_DONE)
    445             {
    446                 avdt_ad_tc_open_ind(p_tbl);
    447             }
    448         }
    449     }
    450 }
    451 
    452 /*******************************************************************************
    453 **
    454 ** Function         avdt_l2c_disconnect_ind_cback
    455 **
    456 ** Description      This is the L2CAP disconnect indication callback function.
    457 **
    458 **
    459 ** Returns          void
    460 **
    461 *******************************************************************************/
    462 void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
    463 {
    464     tAVDT_TC_TBL    *p_tbl;
    465 
    466     AVDT_TRACE_DEBUG("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d",
    467         lcid, ack_needed);
    468     /* look up info for this channel */
    469     if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
    470     {
    471         if (ack_needed)
    472         {
    473             /* send L2CAP disconnect response */
    474             L2CA_DisconnectRsp(lcid);
    475         }
    476 
    477         avdt_ad_tc_close_ind(p_tbl, 0);
    478     }
    479 }
    480 
    481 /*******************************************************************************
    482 **
    483 ** Function         avdt_l2c_disconnect_cfm_cback
    484 **
    485 ** Description      This is the L2CAP disconnect confirm callback function.
    486 **
    487 **
    488 ** Returns          void
    489 **
    490 *******************************************************************************/
    491 void avdt_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
    492 {
    493     tAVDT_TC_TBL    *p_tbl;
    494 
    495     AVDT_TRACE_DEBUG("avdt_l2c_disconnect_cfm_cback lcid: %d, result: %d",
    496         lcid, result);
    497     /* look up info for this channel */
    498     if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
    499     {
    500         avdt_ad_tc_close_ind(p_tbl, result);
    501     }
    502 }
    503 
    504 /*******************************************************************************
    505 **
    506 ** Function         avdt_l2c_congestion_ind_cback
    507 **
    508 ** Description      This is the L2CAP congestion indication callback function.
    509 **
    510 **
    511 ** Returns          void
    512 **
    513 *******************************************************************************/
    514 void avdt_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
    515 {
    516     tAVDT_TC_TBL    *p_tbl;
    517 
    518     /* look up info for this channel */
    519     if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
    520     {
    521         avdt_ad_tc_cong_ind(p_tbl, is_congested);
    522     }
    523 }
    524 
    525 /*******************************************************************************
    526 **
    527 ** Function         avdt_l2c_data_ind_cback
    528 **
    529 ** Description      This is the L2CAP data indication callback function.
    530 **
    531 **
    532 ** Returns          void
    533 **
    534 *******************************************************************************/
    535 void avdt_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
    536 {
    537     tAVDT_TC_TBL    *p_tbl;
    538 
    539     /* look up info for this channel */
    540     if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
    541     {
    542         avdt_ad_tc_data_ind(p_tbl, p_buf);
    543     }
    544     else /* prevent buffer leak */
    545         osi_free(p_buf);
    546 }
    547 
    548