/******************************************************************************* ** ** Function mca_ccb_rsp_tout ** ** Description This function processes the response timeout. ** ** Returns void. ** *******************************************************************************/ void mca_ccb_rsp_tout(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) { tMCA_CTRL evt_data; UNUSED(p_data); mca_ccb_report_event(p_ccb, MCA_RSP_TOUT_IND_EVT, &evt_data); }
/******************************************************************************* ** ** Function mca_ccb_ll_open ** ** Description This function is called to report MCA_CONNECT_IND_EVT event. ** It also clears the congestion flag (ccb.cong). ** ** Returns void. ** *******************************************************************************/ void mca_ccb_ll_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) { tMCA_CTRL evt_data; p_ccb->cong = FALSE; evt_data.connect_ind.mtu = p_data->open.peer_mtu; memcpy (evt_data.connect_ind.bd_addr, p_ccb->peer_addr, BD_ADDR_LEN); mca_ccb_report_event (p_ccb, MCA_CONNECT_IND_EVT, &evt_data); }
/******************************************************************************* ** ** Function mca_dcb_report_cong ** ** Description This function is called to report the congestion flag. ** ** Returns void. ** *******************************************************************************/ void mca_dcb_report_cong (tMCA_DCB *p_dcb) { tMCA_CTRL evt_data; evt_data.cong_chg.cong = p_dcb->cong; evt_data.cong_chg.mdl = mca_dcb_to_hdl(p_dcb); evt_data.cong_chg.mdl_id = p_dcb->mdl_id; mca_ccb_report_event (p_dcb->p_ccb, MCA_CONG_CHG_EVT, &evt_data); }
/******************************************************************************* ** ** Function mca_dcb_tc_open ** ** Description This function is called to report MCA_OPEN_IND_EVT or ** MCA_OPEN_CFM_EVT event. ** It also clears the congestion flag (dcb.cong). ** ** Returns void. ** *******************************************************************************/ void mca_dcb_tc_open (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data) { tMCA_CTRL evt_data; tMCA_CCB *p_ccb = p_dcb->p_ccb; UINT8 event = MCA_OPEN_IND_EVT; if (p_data->open.param == MCA_INT) event = MCA_OPEN_CFM_EVT; p_dcb->cong = FALSE; evt_data.open_cfm.mtu = p_data->open.peer_mtu; evt_data.open_cfm.mdl_id = p_dcb->mdl_id; evt_data.open_cfm.mdl = mca_dcb_to_hdl(p_dcb); mca_ccb_event (p_ccb, MCA_CCB_DL_OPEN_EVT, NULL); mca_ccb_report_event (p_ccb, event, &evt_data); }
/******************************************************************************* ** ** Function mca_dcb_dealloc ** ** Description This function deallocates an DCB. ** ** Returns void. ** *******************************************************************************/ void mca_dcb_dealloc(tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data) { tMCA_CCB *p_ccb = p_dcb->p_ccb; UINT8 event = MCA_CLOSE_IND_EVT; tMCA_CTRL evt_data; MCA_TRACE_DEBUG("mca_dcb_dealloc"); mca_free_buf ((void **)&p_dcb->p_data); if (p_data) { /* non-NULL -> an action function -> report disconnect event */ evt_data.close_cfm.mdl = mca_dcb_to_hdl(p_dcb); evt_data.close_cfm.reason = p_data->close.reason; evt_data.close_cfm.mdl_id = p_dcb->mdl_id; if (p_data->close.param == MCA_INT) event = MCA_CLOSE_CFM_EVT; if (p_data->close.lcid) mca_ccb_report_event(p_ccb, event, &evt_data); } mca_free_tc_tbl_by_lcid (p_dcb->lcid); memset (p_dcb, 0, sizeof (tMCA_DCB)); }
/******************************************************************************* ** ** 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); }
/******************************************************************************* ** ** Function mca_ccb_hdl_req ** ** Description This function is called when a MCAP request is received from ** the peer. It calls the application callback function to ** report the event. ** ** Returns void. ** *******************************************************************************/ void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) { BT_HDR *p_pkt = &p_data->hdr; BT_HDR *p_buf; UINT8 *p, *p_start; tMCA_DCB *p_dcb; tMCA_CTRL evt_data; tMCA_CCB_MSG *p_rx_msg = NULL; UINT8 reject_code = MCA_RSP_NO_RESOURCE; BOOLEAN send_rsp = FALSE; BOOLEAN check_req = FALSE; UINT8 reject_opcode; MCA_TRACE_DEBUG ("mca_ccb_hdl_req status:%d", p_ccb->status); p_rx_msg = (tMCA_CCB_MSG *)p_pkt; p = (UINT8 *)(p_pkt + 1) + p_pkt->offset; evt_data.hdr.op_code = *p++; BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p); reject_opcode = evt_data.hdr.op_code+1; MCA_TRACE_DEBUG ("received mdl id: %d ", evt_data.hdr.mdl_id); if (p_ccb->status == MCA_CCB_STAT_PENDING) { MCA_TRACE_DEBUG ("received req inpending state"); /* allow abort in pending state */ if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (evt_data.hdr.op_code == MCA_OP_MDL_ABORT_REQ)) { reject_code = MCA_RSP_SUCCESS; send_rsp = TRUE; /* clear the pending status */ p_ccb->status = MCA_CCB_STAT_NORM; if (p_ccb->p_tx_req && ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx))!= NULL)) { mca_dcb_dealloc (p_dcb, NULL); mca_free_buf ((void **)&p_ccb->p_tx_req); } } else reject_code = MCA_RSP_BAD_OP; } else if (p_ccb->p_rx_msg) { MCA_TRACE_DEBUG ("still handling prev req"); /* still holding previous message, reject this new one ?? */ } else if (p_ccb->p_tx_req) { MCA_TRACE_DEBUG ("still waiting for a response ctrl_vpsm:0x%x", p_ccb->ctrl_vpsm); /* sent a request; waiting for response */ if (p_ccb->ctrl_vpsm == 0) { MCA_TRACE_DEBUG ("local is ACP. accept the cmd from INT"); /* local is acceptor, need to handle the request */ check_req = TRUE; reject_code = MCA_RSP_SUCCESS; /* drop the previous request */ if ((p_ccb->p_tx_req->op_code == MCA_OP_MDL_CREATE_REQ) && ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL)) { mca_dcb_dealloc(p_dcb, NULL); } mca_free_buf ((void **)&p_ccb->p_tx_req); mca_stop_timer(p_ccb); } else { /* local is initiator, ignore the req */ GKI_freebuf (p_pkt); return; } } else if (p_pkt->layer_specific != MCA_RSP_SUCCESS) { reject_code = (UINT8)p_pkt->layer_specific; if (((evt_data.hdr.op_code >= MCA_NUM_STANDARD_OPCODE) && (evt_data.hdr.op_code < MCA_FIRST_SYNC_OP)) || (evt_data.hdr.op_code > MCA_LAST_SYNC_OP)) { /* invalid op code */ reject_opcode = MCA_OP_ERROR_RSP; evt_data.hdr.mdl_id = 0; } } else { check_req = TRUE; reject_code = MCA_RSP_SUCCESS; } if (check_req) { if (reject_code == MCA_RSP_SUCCESS) { reject_code = MCA_RSP_BAD_MDL; if (MCA_IS_VALID_MDL_ID(evt_data.hdr.mdl_id) || ((evt_data.hdr.mdl_id == MCA_ALL_MDL_ID) && (evt_data.hdr.op_code == MCA_OP_MDL_DELETE_REQ))) { reject_code = MCA_RSP_SUCCESS; /* mdl_id is valid according to the spec */ switch (evt_data.hdr.op_code) { case MCA_OP_MDL_CREATE_REQ: evt_data.create_ind.dep_id = *p++; evt_data.create_ind.cfg = *p++; p_rx_msg->mdep_id = evt_data.create_ind.dep_id; if (!mca_is_valid_dep_id(p_ccb->p_rcb, p_rx_msg->mdep_id)) { MCA_TRACE_ERROR ("not a valid local mdep id"); reject_code = MCA_RSP_BAD_MDEP; } else if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id)) { MCA_TRACE_DEBUG ("the mdl_id is currently used in the CL(create)"); mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id); } else { /* check if this dep still have MDL available */ if (mca_dep_free_mdl(p_ccb, evt_data.create_ind.dep_id) == 0) { MCA_TRACE_ERROR ("the mdep is currently using max_mdl"); reject_code = MCA_RSP_MDEP_BUSY; } } break; case MCA_OP_MDL_RECONNECT_REQ: if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id)) { MCA_TRACE_ERROR ("the mdl_id is currently used in the CL(reconn)"); reject_code = MCA_RSP_MDL_BUSY; } break; case MCA_OP_MDL_ABORT_REQ: reject_code = MCA_RSP_BAD_OP; break; case MCA_OP_MDL_DELETE_REQ: /* delete the associated mdl */ mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id); send_rsp = TRUE; break; } } } } if (((reject_code != MCA_RSP_SUCCESS) && (evt_data.hdr.op_code != MCA_OP_SYNC_INFO_IND)) || send_rsp) { p_buf = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU); if (p_buf) { p_buf->offset = L2CAP_MIN_OFFSET; p = p_start = (UINT8*)(p_buf + 1) + L2CAP_MIN_OFFSET; *p++ = reject_opcode; *p++ = reject_code; UINT16_TO_BE_STREAM (p, evt_data.hdr.mdl_id); /* if (((*p_start) == MCA_OP_MDL_CREATE_RSP) && (reject_code == MCA_RSP_SUCCESS)) { *p++ = evt_data.create_ind.cfg; } */ p_buf->len = p - p_start; L2CA_DataWrite (p_ccb->lcid, p_buf); } } if (reject_code == MCA_RSP_SUCCESS) { /* use the received GKI buffer to store information to double check response API */ p_rx_msg->op_code = evt_data.hdr.op_code; p_rx_msg->mdl_id = evt_data.hdr.mdl_id; p_ccb->p_rx_msg = p_rx_msg; if (send_rsp) { GKI_freebuf (p_pkt); p_ccb->p_rx_msg = NULL; } mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data); } else GKI_freebuf (p_pkt); }