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