diff options
Diffstat (limited to 'stack/mcap/mca_api.c')
-rw-r--r-- | stack/mcap/mca_api.c | 925 |
1 files changed, 925 insertions, 0 deletions
diff --git a/stack/mcap/mca_api.c b/stack/mcap/mca_api.c new file mode 100644 index 0000000..1792f8c --- /dev/null +++ b/stack/mcap/mca_api.c @@ -0,0 +1,925 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the API implementation file for the Multi-Channel Adaptation + * Protocol (MCAP). + * + ******************************************************************************/ +#include <string.h> + +#include "bt_target.h" +#include "btm_api.h" +#include "btm_int.h" +#include "mca_api.h" +#include "mca_defs.h" +#include "mca_int.h" + +#include "wcassert.h" +#include "btu.h" + + +/******************************************************************************* +** +** Function mca_process_timeout +** +** Description This function is called by BTU when an MCA timer +** expires. +** +** This function is for use internal to the stack only. +** +** Returns void +** +*******************************************************************************/ +void mca_process_timeout(TIMER_LIST_ENT *p_tle) +{ + if(p_tle->event == BTU_TTYPE_MCA_CCB_RSP) + { + p_tle->event = 0; + mca_ccb_event ((tMCA_CCB *) p_tle->param, MCA_CCB_RSP_TOUT_EVT, NULL); + } +} + +/******************************************************************************* +** +** Function MCA_Init +** +** Description Initialize MCAP main control block. +** This function is called at stack start up. +** +** Returns void +** +*******************************************************************************/ +void MCA_Init(void) +{ + memset(&mca_cb, 0, sizeof(tMCA_CB)); + +#if defined(MCA_INITIAL_TRACE_LEVEL) + mca_cb.trace_level = MCA_INITIAL_TRACE_LEVEL; +#else + mca_cb.trace_level = BT_TRACE_LEVEL_NONE; +#endif +} + +/******************************************************************************* +** +** Function MCA_SetTraceLevel +** +** Description This function sets the debug trace level for MCA. +** If 0xff is passed, the current trace level is returned. +** +** Input Parameters: +** level: The level to set the MCA tracing to: +** 0xff-returns the current setting. +** 0-turns off tracing. +** >= 1-Errors. +** >= 2-Warnings. +** >= 3-APIs. +** >= 4-Events. +** >= 5-Debug. +** +** Returns The new trace level or current trace level if +** the input parameter is 0xff. +** +*******************************************************************************/ +UINT8 MCA_SetTraceLevel (UINT8 level) +{ + if (level != 0xFF) + mca_cb.trace_level = level; + + return (mca_cb.trace_level); +} + +/******************************************************************************* +** +** Function MCA_Register +** +** Description This function registers an MCAP implementation. +** It is assumed that the control channel PSM and data channel +** PSM are not used by any other instances of the stack. +** If the given p_reg->ctrl_psm is 0, this handle is INT only. +** +** Returns 0, if failed. Otherwise, the MCA handle. +** +*******************************************************************************/ +tMCA_HANDLE MCA_Register(tMCA_REG *p_reg, tMCA_CTRL_CBACK *p_cback) +{ + tMCA_RCB *p_rcb; + tMCA_HANDLE handle = 0; + tL2CAP_APPL_INFO l2c_cacp_appl; + tL2CAP_APPL_INFO l2c_dacp_appl; + + WC_ASSERT(p_reg != NULL ); + WC_ASSERT(p_cback != NULL ); + + MCA_TRACE_API2 ("MCA_Register: ctrl_psm:0x%x, data_psm:0x%x", p_reg->ctrl_psm, p_reg->data_psm); + + if ( (p_rcb = mca_rcb_alloc (p_reg)) != NULL) + { + if (p_reg->ctrl_psm) + { + if (L2C_INVALID_PSM(p_reg->ctrl_psm) || L2C_INVALID_PSM(p_reg->data_psm)) + { + MCA_TRACE_ERROR0 ("INVALID_PSM"); + return 0; + } + + l2c_cacp_appl = *(tL2CAP_APPL_INFO *)&mca_l2c_int_appl; + l2c_cacp_appl.pL2CA_ConnectCfm_Cb = NULL; + l2c_dacp_appl = *(tL2CAP_APPL_INFO *)&l2c_cacp_appl; + l2c_cacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_cconn_ind_cback; + l2c_dacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_dconn_ind_cback; + if (L2CA_Register(p_reg->ctrl_psm, (tL2CAP_APPL_INFO *) &l2c_cacp_appl) && + L2CA_Register(p_reg->data_psm, (tL2CAP_APPL_INFO *) &l2c_dacp_appl)) + { + /* set security level */ + BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_CTRL, p_reg->sec_mask, + p_reg->ctrl_psm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID); + + /* in theory, we do not need this one for data_psm + * If we don't, L2CAP rejects with security block (3), + * which is different reject code from what MCAP spec suggests. + * we set this one, so mca_l2c_dconn_ind_cback can reject /w no resources (4) */ + BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_DATA, p_reg->sec_mask, + p_reg->data_psm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID); + } + else + { + MCA_TRACE_ERROR0 ("Failed to register to L2CAP"); + return 0; + } + } + else + p_rcb->reg.data_psm = 0; + handle = mca_rcb_to_handle (p_rcb); + p_rcb->p_cback = p_cback; + p_rcb->reg.rsp_tout = p_reg->rsp_tout; + } + return handle; +} + + +/******************************************************************************* +** +** Function MCA_Deregister +** +** Description This function is called to deregister an MCAP implementation. +** Before this function can be called, all control and data +** channels must be removed with MCA_DisconnectReq and MCA_CloseReq. +** +** Returns void +** +*******************************************************************************/ +void MCA_Deregister(tMCA_HANDLE handle) +{ + tMCA_RCB *p_rcb = mca_rcb_by_handle(handle); + + MCA_TRACE_API1 ("MCA_Deregister: %d", handle); + if (p_rcb && p_rcb->reg.ctrl_psm) + { + L2CA_Deregister(p_rcb->reg.ctrl_psm); + L2CA_Deregister(p_rcb->reg.data_psm); + btm_sec_clr_service_by_psm (p_rcb->reg.ctrl_psm); + btm_sec_clr_service_by_psm (p_rcb->reg.data_psm); + } + mca_rcb_dealloc(handle); +} + + +/******************************************************************************* +** +** Function MCA_CreateDep +** +** Description Create a data endpoint. If the MDEP is created successfully, +** the MDEP ID is returned in *p_dep. After a data endpoint is +** created, an application can initiate a connection between this +** endpoint and an endpoint on a peer device. +** +** Returns MCA_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +tMCA_RESULT MCA_CreateDep(tMCA_HANDLE handle, tMCA_DEP *p_dep, tMCA_CS *p_cs) +{ + tMCA_RESULT result = MCA_BAD_HANDLE; + int i; + tMCA_RCB *p_rcb = mca_rcb_by_handle(handle); + tMCA_CS *p_depcs; + + WC_ASSERT(p_dep != NULL ); + WC_ASSERT(p_cs != NULL ); + WC_ASSERT(p_cs->p_data_cback != NULL ); + + MCA_TRACE_API1 ("MCA_CreateDep: %d", handle); + if (p_rcb) + { + if (p_cs->max_mdl > MCA_NUM_MDLS) + { + MCA_TRACE_ERROR1 ("max_mdl: %d is too big", p_cs->max_mdl ); + result = MCA_BAD_PARAMS; + } + else + { + p_depcs = p_rcb->dep; + if (p_cs->type == MCA_TDEP_ECHO) + { + if (p_depcs->p_data_cback) + { + MCA_TRACE_ERROR0 ("Already has ECHO MDEP"); + return MCA_NO_RESOURCES; + } + memcpy (p_depcs, p_cs, sizeof (tMCA_CS)); + *p_dep = 0; + result = MCA_SUCCESS; + } + else + { + result = MCA_NO_RESOURCES; + /* non-echo MDEP starts from 1 */ + p_depcs++; + for (i=1; i<MCA_NUM_DEPS; i++, p_depcs++) + { + if (p_depcs->p_data_cback == NULL) + { + memcpy (p_depcs, p_cs, sizeof (tMCA_CS)); + /* internally use type as the mdep id */ + p_depcs->type = i; + *p_dep = i; + result = MCA_SUCCESS; + break; + } + } + } + } + } + return result; +} + + +/******************************************************************************* +** +** Function MCA_DeleteDep +** +** Description Delete a data endpoint. This function is called when +** the implementation is no longer using a data endpoint. +** If this function is called when the endpoint is connected +** the connection is closed and the data endpoint +** is removed. +** +** Returns MCA_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +tMCA_RESULT MCA_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep) +{ + tMCA_RESULT result = MCA_BAD_HANDLE; + tMCA_RCB *p_rcb = mca_rcb_by_handle(handle); + tMCA_DCB *p_dcb; + int i, max; + tMCA_CS *p_depcs; + + MCA_TRACE_API2 ("MCA_DeleteDep: %d dep:%d", handle, dep); + if (p_rcb) + { + if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback) + { + result = MCA_SUCCESS; + p_rcb->dep[dep].p_data_cback = NULL; + p_depcs = &(p_rcb->dep[dep]); + i = handle - 1; + max = MCA_NUM_MDLS*MCA_NUM_LINKS; + p_dcb = &mca_cb.dcb[i*max]; + /* make sure no MDL exists for this MDEP */ + for (i=0; i<max; i++, p_dcb++) + { + if (p_dcb->state && p_dcb->p_cs == p_depcs) + { + mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL); + } + } + } + } + return result; +} + +/******************************************************************************* +** +** Function MCA_ConnectReq +** +** Description This function initiates an MCAP control channel connection +** to the peer device. When the connection is completed, an +** MCA_CONNECT_IND_EVT is reported to the application via its +** control callback function. +** This control channel is identified by the tMCA_CL. +** If the connection attempt fails, an MCA_DISCONNECT_IND_EVT is +** reported. The security mask parameter overrides the outgoing +** security mask set in MCA_Register(). +** +** Returns MCA_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +tMCA_RESULT MCA_ConnectReq(tMCA_HANDLE handle, BD_ADDR bd_addr, + UINT16 ctrl_psm, UINT16 sec_mask) +{ + tMCA_RESULT result = MCA_BAD_HANDLE; + tMCA_CCB *p_ccb; + tMCA_TC_TBL *p_tbl; + + MCA_TRACE_API2 ("MCA_ConnectReq: %d psm:0x%x", handle, ctrl_psm); + if ((p_ccb = mca_ccb_by_bd(handle, bd_addr)) == NULL) + p_ccb = mca_ccb_alloc(handle, bd_addr); + else + { + MCA_TRACE_ERROR0 ("control channel already exists"); + return MCA_BUSY; + } + + if (p_ccb) + { + p_ccb->ctrl_vpsm = L2CA_Register (ctrl_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl); + result = MCA_NO_RESOURCES; + if (p_ccb->ctrl_vpsm) + { + BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_CTRL, sec_mask, + p_ccb->ctrl_vpsm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID); + p_ccb->lcid = mca_l2c_open_req(bd_addr, p_ccb->ctrl_vpsm, NULL); + if (p_ccb->lcid) + { + p_tbl = mca_tc_tbl_calloc(p_ccb); + if (p_tbl) + { + p_tbl->state = MCA_TC_ST_CONN; + p_ccb->sec_mask = sec_mask; + result = MCA_SUCCESS; + } + } + } + if (result != MCA_SUCCESS) + mca_ccb_dealloc (p_ccb, NULL); + } + return result; +} + + +/******************************************************************************* +** +** Function MCA_DisconnectReq +** +** Description This function disconnect an MCAP control channel +** to the peer device. +** If associated data channel exists, they are disconnected. +** When the MCL is disconnected an MCA_DISCONNECT_IND_EVT is +** reported to the application via its control callback function. +** +** Returns MCA_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +tMCA_RESULT MCA_DisconnectReq(tMCA_CL mcl) +{ + tMCA_RESULT result = MCA_BAD_HANDLE; + tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); + + MCA_TRACE_API1 ("MCA_DisconnectReq: %d ", mcl); + if (p_ccb) + { + result = MCA_SUCCESS; + mca_ccb_event (p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL); + } + return result; +} + + +/******************************************************************************* +** +** Function MCA_CreateMdl +** +** Description This function sends a CREATE_MDL request to the peer device. +** When the response is received, a MCA_CREATE_CFM_EVT is reported +** with the given MDL ID. +** If the response is successful, a data channel is open +** with the given p_chnl_cfg +** If p_chnl_cfg is NULL, the data channel is not initiated until +** MCA_DataChnlCfg is called to provide the p_chnl_cfg. +** When the data channel is open successfully, a MCA_OPEN_CFM_EVT +** is reported. This data channel is identified as tMCA_DL. +** +** Returns MCA_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +tMCA_RESULT MCA_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm, + UINT16 mdl_id, UINT8 peer_dep_id, + UINT8 cfg, const tMCA_CHNL_CFG *p_chnl_cfg) +{ + tMCA_RESULT result = MCA_BAD_HANDLE; + tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); + tMCA_CCB_MSG *p_evt_data; + tMCA_DCB *p_dcb; + + MCA_TRACE_API4 ("MCA_CreateMdl: %d dep=%d mdl_id=%d peer_dep_id=%d", mcl, dep, mdl_id, peer_dep_id); + if (p_ccb) + { + if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong) + { + MCA_TRACE_ERROR0 ("pending req"); + return MCA_BUSY; + } + + if ((peer_dep_id > MCA_MAX_MDEP_ID) || (!MCA_IS_VALID_MDL_ID(mdl_id))) + { + MCA_TRACE_ERROR2 ("bad peer dep id:%d or bad mdl id: %d ", peer_dep_id, mdl_id); + return MCA_BAD_PARAMS; + } + + if (mca_ccb_uses_mdl_id(p_ccb, mdl_id)) + { + MCA_TRACE_ERROR1 ("mdl id: %d is used in the control link", mdl_id); + return MCA_BAD_MDL_ID; + } + + p_dcb = mca_dcb_alloc(p_ccb, dep); + result = MCA_NO_RESOURCES; + if (p_dcb) + { + /* save the info required by dcb connection */ + p_dcb->p_chnl_cfg = p_chnl_cfg; + p_dcb->mdl_id = mdl_id; + p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG)); + if (p_evt_data) + { + if (!p_ccb->data_vpsm) + p_ccb->data_vpsm = L2CA_Register (data_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl); + if (p_ccb->data_vpsm) + { + p_evt_data->dcb_idx = mca_dcb_to_hdl (p_dcb); + p_evt_data->mdep_id = peer_dep_id; + p_evt_data->mdl_id = mdl_id; + p_evt_data->param = cfg; + p_evt_data->op_code = MCA_OP_MDL_CREATE_REQ; + p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT; + p_evt_data->hdr.layer_specific = FALSE; + mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data); + return MCA_SUCCESS; + } + else + GKI_freebuf (p_evt_data); + } + mca_dcb_dealloc(p_dcb, NULL); + } + } + return result; +} + + +/******************************************************************************* +** +** Function MCA_CreateMdlRsp +** +** Description This function sends a CREATE_MDL response to the peer device +** in response to a received MCA_CREATE_IND_EVT. +** If the rsp_code is successful, a data channel is open +** with the given p_chnl_cfg +** When the data channel is open successfully, a MCA_OPEN_IND_EVT +** is reported. This data channel is identified as tMCA_DL. +** +** Returns MCA_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +tMCA_RESULT MCA_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep, + UINT16 mdl_id, UINT8 cfg, UINT8 rsp_code, + const tMCA_CHNL_CFG *p_chnl_cfg) +{ + tMCA_RESULT result = MCA_BAD_HANDLE; + tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); + tMCA_CCB_MSG evt_data; + tMCA_DCB *p_dcb; + + MCA_TRACE_API5 ("MCA_CreateMdlRsp: %d dep=%d mdl_id=%d cfg=%d rsp_code=%d", mcl, dep, mdl_id, cfg, rsp_code); + WC_ASSERT(p_chnl_cfg != NULL ); + if (p_ccb) + { + if (p_ccb->cong) + { + MCA_TRACE_ERROR0 ("congested"); + return MCA_BUSY; + } + if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdep_id == dep ) + && (p_ccb->p_rx_msg->mdl_id == mdl_id) && (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_CREATE_REQ)) + { + result = MCA_SUCCESS; + evt_data.dcb_idx = 0; + if (rsp_code == MCA_RSP_SUCCESS) + { + p_dcb = mca_dcb_alloc(p_ccb, dep); + if (p_dcb) + { + evt_data.dcb_idx = mca_dcb_to_hdl(p_dcb); + p_dcb->p_chnl_cfg = p_chnl_cfg; + p_dcb->mdl_id = mdl_id; + } + else + { + rsp_code = MCA_RSP_MDEP_BUSY; + result = MCA_NO_RESOURCES; + } + } + + if (result == MCA_SUCCESS) + { + evt_data.mdl_id = mdl_id; + evt_data.param = cfg; + evt_data.rsp_code = rsp_code; + evt_data.op_code = MCA_OP_MDL_CREATE_RSP; + mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, (tMCA_CCB_EVT *)&evt_data); + } + } + else + { + MCA_TRACE_ERROR0 ("The given MCL is not expecting a MCA_CreateMdlRsp with the given parameters" ); + result = MCA_BAD_PARAMS; + } + } + return result; +} + +/******************************************************************************* +** +** Function MCA_CloseReq +** +** Description Close a data channel. When the channel is closed, an +** MCA_CLOSE_CFM_EVT is sent to the application via the +** control callback function for this handle. +** +** Returns MCA_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +tMCA_RESULT MCA_CloseReq(tMCA_DL mdl) +{ + tMCA_RESULT result = MCA_BAD_HANDLE; + tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl); + + MCA_TRACE_API1 ("MCA_CloseReq: %d ", mdl); + if (p_dcb) + { + result = MCA_SUCCESS; + mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL); + } + return result; +} + + +/******************************************************************************* +** +** Function MCA_ReconnectMdl +** +** Description This function sends a RECONNECT_MDL request to the peer device. +** When the response is received, a MCA_RECONNECT_CFM_EVT is reported. +** If p_chnl_cfg is NULL, the data channel is not initiated until +** MCA_DataChnlCfg is called to provide the p_chnl_cfg. +** If the response is successful, a data channel is open. +** When the data channel is open successfully, a MCA_OPEN_CFM_EVT +** is reported. +** +** Returns MCA_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +tMCA_RESULT MCA_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm, + UINT16 mdl_id, const tMCA_CHNL_CFG *p_chnl_cfg) +{ + tMCA_RESULT result = MCA_BAD_HANDLE; + tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); + tMCA_CCB_MSG *p_evt_data; + tMCA_DCB *p_dcb; + + MCA_TRACE_API1 ("MCA_ReconnectMdl: %d ", mcl); + WC_ASSERT(p_chnl_cfg != NULL ); + if (p_ccb) + { + if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong) + { + MCA_TRACE_ERROR0 ("pending req"); + return MCA_BUSY; + } + + if (!MCA_IS_VALID_MDL_ID(mdl_id)) + { + MCA_TRACE_ERROR1 ("bad mdl id: %d ", mdl_id); + return MCA_BAD_PARAMS; + } + + if (mca_ccb_uses_mdl_id(p_ccb, mdl_id)) + { + MCA_TRACE_ERROR1 ("mdl id: %d is used in the control link", mdl_id); + return MCA_BAD_MDL_ID; + } + + p_dcb = mca_dcb_alloc(p_ccb, dep); + result = MCA_NO_RESOURCES; + if (p_dcb) + { + p_dcb->p_chnl_cfg = p_chnl_cfg; + p_dcb->mdl_id = mdl_id; + p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG)); + if (p_evt_data) + { + if (!p_ccb->data_vpsm) + p_ccb->data_vpsm = L2CA_Register (data_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl); + p_evt_data->dcb_idx = mca_dcb_to_hdl(p_dcb); + p_evt_data->mdl_id = mdl_id; + p_evt_data->op_code = MCA_OP_MDL_RECONNECT_REQ; + p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT; + mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data); + return MCA_SUCCESS; + } + mca_dcb_dealloc(p_dcb, NULL); + } + } + return result; +} + + +/******************************************************************************* +** +** Function MCA_ReconnectMdlRsp +** +** Description This function sends a RECONNECT_MDL response to the peer device +** in response to a MCA_RECONNECT_IND_EVT event. +** If the response is successful, a data channel is open. +** When the data channel is open successfully, a MCA_OPEN_IND_EVT +** is reported. +** +** Returns MCA_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +tMCA_RESULT MCA_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep, + UINT16 mdl_id, UINT8 rsp_code, + const tMCA_CHNL_CFG *p_chnl_cfg) +{ + tMCA_RESULT result = MCA_BAD_HANDLE; + tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); + tMCA_CCB_MSG evt_data; + tMCA_DCB *p_dcb; + + MCA_TRACE_API1 ("MCA_ReconnectMdlRsp: %d ", mcl); + WC_ASSERT(p_chnl_cfg != NULL ); + if (p_ccb) + { + if (p_ccb->cong) + { + MCA_TRACE_ERROR0 ("congested"); + return MCA_BUSY; + } + if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdl_id == mdl_id) && + (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_RECONNECT_REQ)) + { + result = MCA_SUCCESS; + evt_data.dcb_idx = 0; + if (rsp_code == MCA_RSP_SUCCESS) + { + p_dcb = mca_dcb_alloc(p_ccb, dep); + if (p_dcb) + { + evt_data.dcb_idx = mca_dcb_to_hdl(p_dcb); + p_dcb->p_chnl_cfg = p_chnl_cfg; + p_dcb->mdl_id = mdl_id; + } + else + { + MCA_TRACE_ERROR0 ("Out of MDL for this MDEP"); + rsp_code = MCA_RSP_MDEP_BUSY; + result = MCA_NO_RESOURCES; + } + } + + evt_data.mdl_id = mdl_id; + evt_data.rsp_code = rsp_code; + evt_data.op_code = MCA_OP_MDL_RECONNECT_RSP; + mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, (tMCA_CCB_EVT *)&evt_data); + } + else + { + MCA_TRACE_ERROR0 ("The given MCL is not expecting a MCA_ReconnectMdlRsp with the given parameters" ); + result = MCA_BAD_PARAMS; + } + } + return result; +} + + +/******************************************************************************* +** +** Function MCA_DataChnlCfg +** +** Description This function initiates a data channel connection toward the +** connected peer device. +** When the data channel is open successfully, a MCA_OPEN_CFM_EVT +** is reported. This data channel is identified as tMCA_DL. +** +** Returns MCA_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +tMCA_RESULT MCA_DataChnlCfg(tMCA_CL mcl, const tMCA_CHNL_CFG *p_chnl_cfg) +{ + tMCA_RESULT result = MCA_BAD_HANDLE; + tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); + tMCA_DCB *p_dcb; + tMCA_TC_TBL *p_tbl; + + MCA_TRACE_API1 ("MCA_DataChnlCfg: %d ", mcl); + WC_ASSERT(p_chnl_cfg != NULL ); + if (p_ccb) + { + result = MCA_NO_RESOURCES; + if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) || + ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL)) + { + MCA_TRACE_ERROR1 ("The given MCL is not expecting this API:%d", p_ccb->status); + return result; + } + + p_dcb->p_chnl_cfg = p_chnl_cfg; + BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask, + p_ccb->data_vpsm, BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx); + p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg); + if (p_dcb->lcid) + { + p_tbl = mca_tc_tbl_dalloc(p_dcb); + if (p_tbl) + { + p_tbl->state = MCA_TC_ST_CONN; + result = MCA_SUCCESS; + } + } + } + return result; +} + + +/******************************************************************************* +** +** Function MCA_Abort +** +** Description This function sends a ABORT_MDL request to the peer device. +** When the response is received, a MCA_ABORT_CFM_EVT is reported. +** +** Returns MCA_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +tMCA_RESULT MCA_Abort(tMCA_CL mcl) +{ + tMCA_RESULT result = MCA_BAD_HANDLE; + tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); + tMCA_CCB_MSG *p_evt_data; + tMCA_DCB *p_dcb; + + MCA_TRACE_API1 ("MCA_Abort: %d", mcl); + if (p_ccb) + { + result = MCA_NO_RESOURCES; + /* verify that we are waiting for data channel to come up with the given mdl */ + if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) || + ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL)) + { + MCA_TRACE_ERROR1 ("The given MCL is not expecting this API:%d", p_ccb->status); + return result; + } + + if (p_ccb->cong) + { + MCA_TRACE_ERROR0 ("congested"); + return MCA_BUSY; + } + + result = MCA_NO_RESOURCES; + p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG)); + if (p_evt_data) + { + result = MCA_SUCCESS; + p_evt_data->op_code = MCA_OP_MDL_ABORT_REQ; + p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT; + mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data); + } + + } + return result; +} + + +/******************************************************************************* +** +** Function MCA_Delete +** +** Description This function sends a DELETE_MDL request to the peer device. +** When the response is received, a MCA_DELETE_CFM_EVT is reported. +** +** Returns MCA_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +tMCA_RESULT MCA_Delete(tMCA_CL mcl, UINT16 mdl_id) +{ + tMCA_RESULT result = MCA_BAD_HANDLE; + tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); + tMCA_CCB_MSG *p_evt_data; + + MCA_TRACE_API1 ("MCA_Delete: %d ", mcl); + if (p_ccb) + { + if (p_ccb->cong) + { + MCA_TRACE_ERROR0 ("congested"); + return MCA_BUSY; + } + if (!MCA_IS_VALID_MDL_ID(mdl_id) && (mdl_id != MCA_ALL_MDL_ID)) + { + MCA_TRACE_ERROR1 ("bad mdl id: %d ", mdl_id); + return MCA_BAD_PARAMS; + } + p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG)); + if (p_evt_data) + { + result = MCA_SUCCESS; + p_evt_data->mdl_id = mdl_id; + p_evt_data->op_code = MCA_OP_MDL_DELETE_REQ; + p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT; + mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data); + } + else + result = MCA_NO_RESOURCES; + } + return result; +} + +/******************************************************************************* +** +** Function MCA_WriteReq +** +** Description Send a data packet to the peer device. +** +** The application passes the packet using the BT_HDR structure. +** The offset field must be equal to or greater than L2CAP_MIN_OFFSET. +** This allows enough space in the buffer for the L2CAP header. +** +** The memory pointed to by p_pkt must be a GKI buffer +** allocated by the application. This buffer will be freed +** by the protocol stack; the application must not free +** this buffer. +** +** Returns MCA_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +tMCA_RESULT MCA_WriteReq(tMCA_DL mdl, BT_HDR *p_pkt) +{ + tMCA_RESULT result = MCA_BAD_HANDLE; + tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl); + tMCA_DCB_EVT evt_data; + + MCA_TRACE_API1 ("MCA_WriteReq: %d ", mdl); + if (p_dcb) + { + if (p_dcb->cong) + { + result = MCA_BUSY; + } + else + { + evt_data.p_pkt = p_pkt; + result = MCA_SUCCESS; + mca_dcb_event(p_dcb, MCA_DCB_API_WRITE_EVT, &evt_data); + } + } + return result; +} + +/******************************************************************************* +** +** Function MCA_GetL2CapChannel +** +** Description Get the L2CAP CID used by the given data channel handle. +** +** Returns L2CAP channel ID if successful, otherwise 0. +** +*******************************************************************************/ +UINT16 MCA_GetL2CapChannel (tMCA_DL mdl) +{ + UINT16 lcid = 0; + tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl); + + MCA_TRACE_API1 ("MCA_GetL2CapChannel: %d ", mdl); + if (p_dcb) + lcid = p_dcb->lcid; + return lcid; +} + |