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 API implementation file for the Multi-Channel Adaptation
     22  *  Protocol (MCAP).
     23  *
     24  ******************************************************************************/
     25 #include <string.h>
     26 
     27 #include "bt_target.h"
     28 #include "btm_api.h"
     29 #include "btm_int.h"
     30 #include "mca_api.h"
     31 #include "mca_defs.h"
     32 #include "mca_int.h"
     33 
     34 #include "wcassert.h"
     35 #include "btu.h"
     36 
     37 
     38 /*******************************************************************************
     39 **
     40 ** Function         mca_process_timeout
     41 **
     42 ** Description      This function is called by BTU when an MCA timer
     43 **                  expires.
     44 **
     45 **                  This function is for use internal to the stack only.
     46 **
     47 ** Returns          void
     48 **
     49 *******************************************************************************/
     50 void mca_process_timeout(TIMER_LIST_ENT *p_tle)
     51 {
     52     if(p_tle->event == BTU_TTYPE_MCA_CCB_RSP)
     53     {
     54         p_tle->event = 0;
     55         mca_ccb_event ((tMCA_CCB *) p_tle->param, MCA_CCB_RSP_TOUT_EVT, NULL);
     56     }
     57 }
     58 
     59 /*******************************************************************************
     60 **
     61 ** Function         MCA_Init
     62 **
     63 ** Description      Initialize MCAP main control block.
     64 **                  This function is called at stack start up.
     65 **
     66 ** Returns          void
     67 **
     68 *******************************************************************************/
     69 void MCA_Init(void)
     70 {
     71     memset(&mca_cb, 0, sizeof(tMCA_CB));
     72 
     73 #if defined(MCA_INITIAL_TRACE_LEVEL)
     74     mca_cb.trace_level = MCA_INITIAL_TRACE_LEVEL;
     75 #else
     76     mca_cb.trace_level = BT_TRACE_LEVEL_NONE;
     77 #endif
     78 }
     79 
     80 /*******************************************************************************
     81 **
     82 ** Function         MCA_SetTraceLevel
     83 **
     84 ** Description      This function sets the debug trace level for MCA.
     85 **                  If 0xff is passed, the current trace level is returned.
     86 **
     87 **                  Input Parameters:
     88 **                      level:  The level to set the MCA tracing to:
     89 **                      0xff-returns the current setting.
     90 **                      0-turns off tracing.
     91 **                      >= 1-Errors.
     92 **                      >= 2-Warnings.
     93 **                      >= 3-APIs.
     94 **                      >= 4-Events.
     95 **                      >= 5-Debug.
     96 **
     97 ** Returns          The new trace level or current trace level if
     98 **                  the input parameter is 0xff.
     99 **
    100 *******************************************************************************/
    101 UINT8 MCA_SetTraceLevel (UINT8 level)
    102 {
    103     if (level != 0xFF)
    104         mca_cb.trace_level = level;
    105 
    106     return (mca_cb.trace_level);
    107 }
    108 
    109 /*******************************************************************************
    110 **
    111 ** Function         MCA_Register
    112 **
    113 ** Description      This function registers an MCAP implementation.
    114 **                  It is assumed that the control channel PSM and data channel
    115 **                  PSM are not used by any other instances of the stack.
    116 **                  If the given p_reg->ctrl_psm is 0, this handle is INT only.
    117 **
    118 ** Returns          0, if failed. Otherwise, the MCA handle.
    119 **
    120 *******************************************************************************/
    121 tMCA_HANDLE MCA_Register(tMCA_REG *p_reg, tMCA_CTRL_CBACK *p_cback)
    122 {
    123     tMCA_RCB    *p_rcb;
    124     tMCA_HANDLE handle = 0;
    125     tL2CAP_APPL_INFO l2c_cacp_appl;
    126     tL2CAP_APPL_INFO l2c_dacp_appl;
    127 
    128     WC_ASSERT(p_reg != NULL );
    129     WC_ASSERT(p_cback != NULL );
    130 
    131     MCA_TRACE_API ("MCA_Register: ctrl_psm:0x%x, data_psm:0x%x", p_reg->ctrl_psm, p_reg->data_psm);
    132 
    133     if ( (p_rcb = mca_rcb_alloc (p_reg)) != NULL)
    134     {
    135         if (p_reg->ctrl_psm)
    136         {
    137             if (L2C_INVALID_PSM(p_reg->ctrl_psm) || L2C_INVALID_PSM(p_reg->data_psm))
    138             {
    139                 MCA_TRACE_ERROR ("INVALID_PSM");
    140                 return 0;
    141             }
    142 
    143             l2c_cacp_appl = *(tL2CAP_APPL_INFO *)&mca_l2c_int_appl;
    144             l2c_cacp_appl.pL2CA_ConnectCfm_Cb = NULL;
    145             l2c_dacp_appl = *(tL2CAP_APPL_INFO *)&l2c_cacp_appl;
    146             l2c_cacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_cconn_ind_cback;
    147             l2c_dacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_dconn_ind_cback;
    148             if (L2CA_Register(p_reg->ctrl_psm, (tL2CAP_APPL_INFO *) &l2c_cacp_appl) &&
    149                 L2CA_Register(p_reg->data_psm, (tL2CAP_APPL_INFO *) &l2c_dacp_appl))
    150             {
    151                 /* set security level */
    152                 BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_CTRL, p_reg->sec_mask,
    153                     p_reg->ctrl_psm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
    154 
    155                 /* in theory, we do not need this one for data_psm
    156                  * If we don't, L2CAP rejects with security block (3),
    157                  * which is different reject code from what MCAP spec suggests.
    158                  * we set this one, so mca_l2c_dconn_ind_cback can reject /w no resources (4) */
    159                 BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_DATA, p_reg->sec_mask,
    160                     p_reg->data_psm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
    161             }
    162             else
    163             {
    164                 MCA_TRACE_ERROR ("Failed to register to L2CAP");
    165                 return 0;
    166             }
    167         }
    168         else
    169             p_rcb->reg.data_psm = 0;
    170         handle = mca_rcb_to_handle (p_rcb);
    171         p_rcb->p_cback = p_cback;
    172         p_rcb->reg.rsp_tout = p_reg->rsp_tout;
    173     }
    174     return handle;
    175 }
    176 
    177 
    178 /*******************************************************************************
    179 **
    180 ** Function         MCA_Deregister
    181 **
    182 ** Description      This function is called to deregister an MCAP implementation.
    183 **                  Before this function can be called, all control and data
    184 **                  channels must be removed with MCA_DisconnectReq and MCA_CloseReq.
    185 **
    186 ** Returns          void
    187 **
    188 *******************************************************************************/
    189 void MCA_Deregister(tMCA_HANDLE handle)
    190 {
    191     tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
    192 
    193     MCA_TRACE_API ("MCA_Deregister: %d", handle);
    194     if (p_rcb && p_rcb->reg.ctrl_psm)
    195     {
    196         L2CA_Deregister(p_rcb->reg.ctrl_psm);
    197         L2CA_Deregister(p_rcb->reg.data_psm);
    198         btm_sec_clr_service_by_psm (p_rcb->reg.ctrl_psm);
    199         btm_sec_clr_service_by_psm (p_rcb->reg.data_psm);
    200     }
    201     mca_rcb_dealloc(handle);
    202 }
    203 
    204 
    205 /*******************************************************************************
    206 **
    207 ** Function         MCA_CreateDep
    208 **
    209 ** Description      Create a data endpoint.  If the MDEP is created successfully,
    210 **                  the MDEP ID is returned in *p_dep. After a data endpoint is
    211 **                  created, an application can initiate a connection between this
    212 **                  endpoint and an endpoint on a peer device.
    213 **
    214 ** Returns          MCA_SUCCESS if successful, otherwise error.
    215 **
    216 *******************************************************************************/
    217 tMCA_RESULT MCA_CreateDep(tMCA_HANDLE handle, tMCA_DEP *p_dep, tMCA_CS *p_cs)
    218 {
    219     tMCA_RESULT result = MCA_BAD_HANDLE;
    220     int       i;
    221     tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
    222     tMCA_CS  *p_depcs;
    223 
    224     WC_ASSERT(p_dep != NULL );
    225     WC_ASSERT(p_cs != NULL );
    226     WC_ASSERT(p_cs->p_data_cback != NULL );
    227 
    228     MCA_TRACE_API ("MCA_CreateDep: %d", handle);
    229     if (p_rcb)
    230     {
    231         if (p_cs->max_mdl > MCA_NUM_MDLS)
    232         {
    233             MCA_TRACE_ERROR ("max_mdl: %d is too big", p_cs->max_mdl );
    234             result = MCA_BAD_PARAMS;
    235         }
    236         else
    237         {
    238             p_depcs = p_rcb->dep;
    239             if (p_cs->type == MCA_TDEP_ECHO)
    240             {
    241                 if (p_depcs->p_data_cback)
    242                 {
    243                     MCA_TRACE_ERROR ("Already has ECHO MDEP");
    244                     return MCA_NO_RESOURCES;
    245                 }
    246                 memcpy (p_depcs, p_cs, sizeof (tMCA_CS));
    247                 *p_dep = 0;
    248                 result = MCA_SUCCESS;
    249             }
    250             else
    251             {
    252                 result = MCA_NO_RESOURCES;
    253                 /* non-echo MDEP starts from 1 */
    254                 p_depcs++;
    255                 for (i=1; i<MCA_NUM_DEPS; i++, p_depcs++)
    256                 {
    257                     if (p_depcs->p_data_cback == NULL)
    258                     {
    259                         memcpy (p_depcs, p_cs, sizeof (tMCA_CS));
    260                         /* internally use type as the mdep id */
    261                         p_depcs->type = i;
    262                         *p_dep = i;
    263                         result = MCA_SUCCESS;
    264                         break;
    265                     }
    266                 }
    267             }
    268         }
    269     }
    270     return result;
    271 }
    272 
    273 
    274 /*******************************************************************************
    275 **
    276 ** Function         MCA_DeleteDep
    277 **
    278 ** Description      Delete a data endpoint.  This function is called when
    279 **                  the implementation is no longer using a data endpoint.
    280 **                  If this function is called when the endpoint is connected
    281 **                  the connection is closed and the data endpoint
    282 **                  is removed.
    283 **
    284 ** Returns          MCA_SUCCESS if successful, otherwise error.
    285 **
    286 *******************************************************************************/
    287 tMCA_RESULT MCA_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep)
    288 {
    289     tMCA_RESULT result = MCA_BAD_HANDLE;
    290     tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
    291     tMCA_DCB *p_dcb;
    292     int      i, max;
    293     tMCA_CS  *p_depcs;
    294 
    295     MCA_TRACE_API ("MCA_DeleteDep: %d dep:%d", handle, dep);
    296     if (p_rcb)
    297     {
    298         if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback)
    299         {
    300             result = MCA_SUCCESS;
    301             p_rcb->dep[dep].p_data_cback = NULL;
    302             p_depcs = &(p_rcb->dep[dep]);
    303             i = handle - 1;
    304             max = MCA_NUM_MDLS*MCA_NUM_LINKS;
    305             p_dcb = &mca_cb.dcb[i*max];
    306             /* make sure no MDL exists for this MDEP */
    307             for (i=0; i<max; i++, p_dcb++)
    308             {
    309                 if (p_dcb->state && p_dcb->p_cs == p_depcs)
    310                 {
    311                     mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
    312                 }
    313             }
    314         }
    315     }
    316     return result;
    317 }
    318 
    319 /*******************************************************************************
    320 **
    321 ** Function         MCA_ConnectReq
    322 **
    323 ** Description      This function initiates an MCAP control channel connection
    324 **                  to the peer device.  When the connection is completed, an
    325 **                  MCA_CONNECT_IND_EVT is reported to the application via its
    326 **                  control callback function.
    327 **                  This control channel is identified by the tMCA_CL.
    328 **                  If the connection attempt fails, an MCA_DISCONNECT_IND_EVT is
    329 **                  reported. The security mask parameter overrides the outgoing
    330 **                  security mask set in MCA_Register().
    331 **
    332 ** Returns          MCA_SUCCESS if successful, otherwise error.
    333 **
    334 *******************************************************************************/
    335 tMCA_RESULT MCA_ConnectReq(tMCA_HANDLE handle, BD_ADDR bd_addr,
    336                            UINT16 ctrl_psm, UINT16 sec_mask)
    337 {
    338     tMCA_RESULT result = MCA_BAD_HANDLE;
    339     tMCA_CCB    *p_ccb;
    340     tMCA_TC_TBL *p_tbl;
    341 
    342     MCA_TRACE_API ("MCA_ConnectReq: %d psm:0x%x", handle, ctrl_psm);
    343     if ((p_ccb = mca_ccb_by_bd(handle, bd_addr)) == NULL)
    344         p_ccb = mca_ccb_alloc(handle, bd_addr);
    345     else
    346     {
    347         MCA_TRACE_ERROR ("control channel already exists");
    348         return MCA_BUSY;
    349     }
    350 
    351     if (p_ccb)
    352     {
    353         p_ccb->ctrl_vpsm = L2CA_Register (ctrl_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl);
    354         result = MCA_NO_RESOURCES;
    355         if (p_ccb->ctrl_vpsm)
    356         {
    357             BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_CTRL, sec_mask,
    358                 p_ccb->ctrl_vpsm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
    359             p_ccb->lcid = mca_l2c_open_req(bd_addr, p_ccb->ctrl_vpsm, NULL);
    360             if (p_ccb->lcid)
    361             {
    362                 p_tbl = mca_tc_tbl_calloc(p_ccb);
    363                 if (p_tbl)
    364                 {
    365                     p_tbl->state = MCA_TC_ST_CONN;
    366                     p_ccb->sec_mask = sec_mask;
    367                     result = MCA_SUCCESS;
    368                 }
    369             }
    370         }
    371         if (result != MCA_SUCCESS)
    372             mca_ccb_dealloc (p_ccb, NULL);
    373     }
    374     return result;
    375 }
    376 
    377 
    378 /*******************************************************************************
    379 **
    380 ** Function         MCA_DisconnectReq
    381 **
    382 ** Description      This function disconnect an MCAP control channel
    383 **                  to the peer device.
    384 **                  If associated data channel exists, they are disconnected.
    385 **                  When the MCL is disconnected an MCA_DISCONNECT_IND_EVT is
    386 **                  reported to the application via its control callback function.
    387 **
    388 ** Returns          MCA_SUCCESS if successful, otherwise error.
    389 **
    390 *******************************************************************************/
    391 tMCA_RESULT MCA_DisconnectReq(tMCA_CL mcl)
    392 {
    393     tMCA_RESULT result = MCA_BAD_HANDLE;
    394     tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
    395 
    396     MCA_TRACE_API ("MCA_DisconnectReq: %d ", mcl);
    397     if (p_ccb)
    398     {
    399         result = MCA_SUCCESS;
    400         mca_ccb_event (p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
    401     }
    402     return result;
    403 }
    404 
    405 
    406 /*******************************************************************************
    407 **
    408 ** Function         MCA_CreateMdl
    409 **
    410 ** Description      This function sends a CREATE_MDL request to the peer device.
    411 **                  When the response is received, a MCA_CREATE_CFM_EVT is reported
    412 **                  with the given MDL ID.
    413 **                  If the response is successful, a data channel is open
    414 **                  with the given p_chnl_cfg
    415 **                  If p_chnl_cfg is NULL, the data channel is not initiated until
    416 **                  MCA_DataChnlCfg is called to provide the p_chnl_cfg.
    417 **                  When the data channel is open successfully, a MCA_OPEN_CFM_EVT
    418 **                  is reported. This data channel is identified as tMCA_DL.
    419 **
    420 ** Returns          MCA_SUCCESS if successful, otherwise error.
    421 **
    422 *******************************************************************************/
    423 tMCA_RESULT MCA_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm,
    424                                          UINT16 mdl_id, UINT8 peer_dep_id,
    425                                          UINT8 cfg, const tMCA_CHNL_CFG *p_chnl_cfg)
    426 {
    427     tMCA_RESULT     result = MCA_BAD_HANDLE;
    428     tMCA_CCB        *p_ccb = mca_ccb_by_hdl(mcl);
    429     tMCA_CCB_MSG    *p_evt_data;
    430     tMCA_DCB        *p_dcb;
    431 
    432     MCA_TRACE_API ("MCA_CreateMdl: %d dep=%d mdl_id=%d peer_dep_id=%d", mcl, dep, mdl_id, peer_dep_id);
    433     if (p_ccb)
    434     {
    435         if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong)
    436         {
    437             MCA_TRACE_ERROR ("pending req");
    438             return MCA_BUSY;
    439         }
    440 
    441         if ((peer_dep_id > MCA_MAX_MDEP_ID) || (!MCA_IS_VALID_MDL_ID(mdl_id)))
    442         {
    443             MCA_TRACE_ERROR ("bad peer dep id:%d or bad mdl id: %d ", peer_dep_id, mdl_id);
    444             return MCA_BAD_PARAMS;
    445         }
    446 
    447         if (mca_ccb_uses_mdl_id(p_ccb, mdl_id))
    448         {
    449             MCA_TRACE_ERROR ("mdl id: %d is used in the control link", mdl_id);
    450             return MCA_BAD_MDL_ID;
    451         }
    452 
    453         p_dcb = mca_dcb_alloc(p_ccb, dep);
    454         result = MCA_NO_RESOURCES;
    455         if (p_dcb)
    456         {
    457             /* save the info required by dcb connection */
    458             p_dcb->p_chnl_cfg       = p_chnl_cfg;
    459             p_dcb->mdl_id           = mdl_id;
    460             p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG));
    461             if (p_evt_data)
    462             {
    463                 if (!p_ccb->data_vpsm)
    464                     p_ccb->data_vpsm = L2CA_Register (data_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl);
    465                 if (p_ccb->data_vpsm)
    466                 {
    467                     p_evt_data->dcb_idx     = mca_dcb_to_hdl (p_dcb);
    468                     p_evt_data->mdep_id     = peer_dep_id;
    469                     p_evt_data->mdl_id      = mdl_id;
    470                     p_evt_data->param       = cfg;
    471                     p_evt_data->op_code     = MCA_OP_MDL_CREATE_REQ;
    472                     p_evt_data->hdr.event   = MCA_CCB_API_REQ_EVT;
    473                     p_evt_data->hdr.layer_specific   = FALSE;
    474                     mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
    475                     return MCA_SUCCESS;
    476                 }
    477                 else
    478                     GKI_freebuf (p_evt_data);
    479             }
    480             mca_dcb_dealloc(p_dcb, NULL);
    481         }
    482     }
    483     return result;
    484 }
    485 
    486 
    487 /*******************************************************************************
    488 **
    489 ** Function         MCA_CreateMdlRsp
    490 **
    491 ** Description      This function sends a CREATE_MDL response to the peer device
    492 **                  in response to a received MCA_CREATE_IND_EVT.
    493 **                  If the rsp_code is successful, a data channel is open
    494 **                  with the given p_chnl_cfg
    495 **                  When the data channel is open successfully, a MCA_OPEN_IND_EVT
    496 **                  is reported. This data channel is identified as tMCA_DL.
    497 **
    498 ** Returns          MCA_SUCCESS if successful, otherwise error.
    499 **
    500 *******************************************************************************/
    501 tMCA_RESULT MCA_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep,
    502                                             UINT16 mdl_id, UINT8 cfg, UINT8 rsp_code,
    503                                             const tMCA_CHNL_CFG *p_chnl_cfg)
    504 {
    505     tMCA_RESULT     result = MCA_BAD_HANDLE;
    506     tMCA_CCB        *p_ccb = mca_ccb_by_hdl(mcl);
    507     tMCA_CCB_MSG    evt_data;
    508     tMCA_DCB        *p_dcb;
    509 
    510     MCA_TRACE_API ("MCA_CreateMdlRsp: %d dep=%d mdl_id=%d cfg=%d rsp_code=%d", mcl, dep, mdl_id, cfg, rsp_code);
    511     WC_ASSERT(p_chnl_cfg != NULL );
    512     if (p_ccb)
    513     {
    514         if (p_ccb->cong)
    515         {
    516             MCA_TRACE_ERROR ("congested");
    517             return MCA_BUSY;
    518         }
    519         if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdep_id == dep )
    520             && (p_ccb->p_rx_msg->mdl_id == mdl_id) && (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_CREATE_REQ))
    521         {
    522             result = MCA_SUCCESS;
    523             evt_data.dcb_idx    = 0;
    524             if (rsp_code == MCA_RSP_SUCCESS)
    525             {
    526                 p_dcb = mca_dcb_alloc(p_ccb, dep);
    527                 if (p_dcb)
    528                 {
    529                     evt_data.dcb_idx    = mca_dcb_to_hdl(p_dcb);
    530                     p_dcb->p_chnl_cfg   = p_chnl_cfg;
    531                     p_dcb->mdl_id       = mdl_id;
    532                 }
    533                 else
    534                 {
    535                     rsp_code = MCA_RSP_MDEP_BUSY;
    536                     result = MCA_NO_RESOURCES;
    537                 }
    538             }
    539 
    540             if (result == MCA_SUCCESS)
    541             {
    542                 evt_data.mdl_id     = mdl_id;
    543                 evt_data.param      = cfg;
    544                 evt_data.rsp_code   = rsp_code;
    545                 evt_data.op_code    = MCA_OP_MDL_CREATE_RSP;
    546                 mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, (tMCA_CCB_EVT *)&evt_data);
    547             }
    548         }
    549         else
    550         {
    551             MCA_TRACE_ERROR ("The given MCL is not expecting a MCA_CreateMdlRsp with the given parameters" );
    552             result = MCA_BAD_PARAMS;
    553         }
    554     }
    555     return result;
    556 }
    557 
    558 /*******************************************************************************
    559 **
    560 ** Function         MCA_CloseReq
    561 **
    562 ** Description      Close a data channel.  When the channel is closed, an
    563 **                  MCA_CLOSE_CFM_EVT is sent to the application via the
    564 **                  control callback function for this handle.
    565 **
    566 ** Returns          MCA_SUCCESS if successful, otherwise error.
    567 **
    568 *******************************************************************************/
    569 tMCA_RESULT MCA_CloseReq(tMCA_DL mdl)
    570 {
    571     tMCA_RESULT     result = MCA_BAD_HANDLE;
    572     tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl);
    573 
    574     MCA_TRACE_API ("MCA_CloseReq: %d ", mdl);
    575     if (p_dcb)
    576     {
    577         result = MCA_SUCCESS;
    578         mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
    579     }
    580     return result;
    581 }
    582 
    583 
    584 /*******************************************************************************
    585 **
    586 ** Function         MCA_ReconnectMdl
    587 **
    588 ** Description      This function sends a RECONNECT_MDL request to the peer device.
    589 **                  When the response is received, a MCA_RECONNECT_CFM_EVT is reported.
    590 **                  If p_chnl_cfg is NULL, the data channel is not initiated until
    591 **                  MCA_DataChnlCfg is called to provide the p_chnl_cfg.
    592 **                  If the response is successful, a data channel is open.
    593 **                  When the data channel is open successfully, a MCA_OPEN_CFM_EVT
    594 **                  is reported.
    595 **
    596 ** Returns          MCA_SUCCESS if successful, otherwise error.
    597 **
    598 *******************************************************************************/
    599 tMCA_RESULT MCA_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm,
    600                                             UINT16 mdl_id, const tMCA_CHNL_CFG *p_chnl_cfg)
    601 {
    602     tMCA_RESULT     result = MCA_BAD_HANDLE;
    603     tMCA_CCB        *p_ccb = mca_ccb_by_hdl(mcl);
    604     tMCA_CCB_MSG    *p_evt_data;
    605     tMCA_DCB        *p_dcb;
    606 
    607     MCA_TRACE_API ("MCA_ReconnectMdl: %d ", mcl);
    608     WC_ASSERT(p_chnl_cfg != NULL );
    609     if (p_ccb)
    610     {
    611         if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong)
    612         {
    613             MCA_TRACE_ERROR ("pending req");
    614             return MCA_BUSY;
    615         }
    616 
    617         if (!MCA_IS_VALID_MDL_ID(mdl_id))
    618         {
    619             MCA_TRACE_ERROR ("bad mdl id: %d ", mdl_id);
    620             return MCA_BAD_PARAMS;
    621         }
    622 
    623         if (mca_ccb_uses_mdl_id(p_ccb, mdl_id))
    624         {
    625             MCA_TRACE_ERROR ("mdl id: %d is used in the control link", mdl_id);
    626             return MCA_BAD_MDL_ID;
    627         }
    628 
    629         p_dcb = mca_dcb_alloc(p_ccb, dep);
    630         result = MCA_NO_RESOURCES;
    631         if (p_dcb)
    632         {
    633             p_dcb->p_chnl_cfg       = p_chnl_cfg;
    634             p_dcb->mdl_id           = mdl_id;
    635             p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG));
    636             if (p_evt_data)
    637             {
    638                 if (!p_ccb->data_vpsm)
    639                     p_ccb->data_vpsm = L2CA_Register (data_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl);
    640                 p_evt_data->dcb_idx     = mca_dcb_to_hdl(p_dcb);
    641                 p_evt_data->mdl_id      = mdl_id;
    642                 p_evt_data->op_code     = MCA_OP_MDL_RECONNECT_REQ;
    643                 p_evt_data->hdr.event   = MCA_CCB_API_REQ_EVT;
    644                 mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
    645                 return MCA_SUCCESS;
    646             }
    647             mca_dcb_dealloc(p_dcb, NULL);
    648         }
    649     }
    650     return result;
    651 }
    652 
    653 
    654 /*******************************************************************************
    655 **
    656 ** Function         MCA_ReconnectMdlRsp
    657 **
    658 ** Description      This function sends a RECONNECT_MDL response to the peer device
    659 **                  in response to a MCA_RECONNECT_IND_EVT event.
    660 **                  If the response is successful, a data channel is open.
    661 **                  When the data channel is open successfully, a MCA_OPEN_IND_EVT
    662 **                  is reported.
    663 **
    664 ** Returns          MCA_SUCCESS if successful, otherwise error.
    665 **
    666 *******************************************************************************/
    667 tMCA_RESULT MCA_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep,
    668                                                UINT16 mdl_id, UINT8 rsp_code,
    669                                                const tMCA_CHNL_CFG *p_chnl_cfg)
    670 {
    671     tMCA_RESULT     result = MCA_BAD_HANDLE;
    672     tMCA_CCB        *p_ccb = mca_ccb_by_hdl(mcl);
    673     tMCA_CCB_MSG    evt_data;
    674     tMCA_DCB        *p_dcb;
    675 
    676     MCA_TRACE_API ("MCA_ReconnectMdlRsp: %d ", mcl);
    677     WC_ASSERT(p_chnl_cfg != NULL );
    678     if (p_ccb)
    679     {
    680         if (p_ccb->cong)
    681         {
    682             MCA_TRACE_ERROR ("congested");
    683             return MCA_BUSY;
    684         }
    685         if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdl_id == mdl_id) &&
    686             (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_RECONNECT_REQ))
    687         {
    688             result = MCA_SUCCESS;
    689             evt_data.dcb_idx    = 0;
    690             if (rsp_code == MCA_RSP_SUCCESS)
    691             {
    692                 p_dcb = mca_dcb_alloc(p_ccb, dep);
    693                 if (p_dcb)
    694                 {
    695                     evt_data.dcb_idx    = mca_dcb_to_hdl(p_dcb);
    696                     p_dcb->p_chnl_cfg   = p_chnl_cfg;
    697                     p_dcb->mdl_id       = mdl_id;
    698                 }
    699                 else
    700                 {
    701                     MCA_TRACE_ERROR ("Out of MDL for this MDEP");
    702                     rsp_code = MCA_RSP_MDEP_BUSY;
    703                     result = MCA_NO_RESOURCES;
    704                 }
    705             }
    706 
    707             evt_data.mdl_id     = mdl_id;
    708             evt_data.rsp_code   = rsp_code;
    709             evt_data.op_code    = MCA_OP_MDL_RECONNECT_RSP;
    710             mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, (tMCA_CCB_EVT *)&evt_data);
    711         }
    712         else
    713         {
    714             MCA_TRACE_ERROR ("The given MCL is not expecting a MCA_ReconnectMdlRsp with the given parameters" );
    715             result = MCA_BAD_PARAMS;
    716         }
    717     }
    718     return result;
    719 }
    720 
    721 
    722 /*******************************************************************************
    723 **
    724 ** Function         MCA_DataChnlCfg
    725 **
    726 ** Description      This function initiates a data channel connection toward the
    727 **                  connected peer device.
    728 **                  When the data channel is open successfully, a MCA_OPEN_CFM_EVT
    729 **                  is reported. This data channel is identified as tMCA_DL.
    730 **
    731 ** Returns          MCA_SUCCESS if successful, otherwise error.
    732 **
    733 *******************************************************************************/
    734 tMCA_RESULT MCA_DataChnlCfg(tMCA_CL mcl, const tMCA_CHNL_CFG *p_chnl_cfg)
    735 {
    736     tMCA_RESULT     result = MCA_BAD_HANDLE;
    737     tMCA_CCB        *p_ccb = mca_ccb_by_hdl(mcl);
    738     tMCA_DCB        *p_dcb;
    739     tMCA_TC_TBL *p_tbl;
    740 
    741     MCA_TRACE_API ("MCA_DataChnlCfg: %d ", mcl);
    742     WC_ASSERT(p_chnl_cfg != NULL );
    743     if (p_ccb)
    744     {
    745         result = MCA_NO_RESOURCES;
    746         if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) ||
    747             ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL))
    748         {
    749             MCA_TRACE_ERROR ("The given MCL is not expecting this API:%d", p_ccb->status);
    750             return result;
    751         }
    752 
    753         p_dcb->p_chnl_cfg       = p_chnl_cfg;
    754         BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
    755             p_ccb->data_vpsm, BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx);
    756         p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg);
    757         if (p_dcb->lcid)
    758         {
    759             p_tbl = mca_tc_tbl_dalloc(p_dcb);
    760             if (p_tbl)
    761             {
    762                 p_tbl->state = MCA_TC_ST_CONN;
    763                 result = MCA_SUCCESS;
    764             }
    765         }
    766     }
    767     return result;
    768 }
    769 
    770 
    771 /*******************************************************************************
    772 **
    773 ** Function         MCA_Abort
    774 **
    775 ** Description      This function sends a ABORT_MDL request to the peer device.
    776 **                  When the response is received, a MCA_ABORT_CFM_EVT is reported.
    777 **
    778 ** Returns          MCA_SUCCESS if successful, otherwise error.
    779 **
    780 *******************************************************************************/
    781 tMCA_RESULT MCA_Abort(tMCA_CL mcl)
    782 {
    783     tMCA_RESULT     result = MCA_BAD_HANDLE;
    784     tMCA_CCB        *p_ccb = mca_ccb_by_hdl(mcl);
    785     tMCA_CCB_MSG    *p_evt_data;
    786     tMCA_DCB        *p_dcb;
    787 
    788     MCA_TRACE_API ("MCA_Abort: %d", mcl);
    789     if (p_ccb)
    790     {
    791         result = MCA_NO_RESOURCES;
    792         /* verify that we are waiting for data channel to come up with the given mdl */
    793         if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) ||
    794             ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL))
    795         {
    796             MCA_TRACE_ERROR ("The given MCL is not expecting this API:%d", p_ccb->status);
    797             return result;
    798         }
    799 
    800         if (p_ccb->cong)
    801         {
    802             MCA_TRACE_ERROR ("congested");
    803             return MCA_BUSY;
    804         }
    805 
    806         result = MCA_NO_RESOURCES;
    807         p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG));
    808         if (p_evt_data)
    809         {
    810             result = MCA_SUCCESS;
    811             p_evt_data->op_code     = MCA_OP_MDL_ABORT_REQ;
    812             p_evt_data->hdr.event   = MCA_CCB_API_REQ_EVT;
    813             mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
    814         }
    815 
    816     }
    817     return result;
    818 }
    819 
    820 
    821 /*******************************************************************************
    822 **
    823 ** Function         MCA_Delete
    824 **
    825 ** Description      This function sends a DELETE_MDL request to the peer device.
    826 **                  When the response is received, a MCA_DELETE_CFM_EVT is reported.
    827 **
    828 ** Returns          MCA_SUCCESS if successful, otherwise error.
    829 **
    830 *******************************************************************************/
    831 tMCA_RESULT MCA_Delete(tMCA_CL mcl, UINT16 mdl_id)
    832 {
    833     tMCA_RESULT     result = MCA_BAD_HANDLE;
    834     tMCA_CCB        *p_ccb = mca_ccb_by_hdl(mcl);
    835     tMCA_CCB_MSG    *p_evt_data;
    836 
    837     MCA_TRACE_API ("MCA_Delete: %d ", mcl);
    838     if (p_ccb)
    839     {
    840         if (p_ccb->cong)
    841         {
    842             MCA_TRACE_ERROR ("congested");
    843             return MCA_BUSY;
    844         }
    845         if (!MCA_IS_VALID_MDL_ID(mdl_id) && (mdl_id != MCA_ALL_MDL_ID))
    846         {
    847             MCA_TRACE_ERROR ("bad mdl id: %d ", mdl_id);
    848             return MCA_BAD_PARAMS;
    849         }
    850         p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG));
    851         if (p_evt_data)
    852         {
    853             result = MCA_SUCCESS;
    854             p_evt_data->mdl_id      = mdl_id;
    855             p_evt_data->op_code     = MCA_OP_MDL_DELETE_REQ;
    856             p_evt_data->hdr.event   = MCA_CCB_API_REQ_EVT;
    857             mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
    858         }
    859         else
    860             result = MCA_NO_RESOURCES;
    861     }
    862     return result;
    863 }
    864 
    865 /*******************************************************************************
    866 **
    867 ** Function         MCA_WriteReq
    868 **
    869 ** Description      Send a data packet to the peer device.
    870 **
    871 **                  The application passes the packet using the BT_HDR structure.
    872 **                  The offset field must be equal to or greater than L2CAP_MIN_OFFSET.
    873 **                  This allows enough space in the buffer for the L2CAP header.
    874 **
    875 **                  The memory pointed to by p_pkt must be a GKI buffer
    876 **                  allocated by the application.  This buffer will be freed
    877 **                  by the protocol stack; the application must not free
    878 **                  this buffer.
    879 **
    880 ** Returns          MCA_SUCCESS if successful, otherwise error.
    881 **
    882 *******************************************************************************/
    883 tMCA_RESULT MCA_WriteReq(tMCA_DL mdl, BT_HDR *p_pkt)
    884 {
    885     tMCA_RESULT     result = MCA_BAD_HANDLE;
    886     tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl);
    887     tMCA_DCB_EVT    evt_data;
    888 
    889     MCA_TRACE_API ("MCA_WriteReq: %d ", mdl);
    890     if (p_dcb)
    891     {
    892         if (p_dcb->cong)
    893         {
    894             result = MCA_BUSY;
    895         }
    896         else
    897         {
    898             evt_data.p_pkt  = p_pkt;
    899             result = MCA_SUCCESS;
    900             mca_dcb_event(p_dcb, MCA_DCB_API_WRITE_EVT, &evt_data);
    901         }
    902     }
    903     return result;
    904 }
    905 
    906 /*******************************************************************************
    907 **
    908 ** Function         MCA_GetL2CapChannel
    909 **
    910 ** Description      Get the L2CAP CID used by the given data channel handle.
    911 **
    912 ** Returns          L2CAP channel ID if successful, otherwise 0.
    913 **
    914 *******************************************************************************/
    915 UINT16 MCA_GetL2CapChannel (tMCA_DL mdl)
    916 {
    917     UINT16  lcid = 0;
    918     tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl);
    919 
    920     MCA_TRACE_API ("MCA_GetL2CapChannel: %d ", mdl);
    921     if (p_dcb)
    922         lcid = p_dcb->lcid;
    923     return lcid;
    924 }
    925 
    926