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