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