/******************************************************************************* ** ** Function mca_l2c_dconn_ind_cback ** ** Description This is the L2CAP connect indication callback function. ** ** ** Returns void ** *******************************************************************************/ void mca_l2c_dconn_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id) { tMCA_HANDLE handle = mca_handle_by_dpsm(psm); tMCA_CCB *p_ccb; tMCA_DCB *p_dcb; tMCA_TC_TBL *p_tbl = NULL; UINT16 result; tL2CAP_CFG_INFO cfg; tL2CAP_ERTM_INFO *p_ertm_info = NULL, ertm_info; const tMCA_CHNL_CFG *p_chnl_cfg; MCA_TRACE_EVENT2 ("mca_l2c_dconn_ind_cback: lcid:x%x psm:x%x ", lcid, psm); if (((p_ccb = mca_ccb_by_bd(handle, bd_addr)) != NULL) && /* find the CCB */ (p_ccb->status == MCA_CCB_STAT_PENDING) && /* this CCB is expecting a MDL */ (p_ccb->p_tx_req && (p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL)) { /* found the associated dcb in listening mode */ /* proceed with connection */ p_dcb->lcid = lcid; p_tbl = mca_tc_tbl_dalloc(p_dcb); p_tbl->id = id; p_tbl->cfg_flags= MCA_L2C_CFG_CONN_ACP; p_chnl_cfg = p_dcb->p_chnl_cfg; /* assume that control channel has verified the security requirement */ /* Set the FCR options: control channel mandates ERTM */ ertm_info.preferred_mode = p_chnl_cfg->fcr_opt.mode; ertm_info.allowed_modes = (1 << p_chnl_cfg->fcr_opt.mode); ertm_info.user_rx_pool_id = p_chnl_cfg->user_rx_pool_id; ertm_info.user_tx_pool_id = p_chnl_cfg->user_tx_pool_id; ertm_info.fcr_rx_pool_id = p_chnl_cfg->fcr_rx_pool_id; ertm_info.fcr_tx_pool_id = p_chnl_cfg->fcr_tx_pool_id; p_ertm_info = &ertm_info; result = L2CAP_CONN_OK; } else { /* else we're not listening for traffic channel; reject * (this error code is specified by MCAP spec) */ result = L2CAP_CONN_NO_RESOURCES; } /* Send L2CAP connect rsp */ L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, result, p_ertm_info); /* if result ok, proceed with connection */ if (result == L2CAP_CONN_OK) { /* transition to configuration state */ p_tbl->state = MCA_TC_ST_CFG; /* Send L2CAP config req */ mca_set_cfg_by_tbl (&cfg, p_tbl); L2CA_ConfigReq(lcid, &cfg); } }
/******************************************************************************* ** ** Function mca_ccb_hdl_rsp ** ** Description This function is called when a MCAP response is received from ** the peer. It calls the application callback function with ** the results. ** ** Returns void. ** *******************************************************************************/ void mca_ccb_hdl_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) { BT_HDR *p_pkt = &p_data->hdr; UINT8 *p; tMCA_CTRL evt_data; BOOLEAN chk_mdl = FALSE; tMCA_DCB *p_dcb; tMCA_RESULT result = MCA_BAD_HANDLE; tMCA_TC_TBL *p_tbl; if (p_ccb->p_tx_req) { /* verify that the received response matches the sent request */ p = (UINT8 *)(p_pkt + 1) + p_pkt->offset; evt_data.hdr.op_code = *p++; if ((evt_data.hdr.op_code == 0) || ((p_ccb->p_tx_req->op_code + 1) == evt_data.hdr.op_code)) { evt_data.rsp.rsp_code = *p++; mca_stop_timer(p_ccb); BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p); if (evt_data.hdr.op_code == MCA_OP_MDL_CREATE_RSP) { evt_data.create_cfm.cfg = *p++; chk_mdl = TRUE; } else if (evt_data.hdr.op_code == MCA_OP_MDL_RECONNECT_RSP) chk_mdl = TRUE; if (chk_mdl) { p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx); if (p_dcb && evt_data.rsp.rsp_code == MCA_RSP_SUCCESS) { if (evt_data.hdr.mdl_id != p_dcb->mdl_id) { MCA_TRACE_ERROR ("peer's mdl_id=%d != our mdl_id=%d", evt_data.hdr.mdl_id, p_dcb->mdl_id); /* change the response code to be an error */ if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS) { evt_data.rsp.rsp_code = MCA_RSP_BAD_MDL; /* send Abort */ p_ccb->status = MCA_CCB_STAT_PENDING; MCA_Abort(mca_ccb_to_hdl(p_ccb)); } } else if (p_dcb->p_chnl_cfg) { /* the data channel configuration is known. Proceed with data channel initiation */ 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; p_ccb->status = MCA_CCB_STAT_PENDING; result = MCA_SUCCESS; } } } else { /* mark this MCL as pending and wait for MCA_DataChnlCfg */ p_ccb->status = MCA_CCB_STAT_PENDING; result = MCA_SUCCESS; } } if (result != MCA_SUCCESS && p_dcb) { mca_dcb_dealloc(p_dcb, NULL); } } /* end of chk_mdl */ if (p_ccb->status != MCA_CCB_STAT_PENDING) mca_free_buf ((void **)&p_ccb->p_tx_req); mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data); } /* else a bad response is received */ } else { /* not expecting any response. drop it */ MCA_TRACE_WARNING ("dropping received rsp (not expecting a response)"); } GKI_freebuf (p_data); }