/******************************************************************************* ** ** 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 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 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 llcp_sdp_proc_snl ** ** Description Process SDREQ and SDRES in SNL ** ** ** Returns LLCP_STATUS ** *******************************************************************************/ tLLCP_STATUS llcp_sdp_proc_snl (UINT16 sdu_length, UINT8 *p) { UINT8 type, length, tid, sap, *p_value; LLCP_TRACE_DEBUG0 ("llcp_sdp_proc_snl ()"); if ((llcp_cb.lcb.agreed_major_version < LLCP_MIN_SNL_MAJOR_VERSION)|| ((llcp_cb.lcb.agreed_major_version == LLCP_MIN_SNL_MAJOR_VERSION)&&(llcp_cb.lcb.agreed_minor_version < LLCP_MIN_SNL_MINOR_VERSION))) { LLCP_TRACE_DEBUG0 ("llcp_sdp_proc_snl(): version number less than 1.1, SNL not supported."); return LLCP_STATUS_FAIL; } while (sdu_length >= 2) /* at least type and length */ { BE_STREAM_TO_UINT8 (type, p); BE_STREAM_TO_UINT8 (length, p); switch (type) { case LLCP_SDREQ_TYPE: if ( (length > 1) /* TID and sevice name */ &&(sdu_length >= 2 + length) ) /* type, length, TID and service name */ { p_value = p; BE_STREAM_TO_UINT8 (tid, p_value); sap = llcp_sdp_get_sap_by_name ((char*) p_value, (UINT8) (length - 1)); llcp_sdp_send_sdres (tid, sap); } else { LLCP_TRACE_ERROR1 ("llcp_sdp_proc_snl (): bad length (%d) in LLCP_SDREQ_TYPE", length); } break; case LLCP_SDRES_TYPE: if ( (length == LLCP_SDRES_LEN) /* TID and SAP */ &&(sdu_length >= 2 + length) ) /* type, length, TID and SAP */ { p_value = p; BE_STREAM_TO_UINT8 (tid, p_value); BE_STREAM_TO_UINT8 (sap, p_value); llcp_sdp_return_sap (tid, sap); } else { LLCP_TRACE_ERROR1 ("llcp_sdp_proc_snl (): bad length (%d) in LLCP_SDRES_TYPE", length); } break; default: LLCP_TRACE_WARNING1 ("llcp_sdp_proc_snl (): Unknown type (0x%x) is ignored", type); break; } if (sdu_length >= 2 + length) /* type, length, value */ { sdu_length -= 2 + length; p += length; } else { break; } } if (sdu_length) { LLCP_TRACE_ERROR0 ("llcp_sdp_proc_snl (): Bad format of SNL"); return LLCP_STATUS_FAIL; } else { return LLCP_STATUS_SUCCESS; } }
/******************************************************************************* ** ** 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 ce_t4t_process_select_app_cmd ** ** Description This function processes Select Command by AID. ** ** Returns none ** *******************************************************************************/ static void ce_t4t_process_select_app_cmd (UINT8 *p_cmd, BT_HDR *p_c_apdu) { UINT8 data_len; UINT16 status_words = 0x0000; /* invalid status words */ tCE_DATA ce_data; UINT8 xx; CE_TRACE_DEBUG0 ("ce_t4t_process_select_app_cmd ()"); p_cmd++; /* skip P2 */ /* Lc Byte */ BE_STREAM_TO_UINT8 (data_len, p_cmd); #if (CE_TEST_INCLUDED == TRUE) if (mapping_aid_test_enabled) { if ( (data_len == T4T_V20_NDEF_TAG_AID_LEN) &&(!memcmp(p_cmd, ce_test_tag_app_id, data_len)) &&(ce_cb.mem.t4t.p_ndef_msg) ) { GKI_freebuf (p_c_apdu); ce_t4t_send_status ((UINT16) T4T_RSP_CMD_CMPLTED); return; } } #endif /* ** Compare AIDs registered by applications ** if found, use callback of the application ** otherwise, return error and maintain the same status */ ce_cb.mem.t4t.selected_aid_idx = CE_T4T_MAX_REG_AID; for (xx = 0; xx < CE_T4T_MAX_REG_AID; xx++) { if ( (ce_cb.mem.t4t.reg_aid[xx].aid_len > 0) &&(ce_cb.mem.t4t.reg_aid[xx].aid_len == data_len) &&(!(memcmp(ce_cb.mem.t4t.reg_aid[xx].aid, p_cmd, data_len))) ) { ce_cb.mem.t4t.selected_aid_idx = xx; break; } } /* if found matched AID */ if (ce_cb.mem.t4t.selected_aid_idx < CE_T4T_MAX_REG_AID) { ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_CC_FILE_SELECTED); ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_NDEF_SELECTED); ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_T4T_APP_SELECTED); ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_WILDCARD_AID_SELECTED); ce_cb.mem.t4t.status |= CE_T4T_STATUS_REG_AID_SELECTED; CE_TRACE_DEBUG4 ("ce_t4t_process_select_app_cmd (): Registered AID[%02X%02X%02X%02X...] is selected", ce_cb.mem.t4t.reg_aid[ce_cb.mem.t4t.selected_aid_idx].aid[0], ce_cb.mem.t4t.reg_aid[ce_cb.mem.t4t.selected_aid_idx].aid[1], ce_cb.mem.t4t.reg_aid[ce_cb.mem.t4t.selected_aid_idx].aid[2], ce_cb.mem.t4t.reg_aid[ce_cb.mem.t4t.selected_aid_idx].aid[3]); ce_data.raw_frame.status = NFC_STATUS_OK; 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 if ( (data_len == T4T_V20_NDEF_TAG_AID_LEN) &&(!memcmp(p_cmd, t4t_v20_ndef_tag_aid, data_len - 1)) &&(ce_cb.mem.t4t.p_ndef_msg) ) { p_cmd += data_len - 1; /* adjust version if possible */ if ((*p_cmd) == 0x00) { ce_t4t_set_version_in_cc (T4T_VERSION_1_0); status_words = T4T_RSP_CMD_CMPLTED; } else if ((*p_cmd) == 0x01) { ce_t4t_set_version_in_cc (T4T_VERSION_2_0); status_words = T4T_RSP_CMD_CMPLTED; } else { CE_TRACE_DEBUG0 ("ce_t4t_process_select_app_cmd (): Not found matched AID"); status_words = T4T_RSP_NOT_FOUND; } } else if (ce_cb.mem.t4t.p_wildcard_aid_cback) { ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_CC_FILE_SELECTED); ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_NDEF_SELECTED); ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_T4T_APP_SELECTED); ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_REG_AID_SELECTED); ce_cb.mem.t4t.status |= CE_T4T_STATUS_WILDCARD_AID_SELECTED; ce_data.raw_frame.status = NFC_STATUS_OK; 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_TRACE_DEBUG0 ("CET4T: Forward raw frame (SELECT APP) to wildcard AID handler"); (*(ce_cb.mem.t4t.p_wildcard_aid_cback)) (CE_T4T_RAW_FRAME_EVT, &ce_data); } else { CE_TRACE_DEBUG0 ("ce_t4t_process_select_app_cmd (): Not found matched AID or not listening T4T NDEF"); status_words = T4T_RSP_NOT_FOUND; } if (status_words) { /* if T4T CE can support */ if (status_words == T4T_RSP_CMD_CMPLTED) { ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_CC_FILE_SELECTED); ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_NDEF_SELECTED); ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_REG_AID_SELECTED); ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_WILDCARD_AID_SELECTED); ce_cb.mem.t4t.status |= CE_T4T_STATUS_T4T_APP_SELECTED; CE_TRACE_DEBUG0 ("ce_t4t_process_select_app_cmd (): T4T CE App selected"); } ce_t4t_send_status (status_words); GKI_freebuf (p_c_apdu); } /* if status_words is not set then upper layer will send R-APDU */ return; }
/******************************************************************************* ** ** 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 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 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 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; } }