/******************************************************************************* ** ** Function avrc_prs_get_elem_attrs_rsp ** ** Description This function parses the Get Element Attributes ** response. ** ** Returns AVRC_STS_NO_ERROR, if the response is parsed successfully ** Otherwise, the error code. ** *******************************************************************************/ static tAVRC_STS avrc_prs_get_elem_attrs_rsp (tAVRC_GET_ELEM_ATTRS_RSP *p_rsp, UINT8 *p_data) { UINT8 *p_start, *p_len, *p_count; UINT16 len; UINT8 xx; UINT32 attr_id; if (p_rsp->num_attr == 0) return AVRC_STS_NO_ERROR; AVRC_TRACE_API("avrc_prs_get_elem_attrs_rsp num_attr: %d", p_rsp->num_attr); p_rsp->p_attrs = (tAVRC_ATTR_ENTRY*)malloc(sizeof(tAVRC_ATTR_ENTRY) * p_rsp->num_attr); for (xx=0; xx<p_rsp->num_attr; xx++) { BE_STREAM_TO_UINT32(attr_id, p_data); if (!AVRC_IS_VALID_MEDIA_ATTRIBUTE(attr_id)) { AVRC_TRACE_ERROR("avrc_prs_get_elem_attrs_rsp invalid attr id[%d]: %d", xx, attr_id); continue; } p_rsp->p_attrs[xx].attr_id = attr_id; BE_STREAM_TO_UINT16(p_rsp->p_attrs[xx].name.charset_id, p_data); BE_STREAM_TO_UINT16(p_rsp->p_attrs[xx].name.str_len, p_data); p_rsp->p_attrs[xx].name.p_str = (UINT8*)malloc(sizeof(UINT8) * p_rsp->p_attrs[xx].name.str_len); BE_STREAM_TO_ARRAY(p_data, p_rsp->p_attrs[xx].name.p_str, p_rsp->p_attrs[xx].name.str_len); AVRC_TRACE_DEBUG("avrc_prs_get_elem_attrs_rsp str_len: %d, str: %s", p_rsp->p_attrs[xx].name.str_len, p_rsp->p_attrs[xx].name.p_str); } return AVRC_STS_NO_ERROR; }
/******************************************************************************* ** ** Function avrc_pars_vendor_rsp ** ** Description This function parses the vendor specific commands defined by ** Bluetooth SIG ** ** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully. ** Otherwise, the error code defined by AVRCP 1.4 ** *******************************************************************************/ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p_result) { tAVRC_STS status = AVRC_STS_NO_ERROR; UINT8 *p; UINT16 len; UINT8 eventid = 0; /* Check the vendor data */ if (p_msg->vendor_len == 0) { return AVRC_STS_NO_ERROR; } if (p_msg->p_vendor_data == NULL) { return AVRC_STS_INTERNAL_ERR; } p = p_msg->p_vendor_data; BE_STREAM_TO_UINT8 (p_result->pdu, p); p++; /* skip the reserved/packe_type byte */ BE_STREAM_TO_UINT16 (len, p); AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp() ctype:0x%x pdu:0x%x, len:%d/0x%x", p_msg->hdr.ctype, p_result->pdu, len, len); if (p_msg->hdr.ctype == AVRC_RSP_REJ) { p_result->rsp.status = *p; return p_result->rsp.status; } switch (p_result->pdu) { /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */ /* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */ #if (AVRC_ADV_CTRL_INCLUDED == TRUE) case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */ if (len != 1) { status = AVRC_STS_INTERNAL_ERR; } else { BE_STREAM_TO_UINT8 (p_result->volume.volume, p); } break; #endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */ case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */ #if (AVRC_ADV_CTRL_INCLUDED == TRUE) BE_STREAM_TO_UINT8 (eventid, p); if (AVRC_EVT_VOLUME_CHANGE == eventid && (AVRC_RSP_CHANGED == p_msg->hdr.ctype || AVRC_RSP_INTERIM == p_msg->hdr.ctype || AVRC_RSP_REJ == p_msg->hdr.ctype || AVRC_RSP_NOT_IMPL == p_msg->hdr.ctype)) { p_result->reg_notif.status = p_msg->hdr.ctype; p_result->reg_notif.event_id = eventid; BE_STREAM_TO_UINT8 (p_result->reg_notif.param.volume, p); } AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp PDU reg notif response:event %x, volume %x", eventid, p_result->reg_notif.param.volume); #endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */ break; default: status = AVRC_STS_BAD_CMD; break; } return status; }
/******************************************************************************* ** ** Function avrc_bld_app_setting_text_rsp ** ** Description This function builds the Get Application Settings Attribute Text ** or Get Application Settings Value Text response. ** ** Returns AVRC_STS_NO_ERROR, if the response is built successfully ** Otherwise, the error code. ** *******************************************************************************/ static tAVRC_STS avrc_bld_app_setting_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp, BT_HDR *p_pkt) { UINT8 *p_data, *p_start, *p_len, *p_count; UINT16 len, len_left; UINT8 xx; tAVRC_STS sts = AVRC_STS_NO_ERROR; UINT8 num_added = 0; if (!p_rsp->p_attrs) { AVRC_TRACE_ERROR0("avrc_bld_app_setting_text_rsp NULL parameter"); return AVRC_STS_BAD_PARAM; } /* get the existing length, if any, and also the num attributes */ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; p_data = p_len = p_start + 2; /* pdu + rsvd */ len_left = GKI_get_buf_size(p_pkt) - BT_HDR_SIZE - p_pkt->offset - p_pkt->len; BE_STREAM_TO_UINT16(len, p_data); p_count = p_data; if (len == 0) { *p_count = 0; p_data++; } else { p_data = p_start + p_pkt->len; } for (xx=0; xx<p_rsp->num_attr; xx++) { if (len_left < (p_rsp->p_attrs[xx].str_len + 4)) { AVRC_TRACE_ERROR3("avrc_bld_app_setting_text_rsp out of room (str_len:%d, left:%d)", xx, p_rsp->p_attrs[xx].str_len, len_left); p_rsp->num_attr = num_added; sts = AVRC_STS_INTERNAL_ERR; break; } if ( !p_rsp->p_attrs[xx].str_len || !p_rsp->p_attrs[xx].p_str ) { AVRC_TRACE_ERROR1("avrc_bld_app_setting_text_rsp NULL attr text[%d]", xx); continue; } UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id); UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].charset_id); UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].str_len); ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].p_str, p_rsp->p_attrs[xx].str_len); (*p_count)++; num_added++; } len = p_data - p_count; UINT16_TO_BE_STREAM(p_len, len); p_pkt->len = (p_data - p_start); return sts; }
/******************************************************************************* ** ** Function avrc_bld_get_elem_attrs_rsp ** ** Description This function builds the Get Element Attributes ** response. ** ** Returns AVRC_STS_NO_ERROR, if the response is built successfully ** Otherwise, the error code. ** *******************************************************************************/ static tAVRC_STS avrc_bld_get_elem_attrs_rsp (tAVRC_GET_ELEM_ATTRS_RSP *p_rsp, BT_HDR *p_pkt) { UINT8 *p_data, *p_start, *p_len, *p_count; UINT16 len; UINT8 xx; AVRC_TRACE_API0("avrc_bld_get_elem_attrs_rsp"); if (!p_rsp->p_attrs) { AVRC_TRACE_ERROR0("avrc_bld_get_elem_attrs_rsp NULL parameter"); return AVRC_STS_BAD_PARAM; } /* get the existing length, if any, and also the num attributes */ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; p_data = p_len = p_start + 2; /* pdu + rsvd */ BE_STREAM_TO_UINT16(len, p_data); p_count = p_data; if (len == 0) { *p_count = 0; p_data++; } else { p_data = p_start + p_pkt->len; } for (xx=0; xx<p_rsp->num_attr; xx++) { if (!AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_rsp->p_attrs[xx].attr_id)) { AVRC_TRACE_ERROR2("avrc_bld_get_elem_attrs_rsp invalid attr id[%d]: %d", xx, p_rsp->p_attrs[xx].attr_id); continue; } if ( !p_rsp->p_attrs[xx].name.p_str ) { p_rsp->p_attrs[xx].name.str_len = 0; } UINT32_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id); UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.charset_id); UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.str_len); ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.p_str, p_rsp->p_attrs[xx].name.str_len); (*p_count)++; } len = p_data - p_count; UINT16_TO_BE_STREAM(p_len, len); p_pkt->len = (p_data - p_start); return AVRC_STS_NO_ERROR; }
/******************************************************************************* ** ** Function llcp_util_parse_cc ** ** Description Parse CC PDU ** ** Returns tLLCP_STATUS ** *******************************************************************************/ tLLCP_STATUS llcp_util_parse_cc (UINT8 *p_bytes, UINT16 length, UINT16 *p_miu, UINT8 *p_rw) { UINT8 param_type, param_len, *p = p_bytes; *p_miu = LLCP_DEFAULT_MIU; *p_rw = LLCP_DEFAULT_RW; while (length) { BE_STREAM_TO_UINT8 (param_type, p); length--; switch (param_type) { case LLCP_MIUX_TYPE: BE_STREAM_TO_UINT8 (param_len, p); BE_STREAM_TO_UINT16 ((*p_miu), p); (*p_miu) &= LLCP_MIUX_MASK; (*p_miu) += LLCP_DEFAULT_MIU; LLCP_TRACE_DEBUG1 ("llcp_util_parse_cc (): LLCP_MIUX_TYPE:%d", *p_miu); break; case LLCP_RW_TYPE: BE_STREAM_TO_UINT8 (param_len, p); BE_STREAM_TO_UINT8 ((*p_rw), p); (*p_rw) &= 0x0F; LLCP_TRACE_DEBUG1 ("llcp_util_parse_cc (): LLCP_RW_TYPE:%d", *p_rw); break; default: LLCP_TRACE_ERROR1 ("llcp_util_parse_cc (): Unexpected type 0x%x", param_type); BE_STREAM_TO_UINT8 (param_len, p); p += param_len; break; } if (length >= param_len + 1) length -= param_len + 1; else { LLCP_TRACE_ERROR0 ("llcp_util_parse_cc (): Bad LTV's"); return LLCP_STATUS_FAIL; } } return LLCP_STATUS_SUCCESS; }
/******************************************************************************* ** ** Function avrc_bld_get_cur_app_setting_value_rsp ** ** Description This function builds the Get Current Application Setting Value ** response. ** ** Returns AVRC_STS_NO_ERROR, if the response is built successfully ** Otherwise, the error code. ** *******************************************************************************/ static tAVRC_STS avrc_bld_get_cur_app_setting_value_rsp (tAVRC_GET_CUR_APP_VALUE_RSP *p_rsp, BT_HDR *p_pkt) { UINT8 *p_data, *p_start, *p_len, *p_count; UINT16 len; UINT8 xx; if (!p_rsp->p_vals) { AVRC_TRACE_ERROR0("avrc_bld_get_cur_app_setting_value_rsp NULL parameter"); return AVRC_STS_BAD_PARAM; } AVRC_TRACE_API0("avrc_bld_get_cur_app_setting_value_rsp"); /* get the existing length, if any, and also the num attributes */ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; p_data = p_len = p_start + 2; /* pdu + rsvd */ BE_STREAM_TO_UINT16(len, p_data); p_count = p_data; if (len == 0) { /* first time initialize the attribute count */ *p_count = 0; p_data++; } else { p_data = p_start + p_pkt->len; } for (xx=0; xx<p_rsp->num_val; xx++) { if (avrc_is_valid_player_attrib_value(p_rsp->p_vals[xx].attr_id, p_rsp->p_vals[xx].attr_val)) { (*p_count)++; UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_id); UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_val); } } len = ((*p_count) << 1) + 1; UINT16_TO_BE_STREAM(p_len, len); p_pkt->len = (p_data - p_start); return AVRC_STS_NO_ERROR; }
/******************************************************************************* ** ** Function ce_t4t_process_select_file_cmd ** ** Description This function processes Select Command by file ID. ** ** Returns TRUE if success ** *******************************************************************************/ static BOOLEAN ce_t4t_process_select_file_cmd (UINT8 *p_cmd) { UINT8 data_len; UINT16 file_id, status_words; CE_TRACE_DEBUG0 ("ce_t4t_process_select_file_cmd ()"); p_cmd++; /* skip P2 */ /* Lc Byte */ BE_STREAM_TO_UINT8 (data_len, p_cmd); if (data_len == T4T_FILE_ID_SIZE) { /* File ID */ BE_STREAM_TO_UINT16 (file_id, p_cmd); if (ce_t4t_select_file (file_id)) { status_words = T4T_RSP_CMD_CMPLTED; } else { status_words = T4T_RSP_NOT_FOUND; } } else { status_words = T4T_RSP_WRONG_LENGTH; } if (!ce_t4t_send_status (status_words)) { return FALSE; } if (status_words == T4T_RSP_CMD_CMPLTED) { return TRUE; } return FALSE; }
/******************************************************************************* ** ** Function avrc_pars_pass_thru ** ** Description This function parses the pass thru commands defined by ** Bluetooth SIG ** ** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully. ** Otherwise, the error code defined by AVRCP 1.4 ** *******************************************************************************/ tAVRC_STS avrc_pars_pass_thru(tAVRC_MSG_PASS *p_msg, UINT16 *p_vendor_unique_id) { UINT8 *p_data; UINT32 co_id; UINT16 id; tAVRC_STS status = AVRC_STS_BAD_CMD; if (p_msg->op_id == AVRC_ID_VENDOR && p_msg->pass_len == AVRC_PASS_THRU_GROUP_LEN) { p_data = p_msg->p_pass_data; AVRC_BE_STREAM_TO_CO_ID (co_id, p_data); if (co_id == AVRC_CO_METADATA) { BE_STREAM_TO_UINT16 (id, p_data); if (AVRC_IS_VALID_GROUP(id)) { *p_vendor_unique_id = id; status = AVRC_STS_NO_ERROR; } } } return status; }
/******************************************************************************* ** ** Function avrc_bld_list_app_settings_attr_rsp ** ** Description This function builds the List Application Settings Attribute ** response. ** ** Returns AVRC_STS_NO_ERROR, if the response is built successfully ** Otherwise, the error code. ** *******************************************************************************/ static tAVRC_STS avrc_bld_list_app_settings_attr_rsp (tAVRC_LIST_APP_ATTR_RSP *p_rsp, BT_HDR *p_pkt) { UINT8 *p_data, *p_start, *p_len, *p_num; UINT16 len = 0; UINT8 xx; AVRC_TRACE_API0("avrc_bld_list_app_settings_attr_rsp"); /* get the existing length, if any, and also the num attributes */ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; p_data = p_len = p_start + 2; /* pdu + rsvd */ BE_STREAM_TO_UINT16(len, p_data); p_num = p_data; if (len == 0) { /* first time initialize the attribute count */ *p_num = 0; p_data++; } else { p_data = p_start + p_pkt->len; } for (xx=0; xx<p_rsp->num_attr; xx++) { if(AVRC_IsValidPlayerAttr(p_rsp->attrs[xx])) { (*p_num)++; UINT8_TO_BE_STREAM(p_data, p_rsp->attrs[xx]); } } len = *p_num + 1; UINT16_TO_BE_STREAM(p_len, len); p_pkt->len = (p_data - p_start); return AVRC_STS_NO_ERROR; }
/******************************************************************************* ** ** Function avrc_bld_list_app_settings_values_rsp ** ** Description This function builds the List Application Setting Values ** response. ** ** Returns AVRC_STS_NO_ERROR, if the response is built successfully ** Otherwise, the error code. ** *******************************************************************************/ static tAVRC_STS avrc_bld_list_app_settings_values_rsp (tAVRC_LIST_APP_VALUES_RSP *p_rsp, BT_HDR *p_pkt) { UINT8 *p_data, *p_start, *p_len, *p_num; UINT8 xx; UINT16 len; AVRC_TRACE_API0("avrc_bld_list_app_settings_values_rsp"); p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; p_data = p_len = p_start + 2; /* pdu + rsvd */ /* get the existing length, if any, and also the num attributes */ BE_STREAM_TO_UINT16(len, p_data); p_num = p_data; /* first time initialize the attribute count */ if (len == 0) { *p_num = p_rsp->num_val; p_data++; } else { p_data = p_start + p_pkt->len; *p_num += p_rsp->num_val; } for (xx=0; xx<p_rsp->num_val; xx++) { UINT8_TO_BE_STREAM(p_data, p_rsp->vals[xx]); } len = *p_num + 1; UINT16_TO_BE_STREAM(p_len, len); p_pkt->len = (p_data - p_start); return AVRC_STS_NO_ERROR; }
/******************************************************************************* ** ** Function rw_t4t_sm_detect_ndef ** ** Description State machine for NDEF detection procedure ** ** Returns none ** *******************************************************************************/ static void rw_t4t_sm_detect_ndef (BT_HDR *p_r_apdu) { tRW_T4T_CB *p_t4t = &rw_cb.tcb.t4t; UINT8 *p, type, length; UINT16 status_words, nlen; tRW_DATA rw_data; #if (BT_TRACE_VERBOSE == TRUE) RW_TRACE_DEBUG2 ("rw_t4t_sm_detect_ndef (): sub_state:%s (%d)", rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state); #else RW_TRACE_DEBUG1 ("rw_t4t_sm_detect_ndef (): sub_state=%d", p_t4t->sub_state); #endif /* get status words */ p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset; p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE); BE_STREAM_TO_UINT16 (status_words, p); if (status_words != T4T_RSP_CMD_CMPLTED) { /* try V1.0 after failing of V2.0 */ if ( (p_t4t->sub_state == RW_T4T_SUBSTATE_WAIT_SELECT_APP) &&(p_t4t->version == T4T_VERSION_2_0) ) { p_t4t->version = T4T_VERSION_1_0; RW_TRACE_DEBUG1 ("rw_t4t_sm_detect_ndef (): retry with version=0x%02X", p_t4t->version); if (!rw_t4t_select_application (T4T_VERSION_1_0)) { rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0); } return; } p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED); rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1)); return; } switch (p_t4t->sub_state) { case RW_T4T_SUBSTATE_WAIT_SELECT_APP: /* NDEF Tag application has been selected then select CC file */ if (!rw_t4t_select_file (T4T_CC_FILE_ID)) { rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0); } else { p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_CC; } break; case RW_T4T_SUBSTATE_WAIT_SELECT_CC: /* CC file has been selected then read mandatory part of CC file */ if (!rw_t4t_read_file (0x00, T4T_CC_FILE_MIN_LEN, FALSE)) { rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0); } else { p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_CC_FILE; } break; case RW_T4T_SUBSTATE_WAIT_CC_FILE: /* CC file has been read then validate and select mandatory NDEF file */ if (p_r_apdu->len >= T4T_CC_FILE_MIN_LEN + T4T_RSP_STATUS_WORDS_SIZE) { p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset; BE_STREAM_TO_UINT16 (p_t4t->cc_file.cclen, p); BE_STREAM_TO_UINT8 (p_t4t->cc_file.version, p); BE_STREAM_TO_UINT16 (p_t4t->cc_file.max_le, p); BE_STREAM_TO_UINT16 (p_t4t->cc_file.max_lc, p); BE_STREAM_TO_UINT8 (type, p); BE_STREAM_TO_UINT8 (length, p); if ( (type == T4T_NDEF_FILE_CONTROL_TYPE) &&(length == T4T_FILE_CONTROL_LENGTH) ) { BE_STREAM_TO_UINT16 (p_t4t->cc_file.ndef_fc.file_id, p); BE_STREAM_TO_UINT16 (p_t4t->cc_file.ndef_fc.max_file_size, p); BE_STREAM_TO_UINT8 (p_t4t->cc_file.ndef_fc.read_access, p); BE_STREAM_TO_UINT8 (p_t4t->cc_file.ndef_fc.write_access, p); #if (BT_TRACE_VERBOSE == TRUE) RW_TRACE_DEBUG0 ("Capability Container (CC) file"); RW_TRACE_DEBUG1 (" CCLEN: 0x%04X", p_t4t->cc_file.cclen); RW_TRACE_DEBUG1 (" Version:0x%02X", p_t4t->cc_file.version); RW_TRACE_DEBUG1 (" MaxLe: 0x%04X", p_t4t->cc_file.max_le); RW_TRACE_DEBUG1 (" MaxLc: 0x%04X", p_t4t->cc_file.max_lc); RW_TRACE_DEBUG0 (" NDEF File Control TLV"); RW_TRACE_DEBUG1 (" FileID: 0x%04X", p_t4t->cc_file.ndef_fc.file_id); RW_TRACE_DEBUG1 (" MaxFileSize: 0x%04X", p_t4t->cc_file.ndef_fc.max_file_size); RW_TRACE_DEBUG1 (" ReadAccess: 0x%02X", p_t4t->cc_file.ndef_fc.read_access); RW_TRACE_DEBUG1 (" WriteAccess: 0x%02X", p_t4t->cc_file.ndef_fc.write_access); #endif if (rw_t4t_validate_cc_file ()) { if (!rw_t4t_select_file (p_t4t->cc_file.ndef_fc.file_id)) { rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0); } else { p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE; } break; } } } /* invalid response or CC file */ p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED); rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0); break; case RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE: /* NDEF file has been selected then read the first 2 bytes (NLEN) */ if (!rw_t4t_read_file (0, T4T_FILE_LENGTH_SIZE, FALSE)) { rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0); } else { p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_READ_NLEN; } break; case RW_T4T_SUBSTATE_WAIT_READ_NLEN: /* NLEN has been read then report upper layer */ if (p_r_apdu->len == T4T_FILE_LENGTH_SIZE + T4T_RSP_STATUS_WORDS_SIZE) { /* get length of NDEF */ p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset; BE_STREAM_TO_UINT16 (nlen, p); if (nlen <= p_t4t->cc_file.ndef_fc.max_file_size - T4T_FILE_LENGTH_SIZE) { p_t4t->ndef_status = RW_T4T_NDEF_STATUS_NDEF_DETECTED; if (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS) { p_t4t->ndef_status |= RW_T4T_NDEF_STATUS_NDEF_READ_ONLY; } /* Get max bytes to read per command */ if (p_t4t->cc_file.max_le >= RW_T4T_MAX_DATA_PER_READ) { p_t4t->max_read_size = RW_T4T_MAX_DATA_PER_READ; } else { p_t4t->max_read_size = p_t4t->cc_file.max_le; } /* Le: valid range is 0x01 to 0xFF */ if (p_t4t->max_read_size >= T4T_MAX_LENGTH_LE) { p_t4t->max_read_size = T4T_MAX_LENGTH_LE; } /* Get max bytes to update per command */ if (p_t4t->cc_file.max_lc >= RW_T4T_MAX_DATA_PER_WRITE) { p_t4t->max_update_size = RW_T4T_MAX_DATA_PER_WRITE; } else { p_t4t->max_update_size = p_t4t->cc_file.max_lc; } /* Lc: valid range is 0x01 to 0xFF */ if (p_t4t->max_update_size >= T4T_MAX_LENGTH_LC) { p_t4t->max_update_size = T4T_MAX_LENGTH_LC; } p_t4t->ndef_length = nlen; p_t4t->state = RW_T4T_STATE_IDLE; if (rw_cb.p_cback) { rw_data.ndef.status = NFC_STATUS_OK; rw_data.ndef.protocol = NFC_PROTOCOL_ISO_DEP; rw_data.ndef.max_size = (UINT32) (p_t4t->cc_file.ndef_fc.max_file_size - (UINT16) T4T_FILE_LENGTH_SIZE); rw_data.ndef.cur_size = nlen; rw_data.ndef.flags = RW_NDEF_FL_SUPPORTED | RW_NDEF_FL_FORMATED; if (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS) { rw_data.ndef.flags |= RW_NDEF_FL_READ_ONLY; } (*(rw_cb.p_cback)) (RW_T4T_NDEF_DETECT_EVT, &rw_data); RW_TRACE_DEBUG0 ("rw_t4t_sm_detect_ndef (): Sent RW_T4T_NDEF_DETECT_EVT"); } } else { /* NLEN should be less than max file size */ RW_TRACE_ERROR2 ("rw_t4t_sm_detect_ndef (): NLEN (%d) + 2 must be <= max file size (%d)", nlen, p_t4t->cc_file.ndef_fc.max_file_size); p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED); rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0); } } else { /* response payload size should be T4T_FILE_LENGTH_SIZE */ RW_TRACE_ERROR2 ("rw_t4t_sm_detect_ndef (): Length (%d) of R-APDU must be %d", p_r_apdu->len, T4T_FILE_LENGTH_SIZE + T4T_RSP_STATUS_WORDS_SIZE); p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED); rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0); } break; default: RW_TRACE_ERROR1 ("rw_t4t_sm_detect_ndef (): unknown sub_state=%d", p_t4t->sub_state); rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0); break; } }
/******************************************************************************* ** ** Function rw_t4t_sm_update_ndef ** ** Description State machine for NDEF update procedure ** ** Returns none ** *******************************************************************************/ static void rw_t4t_sm_update_ndef (BT_HDR *p_r_apdu) { tRW_T4T_CB *p_t4t = &rw_cb.tcb.t4t; UINT8 *p; UINT16 status_words; tRW_DATA rw_data; #if (BT_TRACE_VERBOSE == TRUE) RW_TRACE_DEBUG2 ("rw_t4t_sm_update_ndef (): sub_state:%s (%d)", rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state); #else RW_TRACE_DEBUG1 ("rw_t4t_sm_update_ndef (): sub_state=%d", p_t4t->sub_state); #endif /* Get status words */ p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset; p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE); BE_STREAM_TO_UINT16 (status_words, p); if (status_words != T4T_RSP_CMD_CMPLTED) { rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1)); return; } switch (p_t4t->sub_state) { case RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN: /* NLEN has been updated */ /* if need to update data */ if (p_t4t->p_update_data) { p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_RESP; if (!rw_t4t_update_file ()) { rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0); p_t4t->p_update_data = NULL; } } else { p_t4t->state = RW_T4T_STATE_IDLE; /* just finished last step of updating (updating NLEN) */ if (rw_cb.p_cback) { rw_data.status = NFC_STATUS_OK; (*(rw_cb.p_cback)) (RW_T4T_NDEF_UPDATE_CPLT_EVT, &rw_data); RW_TRACE_DEBUG0 ("rw_t4t_sm_update_ndef (): Sent RW_T4T_NDEF_UPDATE_CPLT_EVT"); } } break; case RW_T4T_SUBSTATE_WAIT_UPDATE_RESP: /* if updating is not completed */ if (p_t4t->rw_length > 0) { if (!rw_t4t_update_file ()) { rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0); p_t4t->p_update_data = NULL; } } else { p_t4t->p_update_data = NULL; /* update NLEN as last step of updating file */ if (!rw_t4t_update_nlen (p_t4t->ndef_length)) { rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0); } else { p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN; } } break; default: RW_TRACE_ERROR1 ("rw_t4t_sm_update_ndef (): unknown sub_state = %d", p_t4t->sub_state); rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0); break; } }
/******************************************************************************* ** ** Function avrc_bld_get_capability_rsp ** ** Description This function builds the Get Capability response. ** ** Returns AVRC_STS_NO_ERROR, if the response is built successfully ** Otherwise, the error code. ** *******************************************************************************/ static tAVRC_STS avrc_bld_get_capability_rsp (tAVRC_GET_CAPS_RSP *p_rsp, BT_HDR *p_pkt) { UINT8 *p_data, *p_start, *p_len, *p_count; UINT16 len = 0; UINT8 xx; UINT32 *p_company_id; UINT8 *p_event_id; tAVRC_STS status = AVRC_STS_NO_ERROR; if (!(AVRC_IS_VALID_CAP_ID(p_rsp->capability_id))) { AVRC_TRACE_ERROR1("avrc_bld_get_capability_rsp bad parameter. p_rsp: %x", p_rsp); status = AVRC_STS_BAD_PARAM; return status; } AVRC_TRACE_API0("avrc_bld_get_capability_rsp"); /* get the existing length, if any, and also the num attributes */ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; p_data = p_len = p_start + 2; /* pdu + rsvd */ BE_STREAM_TO_UINT16(len, p_data); UINT8_TO_BE_STREAM(p_data, p_rsp->capability_id); p_count = p_data; if (len == 0) { *p_count = p_rsp->count; p_data++; len = 2; /* move past the capability_id and count */ } else { p_data = p_start + p_pkt->len; *p_count += p_rsp->count; } if (p_rsp->capability_id == AVRC_CAP_COMPANY_ID) { p_company_id = p_rsp->param.company_id; for (xx=0; xx< p_rsp->count; xx++) { UINT24_TO_BE_STREAM(p_data, p_company_id[xx]); } len += p_rsp->count * 3; } else { p_event_id = p_rsp->param.event_id; *p_count = 0; for (xx=0; xx< p_rsp->count; xx++) { if (AVRC_IS_VALID_EVENT_ID(p_event_id[xx])) { (*p_count)++; UINT8_TO_BE_STREAM(p_data, p_event_id[xx]); } } len += (*p_count); } UINT16_TO_BE_STREAM(p_len, len); p_pkt->len = (p_data - p_start); status = AVRC_STS_NO_ERROR; return status; }
/******************************************************************************* ** ** Function llcp_util_parse_link_params ** ** Description Parse LLCP Link parameters ** ** Returns TRUE if success ** *******************************************************************************/ BOOLEAN llcp_util_parse_link_params (UINT16 length, UINT8 *p_bytes) { UINT8 param_type, param_len, *p = p_bytes; while (length) { BE_STREAM_TO_UINT8 (param_type, p); length--; switch (param_type) { case LLCP_VERSION_TYPE: BE_STREAM_TO_UINT8 (param_len, p); BE_STREAM_TO_UINT8 (llcp_cb.lcb.peer_version, p); LLCP_TRACE_DEBUG1 ("Peer Version - 0x%02X", llcp_cb.lcb.peer_version); break; case LLCP_MIUX_TYPE: BE_STREAM_TO_UINT8 (param_len, p); BE_STREAM_TO_UINT16 (llcp_cb.lcb.peer_miu, p); llcp_cb.lcb.peer_miu &= LLCP_MIUX_MASK; llcp_cb.lcb.peer_miu += LLCP_DEFAULT_MIU; LLCP_TRACE_DEBUG1 ("Peer MIU - %d bytes", llcp_cb.lcb.peer_miu); break; case LLCP_WKS_TYPE: BE_STREAM_TO_UINT8 (param_len, p); BE_STREAM_TO_UINT16 (llcp_cb.lcb.peer_wks, p); LLCP_TRACE_DEBUG1 ("Peer WKS - 0x%04X", llcp_cb.lcb.peer_wks); break; case LLCP_LTO_TYPE: BE_STREAM_TO_UINT8 (param_len, p); BE_STREAM_TO_UINT8 (llcp_cb.lcb.peer_lto, p); llcp_cb.lcb.peer_lto *= LLCP_LTO_UNIT; /* 10ms unit */ LLCP_TRACE_DEBUG1 ("Peer LTO - %d ms", llcp_cb.lcb.peer_lto); break; case LLCP_OPT_TYPE: BE_STREAM_TO_UINT8 (param_len, p); BE_STREAM_TO_UINT8 (llcp_cb.lcb.peer_opt, p); LLCP_TRACE_DEBUG1 ("Peer OPT - 0x%02X", llcp_cb.lcb.peer_opt); break; default: LLCP_TRACE_ERROR1 ("llcp_util_parse_link_params (): Unexpected type 0x%x", param_type); BE_STREAM_TO_UINT8 (param_len, p); p += param_len; break; } if (length >= param_len + 1) length -= param_len + 1; else { LLCP_TRACE_ERROR0 ("llcp_util_parse_link_params (): Bad LTV's"); return (FALSE); } } return (TRUE); }
/******************************************************************************* ** ** Function llcp_util_parse_connect ** ** Description Parse CONNECT PDU ** ** Returns tLLCP_STATUS ** *******************************************************************************/ tLLCP_STATUS llcp_util_parse_connect (UINT8 *p_bytes, UINT16 length, tLLCP_CONNECTION_PARAMS *p_params) { UINT8 param_type, param_len, *p = p_bytes; p_params->miu = LLCP_DEFAULT_MIU; p_params->rw = LLCP_DEFAULT_RW; p_params->sn[0] = 0; while (length) { BE_STREAM_TO_UINT8 (param_type, p); length--; switch (param_type) { case LLCP_MIUX_TYPE: BE_STREAM_TO_UINT8 (param_len, p); BE_STREAM_TO_UINT16 (p_params->miu, p); p_params->miu &= LLCP_MIUX_MASK; p_params->miu += LLCP_DEFAULT_MIU; LLCP_TRACE_DEBUG1 ("llcp_util_parse_connect (): LLCP_MIUX_TYPE:%d", p_params->miu); break; case LLCP_RW_TYPE: BE_STREAM_TO_UINT8 (param_len, p); BE_STREAM_TO_UINT8 (p_params->rw, p); p_params->rw &= 0x0F; LLCP_TRACE_DEBUG1 ("llcp_util_parse_connect (): LLCP_RW_TYPE:%d", p_params->rw); break; case LLCP_SN_TYPE: BE_STREAM_TO_UINT8 (param_len, p); if (param_len <= LLCP_MAX_SN_LEN) { memcpy (p_params->sn, p, param_len); p_params->sn[param_len] = 0; } else { memcpy (p_params->sn, p, LLCP_MAX_SN_LEN); p_params->sn[LLCP_MAX_SN_LEN] = 0; } p += param_len; LLCP_TRACE_DEBUG1 ("llcp_util_parse_connect (): LLCP_SN_TYPE:<%s>", p_params->sn); break; default: LLCP_TRACE_ERROR1 ("llcp_util_parse_connect (): Unexpected type 0x%x", param_type); BE_STREAM_TO_UINT8 (param_len, p); p += param_len; break; } /* check remaining lengh */ if (length >= param_len + 1) { length -= param_len + 1; } else { LLCP_TRACE_ERROR0 ("llcp_util_parse_connect (): Bad LTV's"); return LLCP_STATUS_FAIL; } } return LLCP_STATUS_SUCCESS; }
/******************************************************************************* ** ** 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); }
/******************************************************************************* ** ** Function avrc_pars_vendor_rsp ** ** Description This function parses the vendor specific commands defined by ** Bluetooth SIG ** ** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully. ** Otherwise, the error code defined by AVRCP 1.4 ** *******************************************************************************/ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p_result) { tAVRC_STS status = AVRC_STS_NO_ERROR; UINT8 *p = p_msg->p_vendor_data; UINT16 len; UINT8 xx, yy; tAVRC_NOTIF_RSP_PARAM *p_param; tAVRC_APP_SETTING *p_app_set; tAVRC_APP_SETTING_TEXT *p_app_txt; tAVRC_ATTR_ENTRY *p_entry; UINT32 *p_u32; UINT8 *p_u8; UINT16 size_needed; UINT8 eventid=0; BE_STREAM_TO_UINT8 (p_result->pdu, p); p++; /* skip the reserved/packe_type byte */ BE_STREAM_TO_UINT16 (len, p); AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp() ctype:0x%x pdu:0x%x, len:%d/0x%x", p_msg->hdr.ctype, p_result->pdu, len, len); if (p_msg->hdr.ctype == AVRC_RSP_REJ) { p_result->rsp.status = *p; return p_result->rsp.status; } switch (p_result->pdu) { /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */ /* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */ #if (AVRC_ADV_CTRL_INCLUDED == TRUE) case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */ if (len != 1) status = AVRC_STS_INTERNAL_ERR; else { BE_STREAM_TO_UINT8 (p_result->volume.volume, p); } break; case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */ BE_STREAM_TO_UINT8 (p_result->get_elem_attrs.num_attr, p); AVRC_TRACE_API("num_attr: %d", p_result->get_elem_attrs.num_attr); if (len == 0) status = AVRC_STS_INTERNAL_ERR; else { status = avrc_prs_get_elem_attrs_rsp(&p_result->get_elem_attrs, p); } break; #endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */ case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */ #if (AVRC_ADV_CTRL_INCLUDED == TRUE) BE_STREAM_TO_UINT8 (eventid, p); if(AVRC_EVT_VOLUME_CHANGE==eventid && (AVRC_RSP_CHANGED==p_msg->hdr.ctype || AVRC_RSP_INTERIM==p_msg->hdr.ctype || AVRC_RSP_REJ==p_msg->hdr.ctype || AVRC_RSP_NOT_IMPL==p_msg->hdr.ctype)) { p_result->reg_notif.status=p_msg->hdr.ctype; p_result->reg_notif.event_id=eventid; BE_STREAM_TO_UINT8 (p_result->reg_notif.param.volume, p); } AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp PDU reg notif response:event %x, volume %x",eventid, p_result->reg_notif.param.volume); #endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */ break; default: status = AVRC_STS_BAD_CMD; break; } return status; }
/******************************************************************************* ** ** Function ce_t4t_data_cback ** ** Description This callback function receives the data from NFCC. ** ** Returns none ** *******************************************************************************/ static void ce_t4t_data_cback (UINT8 conn_id, tNFC_CONN_EVT event, tNFC_CONN *p_data) { BT_HDR *p_c_apdu; UINT8 *p_cmd; UINT8 cla, instruct, select_type = 0, length; UINT16 offset, max_file_size; tCE_DATA ce_data; if (event == NFC_DEACTIVATE_CEVT) { NFC_SetStaticRfCback (NULL); return; } if (event != NFC_DATA_CEVT) { return; } p_c_apdu = (BT_HDR *) p_data->data.p_data; #if (BT_TRACE_PROTOCOL == TRUE) DispCET4Tags (p_c_apdu, TRUE); #endif CE_TRACE_DEBUG1 ("ce_t4t_data_cback (): conn_id = 0x%02X", conn_id); p_cmd = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset; /* Class Byte */ BE_STREAM_TO_UINT8 (cla, p_cmd); /* Don't check class if registered AID has been selected */ if ( (cla != T4T_CMD_CLASS) &&((ce_cb.mem.t4t.status & CE_T4T_STATUS_REG_AID_SELECTED) == 0) &&((ce_cb.mem.t4t.status & CE_T4T_STATUS_WILDCARD_AID_SELECTED) == 0) ) { GKI_freebuf (p_c_apdu); ce_t4t_send_status (T4T_RSP_CLASS_NOT_SUPPORTED); return; } /* Instruction Byte */ BE_STREAM_TO_UINT8 (instruct, p_cmd); if ((cla == T4T_CMD_CLASS) && (instruct == T4T_CMD_INS_SELECT)) { /* P1 Byte */ BE_STREAM_TO_UINT8 (select_type, p_cmd); if (select_type == T4T_CMD_P1_SELECT_BY_NAME) { ce_t4t_process_select_app_cmd (p_cmd, p_c_apdu); return; } } /* if registered AID is selected */ if (ce_cb.mem.t4t.status & CE_T4T_STATUS_REG_AID_SELECTED) { CE_TRACE_DEBUG0 ("CET4T: Forward raw frame to registered AID"); /* forward raw frame to upper layer */ if (ce_cb.mem.t4t.selected_aid_idx < CE_T4T_MAX_REG_AID) { ce_data.raw_frame.status = p_data->data.status; ce_data.raw_frame.p_data = p_c_apdu; ce_data.raw_frame.aid_handle = ce_cb.mem.t4t.selected_aid_idx; p_c_apdu = NULL; (*(ce_cb.mem.t4t.reg_aid[ce_cb.mem.t4t.selected_aid_idx].p_cback)) (CE_T4T_RAW_FRAME_EVT, &ce_data); } else { GKI_freebuf (p_c_apdu); ce_t4t_send_status (T4T_RSP_NOT_FOUND); } } else if (ce_cb.mem.t4t.status & CE_T4T_STATUS_WILDCARD_AID_SELECTED) { CE_TRACE_DEBUG0 ("CET4T: Forward raw frame to wildcard AID handler"); /* forward raw frame to upper layer */ ce_data.raw_frame.status = p_data->data.status; ce_data.raw_frame.p_data = p_c_apdu; ce_data.raw_frame.aid_handle = CE_T4T_WILDCARD_AID_HANDLE; p_c_apdu = NULL; (*(ce_cb.mem.t4t.p_wildcard_aid_cback)) (CE_T4T_RAW_FRAME_EVT, &ce_data); } else if (ce_cb.mem.t4t.status & CE_T4T_STATUS_T4T_APP_SELECTED) { if (instruct == T4T_CMD_INS_SELECT) { /* P1 Byte is already parsed */ if (select_type == T4T_CMD_P1_SELECT_BY_FILE_ID) { ce_t4t_process_select_file_cmd (p_cmd); } else { CE_TRACE_ERROR1 ("CET4T: Bad P1 byte (0x%02X)", select_type); ce_t4t_send_status (T4T_RSP_WRONG_PARAMS); } } else if (instruct == T4T_CMD_INS_READ_BINARY) { if ( (ce_cb.mem.t4t.status & CE_T4T_STATUS_CC_FILE_SELECTED) ||(ce_cb.mem.t4t.status & CE_T4T_STATUS_NDEF_SELECTED) ) { if (ce_cb.mem.t4t.status & CE_T4T_STATUS_CC_FILE_SELECTED) { max_file_size = T4T_FC_TLV_OFFSET_IN_CC + T4T_FILE_CONTROL_TLV_SIZE; } else { max_file_size = ce_cb.mem.t4t.max_file_size; } BE_STREAM_TO_UINT16 (offset, p_cmd); /* Offset */ BE_STREAM_TO_UINT8 (length, p_cmd); /* Le */ /* check if valid parameters */ if (length <= CE_T4T_MAX_LE) { /* CE allows to read more than current file size but not max file size */ if (length + offset > max_file_size) { if (offset < max_file_size) { length = (UINT8) (max_file_size - offset); CE_TRACE_DEBUG2 ("CET4T: length is reduced to %d by max_file_size (%d)", length, max_file_size); } else { CE_TRACE_ERROR2 ("CET4T: offset (%d) must be less than max_file_size (%d)", offset, max_file_size); length = 0; } } } else { CE_TRACE_ERROR2 ("CET4T: length (%d) must be less than MLe (%d)", length, CE_T4T_MAX_LE); length = 0; } if (length > 0) ce_t4t_read_binary (offset, length); else ce_t4t_send_status (T4T_RSP_WRONG_PARAMS); } else { CE_TRACE_ERROR0 ("CET4T: File has not been selected"); ce_t4t_send_status (T4T_RSP_CMD_NOT_ALLOWED); } } else if (instruct == T4T_CMD_INS_UPDATE_BINARY) { if (ce_cb.mem.t4t.status & CE_T4T_STATUS_NDEF_FILE_READ_ONLY) { CE_TRACE_ERROR0 ("CET4T: No access right"); ce_t4t_send_status (T4T_RSP_CMD_NOT_ALLOWED); } else if (ce_cb.mem.t4t.status & CE_T4T_STATUS_NDEF_SELECTED) { BE_STREAM_TO_UINT16 (offset, p_cmd); /* Offset */ BE_STREAM_TO_UINT8 (length, p_cmd); /* Lc */ /* check if valid parameters */ if (length <= CE_T4T_MAX_LC) { if (length + offset > ce_cb.mem.t4t.max_file_size) { CE_TRACE_ERROR3 ("CET4T: length (%d) + offset (%d) must be less than max_file_size (%d)", length, offset, ce_cb.mem.t4t.max_file_size); length = 0; } } else { CE_TRACE_ERROR2 ("CET4T: length (%d) must be less than MLc (%d)", length, CE_T4T_MAX_LC); length = 0; } if (length > 0) ce_t4t_update_binary (offset, length, p_cmd); else ce_t4t_send_status (T4T_RSP_WRONG_PARAMS); } else { CE_TRACE_ERROR0 ("CET4T: NDEF File has not been selected"); ce_t4t_send_status (T4T_RSP_CMD_NOT_ALLOWED); } } else { CE_TRACE_ERROR1 ("CET4T: Unsupported Instruction byte (0x%02X)", instruct); ce_t4t_send_status (T4T_RSP_INSTR_NOT_SUPPORTED); } } else { CE_TRACE_ERROR0 ("CET4T: Application has not been selected"); ce_t4t_send_status (T4T_RSP_CMD_NOT_ALLOWED); } if (p_c_apdu) GKI_freebuf (p_c_apdu); }
/******************************************************************************* ** ** Function rw_t4t_sm_read_ndef ** ** Description State machine for NDEF read procedure ** ** Returns none ** *******************************************************************************/ static void rw_t4t_sm_read_ndef (BT_HDR *p_r_apdu) { tRW_T4T_CB *p_t4t = &rw_cb.tcb.t4t; UINT8 *p; UINT16 status_words; tRW_DATA rw_data; #if (BT_TRACE_VERBOSE == TRUE) RW_TRACE_DEBUG2 ("rw_t4t_sm_read_ndef (): sub_state:%s (%d)", rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state); #else RW_TRACE_DEBUG1 ("rw_t4t_sm_read_ndef (): sub_state=%d", p_t4t->sub_state); #endif /* get status words */ p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset; p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE); BE_STREAM_TO_UINT16 (status_words, p); if (status_words != T4T_RSP_CMD_CMPLTED) { rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1)); GKI_freebuf (p_r_apdu); return; } switch (p_t4t->sub_state) { case RW_T4T_SUBSTATE_WAIT_READ_RESP: /* Read partial or complete data */ p_r_apdu->len -= T4T_RSP_STATUS_WORDS_SIZE; if ((p_r_apdu->len > 0) && (p_r_apdu->len <= p_t4t->rw_length)) { p_t4t->rw_length -= p_r_apdu->len; p_t4t->rw_offset += p_r_apdu->len; if (rw_cb.p_cback) { rw_data.data.status = NFC_STATUS_OK; rw_data.data.p_data = p_r_apdu; /* if need to read more data */ if (p_t4t->rw_length > 0) { (*(rw_cb.p_cback)) (RW_T4T_NDEF_READ_EVT, &rw_data); if (!rw_t4t_read_file (p_t4t->rw_offset, p_t4t->rw_length, TRUE)) { rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0); } } else { p_t4t->state = RW_T4T_STATE_IDLE; (*(rw_cb.p_cback)) (RW_T4T_NDEF_READ_CPLT_EVT, &rw_data); RW_TRACE_DEBUG0 ("rw_t4t_sm_read_ndef (): Sent RW_T4T_NDEF_READ_CPLT_EVT"); } p_r_apdu = NULL; } else { p_t4t->rw_length = 0; p_t4t->state = RW_T4T_STATE_IDLE; } } else { RW_TRACE_ERROR2 ("rw_t4t_sm_read_ndef (): invalid payload length (%d), rw_length (%d)", p_r_apdu->len, p_t4t->rw_length); rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0); } break; default: RW_TRACE_ERROR1 ("rw_t4t_sm_read_ndef (): unknown sub_state = %d", p_t4t->sub_state); rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0); break; } if (p_r_apdu) GKI_freebuf (p_r_apdu); }
/******************************************************************************* ** ** Function ce_t4t_update_binary ** ** Description Update file and send R-APDU to peer ** ** Returns TRUE if success ** *******************************************************************************/ static BOOLEAN ce_t4t_update_binary (UINT16 offset, UINT8 length, UINT8 *p_data) { tCE_T4T_MEM *p_t4t = &ce_cb.mem.t4t; UINT8 *p; UINT8 file_length[2]; UINT16 starting_offset; tCE_DATA ce_data; CE_TRACE_DEBUG3 ("ce_t4t_update_binary (): Offset:0x%04X, Length:0x%04X, selected status = 0x%02X", offset, length, p_t4t->status); starting_offset = offset; /* update file size (NLEN) */ if ((offset < T4T_FILE_LENGTH_SIZE) && (length > 0)) { p = file_length; UINT16_TO_BE_STREAM (p, p_t4t->nlen); while ((offset < T4T_FILE_LENGTH_SIZE) && (length > 0)) { *(file_length + offset++) = *(p_data++); length--; } p = file_length; BE_STREAM_TO_UINT16 (p_t4t->nlen, p); } if (length > 0) memcpy (p_t4t->p_scratch_buf + offset - T4T_FILE_LENGTH_SIZE, p_data, length); /* if this is the last step: writing non-zero length in NLEN */ if ((starting_offset == 0) && (p_t4t->nlen > 0)) { nfc_stop_quick_timer (&p_t4t->timer); if (ce_cb.p_cback) { ce_data.update_info.status = NFC_STATUS_OK; ce_data.update_info.length = p_t4t->nlen; ce_data.update_info.p_data = p_t4t->p_scratch_buf; (*ce_cb.p_cback) (CE_T4T_NDEF_UPDATE_CPLT_EVT, &ce_data); CE_TRACE_DEBUG0 ("ce_t4t_update_binary (): Sent CE_T4T_NDEF_UPDATE_CPLT_EVT"); } p_t4t->status &= ~ (CE_T4T_STATUS_NDEF_FILE_UPDATING); } else if (!(p_t4t->status & CE_T4T_STATUS_NDEF_FILE_UPDATING)) { /* starting of updating */ p_t4t->status |= CE_T4T_STATUS_NDEF_FILE_UPDATING; nfc_start_quick_timer (&p_t4t->timer, NFC_TTYPE_CE_T4T_UPDATE, (CE_T4T_TOUT_UPDATE * QUICK_TIMER_TICKS_PER_SEC) / 1000); if (ce_cb.p_cback) (*ce_cb.p_cback) (CE_T4T_NDEF_UPDATE_START_EVT, NULL); } if (!ce_t4t_send_status (T4T_RSP_CMD_CMPLTED)) { return FALSE; } else { return TRUE; } }
/******************************************************************************* ** ** Function avrc_pars_vendor_cmd ** ** Description This function parses the vendor specific commands defined by ** Bluetooth SIG ** ** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully. ** Otherwise, the error code defined by AVRCP 1.4 ** *******************************************************************************/ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_result, UINT8 *p_buf, UINT16 buf_len) { tAVRC_STS status = AVRC_STS_NO_ERROR; UINT8 *p; UINT16 len; UINT8 xx, yy; UINT8 *p_u8; UINT16 *p_u16; UINT32 u32, u32_2, *p_u32; tAVRC_APP_SETTING *p_app_set; UINT16 size_needed; /* Check the vendor data */ if (p_msg->vendor_len == 0) { return AVRC_STS_NO_ERROR; } if (p_msg->p_vendor_data == NULL) { return AVRC_STS_INTERNAL_ERR; } p = p_msg->p_vendor_data; p_result->pdu = *p++; AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() pdu:0x%x", p_result->pdu); if (!AVRC_IsValidAvcType (p_result->pdu, p_msg->hdr.ctype)) { AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() detects wrong AV/C type!"); status = AVRC_STS_BAD_CMD; } p++; /* skip the reserved byte */ BE_STREAM_TO_UINT16 (len, p); if ((len + 4) != (p_msg->vendor_len)) { status = AVRC_STS_INTERNAL_ERR; } if (status != AVRC_STS_NO_ERROR) { return status; } switch (p_result->pdu) { case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */ p_result->get_caps.capability_id = *p++; if (!AVRC_IS_VALID_CAP_ID(p_result->get_caps.capability_id)) { status = AVRC_STS_BAD_PARAM; } else if (len != 1) { status = AVRC_STS_INTERNAL_ERR; } break; case AVRC_PDU_LIST_PLAYER_APP_ATTR: /* 0x11 */ /* no additional parameters */ if (len != 0) { status = AVRC_STS_INTERNAL_ERR; } break; case AVRC_PDU_LIST_PLAYER_APP_VALUES: /* 0x12 */ p_result->list_app_values.attr_id = *p++; if (!AVRC_IS_VALID_ATTRIBUTE(p_result->list_app_values.attr_id)) { status = AVRC_STS_BAD_PARAM; } else if (len != 1) { status = AVRC_STS_INTERNAL_ERR; } break; case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */ BE_STREAM_TO_UINT8 (p_result->get_cur_app_val.num_attr, p); if (len != (p_result->get_cur_app_val.num_attr + 1)) { status = AVRC_STS_INTERNAL_ERR; break; } p_u8 = p_result->get_cur_app_val.attrs; for (xx = 0, yy = 0; xx < p_result->get_cur_app_val.num_attr; xx++) { /* only report the valid player app attributes */ if (AVRC_IsValidPlayerAttr(*p)) { p_u8[yy++] = *p; } p++; } p_result->get_cur_app_val.num_attr = yy; if (yy == 0) { status = AVRC_STS_BAD_PARAM; } break; case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */ BE_STREAM_TO_UINT8 (p_result->set_app_val.num_val, p); size_needed = sizeof(tAVRC_APP_SETTING); if (p_buf && (len == ((p_result->set_app_val.num_val << 1) + 1))) { p_result->set_app_val.p_vals = (tAVRC_APP_SETTING *)p_buf; p_app_set = p_result->set_app_val.p_vals; for (xx = 0; ((xx < p_result->set_app_val.num_val) && (buf_len > size_needed)); xx++) { p_app_set[xx].attr_id = *p++; p_app_set[xx].attr_val = *p++; if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id, p_app_set[xx].attr_val)) { status = AVRC_STS_BAD_PARAM; } } if (xx != p_result->set_app_val.num_val) { AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d", xx, p_result->set_app_val.num_val); p_result->set_app_val.num_val = xx; } } else { AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len"); status = AVRC_STS_INTERNAL_ERR; } break; case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:/* 0x16 */ if (len < 3) { status = AVRC_STS_INTERNAL_ERR; } else { BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.attr_id, p); if (!AVRC_IS_VALID_ATTRIBUTE(p_result->get_app_val_txt.attr_id)) { status = AVRC_STS_BAD_PARAM; } else { BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.num_val, p); if ( (len - 2/* attr_id & num_val */) != p_result->get_app_val_txt.num_val) { status = AVRC_STS_INTERNAL_ERR; } else { p_u8 = p_result->get_app_val_txt.vals; for (xx = 0; xx < p_result->get_app_val_txt.num_val; xx++) { p_u8[xx] = *p++; if (!avrc_is_valid_player_attrib_value(p_result->get_app_val_txt.attr_id, p_u8[xx])) { status = AVRC_STS_BAD_PARAM; break; } } } } } break; case AVRC_PDU_INFORM_DISPLAY_CHARSET: /* 0x17 */ if (len < 3) { status = AVRC_STS_INTERNAL_ERR; } else { BE_STREAM_TO_UINT8 (p_result->inform_charset.num_id, p); if ( (len - 1/* num_id */) != p_result->inform_charset.num_id * 2) { status = AVRC_STS_INTERNAL_ERR; } else { p_u16 = p_result->inform_charset.charsets; if (p_result->inform_charset.num_id > AVRC_MAX_CHARSET_SIZE) { p_result->inform_charset.num_id = AVRC_MAX_CHARSET_SIZE; } for (xx = 0; xx < p_result->inform_charset.num_id; xx++) { BE_STREAM_TO_UINT16 (p_u16[xx], p); } } } break; case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:/* 0x18 */ if (len != 1) { status = AVRC_STS_INTERNAL_ERR; } else { p_result->inform_battery_status.battery_status = *p++; if (!AVRC_IS_VALID_BATTERY_STATUS(p_result->inform_battery_status.battery_status)) { status = AVRC_STS_BAD_PARAM; } } break; case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */ if (len < 9) { /* UID/8 and num_attr/1 */ status = AVRC_STS_INTERNAL_ERR; } else { BE_STREAM_TO_UINT32 (u32, p); BE_STREAM_TO_UINT32 (u32_2, p); if (u32 == 0 && u32_2 == 0) { BE_STREAM_TO_UINT8 (p_result->get_elem_attrs.num_attr, p); if ( (len - 9/* UID/8 and num_attr/1 */) != (p_result->get_elem_attrs.num_attr * 4)) { status = AVRC_STS_INTERNAL_ERR; } else { p_u32 = p_result->get_elem_attrs.attrs; if (p_result->get_elem_attrs.num_attr > AVRC_MAX_ELEM_ATTR_SIZE) { p_result->get_elem_attrs.num_attr = AVRC_MAX_ELEM_ATTR_SIZE; } for (xx = 0; xx < p_result->get_elem_attrs.num_attr; xx++) { BE_STREAM_TO_UINT32 (p_u32[xx], p); } } } else { status = AVRC_STS_NOT_FOUND; } } break; case AVRC_PDU_GET_PLAY_STATUS: /* 0x30 */ /* no additional parameters */ if (len != 0) { status = AVRC_STS_INTERNAL_ERR; } break; case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */ if (len != 5) { status = AVRC_STS_INTERNAL_ERR; } else { BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p); BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p); } break; case AVRC_PDU_SET_ABSOLUTE_VOLUME: { if (len != 1) { status = AVRC_STS_INTERNAL_ERR; } break; } /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */ /* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */ default: status = AVRC_STS_BAD_CMD; break; } return status; }
/******************************************************************************* ** ** 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); }