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 "data_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 
     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             /* Check the security */
    206             rc = btm_sec_mx_access_request (bd_addr, AVDT_PSM,
    207                 FALSE, BTM_SEC_PROTO_AVDT,
    208                 AVDT_CHAN_SIG,
    209                 &avdt_sec_check_complete_term, NULL);
    210             if(rc == BTM_CMD_STARTED)
    211             {
    212                 L2CA_ConnectRsp (p_ccb->peer_addr, p_tbl->id, lcid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
    213             }
    214             return;
    215         }
    216     }
    217     /* deal with simultaneous control channel connect case */
    218     else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_CONN)) != NULL)
    219     {
    220         /* reject their connection */
    221         result = L2CAP_CONN_NO_RESOURCES;
    222     }
    223     /* this must be a traffic channel; are we accepting a traffic channel
    224     ** for this ccb?
    225     */
    226     else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_MEDIA, p_ccb, AVDT_AD_ST_ACP)) != NULL)
    227     {
    228         /* yes; proceed with connection */
    229         result = L2CAP_CONN_OK;
    230     }
    231 #if AVDT_REPORTING == TRUE
    232     /* this must be a reporting channel; are we accepting a reporting channel
    233     ** for this ccb?
    234     */
    235     else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_REPORT, p_ccb, AVDT_AD_ST_ACP)) != NULL)
    236     {
    237         /* yes; proceed with connection */
    238         result = L2CAP_CONN_OK;
    239     }
    240 #endif
    241     /* else we're not listening for traffic channel; reject */
    242     else
    243     {
    244         result = L2CAP_CONN_NO_PSM;
    245     }
    246 
    247     /* Send L2CAP connect rsp */
    248     L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
    249 
    250     /* if result ok, proceed with connection */
    251     if (result == L2CAP_CONN_OK)
    252     {
    253         /* store idx in LCID table, store LCID in routing table */
    254         avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
    255         avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
    256 
    257         /* transition to configuration state */
    258         p_tbl->state = AVDT_AD_ST_CFG;
    259 
    260         /* Send L2CAP config req */
    261         memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
    262         cfg.mtu_present = TRUE;
    263         cfg.mtu = p_tbl->my_mtu;
    264         cfg.flush_to_present = TRUE;
    265         cfg.flush_to = p_tbl->my_flush_to;
    266         L2CA_ConfigReq(lcid, &cfg);
    267     }
    268 }
    269 
    270 /*******************************************************************************
    271 **
    272 ** Function         avdt_l2c_connect_cfm_cback
    273 **
    274 ** Description      This is the L2CAP connect confirm callback function.
    275 **
    276 **
    277 ** Returns          void
    278 **
    279 *******************************************************************************/
    280 void avdt_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
    281 {
    282     tAVDT_TC_TBL    *p_tbl;
    283     tL2CAP_CFG_INFO cfg;
    284     tAVDT_CCB *p_ccb;
    285 
    286     AVDT_TRACE_DEBUG("avdt_l2c_connect_cfm_cback lcid: %d, result: %d",
    287         lcid, result);
    288     /* look up info for this channel */
    289     if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
    290     {
    291         /* if in correct state */
    292         if (p_tbl->state == AVDT_AD_ST_CONN)
    293         {
    294             /* if result successful */
    295             if (result == L2CAP_CONN_OK)
    296             {
    297                 if(p_tbl->tcid != AVDT_CHAN_SIG)
    298                 {
    299                     /* set channel state */
    300                     p_tbl->state = AVDT_AD_ST_CFG;
    301 
    302                     /* Send L2CAP config req */
    303                     memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
    304                     cfg.mtu_present = TRUE;
    305                     cfg.mtu = p_tbl->my_mtu;
    306                     cfg.flush_to_present = TRUE;
    307                     cfg.flush_to = p_tbl->my_flush_to;
    308                     L2CA_ConfigReq(lcid, &cfg);
    309                 }
    310                 else
    311                 {
    312                     p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
    313                     if(p_ccb == NULL)
    314                     {
    315                         result = L2CAP_CONN_NO_RESOURCES;
    316                     }
    317                     else
    318                     {
    319                         /* set channel state */
    320                         p_tbl->state = AVDT_AD_ST_SEC_INT;
    321                         p_tbl->lcid = lcid;
    322                         p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_INT;
    323 
    324                         /* Check the security */
    325                         btm_sec_mx_access_request (p_ccb->peer_addr, AVDT_PSM,
    326                             TRUE, BTM_SEC_PROTO_AVDT,
    327                             AVDT_CHAN_SIG,
    328                             &avdt_sec_check_complete_orig, NULL);
    329                     }
    330                 }
    331             }
    332 
    333             /* failure; notify adaption that channel closed */
    334             if (result != L2CAP_CONN_OK)
    335             {
    336                 avdt_ad_tc_close_ind(p_tbl, result);
    337             }
    338         }
    339     }
    340 }
    341 
    342 /*******************************************************************************
    343 **
    344 ** Function         avdt_l2c_config_cfm_cback
    345 **
    346 ** Description      This is the L2CAP config confirm callback function.
    347 **
    348 **
    349 ** Returns          void
    350 **
    351 *******************************************************************************/
    352 void avdt_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
    353 {
    354     tAVDT_TC_TBL    *p_tbl;
    355 
    356     /* look up info for this channel */
    357     if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
    358     {
    359         /* if in correct state */
    360         if (p_tbl->state == AVDT_AD_ST_CFG)
    361         {
    362             /* if result successful */
    363             if (p_cfg->result == L2CAP_CONN_OK)
    364             {
    365                 /* update cfg_flags */
    366                 p_tbl->cfg_flags |= AVDT_L2C_CFG_CFM_DONE;
    367 
    368                 /* if configuration complete */
    369                 if (p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE)
    370                 {
    371                     avdt_ad_tc_open_ind(p_tbl);
    372                 }
    373             }
    374             /* else failure */
    375             else
    376             {
    377                 /* Send L2CAP disconnect req */
    378                 L2CA_DisconnectReq(lcid);
    379             }
    380         }
    381     }
    382 }
    383 
    384 /*******************************************************************************
    385 **
    386 ** Function         avdt_l2c_config_ind_cback
    387 **
    388 ** Description      This is the L2CAP config indication callback function.
    389 **
    390 **
    391 ** Returns          void
    392 **
    393 *******************************************************************************/
    394 void avdt_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
    395 {
    396     tAVDT_TC_TBL    *p_tbl;
    397 
    398     /* look up info for this channel */
    399     if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
    400     {
    401         /* store the mtu in tbl */
    402         if (p_cfg->mtu_present)
    403         {
    404             p_tbl->peer_mtu = p_cfg->mtu;
    405         }
    406         else
    407         {
    408             p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
    409         }
    410         AVDT_TRACE_DEBUG("peer_mtu: %d, lcid: x%x",p_tbl->peer_mtu, lcid);
    411 
    412         /* send L2CAP configure response */
    413         memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
    414         p_cfg->result = L2CAP_CFG_OK;
    415         L2CA_ConfigRsp(lcid, p_cfg);
    416 
    417         /* if first config ind */
    418         if ((p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE) == 0)
    419         {
    420             /* update cfg_flags */
    421             p_tbl->cfg_flags |= AVDT_L2C_CFG_IND_DONE;
    422 
    423             /* if configuration complete */
    424             if (p_tbl->cfg_flags & AVDT_L2C_CFG_CFM_DONE)
    425             {
    426                 avdt_ad_tc_open_ind(p_tbl);
    427             }
    428         }
    429     }
    430 }
    431 
    432 /*******************************************************************************
    433 **
    434 ** Function         avdt_l2c_disconnect_ind_cback
    435 **
    436 ** Description      This is the L2CAP disconnect indication callback function.
    437 **
    438 **
    439 ** Returns          void
    440 **
    441 *******************************************************************************/
    442 void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
    443 {
    444     tAVDT_TC_TBL    *p_tbl;
    445 
    446     AVDT_TRACE_DEBUG("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d",
    447         lcid, ack_needed);
    448     /* look up info for this channel */
    449     if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
    450     {
    451         if (ack_needed)
    452         {
    453             /* send L2CAP disconnect response */
    454             L2CA_DisconnectRsp(lcid);
    455         }
    456 
    457         avdt_ad_tc_close_ind(p_tbl, 0);
    458     }
    459 }
    460 
    461 /*******************************************************************************
    462 **
    463 ** Function         avdt_l2c_disconnect_cfm_cback
    464 **
    465 ** Description      This is the L2CAP disconnect confirm callback function.
    466 **
    467 **
    468 ** Returns          void
    469 **
    470 *******************************************************************************/
    471 void avdt_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
    472 {
    473     tAVDT_TC_TBL    *p_tbl;
    474 
    475     AVDT_TRACE_DEBUG("avdt_l2c_disconnect_cfm_cback lcid: %d, result: %d",
    476         lcid, result);
    477     /* look up info for this channel */
    478     if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
    479     {
    480         avdt_ad_tc_close_ind(p_tbl, result);
    481     }
    482 }
    483 
    484 /*******************************************************************************
    485 **
    486 ** Function         avdt_l2c_congestion_ind_cback
    487 **
    488 ** Description      This is the L2CAP congestion indication callback function.
    489 **
    490 **
    491 ** Returns          void
    492 **
    493 *******************************************************************************/
    494 void avdt_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
    495 {
    496     tAVDT_TC_TBL    *p_tbl;
    497 
    498     /* look up info for this channel */
    499     if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
    500     {
    501         avdt_ad_tc_cong_ind(p_tbl, is_congested);
    502     }
    503 }
    504 
    505 /*******************************************************************************
    506 **
    507 ** Function         avdt_l2c_data_ind_cback
    508 **
    509 ** Description      This is the L2CAP data indication callback function.
    510 **
    511 **
    512 ** Returns          void
    513 **
    514 *******************************************************************************/
    515 void avdt_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
    516 {
    517     tAVDT_TC_TBL    *p_tbl;
    518 
    519     /* look up info for this channel */
    520     if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
    521     {
    522         avdt_ad_tc_data_ind(p_tbl, p_buf);
    523     }
    524     else /* prevent buffer leak */
    525         GKI_freebuf(p_buf);
    526 }
    527 
    528