Home | History | Annotate | Download | only in mcap
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2009-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 is the implementation file for the MCAP at L2CAP Interface.
     22  *
     23  ******************************************************************************/
     24 #include <string.h>
     25 
     26 #include "bt_target.h"
     27 #include "btm_api.h"
     28 #include "btm_int.h"
     29 #include "mca_api.h"
     30 #include "mca_defs.h"
     31 #include "mca_int.h"
     32 
     33 
     34 /* L2CAP callback function structure */
     35 const tL2CAP_APPL_INFO mca_l2c_int_appl =
     36 {
     37     NULL,
     38     mca_l2c_connect_cfm_cback,
     39     NULL,
     40     mca_l2c_config_ind_cback,
     41     mca_l2c_config_cfm_cback,
     42     mca_l2c_disconnect_ind_cback,
     43     mca_l2c_disconnect_cfm_cback,
     44     NULL,
     45     mca_l2c_data_ind_cback,
     46     mca_l2c_congestion_ind_cback,
     47 	NULL
     48 };
     49 
     50 /* Control channel eL2CAP default options */
     51 const tL2CAP_FCR_OPTS mca_l2c_fcr_opts_def =
     52 {
     53     L2CAP_FCR_ERTM_MODE,            /* Mandatory for MCAP */
     54     MCA_FCR_OPT_TX_WINDOW_SIZE,     /* Tx window size */
     55     MCA_FCR_OPT_MAX_TX_B4_DISCNT,   /* Maximum transmissions before disconnecting */
     56     MCA_FCR_OPT_RETX_TOUT,          /* Retransmission timeout (2 secs) */
     57     MCA_FCR_OPT_MONITOR_TOUT,       /* Monitor timeout (12 secs) */
     58     MCA_FCR_OPT_MPS_SIZE            /* MPS segment size */
     59 };
     60 
     61 
     62 /*******************************************************************************
     63 **
     64 ** Function         mca_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 mca_sec_check_complete_term (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
     73 {
     74     tMCA_TC_TBL     *p_tbl = (tMCA_TC_TBL *)p_ref_data;
     75     tL2CAP_CFG_INFO cfg;
     76     tL2CAP_ERTM_INFO ertm_info;
     77 
     78     MCA_TRACE_DEBUG1("mca_sec_check_complete_term res: %d", res);
     79 
     80     if ( res == BTM_SUCCESS )
     81     {
     82         MCA_TRACE_DEBUG2 ("lcid:x%x id:x%x", p_tbl->lcid, p_tbl->id);
     83         /* Set the FCR options: control channel mandates ERTM */
     84         ertm_info.preferred_mode    = mca_l2c_fcr_opts_def.mode;
     85         ertm_info.allowed_modes     = L2CAP_FCR_CHAN_OPT_ERTM;
     86         ertm_info.user_rx_pool_id   = MCA_USER_RX_POOL_ID;
     87         ertm_info.user_tx_pool_id   = MCA_USER_TX_POOL_ID;
     88         ertm_info.fcr_rx_pool_id    = MCA_FCR_RX_POOL_ID;
     89         ertm_info.fcr_tx_pool_id    = MCA_FCR_TX_POOL_ID;
     90         /* Send response to the L2CAP layer. */
     91         L2CA_ErtmConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK, L2CAP_CONN_OK, &ertm_info);
     92 
     93         /* transition to configuration state */
     94         p_tbl->state = MCA_TC_ST_CFG;
     95 
     96         /* Send L2CAP config req */
     97         mca_set_cfg_by_tbl (&cfg, p_tbl);
     98         L2CA_ConfigReq(p_tbl->lcid, &cfg);
     99     }
    100     else
    101     {
    102         L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
    103         mca_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
    104     }
    105 }
    106 
    107 /*******************************************************************************
    108 **
    109 ** Function         mca_sec_check_complete_orig
    110 **
    111 ** Description      The function called when Security Manager finishes
    112 **                  verification of the service side connection
    113 **
    114 ** Returns          void
    115 **
    116 *******************************************************************************/
    117 static void mca_sec_check_complete_orig (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
    118 {
    119     tMCA_TC_TBL     *p_tbl = (tMCA_TC_TBL *)p_ref_data;
    120     tL2CAP_CFG_INFO cfg;
    121 
    122     MCA_TRACE_DEBUG1("mca_sec_check_complete_orig res: %d", res);
    123 
    124     if ( res == BTM_SUCCESS )
    125     {
    126         /* set channel state */
    127         p_tbl->state = MCA_TC_ST_CFG;
    128 
    129         /* Send L2CAP config req */
    130         mca_set_cfg_by_tbl (&cfg, p_tbl);
    131         L2CA_ConfigReq(p_tbl->lcid, &cfg);
    132     }
    133     else
    134     {
    135         L2CA_DisconnectReq (p_tbl->lcid);
    136         mca_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
    137     }
    138 }
    139 /*******************************************************************************
    140 **
    141 ** Function         mca_l2c_cconn_ind_cback
    142 **
    143 ** Description      This is the L2CAP connect indication callback function.
    144 **
    145 ** Returns          void
    146 **
    147 *******************************************************************************/
    148 void mca_l2c_cconn_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
    149 {
    150     tMCA_HANDLE handle = mca_handle_by_cpsm(psm);
    151     tMCA_CCB    *p_ccb;
    152     tMCA_TC_TBL *p_tbl = NULL;
    153     UINT16      result = L2CAP_CONN_NO_RESOURCES;
    154     tBTM_STATUS rc;
    155     tL2CAP_ERTM_INFO ertm_info, *p_ertm_info = NULL;
    156     tL2CAP_CFG_INFO  cfg;
    157 
    158     MCA_TRACE_EVENT3 ("mca_l2c_cconn_ind_cback: lcid:x%x psm:x%x id:x%x", lcid, psm, id);
    159 
    160     /* do we already have a control channel for this peer? */
    161     if ((p_ccb = mca_ccb_by_bd(handle, bd_addr)) == NULL)
    162     {
    163         /* no, allocate ccb */
    164         if ((p_ccb = mca_ccb_alloc(handle, bd_addr)) != NULL)
    165         {
    166             /* allocate and set up entry */
    167             p_ccb->lcid     = lcid;
    168             p_tbl           = mca_tc_tbl_calloc(p_ccb);
    169             p_tbl->id       = id;
    170             p_tbl->cfg_flags= MCA_L2C_CFG_CONN_ACP;
    171             /* proceed with connection */
    172             /* Check the security */
    173             rc = btm_sec_mx_access_request (bd_addr, psm, FALSE, BTM_SEC_PROTO_MCA, 0,
    174                                             &mca_sec_check_complete_term, p_tbl);
    175             if (rc == BTM_CMD_STARTED)
    176             {
    177                 /* Set the FCR options: control channel mandates ERTM */
    178                 ertm_info.preferred_mode    = mca_l2c_fcr_opts_def.mode;
    179                 ertm_info.allowed_modes     = L2CAP_FCR_CHAN_OPT_ERTM;
    180                 ertm_info.user_rx_pool_id   = MCA_USER_RX_POOL_ID;
    181                 ertm_info.user_tx_pool_id   = MCA_USER_TX_POOL_ID;
    182                 ertm_info.fcr_rx_pool_id    = MCA_FCR_RX_POOL_ID;
    183                 ertm_info.fcr_tx_pool_id    = MCA_FCR_TX_POOL_ID;
    184                 p_ertm_info = &ertm_info;
    185                 result = L2CAP_CONN_PENDING;
    186             }
    187             else
    188                 result = L2CAP_CONN_OK;
    189         }
    190 
    191         /*  deal with simultaneous control channel connect case */
    192     }
    193     /* else reject their connection */
    194 
    195     if (!p_tbl || (p_tbl->state != MCA_TC_ST_CFG))
    196     {
    197         /* Send L2CAP connect rsp */
    198         L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, L2CAP_CONN_OK, p_ertm_info);
    199 
    200         /* if result ok, proceed with connection and send L2CAP
    201            config req */
    202         if (result == L2CAP_CONN_OK)
    203         {
    204             /* set channel state */
    205             p_tbl->state = MCA_TC_ST_CFG;
    206 
    207             /* Send L2CAP config req */
    208             mca_set_cfg_by_tbl (&cfg, p_tbl);
    209             L2CA_ConfigReq(p_tbl->lcid, &cfg);
    210         }
    211     }
    212 }
    213 
    214 /*******************************************************************************
    215 **
    216 ** Function         mca_l2c_dconn_ind_cback
    217 **
    218 ** Description      This is the L2CAP connect indication callback function.
    219 **
    220 **
    221 ** Returns          void
    222 **
    223 *******************************************************************************/
    224 void mca_l2c_dconn_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
    225 {
    226     tMCA_HANDLE handle = mca_handle_by_dpsm(psm);
    227     tMCA_CCB    *p_ccb;
    228     tMCA_DCB       *p_dcb;
    229     tMCA_TC_TBL    *p_tbl = NULL;
    230     UINT16          result;
    231     tL2CAP_CFG_INFO cfg;
    232     tL2CAP_ERTM_INFO *p_ertm_info = NULL, ertm_info;
    233     const tMCA_CHNL_CFG   *p_chnl_cfg;
    234 
    235     MCA_TRACE_EVENT2 ("mca_l2c_dconn_ind_cback: lcid:x%x psm:x%x ", lcid, psm);
    236 
    237     if (((p_ccb = mca_ccb_by_bd(handle, bd_addr)) != NULL) && /* find the CCB */
    238         (p_ccb->status == MCA_CCB_STAT_PENDING) &&  /* this CCB is expecting a MDL */
    239         (p_ccb->p_tx_req && (p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL))
    240     {
    241         /* found the associated dcb in listening mode */
    242         /* proceed with connection */
    243         p_dcb->lcid     = lcid;
    244         p_tbl           = mca_tc_tbl_dalloc(p_dcb);
    245         p_tbl->id       = id;
    246         p_tbl->cfg_flags= MCA_L2C_CFG_CONN_ACP;
    247         p_chnl_cfg = p_dcb->p_chnl_cfg;
    248         /* assume that control channel has verified the security requirement */
    249         /* Set the FCR options: control channel mandates ERTM */
    250         ertm_info.preferred_mode    = p_chnl_cfg->fcr_opt.mode;
    251         ertm_info.allowed_modes     = (1 << p_chnl_cfg->fcr_opt.mode);
    252         ertm_info.user_rx_pool_id   = p_chnl_cfg->user_rx_pool_id;
    253         ertm_info.user_tx_pool_id   = p_chnl_cfg->user_tx_pool_id;
    254         ertm_info.fcr_rx_pool_id    = p_chnl_cfg->fcr_rx_pool_id;
    255         ertm_info.fcr_tx_pool_id    = p_chnl_cfg->fcr_tx_pool_id;
    256         p_ertm_info = &ertm_info;
    257         result = L2CAP_CONN_OK;
    258     }
    259     else
    260     {
    261         /* else we're not listening for traffic channel; reject
    262          * (this error code is specified by MCAP spec) */
    263         result = L2CAP_CONN_NO_RESOURCES;
    264     }
    265 
    266     /* Send L2CAP connect rsp */
    267     L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, result, p_ertm_info);
    268 
    269     /* if result ok, proceed with connection */
    270     if (result == L2CAP_CONN_OK)
    271     {
    272         /* transition to configuration state */
    273         p_tbl->state = MCA_TC_ST_CFG;
    274 
    275         /* Send L2CAP config req */
    276         mca_set_cfg_by_tbl (&cfg, p_tbl);
    277         L2CA_ConfigReq(lcid, &cfg);
    278     }
    279 }
    280 
    281 /*******************************************************************************
    282 **
    283 ** Function         mca_l2c_connect_cfm_cback
    284 **
    285 ** Description      This is the L2CAP connect confirm callback function.
    286 **
    287 **
    288 ** Returns          void
    289 **
    290 *******************************************************************************/
    291 void mca_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
    292 {
    293     tMCA_TC_TBL    *p_tbl;
    294     tL2CAP_CFG_INFO cfg;
    295     tMCA_CCB *p_ccb;
    296 
    297     MCA_TRACE_DEBUG2("mca_l2c_connect_cfm_cback lcid: x%x, result: %d",
    298                      lcid, result);
    299     /* look up info for this channel */
    300     if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
    301     {
    302         MCA_TRACE_DEBUG2("p_tbl state: %d, tcid: %d", p_tbl->state, p_tbl->tcid);
    303         /* if in correct state */
    304         if (p_tbl->state == MCA_TC_ST_CONN)
    305         {
    306             /* if result successful */
    307             if (result == L2CAP_CONN_OK)
    308             {
    309                 if (p_tbl->tcid != 0)
    310                 {
    311                     /* set channel state */
    312                     p_tbl->state = MCA_TC_ST_CFG;
    313 
    314                     /* Send L2CAP config req */
    315                     mca_set_cfg_by_tbl (&cfg, p_tbl);
    316                     L2CA_ConfigReq(lcid, &cfg);
    317                 }
    318                 else
    319                 {
    320                     p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
    321                     if (p_ccb == NULL)
    322                     {
    323                         result = L2CAP_CONN_NO_RESOURCES;
    324                     }
    325                     else
    326                     {
    327                         /* set channel state */
    328                         p_tbl->state    = MCA_TC_ST_SEC_INT;
    329                         p_tbl->lcid     = lcid;
    330                         p_tbl->cfg_flags= MCA_L2C_CFG_CONN_INT;
    331 
    332                         /* Check the security */
    333                         btm_sec_mx_access_request (p_ccb->peer_addr, p_ccb->ctrl_vpsm,
    334                                                    TRUE, BTM_SEC_PROTO_MCA,
    335                                                    p_tbl->tcid,
    336                                                    &mca_sec_check_complete_orig, p_tbl);
    337                     }
    338                 }
    339             }
    340 
    341             /* failure; notify adaption that channel closed */
    342             if (result != L2CAP_CONN_OK)
    343             {
    344                 p_tbl->cfg_flags |= MCA_L2C_CFG_DISCN_INT;
    345                 mca_tc_close_ind(p_tbl, result);
    346             }
    347         }
    348     }
    349 }
    350 
    351 /*******************************************************************************
    352 **
    353 ** Function         mca_l2c_config_cfm_cback
    354 **
    355 ** Description      This is the L2CAP config confirm callback function.
    356 **
    357 **
    358 ** Returns          void
    359 **
    360 *******************************************************************************/
    361 void mca_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
    362 {
    363     tMCA_TC_TBL    *p_tbl;
    364 
    365     /* look up info for this channel */
    366     if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
    367     {
    368         /* if in correct state */
    369         if (p_tbl->state == MCA_TC_ST_CFG)
    370         {
    371             /* if result successful */
    372             if (p_cfg->result == L2CAP_CONN_OK)
    373             {
    374                 /* update cfg_flags */
    375                 p_tbl->cfg_flags |= MCA_L2C_CFG_CFM_DONE;
    376 
    377                 /* if configuration complete */
    378                 if (p_tbl->cfg_flags & MCA_L2C_CFG_IND_DONE)
    379                 {
    380                     mca_tc_open_ind(p_tbl);
    381                 }
    382             }
    383             /* else failure */
    384             else
    385             {
    386                 /* Send L2CAP disconnect req */
    387                 L2CA_DisconnectReq(lcid);
    388             }
    389         }
    390     }
    391 }
    392 
    393 /*******************************************************************************
    394 **
    395 ** Function         mca_l2c_config_ind_cback
    396 **
    397 ** Description      This is the L2CAP config indication callback function.
    398 **
    399 **
    400 ** Returns          void
    401 **
    402 *******************************************************************************/
    403 void mca_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
    404 {
    405     tMCA_TC_TBL    *p_tbl;
    406     UINT16          result = L2CAP_CFG_OK;
    407 
    408     /* look up info for this channel */
    409     if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
    410     {
    411         /* store the mtu in tbl */
    412         if (p_cfg->mtu_present)
    413         {
    414             p_tbl->peer_mtu = p_cfg->mtu;
    415             if (p_tbl->peer_mtu < MCA_MIN_MTU)
    416             {
    417                 result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
    418             }
    419         }
    420         else
    421         {
    422             p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
    423         }
    424         MCA_TRACE_DEBUG3("peer_mtu: %d, lcid: x%x mtu_present:%d",p_tbl->peer_mtu, lcid, p_cfg->mtu_present);
    425 
    426         /* send L2CAP configure response */
    427         memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
    428         p_cfg->result = result;
    429         L2CA_ConfigRsp(lcid, p_cfg);
    430 
    431         /* if first config ind */
    432         if ((p_tbl->cfg_flags & MCA_L2C_CFG_IND_DONE) == 0)
    433         {
    434             /* update cfg_flags */
    435             p_tbl->cfg_flags |= MCA_L2C_CFG_IND_DONE;
    436 
    437             /* if configuration complete */
    438             if (p_tbl->cfg_flags & MCA_L2C_CFG_CFM_DONE)
    439             {
    440                 mca_tc_open_ind(p_tbl);
    441             }
    442         }
    443     }
    444 }
    445 
    446 /*******************************************************************************
    447 **
    448 ** Function         mca_l2c_disconnect_ind_cback
    449 **
    450 ** Description      This is the L2CAP disconnect indication callback function.
    451 **
    452 **
    453 ** Returns          void
    454 **
    455 *******************************************************************************/
    456 void mca_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
    457 {
    458     tMCA_TC_TBL    *p_tbl;
    459     UINT16         reason = L2CAP_DISC_TIMEOUT;
    460 
    461     MCA_TRACE_DEBUG2("mca_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d",
    462                      lcid, ack_needed);
    463     /* look up info for this channel */
    464     if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
    465     {
    466         if (ack_needed)
    467         {
    468             /* send L2CAP disconnect response */
    469             L2CA_DisconnectRsp(lcid);
    470         }
    471 
    472         p_tbl->cfg_flags = MCA_L2C_CFG_DISCN_ACP;
    473         if (ack_needed)
    474             reason = L2CAP_DISC_OK;
    475         mca_tc_close_ind(p_tbl, reason);
    476     }
    477 }
    478 
    479 /*******************************************************************************
    480 **
    481 ** Function         mca_l2c_disconnect_cfm_cback
    482 **
    483 ** Description      This is the L2CAP disconnect confirm callback function.
    484 **
    485 **
    486 ** Returns          void
    487 **
    488 *******************************************************************************/
    489 void mca_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
    490 {
    491     tMCA_TC_TBL    *p_tbl;
    492 
    493     MCA_TRACE_DEBUG2("mca_l2c_disconnect_cfm_cback lcid: x%x, result: %d",
    494                      lcid, result);
    495     /* look up info for this channel */
    496     if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
    497     {
    498         p_tbl->cfg_flags = MCA_L2C_CFG_DISCN_INT;
    499         mca_tc_close_ind(p_tbl, result);
    500     }
    501 }
    502 
    503 
    504 /*******************************************************************************
    505 **
    506 ** Function         mca_l2c_congestion_ind_cback
    507 **
    508 ** Description      This is the L2CAP congestion indication callback function.
    509 **
    510 **
    511 ** Returns          void
    512 **
    513 *******************************************************************************/
    514 void mca_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
    515 {
    516     tMCA_TC_TBL    *p_tbl;
    517 
    518     /* look up info for this channel */
    519     if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
    520     {
    521         mca_tc_cong_ind(p_tbl, is_congested);
    522     }
    523 }
    524 
    525 /*******************************************************************************
    526 **
    527 ** Function         mca_l2c_data_ind_cback
    528 **
    529 ** Description      This is the L2CAP data indication callback function.
    530 **
    531 **
    532 ** Returns          void
    533 **
    534 *******************************************************************************/
    535 void mca_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
    536 {
    537     tMCA_TC_TBL    *p_tbl;
    538 
    539     /* look up info for this channel */
    540     if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
    541     {
    542         mca_tc_data_ind(p_tbl, p_buf);
    543     }
    544     else /* prevent buffer leak */
    545         GKI_freebuf(p_buf);
    546 }
    547 
    548 
    549 /*******************************************************************************
    550 **
    551 ** Function         mca_l2c_open_req
    552 **
    553 ** Description      This function calls L2CA_ConnectReq() to initiate a L2CAP channel.
    554 **
    555 ** Returns          void.
    556 **
    557 *******************************************************************************/
    558 UINT16 mca_l2c_open_req(BD_ADDR bd_addr, UINT16 psm, const tMCA_CHNL_CFG *p_chnl_cfg)
    559 {
    560     tL2CAP_ERTM_INFO ertm_info;
    561 
    562     if (p_chnl_cfg)
    563     {
    564         ertm_info.preferred_mode    = p_chnl_cfg->fcr_opt.mode;
    565         ertm_info.allowed_modes     = (1 << p_chnl_cfg->fcr_opt.mode);
    566         ertm_info.user_rx_pool_id   = p_chnl_cfg->user_rx_pool_id;
    567         ertm_info.user_tx_pool_id   = p_chnl_cfg->user_tx_pool_id;
    568         ertm_info.fcr_rx_pool_id    = p_chnl_cfg->fcr_rx_pool_id;
    569         ertm_info.fcr_tx_pool_id    = p_chnl_cfg->fcr_tx_pool_id;
    570     }
    571     else
    572     {
    573         ertm_info.preferred_mode    = mca_l2c_fcr_opts_def.mode;
    574         ertm_info.allowed_modes     = L2CAP_FCR_CHAN_OPT_ERTM;
    575         ertm_info.user_rx_pool_id   = MCA_USER_RX_POOL_ID;
    576         ertm_info.user_tx_pool_id   = MCA_USER_TX_POOL_ID;
    577         ertm_info.fcr_rx_pool_id    = MCA_FCR_RX_POOL_ID;
    578         ertm_info.fcr_tx_pool_id    = MCA_FCR_TX_POOL_ID;
    579     }
    580     return L2CA_ErtmConnectReq (psm, bd_addr, &ertm_info);
    581 }
    582 
    583