/****************************************************************************** * * Copyright (C) 2010-2014 Broadcom Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * * This file contains the action functions the NFA_RW state machine. * ******************************************************************************/ #include <log/log.h> #include <string.h> #include <android-base/stringprintf.h> #include <base/logging.h> #include "ndef_utils.h" #include "nfa_dm_int.h" #include "nfa_mem_co.h" #include "nfa_rw_int.h" using android::base::StringPrintf; extern bool nfc_debug_enabled; #define NFA_RW_OPTION_INVALID 0xFF /* Tag sleep req cmd*/ uint8_t NFA_RW_TAG_SLP_REQ[] = {0x50, 0x00}; /* Local static function prototypes */ static tNFC_STATUS nfa_rw_start_ndef_read(void); static tNFC_STATUS nfa_rw_start_ndef_write(void); static tNFC_STATUS nfa_rw_start_ndef_detection(void); static tNFC_STATUS nfa_rw_config_tag_ro(bool b_hard_lock); static bool nfa_rw_op_req_while_busy(tNFA_RW_MSG* p_data); static bool nfa_rw_op_req_while_inactive(tNFA_RW_MSG* p_data); static void nfa_rw_error_cleanup(uint8_t event); static void nfa_rw_presence_check(tNFA_RW_MSG* p_data); static void nfa_rw_handle_t2t_evt(tRW_EVENT event, tRW_DATA* p_rw_data); static bool nfa_rw_detect_ndef(void); static void nfa_rw_cback(tRW_EVENT event, tRW_DATA* p_rw_data); static void nfa_rw_handle_mfc_evt(tRW_EVENT event, tRW_DATA* p_rw_data); /******************************************************************************* ** ** Function nfa_rw_free_ndef_rx_buf ** ** Description Free buffer allocated to hold incoming NDEF message ** ** Returns Nothing ** *******************************************************************************/ void nfa_rw_free_ndef_rx_buf(void) { if (nfa_rw_cb.p_ndef_buf) { nfa_mem_co_free(nfa_rw_cb.p_ndef_buf); nfa_rw_cb.p_ndef_buf = nullptr; } } /******************************************************************************* ** ** Function nfa_rw_store_ndef_rx_buf ** ** Description Store data into NDEF buffer ** ** Returns Nothing ** *******************************************************************************/ static void nfa_rw_store_ndef_rx_buf(tRW_DATA* p_rw_data) { uint8_t* p; p = (uint8_t*)(p_rw_data->data.p_data + 1) + p_rw_data->data.p_data->offset; if ((nfa_rw_cb.ndef_rd_offset + p_rw_data->data.p_data->len) <= nfa_rw_cb.ndef_cur_size) { /* Save data into buffer */ memcpy(&nfa_rw_cb.p_ndef_buf[nfa_rw_cb.ndef_rd_offset], p, p_rw_data->data.p_data->len); nfa_rw_cb.ndef_rd_offset += p_rw_data->data.p_data->len; } else { LOG(ERROR) << StringPrintf("Exceed ndef_cur_size error"); android_errorWriteLog(0x534e4554, "123583388"); } GKI_freebuf(p_rw_data->data.p_data); p_rw_data->data.p_data = nullptr; } /******************************************************************************* ** ** Function nfa_rw_send_data_to_upper ** ** Description Send data to upper layer ** ** Returns Nothing ** *******************************************************************************/ static void nfa_rw_send_data_to_upper(tRW_DATA* p_rw_data) { tNFA_CONN_EVT_DATA conn_evt_data; if ((p_rw_data->status == NFC_STATUS_TIMEOUT) || (p_rw_data->data.p_data == nullptr)) return; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("nfa_rw_send_data_to_upper: Len [0x%X] Status [%s]", p_rw_data->data.p_data->len, NFC_GetStatusName(p_rw_data->data.status).c_str()); /* Notify conn cback of NFA_DATA_EVT */ conn_evt_data.data.status = p_rw_data->data.status; conn_evt_data.data.p_data = (uint8_t*)(p_rw_data->data.p_data + 1) + p_rw_data->data.p_data->offset; conn_evt_data.data.len = p_rw_data->data.p_data->len; nfa_dm_act_conn_cback_notify(NFA_DATA_EVT, &conn_evt_data); GKI_freebuf(p_rw_data->data.p_data); p_rw_data->data.p_data = nullptr; } /******************************************************************************* ** ** Function nfa_rw_error_cleanup ** ** Description Handle failure - signal command complete and notify app ** ** Returns Nothing ** *******************************************************************************/ static void nfa_rw_error_cleanup(uint8_t event) { tNFA_CONN_EVT_DATA conn_evt_data; nfa_rw_command_complete(); conn_evt_data.status = NFA_STATUS_FAILED; nfa_dm_act_conn_cback_notify(event, &conn_evt_data); } /******************************************************************************* ** ** Function nfa_rw_check_start_presence_check_timer ** ** Description Start timer to wait for specified time before presence check ** ** Returns Nothing ** *******************************************************************************/ static void nfa_rw_check_start_presence_check_timer( uint16_t presence_check_start_delay) { if (!p_nfa_dm_cfg->auto_presence_check) return; if (nfa_rw_cb.flags & NFA_RW_FL_NOT_EXCL_RF_MODE) { if (presence_check_start_delay) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("Starting presence check timer..."); nfa_sys_start_timer(&nfa_rw_cb.tle, NFA_RW_PRESENCE_CHECK_TICK_EVT, presence_check_start_delay); } else { /* Presence check now */ nfa_rw_presence_check(nullptr); } } } /******************************************************************************* ** ** Function nfa_rw_stop_presence_check_timer ** ** Description Stop timer for presence check ** ** Returns Nothing ** *******************************************************************************/ void nfa_rw_stop_presence_check_timer(void) { nfa_sys_stop_timer(&nfa_rw_cb.tle); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("Stopped presence check timer (if started)"); } /******************************************************************************* ** ** Function nfa_rw_handle_ndef_detect ** ** Description Handler for NDEF detection reader/writer event ** ** Returns Nothing ** *******************************************************************************/ static void nfa_rw_handle_ndef_detect(tRW_DATA* p_rw_data) { tNFA_CONN_EVT_DATA conn_evt_data; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "NDEF Detection completed: cur_size=%i, max_size=%i, flags=0x%x", p_rw_data->ndef.cur_size, p_rw_data->ndef.max_size, p_rw_data->ndef.flags); /* Check if NDEF detection succeeded */ if (p_rw_data->ndef.status == NFC_STATUS_OK) { /* Set NDEF detection state */ nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_TRUE; nfa_rw_cb.flags |= NFA_RW_FL_NDEF_OK; /* Store ndef properties */ conn_evt_data.ndef_detect.status = NFA_STATUS_OK; conn_evt_data.ndef_detect.protocol = p_rw_data->ndef.protocol; conn_evt_data.ndef_detect.cur_size = nfa_rw_cb.ndef_cur_size = p_rw_data->ndef.cur_size; conn_evt_data.ndef_detect.max_size = nfa_rw_cb.ndef_max_size = p_rw_data->ndef.max_size; conn_evt_data.ndef_detect.flags = p_rw_data->ndef.flags; if (p_rw_data->ndef.flags & RW_NDEF_FL_READ_ONLY) nfa_rw_cb.flags |= NFA_RW_FL_TAG_IS_READONLY; else nfa_rw_cb.flags &= ~NFA_RW_FL_TAG_IS_READONLY; /* Determine what operation triggered the NDEF detection procedure */ if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { /* if ndef detection was done as part of ndef-read operation, then perform * ndef read now */ conn_evt_data.status = nfa_rw_start_ndef_read(); if (conn_evt_data.status != NFA_STATUS_OK) { /* Failed to start NDEF Read */ /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); } } else if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { /* if ndef detection was done as part of ndef-write operation, then * perform ndef write now */ conn_evt_data.status = nfa_rw_start_ndef_write(); if (conn_evt_data.status != NFA_STATUS_OK) { /* Failed to start NDEF Write. */ /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); } } else { /* current op was stand-alone NFA_DetectNDef. Command complete - perform * cleanup and notify app */ nfa_rw_cb.cur_op = NFA_RW_OP_MAX; nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_NDEF_DETECT_EVT, &conn_evt_data); } } else { /* NDEF detection failed... */ /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_FALSE; conn_evt_data.status = p_rw_data->ndef.status; if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { /* if ndef detection was done as part of ndef-read operation, then notify * NDEF handlers of failure */ nfa_dm_ndef_handle_message(NFA_STATUS_FAILED, nullptr, 0); /* Notify app of read status */ nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); } else if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { /* if ndef detection was done as part of ndef-write operation, then notify * app of failure */ nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); } else if (nfa_rw_cb.cur_op == NFA_RW_OP_DETECT_NDEF) { conn_evt_data.ndef_detect.protocol = p_rw_data->ndef.protocol; /* current op was stand-alone NFA_DetectNDef. Notify app of failure */ if (p_rw_data->ndef.status == NFC_STATUS_TIMEOUT) { /* Tag could have moved away */ conn_evt_data.ndef_detect.cur_size = 0; conn_evt_data.ndef_detect.max_size = 0; conn_evt_data.ndef_detect.flags = RW_NDEF_FL_UNKNOWN; conn_evt_data.ndef_detect.status = NFA_STATUS_TIMEOUT; } else { /* NDEF Detection failed for other reasons */ conn_evt_data.ndef_detect.cur_size = nfa_rw_cb.ndef_cur_size = p_rw_data->ndef.cur_size; conn_evt_data.ndef_detect.max_size = nfa_rw_cb.ndef_max_size = p_rw_data->ndef.max_size; conn_evt_data.ndef_detect.flags = p_rw_data->ndef.flags; } nfa_dm_act_conn_cback_notify(NFA_NDEF_DETECT_EVT, &conn_evt_data); } nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ } } /******************************************************************************* ** ** Function nfa_rw_handle_tlv_detect ** ** Description Handler for TLV detection reader/writer event ** ** Returns Nothing ** *******************************************************************************/ static void nfa_rw_handle_tlv_detect(tRW_DATA* p_rw_data) { tNFA_CONN_EVT_DATA conn_evt_data; /* Set TLV detection state */ if (nfa_rw_cb.cur_op == NFA_RW_OP_SET_TAG_RO) { if (nfa_rw_cb.tlv_st == NFA_RW_TLV_DETECT_ST_OP_NOT_STARTED) { nfa_rw_cb.tlv_st = NFA_RW_TLV_DETECT_ST_LOCK_TLV_OP_COMPLETE; } else { nfa_rw_cb.tlv_st = NFA_RW_TLV_DETECT_ST_COMPLETE; } } else { if (nfa_rw_cb.cur_op == NFA_RW_OP_DETECT_LOCK_TLV) { nfa_rw_cb.tlv_st |= NFA_RW_TLV_DETECT_ST_LOCK_TLV_OP_COMPLETE; } else if (nfa_rw_cb.cur_op == NFA_RW_OP_DETECT_MEM_TLV) { nfa_rw_cb.tlv_st |= NFA_RW_TLV_DETECT_ST_MEM_TLV_OP_COMPLETE; } } /* Check if TLV detection succeeded */ if (p_rw_data->tlv.status == NFC_STATUS_OK) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "TLV Detection succeeded: num_bytes=%i", p_rw_data->tlv.num_bytes); /* Store tlv properties */ conn_evt_data.tlv_detect.status = NFA_STATUS_OK; conn_evt_data.tlv_detect.protocol = p_rw_data->tlv.protocol; conn_evt_data.tlv_detect.num_bytes = p_rw_data->tlv.num_bytes; /* Determine what operation triggered the TLV detection procedure */ if (nfa_rw_cb.cur_op == NFA_RW_OP_SET_TAG_RO) { if (nfa_rw_config_tag_ro(nfa_rw_cb.b_hard_lock) != NFC_STATUS_OK) { /* Failed to set tag read only */ conn_evt_data.tlv_detect.status = NFA_STATUS_FAILED; nfa_dm_act_conn_cback_notify(NFA_SET_TAG_RO_EVT, &conn_evt_data); } } else { /* current op was stand-alone NFA_DetectTlv. Command complete - perform * cleanup and notify app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_TLV_DETECT_EVT, &conn_evt_data); } } /* Handle failures */ if (p_rw_data->tlv.status != NFC_STATUS_OK) { /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); conn_evt_data.tlv_detect.status = NFA_STATUS_FAILED; if ((nfa_rw_cb.cur_op == NFA_RW_OP_DETECT_LOCK_TLV) || (nfa_rw_cb.cur_op == NFA_RW_OP_DETECT_MEM_TLV)) { nfa_dm_act_conn_cback_notify(NFA_TLV_DETECT_EVT, &conn_evt_data); } else if (nfa_rw_cb.cur_op == NFA_RW_OP_SET_TAG_RO) { if (nfa_rw_config_tag_ro(nfa_rw_cb.b_hard_lock) != NFC_STATUS_OK) { /* Failed to set tag read only */ conn_evt_data.tlv_detect.status = NFA_STATUS_FAILED; nfa_dm_act_conn_cback_notify(NFA_SET_TAG_RO_EVT, &conn_evt_data); } } } } /******************************************************************************* ** ** Function nfa_rw_handle_sleep_wakeup_rsp ** ** Description Handl sleep wakeup ** ** Returns Nothing ** *******************************************************************************/ void nfa_rw_handle_sleep_wakeup_rsp(tNFC_STATUS status) { tNFC_ACTIVATE_DEVT activate_params; tRW_EVENT event; if ((nfa_rw_cb.halt_event != RW_T2T_MAX_EVT) && (nfa_rw_cb.activated_tech_mode == NFC_DISCOVERY_TYPE_POLL_A) && (nfa_rw_cb.protocol == NFC_PROTOCOL_T2T) && (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T)) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "nfa_rw_handle_sleep_wakeup_rsp; Attempt to wake up Type 2 tag from " "HALT State is complete"); if (status == NFC_STATUS_OK) { /* Type 2 Tag is wakeup from HALT state */ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "nfa_rw_handle_sleep_wakeup_rsp; Handle the NACK rsp received now"); /* Initialize control block */ activate_params.protocol = nfa_rw_cb.protocol; activate_params.rf_tech_param.param.pa.sel_rsp = nfa_rw_cb.pa_sel_res; activate_params.rf_tech_param.mode = nfa_rw_cb.activated_tech_mode; /* Initialize RW module */ if ((RW_SetActivatedTagType(&activate_params, nfa_rw_cback)) != NFC_STATUS_OK) { /* Log error (stay in NFA_RW_ST_ACTIVATED state until deactivation) */ LOG(ERROR) << StringPrintf("RW_SetActivatedTagType failed."); if (nfa_rw_cb.halt_event == RW_T2T_READ_CPLT_EVT) { if (nfa_rw_cb.rw_data.data.p_data) GKI_freebuf(nfa_rw_cb.rw_data.data.p_data); nfa_rw_cb.rw_data.data.p_data = nullptr; } /* Do not try to detect NDEF again but just notify current operation * failed */ nfa_rw_cb.halt_event = RW_T2T_MAX_EVT; } } /* The current operation failed with NACK rsp from type 2 tag */ nfa_rw_cb.rw_data.status = NFC_STATUS_FAILED; event = nfa_rw_cb.halt_event; /* Got NACK rsp during presence check and legacy presence check performed */ if (nfa_rw_cb.cur_op == NFA_RW_OP_PRESENCE_CHECK) nfa_rw_cb.rw_data.status = status; /* If cannot Sleep wakeup tag, then NDEF Detect operation is complete */ if ((status != NFC_STATUS_OK) && (nfa_rw_cb.halt_event == RW_T2T_NDEF_DETECT_EVT)) nfa_rw_cb.halt_event = RW_T2T_MAX_EVT; nfa_rw_handle_t2t_evt(event, &nfa_rw_cb.rw_data); nfa_rw_cb.halt_event = RW_T2T_MAX_EVT; /* If Type 2 tag sleep wakeup failed and If in normal mode (not-exclusive RF * mode) then deactivate the link if sleep wakeup failed */ if ((nfa_rw_cb.flags & NFA_RW_FL_NOT_EXCL_RF_MODE) && (status != NFC_STATUS_OK)) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("Sleep wakeup failed. Deactivating..."); nfa_dm_rf_deactivate(NFA_DEACTIVATE_TYPE_DISCOVERY); } } else { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "nfa_rw_handle_sleep_wakeup_rsp; Legacy presence check performed"); /* Legacy presence check performed */ nfa_rw_handle_presence_check_rsp(status); } } /******************************************************************************* ** ** Function nfa_rw_handle_presence_check_rsp ** ** Description Handler RW_T#t_PRESENCE_CHECK_EVT ** ** Returns Nothing ** *******************************************************************************/ void nfa_rw_handle_presence_check_rsp(tNFC_STATUS status) { NFC_HDR* p_pending_msg; /* Stop the presence check timer - timer may have been started when presence * check started */ nfa_rw_stop_presence_check_timer(); if (status == NFA_STATUS_OK) { /* Clear the BUSY flag and restart the presence-check timer */ nfa_rw_command_complete(); } else { /* If presence check failed just clear the BUSY flag */ nfa_rw_cb.flags &= ~NFA_RW_FL_API_BUSY; } /* Handle presence check due to auto-presence-check */ if (nfa_rw_cb.flags & NFA_RW_FL_AUTO_PRESENCE_CHECK_BUSY) { nfa_rw_cb.flags &= ~NFA_RW_FL_AUTO_PRESENCE_CHECK_BUSY; /* If an API was called during auto-presence-check, then handle it now */ if (nfa_rw_cb.p_pending_msg) { /* If NFA_RwPresenceCheck was called during auto-presence-check, notify * app of result */ if (nfa_rw_cb.p_pending_msg->op_req.op == NFA_RW_OP_PRESENCE_CHECK) { /* Notify app of presence check status */ tNFA_CONN_EVT_DATA nfa_conn_evt_data; nfa_conn_evt_data.status = status; nfa_dm_act_conn_cback_notify(NFA_PRESENCE_CHECK_EVT, &nfa_conn_evt_data); GKI_freebuf(nfa_rw_cb.p_pending_msg); nfa_rw_cb.p_pending_msg = nullptr; } /* For all other APIs called during auto-presence check, perform the command now (if tag is still present) */ else if (status == NFC_STATUS_OK) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "Performing deferred operation after presence check..."); p_pending_msg = (NFC_HDR*)nfa_rw_cb.p_pending_msg; nfa_rw_cb.p_pending_msg = nullptr; nfa_rw_handle_event(p_pending_msg); GKI_freebuf(p_pending_msg); } else { /* Tag no longer present. Free command for pending API command */ GKI_freebuf(nfa_rw_cb.p_pending_msg); nfa_rw_cb.p_pending_msg = nullptr; } } /* Auto-presence check failed. Deactivate */ if (status != NFC_STATUS_OK) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("Auto presence check failed. Deactivating..."); nfa_dm_rf_deactivate(NFA_DEACTIVATE_TYPE_DISCOVERY); } } /* Handle presence check due to NFA_RwPresenceCheck API call */ else { /* Notify app of presence check status */ tNFA_CONN_EVT_DATA nfa_conn_evt_data; nfa_conn_evt_data.status = status; nfa_dm_act_conn_cback_notify(NFA_PRESENCE_CHECK_EVT, &nfa_conn_evt_data); /* If in normal mode (not-exclusive RF mode) then deactivate the link if * presence check failed */ if ((nfa_rw_cb.flags & NFA_RW_FL_NOT_EXCL_RF_MODE) && (nfa_conn_evt_data.status != NFC_STATUS_OK)) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("Presence check failed. Deactivating..."); nfa_dm_rf_deactivate(NFA_DEACTIVATE_TYPE_DISCOVERY); } } } /******************************************************************************* ** ** Function nfa_rw_handle_t1t_evt ** ** Description Handler for Type-1 tag reader/writer events ** ** Returns Nothing ** *******************************************************************************/ static void nfa_rw_handle_t1t_evt(tRW_EVENT event, tRW_DATA* p_rw_data) { tNFA_CONN_EVT_DATA conn_evt_data; tNFA_TAG_PARAMS tag_params; uint8_t* p_rid_rsp; tNFA_STATUS activation_status; conn_evt_data.status = p_rw_data->data.status; switch (event) { case RW_T1T_RID_EVT: if (p_rw_data->data.p_data != nullptr) { /* Assume the data is just the response byte sequence */ p_rid_rsp = (uint8_t*)(p_rw_data->data.p_data + 1) + p_rw_data->data.p_data->offset; /* Fetch HR from RID response message */ STREAM_TO_ARRAY(tag_params.t1t.hr, p_rid_rsp, T1T_HR_LEN); /* Fetch UID0-3 from RID response message */ STREAM_TO_ARRAY(tag_params.t1t.uid, p_rid_rsp, T1T_CMD_UID_LEN); GKI_freebuf(p_rw_data->data.p_data); p_rw_data->data.p_data = nullptr; } /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); if (p_rw_data->status == NFC_STATUS_TIMEOUT) { activation_status = NFA_STATUS_TIMEOUT; } else { activation_status = NFA_STATUS_OK; } nfa_dm_notify_activation_status(activation_status, &tag_params); break; case RW_T1T_RALL_CPLT_EVT: case RW_T1T_READ_CPLT_EVT: case RW_T1T_RSEG_CPLT_EVT: case RW_T1T_READ8_CPLT_EVT: nfa_rw_send_data_to_upper(p_rw_data); /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); break; case RW_T1T_WRITE_E_CPLT_EVT: case RW_T1T_WRITE_NE_CPLT_EVT: case RW_T1T_WRITE_E8_CPLT_EVT: case RW_T1T_WRITE_NE8_CPLT_EVT: nfa_rw_send_data_to_upper(p_rw_data); /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); break; case RW_T1T_TLV_DETECT_EVT: nfa_rw_handle_tlv_detect(p_rw_data); break; case RW_T1T_NDEF_DETECT_EVT: nfa_rw_cb.tlv_st = NFA_RW_TLV_DETECT_ST_COMPLETE; if ((p_rw_data->status != NFC_STATUS_OK) && (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) && (p_rw_data->ndef.flags & NFA_RW_NDEF_FL_FORMATABLE) && (!(p_rw_data->ndef.flags & NFA_RW_NDEF_FL_FORMATED)) && (p_rw_data->ndef.flags & NFA_RW_NDEF_FL_SUPPORTED)) { /* Tag is in Initialized state, Format the tag first and then Write NDEF */ if (RW_T1tFormatNDef() == NFC_STATUS_OK) break; } nfa_rw_handle_ndef_detect(p_rw_data); break; case RW_T1T_NDEF_READ_EVT: nfa_rw_cb.tlv_st = NFA_RW_TLV_DETECT_ST_COMPLETE; if (p_rw_data->status == NFC_STATUS_OK) { /* Process the ndef record */ nfa_dm_ndef_handle_message(NFA_STATUS_OK, nfa_rw_cb.p_ndef_buf, nfa_rw_cb.ndef_cur_size); } else { /* Notify app of failure */ if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { /* If current operation is READ_NDEF, then notify ndef handlers of * failure */ nfa_dm_ndef_handle_message(NFA_STATUS_FAILED, nullptr, 0); } } /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); /* Free ndef buffer */ nfa_rw_free_ndef_rx_buf(); break; case RW_T1T_NDEF_WRITE_EVT: if (p_rw_data->data.status != NFA_STATUS_OK) nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; nfa_rw_cb.tlv_st = NFA_RW_TLV_DETECT_ST_COMPLETE; /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); /* Notify app */ conn_evt_data.status = (p_rw_data->data.status == NFC_STATUS_OK) ? NFA_STATUS_OK : NFA_STATUS_FAILED; if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { /* Update local cursize of ndef message */ nfa_rw_cb.ndef_cur_size = nfa_rw_cb.ndef_wr_len; } /* Notify app of ndef write complete status */ nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); break; case RW_T1T_SET_TAG_RO_EVT: /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_SET_TAG_RO_EVT, &conn_evt_data); break; case RW_T1T_RAW_FRAME_EVT: nfa_rw_send_data_to_upper(p_rw_data); /* Command complete - perform cleanup */ nfa_rw_command_complete(); break; case RW_T1T_PRESENCE_CHECK_EVT: /* Presence check completed */ nfa_rw_handle_presence_check_rsp(p_rw_data->status); break; case RW_T1T_FORMAT_CPLT_EVT: if (p_rw_data->data.status == NFA_STATUS_OK) nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { /* if format operation was done as part of ndef-write operation, now * start NDEF Write */ if ((p_rw_data->data.status != NFA_STATUS_OK) || ((conn_evt_data.status = RW_T1tDetectNDef()) != NFC_STATUS_OK)) { /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_FALSE; /* if format operation failed or ndef detection did not start, then * notify app of ndef-write operation failure */ conn_evt_data.status = NFA_STATUS_FAILED; nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); } } else { /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_FORMAT_CPLT_EVT, &conn_evt_data); } break; case RW_T1T_INTF_ERROR_EVT: nfa_dm_act_conn_cback_notify(NFA_RW_INTF_ERROR_EVT, &conn_evt_data); break; } } /******************************************************************************* ** ** Function nfa_rw_handle_t2t_evt ** ** Description Handler for Type-2 tag reader/writer events ** ** Returns Nothing ** *******************************************************************************/ static void nfa_rw_handle_t2t_evt(tRW_EVENT event, tRW_DATA* p_rw_data) { tNFA_CONN_EVT_DATA conn_evt_data; conn_evt_data.status = p_rw_data->status; if (p_rw_data->status == NFC_STATUS_REJECTED) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "; Waking the tag first before handling the " "response!"); /* Received NACK. Let DM wakeup the tag first (by putting tag to sleep and * then waking it up) */ p_rw_data->status = nfa_dm_disc_sleep_wakeup(); if (p_rw_data->status == NFC_STATUS_OK) { nfa_rw_cb.halt_event = event; memcpy(&nfa_rw_cb.rw_data, p_rw_data, sizeof(tRW_DATA)); return; } } switch (event) { case RW_T2T_READ_CPLT_EVT: /* Read completed */ nfa_rw_send_data_to_upper(p_rw_data); /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); break; case RW_T2T_WRITE_CPLT_EVT: /* Write completed */ /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); break; case RW_T2T_SELECT_CPLT_EVT: /* Sector select completed */ /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_SELECT_CPLT_EVT, &conn_evt_data); break; case RW_T2T_NDEF_DETECT_EVT: /* NDEF detection complete */ if ((p_rw_data->status == NFC_STATUS_OK) || ((p_rw_data->status == NFC_STATUS_FAILED) && ((p_rw_data->ndef.flags == NFA_RW_NDEF_FL_UNKNOWN) || (nfa_rw_cb.halt_event == RW_T2T_MAX_EVT))) || (nfa_rw_cb.skip_dyn_locks == true)) { /* NDEF Detection is complete */ nfa_rw_cb.skip_dyn_locks = false; nfa_rw_handle_ndef_detect(p_rw_data); } else { /* Try to detect NDEF again, this time without reading dynamic lock * bytes */ nfa_rw_cb.skip_dyn_locks = true; nfa_rw_detect_ndef(); } break; case RW_T2T_TLV_DETECT_EVT: /* Lock control/Mem/Prop tlv detection complete */ nfa_rw_handle_tlv_detect(p_rw_data); break; case RW_T2T_NDEF_READ_EVT: /* NDEF read completed */ if (p_rw_data->status == NFC_STATUS_OK) { /* Process the ndef record */ nfa_dm_ndef_handle_message(NFA_STATUS_OK, nfa_rw_cb.p_ndef_buf, nfa_rw_cb.ndef_cur_size); } else { /* Notify app of failure */ if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { /* If current operation is READ_NDEF, then notify ndef handlers of * failure */ nfa_dm_ndef_handle_message(NFA_STATUS_FAILED, nullptr, 0); } } /* Notify app of read status */ conn_evt_data.status = p_rw_data->status; nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); /* Free ndef buffer */ nfa_rw_free_ndef_rx_buf(); /* Command complete - perform cleanup */ nfa_rw_command_complete(); break; case RW_T2T_NDEF_WRITE_EVT: /* NDEF write complete */ /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); /* Notify app */ conn_evt_data.status = (p_rw_data->data.status == NFC_STATUS_OK) ? NFA_STATUS_OK : NFA_STATUS_FAILED; if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { /* Update local cursize of ndef message */ nfa_rw_cb.ndef_cur_size = nfa_rw_cb.ndef_wr_len; } /* Notify app of ndef write complete status */ nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); break; case RW_T2T_SET_TAG_RO_EVT: /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_SET_TAG_RO_EVT, &conn_evt_data); break; case RW_T2T_RAW_FRAME_EVT: nfa_rw_send_data_to_upper(p_rw_data); /* Command complete - perform cleanup */ if (p_rw_data->status != NFC_STATUS_CONTINUE) { nfa_rw_command_complete(); } break; case RW_T2T_PRESENCE_CHECK_EVT: /* Presence check completed */ nfa_rw_handle_presence_check_rsp(p_rw_data->status); break; case RW_T2T_FORMAT_CPLT_EVT: if (p_rw_data->data.status == NFA_STATUS_OK) nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_FORMAT_CPLT_EVT, &conn_evt_data); break; case RW_T2T_INTF_ERROR_EVT: nfa_dm_act_conn_cback_notify(NFA_RW_INTF_ERROR_EVT, &conn_evt_data); break; } } /******************************************************************************* ** ** Function nfa_rw_handle_t3t_evt ** ** Description Handler for Type-3 tag reader/writer events ** ** Returns Nothing ** *******************************************************************************/ static void nfa_rw_handle_t3t_evt(tRW_EVENT event, tRW_DATA* p_rw_data) { tNFA_CONN_EVT_DATA conn_evt_data; tNFA_TAG_PARAMS tag_params; switch (event) { case RW_T3T_NDEF_DETECT_EVT: /* NDEF detection complete */ nfa_rw_handle_ndef_detect(p_rw_data); break; case RW_T3T_UPDATE_CPLT_EVT: /* Write completed */ /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); /* Notify app */ conn_evt_data.status = (p_rw_data->data.status == NFC_STATUS_OK) ? NFA_STATUS_OK : NFA_STATUS_FAILED; if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { /* Update local cursize of ndef message */ nfa_rw_cb.ndef_cur_size = nfa_rw_cb.ndef_wr_len; } /* Notify app of ndef write complete status */ nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); break; case RW_T3T_CHECK_CPLT_EVT: /* Read completed */ if (p_rw_data->status == NFC_STATUS_OK) { /* Process the ndef record */ nfa_dm_ndef_handle_message(NFA_STATUS_OK, nfa_rw_cb.p_ndef_buf, nfa_rw_cb.ndef_cur_size); } else { /* Notify app of failure */ if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { /* If current operation is READ_NDEF, then notify ndef handlers of * failure */ nfa_dm_ndef_handle_message(NFA_STATUS_FAILED, nullptr, 0); } } /* Free ndef buffer */ nfa_rw_free_ndef_rx_buf(); /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); conn_evt_data.status = p_rw_data->status; nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); break; case RW_T3T_CHECK_EVT: /* Segment of data received from type 3 tag */ if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { nfa_rw_store_ndef_rx_buf(p_rw_data); } else { nfa_rw_send_data_to_upper(p_rw_data); } break; case RW_T3T_RAW_FRAME_EVT: /* SendRawFrame response */ nfa_rw_send_data_to_upper(p_rw_data); if (p_rw_data->status != NFC_STATUS_CONTINUE) { /* Command complete - perform cleanup */ nfa_rw_command_complete(); } break; case RW_T3T_PRESENCE_CHECK_EVT: /* Presence check completed */ nfa_rw_handle_presence_check_rsp(p_rw_data->status); break; case RW_T3T_GET_SYSTEM_CODES_EVT: /* Presence check completed */ /* Command complete - perform cleanup */ nfa_rw_command_complete(); /* System codes retrieved - notify app of ACTIVATION */ if (p_rw_data->status == NFC_STATUS_OK) { tag_params.t3t.num_system_codes = p_rw_data->t3t_sc.num_system_codes; tag_params.t3t.p_system_codes = p_rw_data->t3t_sc.p_system_codes; } else { tag_params.t3t.num_system_codes = 0; tag_params.t3t.p_system_codes = nullptr; } nfa_dm_notify_activation_status(NFA_STATUS_OK, &tag_params); break; case RW_T3T_FORMAT_CPLT_EVT: /* Format completed */ /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); /* Notify app */ conn_evt_data.status = (p_rw_data->data.status == NFC_STATUS_OK) ? NFA_STATUS_OK : NFA_STATUS_FAILED; /* Notify app of ndef write complete status */ nfa_dm_act_conn_cback_notify(NFA_FORMAT_CPLT_EVT, &conn_evt_data); break; case RW_T3T_INTF_ERROR_EVT: conn_evt_data.status = p_rw_data->status; nfa_dm_act_conn_cback_notify(NFA_RW_INTF_ERROR_EVT, &conn_evt_data); break; case RW_T3T_SET_READ_ONLY_CPLT_EVT: /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); conn_evt_data.status = p_rw_data->status; nfa_dm_act_conn_cback_notify(NFA_SET_TAG_RO_EVT, &conn_evt_data); break; default: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("; Unhandled RW event 0x%X", event); break; } } /******************************************************************************* ** ** Function nfa_rw_handle_t4t_evt ** ** Description Handler for Type-4 tag reader/writer events ** ** Returns Nothing ** *******************************************************************************/ static void nfa_rw_handle_t4t_evt(tRW_EVENT event, tRW_DATA* p_rw_data) { tNFA_CONN_EVT_DATA conn_evt_data; switch (event) { case RW_T4T_NDEF_DETECT_EVT: /* Result of NDEF detection procedure */ nfa_rw_handle_ndef_detect(p_rw_data); break; case RW_T4T_NDEF_FORMAT_CPLT_EVT: /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_rw_cb.cur_op = NFA_RW_OP_MAX; nfa_rw_cb.ndef_cur_size = p_rw_data->ndef.cur_size; nfa_rw_cb.ndef_max_size = p_rw_data->ndef.max_size; conn_evt_data.status = (p_rw_data->status == NFC_STATUS_OK) ? NFA_STATUS_OK : NFA_STATUS_FAILED; nfa_dm_act_conn_cback_notify(NFA_FORMAT_CPLT_EVT, &conn_evt_data); break; case RW_T4T_NDEF_READ_EVT: /* Segment of data received from type 4 tag */ if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { nfa_rw_store_ndef_rx_buf(p_rw_data); } else { nfa_rw_send_data_to_upper(p_rw_data); } break; case RW_T4T_NDEF_READ_CPLT_EVT: /* Read operation completed */ if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { nfa_rw_store_ndef_rx_buf(p_rw_data); /* Process the ndef record */ nfa_dm_ndef_handle_message(NFA_STATUS_OK, nfa_rw_cb.p_ndef_buf, nfa_rw_cb.ndef_cur_size); /* Free ndef buffer */ nfa_rw_free_ndef_rx_buf(); } else { nfa_rw_send_data_to_upper(p_rw_data); } /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_rw_cb.cur_op = NFA_RW_OP_MAX; conn_evt_data.status = NFC_STATUS_OK; nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); break; case RW_T4T_NDEF_READ_FAIL_EVT: /* Read operation failed */ if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { /* If current operation is READ_NDEF, then notify ndef handlers of * failure */ nfa_dm_ndef_handle_message(NFA_STATUS_FAILED, nullptr, 0); /* Free ndef buffer */ nfa_rw_free_ndef_rx_buf(); } /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_rw_cb.cur_op = NFA_RW_OP_MAX; conn_evt_data.status = NFA_STATUS_FAILED; nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); break; case RW_T4T_NDEF_UPDATE_CPLT_EVT: /* Update operation completed */ case RW_T4T_NDEF_UPDATE_FAIL_EVT: /* Update operation failed */ if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { /* Update local cursize of ndef message */ nfa_rw_cb.ndef_cur_size = nfa_rw_cb.ndef_wr_len; } /* Notify app */ if (event == RW_T4T_NDEF_UPDATE_CPLT_EVT) conn_evt_data.status = NFA_STATUS_OK; else conn_evt_data.status = NFA_STATUS_FAILED; /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_rw_cb.cur_op = NFA_RW_OP_MAX; nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); break; case RW_T4T_RAW_FRAME_EVT: /* Raw Frame data event */ nfa_rw_send_data_to_upper(p_rw_data); if (p_rw_data->status != NFC_STATUS_CONTINUE) { /* Command complete - perform cleanup */ nfa_rw_command_complete(); nfa_rw_cb.cur_op = NFA_RW_OP_MAX; } break; case RW_T4T_SET_TO_RO_EVT: /* Tag is set as read only */ conn_evt_data.status = p_rw_data->status; nfa_dm_act_conn_cback_notify(NFA_SET_TAG_RO_EVT, &conn_evt_data); nfa_rw_command_complete(); nfa_rw_cb.cur_op = NFA_RW_OP_MAX; break; case RW_T4T_INTF_ERROR_EVT: /* RF Interface error event */ conn_evt_data.status = p_rw_data->status; nfa_dm_act_conn_cback_notify(NFA_RW_INTF_ERROR_EVT, &conn_evt_data); nfa_rw_command_complete(); nfa_rw_cb.cur_op = NFA_RW_OP_MAX; break; case RW_T4T_PRESENCE_CHECK_EVT: /* Presence check completed */ nfa_rw_handle_presence_check_rsp(p_rw_data->status); break; default: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("; Unhandled RW event 0x%X", event); break; } } /******************************************************************************* ** ** Function nfa_rw_handle_i93_evt ** ** Description Handler for ISO 15693 tag reader/writer events ** ** Returns Nothing ** *******************************************************************************/ static void nfa_rw_handle_i93_evt(tRW_EVENT event, tRW_DATA* p_rw_data) { tNFA_CONN_EVT_DATA conn_evt_data; tNFA_TAG_PARAMS i93_params; switch (event) { case RW_I93_NDEF_DETECT_EVT: /* Result of NDEF detection procedure */ nfa_rw_handle_ndef_detect(p_rw_data); break; case RW_I93_NDEF_READ_EVT: /* Segment of data received from type 4 tag */ if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { nfa_rw_store_ndef_rx_buf(p_rw_data); } else { nfa_rw_send_data_to_upper(p_rw_data); } break; case RW_I93_NDEF_READ_CPLT_EVT: /* Read operation completed */ if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { nfa_rw_store_ndef_rx_buf(p_rw_data); /* Process the ndef record */ nfa_dm_ndef_handle_message(NFA_STATUS_OK, nfa_rw_cb.p_ndef_buf, nfa_rw_cb.ndef_cur_size); /* Free ndef buffer */ nfa_rw_free_ndef_rx_buf(); } else { nfa_rw_send_data_to_upper(p_rw_data); } /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ conn_evt_data.status = NFC_STATUS_OK; nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); break; case RW_I93_NDEF_READ_FAIL_EVT: /* Read operation failed */ if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { /* If current operation is READ_NDEF, then notify ndef handlers of * failure */ nfa_dm_ndef_handle_message(NFA_STATUS_FAILED, nullptr, 0); /* Free ndef buffer */ nfa_rw_free_ndef_rx_buf(); } /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ conn_evt_data.status = NFA_STATUS_FAILED; nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); break; case RW_I93_NDEF_UPDATE_CPLT_EVT: /* Update operation completed */ case RW_I93_NDEF_UPDATE_FAIL_EVT: /* Update operation failed */ if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { /* Update local cursize of ndef message */ nfa_rw_cb.ndef_cur_size = nfa_rw_cb.ndef_wr_len; } /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ if (event == RW_I93_NDEF_UPDATE_CPLT_EVT) conn_evt_data.status = NFA_STATUS_OK; else conn_evt_data.status = NFA_STATUS_FAILED; /* Notify app of ndef write complete status */ nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); break; case RW_I93_RAW_FRAME_EVT: /* Raw Frame data event */ nfa_rw_send_data_to_upper(p_rw_data); if (p_rw_data->status != NFC_STATUS_CONTINUE) { /* Command complete - perform cleanup */ nfa_rw_command_complete(); } break; case RW_I93_INTF_ERROR_EVT: /* RF Interface error event */ /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); if (nfa_rw_cb.flags & NFA_RW_FL_ACTIVATION_NTF_PENDING) { nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING; memset(&i93_params, 0x00, sizeof(tNFA_TAG_PARAMS)); memcpy(i93_params.i93.uid, nfa_rw_cb.i93_uid, I93_UID_BYTE_LEN); nfa_dm_notify_activation_status(NFA_STATUS_OK, &i93_params); } else { conn_evt_data.status = p_rw_data->status; nfa_dm_act_conn_cback_notify(NFA_RW_INTF_ERROR_EVT, &conn_evt_data); } nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ break; case RW_I93_PRESENCE_CHECK_EVT: /* Presence check completed */ nfa_rw_handle_presence_check_rsp(p_rw_data->status); break; case RW_I93_FORMAT_CPLT_EVT: /* Format procedure complete */ if (p_rw_data->data.status == NFA_STATUS_OK) nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ conn_evt_data.status = p_rw_data->status; nfa_dm_act_conn_cback_notify(NFA_FORMAT_CPLT_EVT, &conn_evt_data); break; case RW_I93_SET_TAG_RO_EVT: /* Set read-only procedure complete */ nfa_rw_cb.flags |= NFA_RW_FL_TAG_IS_READONLY; /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ conn_evt_data.status = p_rw_data->status; nfa_dm_act_conn_cback_notify(NFA_SET_TAG_RO_EVT, &conn_evt_data); break; case RW_I93_INVENTORY_EVT: /* Response of Inventory */ /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); conn_evt_data.i93_cmd_cplt.status = p_rw_data->i93_inventory.status; conn_evt_data.i93_cmd_cplt.sent_command = I93_CMD_INVENTORY; conn_evt_data.i93_cmd_cplt.params.inventory.dsfid = p_rw_data->i93_inventory.dsfid; memcpy(conn_evt_data.i93_cmd_cplt.params.inventory.uid, p_rw_data->i93_inventory.uid, I93_UID_BYTE_LEN); nfa_dm_act_conn_cback_notify(NFA_I93_CMD_CPLT_EVT, &conn_evt_data); nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ break; case RW_I93_DATA_EVT: /* Response of Read, Get Multi Security */ /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); conn_evt_data.data.p_data = (uint8_t*)(p_rw_data->i93_data.p_data + 1) + p_rw_data->i93_data.p_data->offset; if (nfa_rw_cb.flags & NFA_RW_FL_ACTIVATION_NTF_PENDING) { nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING; i93_params.i93.info_flags = (I93_INFO_FLAG_DSFID | I93_INFO_FLAG_MEM_SIZE | I93_INFO_FLAG_AFI); i93_params.i93.afi = *(conn_evt_data.data.p_data + nfa_rw_cb.i93_afi_location % nfa_rw_cb.i93_block_size); i93_params.i93.dsfid = nfa_rw_cb.i93_dsfid; i93_params.i93.block_size = nfa_rw_cb.i93_block_size; i93_params.i93.num_block = nfa_rw_cb.i93_num_block; memcpy(i93_params.i93.uid, nfa_rw_cb.i93_uid, I93_UID_BYTE_LEN); nfa_dm_notify_activation_status(NFA_STATUS_OK, &i93_params); } else { conn_evt_data.data.len = p_rw_data->i93_data.p_data->len; nfa_dm_act_conn_cback_notify(NFA_DATA_EVT, &conn_evt_data); } GKI_freebuf(p_rw_data->i93_data.p_data); p_rw_data->i93_data.p_data = nullptr; nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ break; case RW_I93_SYS_INFO_EVT: /* Response of System Information */ /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); if (nfa_rw_cb.flags & NFA_RW_FL_ACTIVATION_NTF_PENDING) { nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING; nfa_rw_cb.i93_block_size = p_rw_data->i93_sys_info.block_size; nfa_rw_cb.i93_num_block = p_rw_data->i93_sys_info.num_block; i93_params.i93.info_flags = p_rw_data->i93_sys_info.info_flags; i93_params.i93.dsfid = p_rw_data->i93_sys_info.dsfid; i93_params.i93.afi = p_rw_data->i93_sys_info.afi; i93_params.i93.num_block = p_rw_data->i93_sys_info.num_block; i93_params.i93.block_size = p_rw_data->i93_sys_info.block_size; i93_params.i93.IC_reference = p_rw_data->i93_sys_info.IC_reference; memcpy(i93_params.i93.uid, p_rw_data->i93_sys_info.uid, I93_UID_BYTE_LEN); nfa_dm_notify_activation_status(NFA_STATUS_OK, &i93_params); } else { conn_evt_data.i93_cmd_cplt.status = p_rw_data->i93_sys_info.status; conn_evt_data.i93_cmd_cplt.sent_command = I93_CMD_GET_SYS_INFO; conn_evt_data.i93_cmd_cplt.params.sys_info.info_flags = p_rw_data->i93_sys_info.info_flags; memcpy(conn_evt_data.i93_cmd_cplt.params.sys_info.uid, p_rw_data->i93_sys_info.uid, I93_UID_BYTE_LEN); conn_evt_data.i93_cmd_cplt.params.sys_info.dsfid = p_rw_data->i93_sys_info.dsfid; conn_evt_data.i93_cmd_cplt.params.sys_info.afi = p_rw_data->i93_sys_info.afi; conn_evt_data.i93_cmd_cplt.params.sys_info.num_block = p_rw_data->i93_sys_info.num_block; conn_evt_data.i93_cmd_cplt.params.sys_info.block_size = p_rw_data->i93_sys_info.block_size; conn_evt_data.i93_cmd_cplt.params.sys_info.IC_reference = p_rw_data->i93_sys_info.IC_reference; /* store tag memory information for writing blocks */ nfa_rw_cb.i93_block_size = p_rw_data->i93_sys_info.block_size; nfa_rw_cb.i93_num_block = p_rw_data->i93_sys_info.num_block; nfa_dm_act_conn_cback_notify(NFA_I93_CMD_CPLT_EVT, &conn_evt_data); } nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ break; case RW_I93_CMD_CMPL_EVT: /* Command complete */ /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); if (nfa_rw_cb.flags & NFA_RW_FL_ACTIVATION_NTF_PENDING) { /* Reader got error code from tag */ nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING; memset(&i93_params, 0x00, sizeof(i93_params)); memcpy(i93_params.i93.uid, nfa_rw_cb.i93_uid, I93_UID_BYTE_LEN); nfa_dm_notify_activation_status(NFA_STATUS_OK, &i93_params); } else { conn_evt_data.i93_cmd_cplt.status = p_rw_data->i93_cmd_cmpl.status; conn_evt_data.i93_cmd_cplt.sent_command = p_rw_data->i93_cmd_cmpl.command; if (conn_evt_data.i93_cmd_cplt.status != NFC_STATUS_OK) conn_evt_data.i93_cmd_cplt.params.error_code = p_rw_data->i93_cmd_cmpl.error_code; nfa_dm_act_conn_cback_notify(NFA_I93_CMD_CPLT_EVT, &conn_evt_data); } nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ break; default: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("; Unhandled RW event 0x%X", event); break; } } /******************************************************************************* ** ** Function nfa_rw_handle_mfc_evt ** ** Description Handler for Mifare Classic tag reader/writer events ** ** Returns Nothing ** *******************************************************************************/ static void nfa_rw_handle_mfc_evt(tRW_EVENT event, tRW_DATA* p_rw_data) { tNFA_CONN_EVT_DATA conn_evt_data; conn_evt_data.status = p_rw_data->status; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("nfa_rw_handle_mfc_evt() event = 0x%X", event); switch (event) { /* Read completed */ case RW_MFC_NDEF_READ_CPLT_EVT: nfa_rw_send_data_to_upper(p_rw_data); /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); break; /* NDEF detection complete */ case RW_MFC_NDEF_DETECT_EVT: nfa_rw_handle_ndef_detect(p_rw_data); break; /* NDEF read completed */ case RW_MFC_NDEF_READ_EVT: if (p_rw_data->status == NFC_STATUS_OK) { /* Process the ndef record */ nfa_dm_ndef_handle_message(NFA_STATUS_OK, nfa_rw_cb.p_ndef_buf, nfa_rw_cb.ndef_cur_size); } else { /* Notify app of failure */ if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { /* If current operation is READ_NDEF, then notify ndef handlers of * failure */ nfa_dm_ndef_handle_message(NFA_STATUS_FAILED, NULL, 0); } } /* Notify app of read status */ conn_evt_data.status = p_rw_data->status; nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); /* Free ndef buffer */ nfa_rw_free_ndef_rx_buf(); /* Command complete - perform cleanup */ nfa_rw_command_complete(); break; /* Raw Frame data event */ case RW_MFC_RAW_FRAME_EVT: nfa_rw_send_data_to_upper(p_rw_data); if (p_rw_data->status != NFC_STATUS_CONTINUE) { /* Command complete - perform cleanup */ nfa_rw_command_complete(); nfa_rw_cb.cur_op = NFA_RW_OP_MAX; } break; /* RF Interface error event */ case RW_MFC_INTF_ERROR_EVT: nfa_dm_act_conn_cback_notify(NFA_RW_INTF_ERROR_EVT, &conn_evt_data); break; case RW_MFC_NDEF_FORMAT_CPLT_EVT: /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_FORMAT_CPLT_EVT, &conn_evt_data); break; /* NDEF write completed or failed*/ case RW_MFC_NDEF_WRITE_CPLT_EVT: case RW_MFC_NDEF_WRITE_FAIL_EVT: /* Command complete - perform cleanup, notify the app */ nfa_rw_command_complete(); nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); break; default: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("; Unhandled RW event 0x%X", event); } } /******************************************************************************* ** ** Function nfa_rw_cback ** ** Description Callback for reader/writer event notification ** ** Returns Nothing ** *******************************************************************************/ static void nfa_rw_cback(tRW_EVENT event, tRW_DATA* p_rw_data) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("nfa_rw_cback: event=0x%02x", event); /* Call appropriate event handler for tag type */ if (event < RW_T1T_MAX_EVT) { /* Handle Type-1 tag events */ nfa_rw_handle_t1t_evt(event, p_rw_data); } else if (event < RW_T2T_MAX_EVT) { /* Handle Type-2 tag events */ nfa_rw_handle_t2t_evt(event, p_rw_data); } else if (event < RW_T3T_MAX_EVT) { /* Handle Type-3 tag events */ nfa_rw_handle_t3t_evt(event, p_rw_data); } else if (event < RW_T4T_MAX_EVT) { /* Handle Type-4 tag events */ nfa_rw_handle_t4t_evt(event, p_rw_data); } else if (event < RW_I93_MAX_EVT) { /* Handle ISO 15693 tag events */ nfa_rw_handle_i93_evt(event, p_rw_data); } else if (event < RW_MFC_MAX_EVT) { /* Handle Mifare Classic tag events */ nfa_rw_handle_mfc_evt(event, p_rw_data); } else { LOG(ERROR) << StringPrintf("nfa_rw_cback: unhandled event=0x%02x", event); } } /******************************************************************************* ** ** Function nfa_rw_start_ndef_detection ** ** Description Start NDEF detection on activated tag ** ** Returns Nothing ** *******************************************************************************/ static tNFC_STATUS nfa_rw_start_ndef_detection(void) { tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; tNFC_STATUS status = NFC_STATUS_FAILED; if (NFC_PROTOCOL_T1T == protocol) { /* Type1Tag - NFC-A */ status = RW_T1tDetectNDef(); } else if (NFC_PROTOCOL_T2T == protocol) { /* Type2Tag - NFC-A */ if (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T) { status = RW_T2tDetectNDef(nfa_rw_cb.skip_dyn_locks); } } else if (NFC_PROTOCOL_T3T == protocol) { /* Type3Tag - NFC-F */ status = RW_T3tDetectNDef(); } else if (NFC_PROTOCOL_ISO_DEP == protocol) { /* ISODEP/4A,4B- NFC-A or NFC-B */ status = RW_T4tDetectNDef(); } else if (NFC_PROTOCOL_T5T == protocol) { /* ISO 15693 */ status = RW_I93DetectNDef(); } else if (NFC_PROTOCOL_MIFARE == protocol) { status = RW_MfcDetectNDef(); } return (status); } /******************************************************************************* ** ** Function nfa_rw_start_ndef_read ** ** Description Start NDEF read on activated tag ** ** Returns Nothing ** *******************************************************************************/ static tNFC_STATUS nfa_rw_start_ndef_read(void) { tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; tNFC_STATUS status = NFC_STATUS_FAILED; tNFA_CONN_EVT_DATA conn_evt_data; /* Handle zero length NDEF message */ if (nfa_rw_cb.ndef_cur_size == 0) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("NDEF message is zero-length"); /* Send zero-lengh NDEF message to ndef callback */ nfa_dm_ndef_handle_message(NFA_STATUS_OK, nullptr, 0); /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); conn_evt_data.status = NFA_STATUS_OK; nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); return NFC_STATUS_OK; } /* Allocate buffer for incoming NDEF message (free previous NDEF rx buffer, if * needed) */ nfa_rw_free_ndef_rx_buf(); nfa_rw_cb.p_ndef_buf = (uint8_t*)nfa_mem_co_alloc(nfa_rw_cb.ndef_cur_size); if (nfa_rw_cb.p_ndef_buf == nullptr) { LOG(ERROR) << StringPrintf( "Unable to allocate a buffer for reading NDEF (size=%i)", nfa_rw_cb.ndef_cur_size); /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); conn_evt_data.status = NFA_STATUS_FAILED; nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); return NFC_STATUS_FAILED; } nfa_rw_cb.ndef_rd_offset = 0; if (NFC_PROTOCOL_T1T == protocol) { /* Type1Tag - NFC-A */ status = RW_T1tReadNDef(nfa_rw_cb.p_ndef_buf, (uint16_t)nfa_rw_cb.ndef_cur_size); } else if (NFC_PROTOCOL_T2T == protocol) { /* Type2Tag - NFC-A */ if (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T) { status = RW_T2tReadNDef(nfa_rw_cb.p_ndef_buf, (uint16_t)nfa_rw_cb.ndef_cur_size); } } else if (NFC_PROTOCOL_T3T == protocol) { /* Type3Tag - NFC-F */ status = RW_T3tCheckNDef(); } else if (NFC_PROTOCOL_ISO_DEP == protocol) { /* ISODEP/4A,4B- NFC-A or NFC-B */ status = RW_T4tReadNDef(); } else if (NFC_PROTOCOL_T5T == protocol) { /* ISO 15693 */ status = RW_I93ReadNDef(); } else if (NFC_PROTOCOL_MIFARE == protocol) { /* Mifare Classic*/ status = RW_MfcReadNDef(nfa_rw_cb.p_ndef_buf, (uint16_t)nfa_rw_cb.ndef_cur_size); } return (status); } /******************************************************************************* ** ** Function nfa_rw_detect_ndef ** ** Description Handler for NFA_RW_API_DETECT_NDEF_EVT ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_detect_ndef() { tNFA_CONN_EVT_DATA conn_evt_data; DLOG_IF(INFO, nfc_debug_enabled) << __func__; conn_evt_data.ndef_detect.status = nfa_rw_start_ndef_detection(); if (conn_evt_data.ndef_detect.status != NFC_STATUS_OK) { /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); conn_evt_data.ndef_detect.cur_size = 0; conn_evt_data.ndef_detect.max_size = 0; conn_evt_data.ndef_detect.flags = RW_NDEF_FL_UNKNOWN; nfa_dm_act_conn_cback_notify(NFA_NDEF_DETECT_EVT, &conn_evt_data); } return true; } /******************************************************************************* ** ** Function nfa_rw_start_ndef_write ** ** Description Start NDEF write on activated tag ** ** Returns Nothing ** *******************************************************************************/ static tNFC_STATUS nfa_rw_start_ndef_write(void) { tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; tNFC_STATUS status = NFC_STATUS_FAILED; if (nfa_rw_cb.flags & NFA_RW_FL_TAG_IS_READONLY) { /* error: ndef tag is read-only */ status = NFC_STATUS_FAILED; LOG(ERROR) << StringPrintf("Unable to write NDEF. Tag is read-only"); } else if (nfa_rw_cb.ndef_max_size < nfa_rw_cb.ndef_wr_len) { /* error: ndef tag size is too small */ status = NFC_STATUS_BUFFER_FULL; LOG(ERROR) << StringPrintf( "Unable to write NDEF. Tag maxsize=%i, request write size=%i", nfa_rw_cb.ndef_max_size, nfa_rw_cb.ndef_wr_len); } else { if (NFC_PROTOCOL_T1T == protocol) { /* Type1Tag - NFC-A */ status = RW_T1tWriteNDef((uint16_t)nfa_rw_cb.ndef_wr_len, nfa_rw_cb.p_ndef_wr_buf); } else if (NFC_PROTOCOL_T2T == protocol) { /* Type2Tag - NFC-A */ if (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T) { status = RW_T2tWriteNDef((uint16_t)nfa_rw_cb.ndef_wr_len, nfa_rw_cb.p_ndef_wr_buf); } } else if (NFC_PROTOCOL_T3T == protocol) { /* Type3Tag - NFC-F */ status = RW_T3tUpdateNDef(nfa_rw_cb.ndef_wr_len, nfa_rw_cb.p_ndef_wr_buf); } else if (NFC_PROTOCOL_ISO_DEP == protocol) { /* ISODEP/4A,4B- NFC-A or NFC-B */ status = RW_T4tUpdateNDef((uint16_t)nfa_rw_cb.ndef_wr_len, nfa_rw_cb.p_ndef_wr_buf); } else if (NFC_PROTOCOL_T5T == protocol) { /* ISO 15693 */ status = RW_I93UpdateNDef((uint16_t)nfa_rw_cb.ndef_wr_len, nfa_rw_cb.p_ndef_wr_buf); } else if (NFC_PROTOCOL_MIFARE == protocol) { /* Mifare Tag */ status = RW_MfcWriteNDef((uint16_t)nfa_rw_cb.ndef_wr_len, nfa_rw_cb.p_ndef_wr_buf); } } return (status); } /******************************************************************************* ** ** Function nfa_rw_read_ndef ** ** Description Handler for NFA_RW_API_READ_NDEF_EVT ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_read_ndef() { tNFA_STATUS status = NFA_STATUS_OK; tNFA_CONN_EVT_DATA conn_evt_data; DLOG_IF(INFO, nfc_debug_enabled) << __func__; /* Check if ndef detection has been performed yet */ if (nfa_rw_cb.ndef_st == NFA_RW_NDEF_ST_UNKNOWN) { /* Perform ndef detection first */ status = nfa_rw_start_ndef_detection(); } else if (nfa_rw_cb.ndef_st == NFA_RW_NDEF_ST_FALSE) { /* Tag is not NDEF */ status = NFA_STATUS_FAILED; } else { /* Perform the NDEF read operation */ status = nfa_rw_start_ndef_read(); } /* Handle failure */ if (status != NFA_STATUS_OK) { /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); conn_evt_data.status = status; nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); } return true; } /******************************************************************************* ** ** Function nfa_rw_write_ndef ** ** Description Handler for NFA_RW_API_WRITE_NDEF_EVT ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_write_ndef(tNFA_RW_MSG* p_data) { tNDEF_STATUS ndef_status; tNFA_STATUS write_status = NFA_STATUS_OK; tNFA_CONN_EVT_DATA conn_evt_data; DLOG_IF(INFO, nfc_debug_enabled) << __func__; /* Validate NDEF message */ ndef_status = NDEF_MsgValidate(p_data->op_req.params.write_ndef.p_data, p_data->op_req.params.write_ndef.len, false); if (ndef_status != NDEF_OK) { LOG(ERROR) << StringPrintf( "Invalid NDEF message. NDEF_MsgValidate returned %i", ndef_status); /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); conn_evt_data.status = NFA_STATUS_FAILED; nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); return true; } /* Store pointer to source NDEF */ nfa_rw_cb.p_ndef_wr_buf = p_data->op_req.params.write_ndef.p_data; nfa_rw_cb.ndef_wr_len = p_data->op_req.params.write_ndef.len; /* Check if ndef detection has been performed yet */ if (nfa_rw_cb.ndef_st == NFA_RW_NDEF_ST_UNKNOWN) { /* Perform ndef detection first */ write_status = nfa_rw_start_ndef_detection(); } else if (nfa_rw_cb.ndef_st == NFA_RW_NDEF_ST_FALSE) { if (nfa_rw_cb.protocol == NFC_PROTOCOL_T1T) { /* For Type 1 tag, NDEF can be written on Initialized tag * Perform ndef detection first to check if tag is in Initialized state to * Write NDEF */ write_status = nfa_rw_start_ndef_detection(); } else { /* Tag is not NDEF */ write_status = NFA_STATUS_FAILED; } } else { /* Perform the NDEF read operation */ write_status = nfa_rw_start_ndef_write(); } /* Handle failure */ if (write_status != NFA_STATUS_OK) { /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); conn_evt_data.status = write_status; nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); } return true; } /******************************************************************************* ** ** Function nfa_rw_presence_check ** ** Description Handler for NFA_RW_API_PRESENCE_CHECK ** ** Returns Nothing ** *******************************************************************************/ void nfa_rw_presence_check(tNFA_RW_MSG* p_data) { tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; uint8_t sel_res = nfa_rw_cb.pa_sel_res; tNFC_STATUS status = NFC_STATUS_FAILED; bool unsupported = false; uint8_t option = NFA_RW_OPTION_INVALID; tNFA_RW_PRES_CHK_OPTION op_param = NFA_RW_PRES_CHK_DEFAULT; if (NFC_PROTOCOL_T1T == protocol) { /* Type1Tag - NFC-A */ status = RW_T1tPresenceCheck(); } else if (NFC_PROTOCOL_T2T == protocol) { /* If T2T NFC-Forum, then let RW handle presence check */ if (sel_res == NFC_SEL_RES_NFC_FORUM_T2T) { /* Type 2 tag have not sent NACK after activation */ status = RW_T2tPresenceCheck(); } else { /* Will fall back to deactivate/reactivate */ unsupported = true; } } else if (NFC_PROTOCOL_T3T == protocol) { /* Type3Tag - NFC-F */ status = RW_T3tPresenceCheck(); } else if (NFC_PROTOCOL_ISO_DEP == protocol) { /* ISODEP/4A,4B- NFC-A or NFC-B */ if (p_data) { op_param = p_data->op_req.params.option; } switch (op_param) { case NFA_RW_PRES_CHK_I_BLOCK: option = RW_T4T_CHK_EMPTY_I_BLOCK; break; case NFA_RW_PRES_CHK_ISO_DEP_NAK: if (NFC_GetNCIVersion() == NCI_VERSION_2_0) { option = RW_T4T_CHK_ISO_DEP_NAK_PRES_CHK; } break; default: /* empty I block */ option = RW_T4T_CHK_EMPTY_I_BLOCK; } if (option != NFA_RW_OPTION_INVALID) { /* use the presence check with the chosen option */ status = RW_T4tPresenceCheck(option); } else { /* use sleep/wake for presence check */ unsupported = true; } } else if (NFC_PROTOCOL_T5T == protocol) { /* T5T/ISO 15693 */ status = RW_I93PresenceCheck(); } else { /* Protocol unsupported by RW module... */ unsupported = true; } if (unsupported) { if (nfa_rw_cb.activated_tech_mode == NFC_DISCOVERY_TYPE_POLL_KOVIO) { /* start Kovio presence check (deactivate and wait for activation) */ status = nfa_dm_disc_start_kovio_presence_check(); } else { /* Let DM perform presence check (by putting tag to sleep and then waking * it up) */ status = nfa_dm_disc_sleep_wakeup(); } } /* Handle presence check failure */ if (status != NFC_STATUS_OK) nfa_rw_handle_presence_check_rsp(NFC_STATUS_FAILED); else if (!unsupported) { nfa_sys_start_timer(&nfa_rw_cb.tle, NFA_RW_PRESENCE_CHECK_TIMEOUT_EVT, p_nfa_dm_cfg->presence_check_timeout); } } /******************************************************************************* ** ** Function nfa_rw_presence_check_tick ** ** Description Called on expiration of NFA_RW_PRESENCE_CHECK_INTERVAL ** Initiate presence check ** ** Returns TRUE (caller frees message buffer) ** *******************************************************************************/ bool nfa_rw_presence_check_tick(__attribute__((unused)) tNFA_RW_MSG* p_data) { /* Store the current operation */ nfa_rw_cb.cur_op = NFA_RW_OP_PRESENCE_CHECK; nfa_rw_cb.flags |= NFA_RW_FL_AUTO_PRESENCE_CHECK_BUSY; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("Auto-presence check starting..."); /* Perform presence check */ nfa_rw_presence_check(nullptr); return true; } /******************************************************************************* ** ** Function nfa_rw_presence_check_timeout ** ** Description presence check timeout: report presence check failure ** ** Returns TRUE (caller frees message buffer) ** *******************************************************************************/ bool nfa_rw_presence_check_timeout(__attribute__((unused)) tNFA_RW_MSG* p_data) { nfa_rw_handle_presence_check_rsp(NFC_STATUS_FAILED); return true; } /******************************************************************************* ** ** Function nfa_rw_format_tag ** ** Description Handler for NFA_RW_API_FORMAT_TAG ** ** Returns Nothing ** *******************************************************************************/ static void nfa_rw_format_tag() { tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; tNFC_STATUS status = NFC_STATUS_FAILED; if (protocol == NFC_PROTOCOL_T1T) { status = RW_T1tFormatNDef(); } else if ((protocol == NFC_PROTOCOL_T2T) && (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T)) { status = RW_T2tFormatNDef(); } else if (protocol == NFC_PROTOCOL_T3T) { status = RW_T3tFormatNDef(); } else if (protocol == NFC_PROTOCOL_T5T) { status = RW_I93FormatNDef(); } else if (protocol == NFC_PROTOCOL_ISO_DEP) { status = RW_T4tFormatNDef(); } else if (protocol == NFC_PROTOCOL_MIFARE) { status = RW_MfcFormatNDef(); } /* If unable to format NDEF, notify the app */ if (status != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_FORMAT_CPLT_EVT); } /******************************************************************************* ** ** Function nfa_rw_detect_tlv ** ** Description Handler for NFA_RW_API_DETECT_NDEF_EVT ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_detect_tlv(uint8_t tlv) { DLOG_IF(INFO, nfc_debug_enabled) << __func__; switch (nfa_rw_cb.protocol) { case NFC_PROTOCOL_T1T: if (RW_T1tLocateTlv(tlv) != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_TLV_DETECT_EVT); break; case NFC_PROTOCOL_T2T: if (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T) { if (RW_T2tLocateTlv(tlv) != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_TLV_DETECT_EVT); } break; default: break; } return true; } /******************************************************************************* ** ** Function nfa_rw_config_tag_ro ** ** Description Handler for NFA_RW_OP_SET_TAG_RO ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static tNFC_STATUS nfa_rw_config_tag_ro(bool b_hard_lock) { tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; tNFC_STATUS status = NFC_STATUS_FAILED; DLOG_IF(INFO, nfc_debug_enabled) << __func__; if (NFC_PROTOCOL_T1T == protocol) { /* Type1Tag - NFC-A */ if ((nfa_rw_cb.tlv_st == NFA_RW_TLV_DETECT_ST_OP_NOT_STARTED) || (nfa_rw_cb.tlv_st == NFA_RW_TLV_DETECT_ST_MEM_TLV_OP_COMPLETE)) { status = RW_T1tLocateTlv(TAG_LOCK_CTRL_TLV); return (status); } else { status = RW_T1tSetTagReadOnly(b_hard_lock); } } else if (NFC_PROTOCOL_T2T == protocol) { /* Type2Tag - NFC-A */ if (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T) { status = RW_T2tSetTagReadOnly(b_hard_lock); } } else if (NFC_PROTOCOL_T3T == protocol) { /* Type3Tag - NFC-F */ status = RW_T3tSetReadOnly(b_hard_lock); } else if (NFC_PROTOCOL_ISO_DEP == protocol) { /* ISODEP/4A,4B- NFC-A or NFC-B */ status = RW_T4tSetNDefReadOnly(); } else if (NFC_PROTOCOL_T5T == protocol) { /* ISO 15693 */ status = RW_I93SetTagReadOnly(); } if (status == NFC_STATUS_OK) { nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; } else { nfa_rw_error_cleanup(NFA_SET_TAG_RO_EVT); } return (status); } /******************************************************************************* ** ** Function nfa_rw_t1t_rid ** ** Description Handler for T1T_RID API ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_t1t_rid() { if (RW_T1tRid() != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_READ_CPLT_EVT); return true; } /******************************************************************************* ** ** Function nfa_rw_t1t_rall ** ** Description Handler for T1T_ReadAll API ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_t1t_rall() { if (RW_T1tReadAll() != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_READ_CPLT_EVT); return true; } /******************************************************************************* ** ** Function nfa_rw_t1t_read ** ** Description Handler for T1T_Read API ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_t1t_read(tNFA_RW_MSG* p_data) { tNFA_RW_OP_PARAMS_T1T_READ* p_t1t_read = (tNFA_RW_OP_PARAMS_T1T_READ*)&(p_data->op_req.params.t1t_read); if (RW_T1tRead(p_t1t_read->block_number, p_t1t_read->index) != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_READ_CPLT_EVT); return true; } /******************************************************************************* ** ** Function nfa_rw_t1t_write ** ** Description Handler for T1T_WriteErase/T1T_WriteNoErase API ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_t1t_write(tNFA_RW_MSG* p_data) { tNFA_RW_OP_PARAMS_T1T_WRITE* p_t1t_write = (tNFA_RW_OP_PARAMS_T1T_WRITE*)&(p_data->op_req.params.t1t_write); tNFC_STATUS status; if (p_t1t_write->b_erase) { status = RW_T1tWriteErase(p_t1t_write->block_number, p_t1t_write->index, p_t1t_write->p_block_data[0]); } else { status = RW_T1tWriteNoErase(p_t1t_write->block_number, p_t1t_write->index, p_t1t_write->p_block_data[0]); } if (status != NFC_STATUS_OK) { nfa_rw_error_cleanup(NFA_WRITE_CPLT_EVT); } else { if (p_t1t_write->block_number == 0x01) nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; } return true; } /******************************************************************************* ** ** Function nfa_rw_t1t_rseg ** ** Description Handler for T1t_ReadSeg API ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_t1t_rseg(tNFA_RW_MSG* p_data) { tNFA_RW_OP_PARAMS_T1T_READ* p_t1t_read = (tNFA_RW_OP_PARAMS_T1T_READ*)&(p_data->op_req.params.t1t_read); if (RW_T1tReadSeg(p_t1t_read->segment_number) != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_READ_CPLT_EVT); return true; } /******************************************************************************* ** ** Function nfa_rw_t1t_read8 ** ** Description Handler for T1T_Read8 API ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_t1t_read8(tNFA_RW_MSG* p_data) { tNFA_RW_OP_PARAMS_T1T_READ* p_t1t_read = (tNFA_RW_OP_PARAMS_T1T_READ*)&(p_data->op_req.params.t1t_read); if (RW_T1tRead8(p_t1t_read->block_number) != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_READ_CPLT_EVT); return true; } /******************************************************************************* ** ** Function nfa_rw_t1t_write8 ** ** Description Handler for T1T_WriteErase8/T1T_WriteNoErase8 API ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_t1t_write8(tNFA_RW_MSG* p_data) { tNFA_RW_OP_PARAMS_T1T_WRITE* p_t1t_write = (tNFA_RW_OP_PARAMS_T1T_WRITE*)&(p_data->op_req.params.t1t_write); tNFC_STATUS status; if (p_t1t_write->b_erase) { status = RW_T1tWriteErase8(p_t1t_write->block_number, p_t1t_write->p_block_data); } else { status = RW_T1tWriteNoErase8(p_t1t_write->block_number, p_t1t_write->p_block_data); } if (status != NFC_STATUS_OK) { nfa_rw_error_cleanup(NFA_WRITE_CPLT_EVT); } else { if (p_t1t_write->block_number == 0x01) nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; } return true; } /******************************************************************************* ** ** Function nfa_rw_t2t_read ** ** Description Handler for T2T_Read API ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_t2t_read(tNFA_RW_MSG* p_data) { tNFA_RW_OP_PARAMS_T2T_READ* p_t2t_read = (tNFA_RW_OP_PARAMS_T2T_READ*)&(p_data->op_req.params.t2t_read); tNFC_STATUS status = NFC_STATUS_FAILED; if (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T) status = RW_T2tRead(p_t2t_read->block_number); if (status != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_READ_CPLT_EVT); return true; } /******************************************************************************* ** ** Function nfa_rw_t2t_write ** ** Description Handler for T2T_Write API ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_t2t_write(tNFA_RW_MSG* p_data) { tNFA_RW_OP_PARAMS_T2T_WRITE* p_t2t_write = (tNFA_RW_OP_PARAMS_T2T_WRITE*)&(p_data->op_req.params.t2t_write); if (RW_T2tWrite(p_t2t_write->block_number, p_t2t_write->p_block_data) != NFC_STATUS_OK) { nfa_rw_error_cleanup(NFA_WRITE_CPLT_EVT); } else { if (p_t2t_write->block_number == 0x03) nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; } return true; } /******************************************************************************* ** ** Function nfa_rw_t2t_sector_select ** ** Description Handler for T2T_Sector_Select API ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_t2t_sector_select(tNFA_RW_MSG* p_data) { tNFA_RW_OP_PARAMS_T2T_SECTOR_SELECT* p_t2t_sector_select = (tNFA_RW_OP_PARAMS_T2T_SECTOR_SELECT*)&( p_data->op_req.params.t2t_sector_select); if (RW_T2tSectorSelect(p_t2t_sector_select->sector_number) != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_SELECT_CPLT_EVT); return true; } /******************************************************************************* ** ** Function nfa_rw_t3t_read ** ** Description Handler for T3T_Read API ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_t3t_read(tNFA_RW_MSG* p_data) { tNFA_RW_OP_PARAMS_T3T_READ* p_t3t_read = (tNFA_RW_OP_PARAMS_T3T_READ*)&(p_data->op_req.params.t3t_read); if (RW_T3tCheck(p_t3t_read->num_blocks, (tT3T_BLOCK_DESC*)p_t3t_read->p_block_desc) != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_READ_CPLT_EVT); return true; } /******************************************************************************* ** ** Function nfa_rw_t3t_write ** ** Description Handler for T3T_Write API ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_t3t_write(tNFA_RW_MSG* p_data) { tNFA_RW_OP_PARAMS_T3T_WRITE* p_t3t_write = (tNFA_RW_OP_PARAMS_T3T_WRITE*)&(p_data->op_req.params.t3t_write); if (RW_T3tUpdate(p_t3t_write->num_blocks, (tT3T_BLOCK_DESC*)p_t3t_write->p_block_desc, p_t3t_write->p_block_data) != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_WRITE_CPLT_EVT); return true; } /******************************************************************************* ** ** Function nfa_rw_t3t_get_system_codes ** ** Description Get system codes (initiated by NFA after activation) ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_t3t_get_system_codes() { tNFC_STATUS status; tNFA_TAG_PARAMS tag_params; status = RW_T3tGetSystemCodes(); if (status != NFC_STATUS_OK) { /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); tag_params.t3t.num_system_codes = 0; tag_params.t3t.p_system_codes = nullptr; nfa_dm_notify_activation_status(NFA_STATUS_OK, &tag_params); } return true; } /******************************************************************************* ** ** Function nfa_rw_i93_command ** ** Description Handler for ISO 15693 command ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ static bool nfa_rw_i93_command(tNFA_RW_MSG* p_data) { tNFA_CONN_EVT_DATA conn_evt_data; tNFC_STATUS status = NFC_STATUS_OK; uint8_t i93_command = I93_CMD_STAY_QUIET; switch (p_data->op_req.op) { case NFA_RW_OP_I93_INVENTORY: i93_command = I93_CMD_INVENTORY; if (p_data->op_req.params.i93_cmd.uid_present) { status = RW_I93Inventory(p_data->op_req.params.i93_cmd.afi_present, p_data->op_req.params.i93_cmd.afi, p_data->op_req.params.i93_cmd.uid); } else { status = RW_I93Inventory(p_data->op_req.params.i93_cmd.afi_present, p_data->op_req.params.i93_cmd.afi, nullptr); } break; case NFA_RW_OP_I93_STAY_QUIET: i93_command = I93_CMD_STAY_QUIET; status = RW_I93StayQuiet(); break; case NFA_RW_OP_I93_READ_SINGLE_BLOCK: i93_command = I93_CMD_READ_SINGLE_BLOCK; status = RW_I93ReadSingleBlock( p_data->op_req.params.i93_cmd.first_block_number); break; case NFA_RW_OP_I93_WRITE_SINGLE_BLOCK: i93_command = I93_CMD_WRITE_SINGLE_BLOCK; status = RW_I93WriteSingleBlock( p_data->op_req.params.i93_cmd.first_block_number, p_data->op_req.params.i93_cmd.p_data); break; case NFA_RW_OP_I93_LOCK_BLOCK: i93_command = I93_CMD_LOCK_BLOCK; status = RW_I93LockBlock( (uint8_t)p_data->op_req.params.i93_cmd.first_block_number); break; case NFA_RW_OP_I93_READ_MULTI_BLOCK: i93_command = I93_CMD_READ_MULTI_BLOCK; status = RW_I93ReadMultipleBlocks( p_data->op_req.params.i93_cmd.first_block_number, p_data->op_req.params.i93_cmd.number_blocks); break; case NFA_RW_OP_I93_WRITE_MULTI_BLOCK: i93_command = I93_CMD_WRITE_MULTI_BLOCK; status = RW_I93WriteMultipleBlocks( (uint8_t)p_data->op_req.params.i93_cmd.first_block_number, p_data->op_req.params.i93_cmd.number_blocks, p_data->op_req.params.i93_cmd.p_data); break; case NFA_RW_OP_I93_SELECT: i93_command = I93_CMD_SELECT; status = RW_I93Select(p_data->op_req.params.i93_cmd.p_data); break; case NFA_RW_OP_I93_RESET_TO_READY: i93_command = I93_CMD_RESET_TO_READY; status = RW_I93ResetToReady(); break; case NFA_RW_OP_I93_WRITE_AFI: i93_command = I93_CMD_WRITE_AFI; status = RW_I93WriteAFI(p_data->op_req.params.i93_cmd.afi); break; case NFA_RW_OP_I93_LOCK_AFI: i93_command = I93_CMD_LOCK_AFI; status = RW_I93LockAFI(); break; case NFA_RW_OP_I93_WRITE_DSFID: i93_command = I93_CMD_WRITE_DSFID; status = RW_I93WriteDSFID(p_data->op_req.params.i93_cmd.dsfid); break; case NFA_RW_OP_I93_LOCK_DSFID: i93_command = I93_CMD_LOCK_DSFID; status = RW_I93LockDSFID(); break; case NFA_RW_OP_I93_GET_SYS_INFO: i93_command = I93_CMD_GET_SYS_INFO; if (p_data->op_req.params.i93_cmd.uid_present) { status = RW_I93GetSysInfo(p_data->op_req.params.i93_cmd.uid); } else { status = RW_I93GetSysInfo(nullptr); } break; case NFA_RW_OP_I93_GET_MULTI_BLOCK_STATUS: i93_command = I93_CMD_GET_MULTI_BLK_SEC; status = RW_I93GetMultiBlockSecurityStatus( p_data->op_req.params.i93_cmd.first_block_number, p_data->op_req.params.i93_cmd.number_blocks); break; default: break; } if (status != NFC_STATUS_OK) { /* Command complete - perform cleanup, notify app */ nfa_rw_command_complete(); conn_evt_data.i93_cmd_cplt.status = NFA_STATUS_FAILED; conn_evt_data.i93_cmd_cplt.sent_command = i93_command; nfa_dm_act_conn_cback_notify(NFA_I93_CMD_CPLT_EVT, &conn_evt_data); } return true; } /******************************************************************************* ** ** Function nfa_rw_raw_mode_data_cback ** ** Description Handler for incoming tag data for unsupported tag protocols ** (forward data to upper layer) ** ** Returns nothing ** *******************************************************************************/ static void nfa_rw_raw_mode_data_cback(__attribute__((unused)) uint8_t conn_id, tNFC_CONN_EVT event, tNFC_CONN* p_data) { NFC_HDR* p_msg; tNFA_CONN_EVT_DATA evt_data; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("event = 0x%X", event); if ((event == NFC_DATA_CEVT) && ((p_data->data.status == NFC_STATUS_OK) || (p_data->data.status == NFC_STATUS_CONTINUE))) { p_msg = (NFC_HDR*)p_data->data.p_data; if (p_msg) { evt_data.data.status = p_data->data.status; evt_data.data.p_data = (uint8_t*)(p_msg + 1) + p_msg->offset; evt_data.data.len = p_msg->len; nfa_dm_conn_cback_event_notify(NFA_DATA_EVT, &evt_data); GKI_freebuf(p_msg); } else { LOG(ERROR) << StringPrintf( "received NFC_DATA_CEVT with NULL data pointer"); } } else if (event == NFC_DEACTIVATE_CEVT) { NFC_SetStaticRfCback(nullptr); } } /******************************************************************************* ** ** Function nfa_rw_activate_ntf ** ** Description Handler for NFA_RW_ACTIVATE_NTF ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ bool nfa_rw_activate_ntf(tNFA_RW_MSG* p_data) { tNFC_ACTIVATE_DEVT* p_activate_params = p_data->activate_ntf.p_activate_params; tNFA_TAG_PARAMS tag_params; bool activate_notify = true; uint8_t* p; if ((nfa_rw_cb.halt_event != RW_T2T_MAX_EVT) && (nfa_rw_cb.activated_tech_mode == NFC_DISCOVERY_TYPE_POLL_A) && (nfa_rw_cb.protocol == NFC_PROTOCOL_T2T) && (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T)) { /* Type 2 tag is wake up from HALT State */ if (nfa_dm_cb.p_activate_ntf != nullptr) { GKI_freebuf(nfa_dm_cb.p_activate_ntf); nfa_dm_cb.p_activate_ntf = nullptr; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("- Type 2 tag wake up from HALT State"); return true; } DLOG_IF(INFO, nfc_debug_enabled) << __func__; /* Initialize control block */ nfa_rw_cb.protocol = p_activate_params->protocol; nfa_rw_cb.intf_type = p_activate_params->intf_param.type; nfa_rw_cb.pa_sel_res = p_activate_params->rf_tech_param.param.pa.sel_rsp; nfa_rw_cb.activated_tech_mode = p_activate_params->rf_tech_param.mode; nfa_rw_cb.flags = NFA_RW_FL_ACTIVATED; nfa_rw_cb.cur_op = NFA_RW_OP_MAX; nfa_rw_cb.halt_event = RW_T2T_MAX_EVT; nfa_rw_cb.skip_dyn_locks = false; nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; nfa_rw_cb.tlv_st = NFA_RW_TLV_DETECT_ST_OP_NOT_STARTED; memset(&tag_params, 0, sizeof(tNFA_TAG_PARAMS)); /* Check if we are in exclusive RF mode */ if (p_data->activate_ntf.excl_rf_not_active) { /* Not in exclusive RF mode */ nfa_rw_cb.flags |= NFA_RW_FL_NOT_EXCL_RF_MODE; } /* check if the protocol is activated with supported interface */ if (p_activate_params->intf_param.type == NCI_INTERFACE_FRAME) { if ((p_activate_params->protocol != NFA_PROTOCOL_T1T) && (p_activate_params->protocol != NFA_PROTOCOL_T2T) && (p_activate_params->protocol != NFA_PROTOCOL_T3T) && (p_activate_params->protocol != NFA_PROTOCOL_T5T)) { nfa_rw_cb.protocol = NFA_PROTOCOL_INVALID; } } else if (p_activate_params->intf_param.type == NCI_INTERFACE_ISO_DEP) { if (p_activate_params->protocol != NFA_PROTOCOL_ISO_DEP) { nfa_rw_cb.protocol = NFA_PROTOCOL_INVALID; } } if (nfa_rw_cb.protocol == NFA_PROTOCOL_INVALID) { /* Only sending raw frame and presence check are supported in this state */ NFC_SetStaticRfCback(nfa_rw_raw_mode_data_cback); /* Notify app of NFA_ACTIVATED_EVT and start presence check timer */ nfa_dm_notify_activation_status(NFA_STATUS_OK, nullptr); nfa_rw_check_start_presence_check_timer(NFA_RW_PRESENCE_CHECK_INTERVAL); return true; } /* If protocol not supported by RW module, notify app of NFA_ACTIVATED_EVT and * start presence check if needed */ if (!nfa_dm_is_protocol_supported( p_activate_params->protocol, p_activate_params->rf_tech_param.param.pa.sel_rsp)) { /* Notify upper layer of NFA_ACTIVATED_EVT if needed, and start presence * check timer */ /* Set data callback (pass all incoming data to upper layer using * NFA_DATA_EVT) */ NFC_SetStaticRfCback(nfa_rw_raw_mode_data_cback); /* Notify app of NFA_ACTIVATED_EVT and start presence check timer */ nfa_dm_notify_activation_status(NFA_STATUS_OK, nullptr); nfa_rw_check_start_presence_check_timer(NFA_RW_PRESENCE_CHECK_INTERVAL); return true; } /* Initialize RW module */ if ((RW_SetActivatedTagType(p_activate_params, nfa_rw_cback)) != NFC_STATUS_OK) { /* Log error (stay in NFA_RW_ST_ACTIVATED state until deactivation) */ LOG(ERROR) << StringPrintf("RW_SetActivatedTagType failed."); return true; } /* Perform protocol-specific actions */ if (NFC_PROTOCOL_T1T == nfa_rw_cb.protocol) { /* Retrieve HR and UID fields from activation notification */ memcpy(tag_params.t1t.uid, p_activate_params->rf_tech_param.param.pa.nfcid1, p_activate_params->rf_tech_param.param.pa.nfcid1_len); if (NFC_GetNCIVersion() == NCI_VERSION_2_0) { memcpy(tag_params.t1t.hr, p_activate_params->rf_tech_param.param.pa.hr, NFA_T1T_HR_LEN); } else { memcpy(tag_params.t1t.hr, p_activate_params->intf_param.intf_param.frame.param, NFA_T1T_HR_LEN); tNFA_RW_MSG msg; msg.op_req.op = NFA_RW_OP_T1T_RID; bool free_buf = nfa_rw_handle_op_req(&msg); CHECK(free_buf) << "nfa_rw_handle_op_req is holding on to soon-garbage stack memory."; /* Delay notifying upper layer of NFA_ACTIVATED_EVT until HR0/HR1 is received */ activate_notify = false; } } else if (NFC_PROTOCOL_T2T == nfa_rw_cb.protocol) { /* Retrieve UID fields from activation notification */ memcpy(tag_params.t2t.uid, p_activate_params->rf_tech_param.param.pa.nfcid1, p_activate_params->rf_tech_param.param.pa.nfcid1_len); } else if (NFC_PROTOCOL_T3T == nfa_rw_cb.protocol) { if (appl_dta_mode_flag) { /* Incase of DTA mode Dont send commands to get system code. Just notify * activation */ activate_notify = true; } else { /* Delay notifying upper layer of NFA_ACTIVATED_EVT until system codes * are retrieved */ activate_notify = false; /* Issue command to get Felica system codes */ tNFA_RW_MSG msg; msg.op_req.op = NFA_RW_OP_T3T_GET_SYSTEM_CODES; bool free_buf = nfa_rw_handle_op_req(&msg); CHECK(free_buf) << "nfa_rw_handle_op_req is holding on to soon-garbage stack memory."; } } else if (NFA_PROTOCOL_T5T == nfa_rw_cb.protocol) { /* Delay notifying upper layer of NFA_ACTIVATED_EVT to retrieve additional * tag infomation */ nfa_rw_cb.flags |= NFA_RW_FL_ACTIVATION_NTF_PENDING; activate_notify = false; /* store DSFID and UID from activation NTF */ nfa_rw_cb.i93_dsfid = p_activate_params->rf_tech_param.param.pi93.dsfid; p = nfa_rw_cb.i93_uid; ARRAY8_TO_STREAM(p, p_activate_params->rf_tech_param.param.pi93.uid); if ((nfa_rw_cb.i93_uid[1] == I93_UID_IC_MFG_CODE_TI) && (((nfa_rw_cb.i93_uid[2] & I93_UID_TAG_IT_HF_I_PRODUCT_ID_MASK) == I93_UID_TAG_IT_HF_I_STD_CHIP_INLAY) || ((nfa_rw_cb.i93_uid[2] & I93_UID_TAG_IT_HF_I_PRODUCT_ID_MASK) == I93_UID_TAG_IT_HF_I_PRO_CHIP_INLAY))) { /* these don't support Get System Information Command */ nfa_rw_cb.i93_block_size = I93_TAG_IT_HF_I_STD_PRO_CHIP_INLAY_BLK_SIZE; nfa_rw_cb.i93_afi_location = I93_TAG_IT_HF_I_STD_PRO_CHIP_INLAY_AFI_LOCATION; if ((nfa_rw_cb.i93_uid[2] & I93_UID_TAG_IT_HF_I_PRODUCT_ID_MASK) == I93_UID_TAG_IT_HF_I_STD_CHIP_INLAY) { nfa_rw_cb.i93_num_block = I93_TAG_IT_HF_I_STD_CHIP_INLAY_NUM_TOTAL_BLK; } else { nfa_rw_cb.i93_num_block = I93_TAG_IT_HF_I_PRO_CHIP_INLAY_NUM_TOTAL_BLK; } /* read AFI */ if (RW_I93ReadSingleBlock((uint8_t)(nfa_rw_cb.i93_afi_location / nfa_rw_cb.i93_block_size)) != NFC_STATUS_OK) { /* notify activation without AFI/IC-Ref */ nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING; activate_notify = true; tag_params.i93.info_flags = (I93_INFO_FLAG_DSFID | I93_INFO_FLAG_MEM_SIZE); tag_params.i93.dsfid = nfa_rw_cb.i93_dsfid; tag_params.i93.block_size = nfa_rw_cb.i93_block_size; tag_params.i93.num_block = nfa_rw_cb.i93_num_block; memcpy(tag_params.i93.uid, nfa_rw_cb.i93_uid, I93_UID_BYTE_LEN); } } else { /* All of ICODE supports Get System Information Command */ /* Tag-it HF-I Plus Chip/Inlay supports Get System Information Command */ /* just try for others */ if (RW_I93GetSysInfo(nfa_rw_cb.i93_uid) != NFC_STATUS_OK) { /* notify activation without AFI/MEM size/IC-Ref */ nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING; activate_notify = true; tag_params.i93.info_flags = I93_INFO_FLAG_DSFID; tag_params.i93.dsfid = nfa_rw_cb.i93_dsfid; tag_params.i93.block_size = 0; tag_params.i93.num_block = 0; memcpy(tag_params.i93.uid, nfa_rw_cb.i93_uid, I93_UID_BYTE_LEN); } else { /* reset memory size */ nfa_rw_cb.i93_block_size = 0; nfa_rw_cb.i93_num_block = 0; } } } /* Notify upper layer of NFA_ACTIVATED_EVT if needed, and start presence check * timer */ if (activate_notify) { nfa_dm_notify_activation_status(NFA_STATUS_OK, &tag_params); nfa_rw_check_start_presence_check_timer(NFA_RW_PRESENCE_CHECK_INTERVAL); } return true; } /******************************************************************************* ** ** Function nfa_rw_deactivate_ntf ** ** Description Handler for NFA_RW_DEACTIVATE_NTF ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ bool nfa_rw_deactivate_ntf(__attribute__((unused)) tNFA_RW_MSG* p_data) { /* Clear the activated flag */ nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATED; /* Free buffer for incoming NDEF message, in case we were in the middle of a * read operation */ nfa_rw_free_ndef_rx_buf(); /* If there is a pending command message, then free it */ if (nfa_rw_cb.p_pending_msg) { if ((nfa_rw_cb.p_pending_msg->op_req.op == NFA_RW_OP_SEND_RAW_FRAME) && (nfa_rw_cb.p_pending_msg->op_req.params.send_raw_frame.p_data)) { GKI_freebuf(nfa_rw_cb.p_pending_msg->op_req.params.send_raw_frame.p_data); } GKI_freebuf(nfa_rw_cb.p_pending_msg); nfa_rw_cb.p_pending_msg = nullptr; } /* If we are in the process of waking up tag from HALT state */ if (nfa_rw_cb.halt_event == RW_T2T_READ_CPLT_EVT) { if (nfa_rw_cb.rw_data.data.p_data) GKI_freebuf(nfa_rw_cb.rw_data.data.p_data); nfa_rw_cb.rw_data.data.p_data = nullptr; } /* Stop presence check timer (if started) */ nfa_rw_stop_presence_check_timer(); return true; } /******************************************************************************* ** ** Function nfa_rw_handle_op_req ** ** Description Handler for NFA_RW_OP_REQUEST_EVT, operation request ** ** Returns TRUE if caller should free p_data ** FALSE if caller does not need to free p_data ** *******************************************************************************/ bool nfa_rw_handle_op_req(tNFA_RW_MSG* p_data) { bool freebuf = true; uint16_t presence_check_start_delay = 0; /* Check if activated */ if (!(nfa_rw_cb.flags & NFA_RW_FL_ACTIVATED)) { LOG(ERROR) << StringPrintf("nfa_rw_handle_op_req: not activated"); return (nfa_rw_op_req_while_inactive(p_data)); } /* Check if currently busy with another API call */ else if (nfa_rw_cb.flags & NFA_RW_FL_API_BUSY) { return (nfa_rw_op_req_while_busy(p_data)); } /* Check if currently busy with auto-presence check */ else if (nfa_rw_cb.flags & NFA_RW_FL_AUTO_PRESENCE_CHECK_BUSY) { /* Cache the command (will be handled once auto-presence check is completed) */ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "Deferring operation %i until after auto-presence check is completed", p_data->op_req.op); nfa_rw_cb.p_pending_msg = p_data; nfa_rw_cb.flags |= NFA_RW_FL_API_BUSY; return false; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("nfa_rw_handle_op_req: op=0x%02x", p_data->op_req.op); nfa_rw_cb.flags |= NFA_RW_FL_API_BUSY; /* Stop the presence check timer */ nfa_rw_stop_presence_check_timer(); /* Store the current operation */ nfa_rw_cb.cur_op = p_data->op_req.op; /* Call appropriate handler for requested operation */ switch (p_data->op_req.op) { case NFA_RW_OP_DETECT_NDEF: nfa_rw_cb.skip_dyn_locks = false; nfa_rw_detect_ndef(); break; case NFA_RW_OP_READ_NDEF: nfa_rw_read_ndef(); break; case NFA_RW_OP_WRITE_NDEF: nfa_rw_write_ndef(p_data); break; case NFA_RW_OP_SEND_RAW_FRAME: presence_check_start_delay = p_data->op_req.params.send_raw_frame.p_data->layer_specific; NFC_SendData(NFC_RF_CONN_ID, p_data->op_req.params.send_raw_frame.p_data); /* Clear the busy flag */ nfa_rw_cb.flags &= ~NFA_RW_FL_API_BUSY; /* Start presence_check after specified delay */ nfa_rw_check_start_presence_check_timer(presence_check_start_delay); break; case NFA_RW_OP_PRESENCE_CHECK: nfa_rw_presence_check(p_data); break; case NFA_RW_OP_FORMAT_TAG: nfa_rw_format_tag(); break; case NFA_RW_OP_DETECT_LOCK_TLV: nfa_rw_detect_tlv(TAG_LOCK_CTRL_TLV); break; case NFA_RW_OP_DETECT_MEM_TLV: nfa_rw_detect_tlv(TAG_MEM_CTRL_TLV); break; case NFA_RW_OP_SET_TAG_RO: nfa_rw_cb.b_hard_lock = p_data->op_req.params.set_readonly.b_hard_lock; nfa_rw_config_tag_ro(nfa_rw_cb.b_hard_lock); break; case NFA_RW_OP_T1T_RID: nfa_rw_t1t_rid(); break; case NFA_RW_OP_T1T_RALL: nfa_rw_t1t_rall(); break; case NFA_RW_OP_T1T_READ: nfa_rw_t1t_read(p_data); break; case NFA_RW_OP_T1T_WRITE: nfa_rw_t1t_write(p_data); break; case NFA_RW_OP_T1T_RSEG: nfa_rw_t1t_rseg(p_data); break; case NFA_RW_OP_T1T_READ8: nfa_rw_t1t_read8(p_data); break; case NFA_RW_OP_T1T_WRITE8: nfa_rw_t1t_write8(p_data); break; /* Type-2 tag commands */ case NFA_RW_OP_T2T_READ: nfa_rw_t2t_read(p_data); break; case NFA_RW_OP_T2T_WRITE: nfa_rw_t2t_write(p_data); break; case NFA_RW_OP_T2T_SECTOR_SELECT: nfa_rw_t2t_sector_select(p_data); break; /* Type-3 tag commands */ case NFA_RW_OP_T3T_READ: nfa_rw_t3t_read(p_data); break; case NFA_RW_OP_T3T_WRITE: nfa_rw_t3t_write(p_data); break; case NFA_RW_OP_T3T_GET_SYSTEM_CODES: nfa_rw_t3t_get_system_codes(); break; /* ISO 15693 tag commands */ case NFA_RW_OP_I93_INVENTORY: case NFA_RW_OP_I93_STAY_QUIET: case NFA_RW_OP_I93_READ_SINGLE_BLOCK: case NFA_RW_OP_I93_WRITE_SINGLE_BLOCK: case NFA_RW_OP_I93_LOCK_BLOCK: case NFA_RW_OP_I93_READ_MULTI_BLOCK: case NFA_RW_OP_I93_WRITE_MULTI_BLOCK: case NFA_RW_OP_I93_SELECT: case NFA_RW_OP_I93_RESET_TO_READY: case NFA_RW_OP_I93_WRITE_AFI: case NFA_RW_OP_I93_LOCK_AFI: case NFA_RW_OP_I93_WRITE_DSFID: case NFA_RW_OP_I93_LOCK_DSFID: case NFA_RW_OP_I93_GET_SYS_INFO: case NFA_RW_OP_I93_GET_MULTI_BLOCK_STATUS: nfa_rw_i93_command(p_data); break; default: LOG(ERROR) << StringPrintf("nfa_rw_handle_api: unhandled operation: %i", p_data->op_req.op); break; } return (freebuf); } /******************************************************************************* ** ** Function nfa_rw_op_req_while_busy ** ** Description Handle operation request while busy ** ** Returns TRUE if caller should free p_data ** FALSE if caller does not need to free p_data ** *******************************************************************************/ static bool nfa_rw_op_req_while_busy(tNFA_RW_MSG* p_data) { bool freebuf = true; tNFA_CONN_EVT_DATA conn_evt_data; uint8_t event; LOG(ERROR) << StringPrintf("nfa_rw_op_req_while_busy: unable to handle API"); /* Return appropriate event for requested API, with status=BUSY */ conn_evt_data.status = NFA_STATUS_BUSY; switch (p_data->op_req.op) { case NFA_RW_OP_DETECT_NDEF: conn_evt_data.ndef_detect.cur_size = 0; conn_evt_data.ndef_detect.max_size = 0; conn_evt_data.ndef_detect.flags = RW_NDEF_FL_UNKNOWN; event = NFA_NDEF_DETECT_EVT; break; case NFA_RW_OP_READ_NDEF: case NFA_RW_OP_T1T_RID: case NFA_RW_OP_T1T_RALL: case NFA_RW_OP_T1T_READ: case NFA_RW_OP_T1T_RSEG: case NFA_RW_OP_T1T_READ8: case NFA_RW_OP_T2T_READ: case NFA_RW_OP_T3T_READ: event = NFA_READ_CPLT_EVT; break; case NFA_RW_OP_WRITE_NDEF: case NFA_RW_OP_T1T_WRITE: case NFA_RW_OP_T1T_WRITE8: case NFA_RW_OP_T2T_WRITE: case NFA_RW_OP_T3T_WRITE: event = NFA_WRITE_CPLT_EVT; break; case NFA_RW_OP_FORMAT_TAG: event = NFA_FORMAT_CPLT_EVT; break; case NFA_RW_OP_DETECT_LOCK_TLV: case NFA_RW_OP_DETECT_MEM_TLV: event = NFA_TLV_DETECT_EVT; break; case NFA_RW_OP_SET_TAG_RO: event = NFA_SET_TAG_RO_EVT; break; case NFA_RW_OP_T2T_SECTOR_SELECT: event = NFA_SELECT_CPLT_EVT; break; case NFA_RW_OP_I93_INVENTORY: case NFA_RW_OP_I93_STAY_QUIET: case NFA_RW_OP_I93_READ_SINGLE_BLOCK: case NFA_RW_OP_I93_WRITE_SINGLE_BLOCK: case NFA_RW_OP_I93_LOCK_BLOCK: case NFA_RW_OP_I93_READ_MULTI_BLOCK: case NFA_RW_OP_I93_WRITE_MULTI_BLOCK: case NFA_RW_OP_I93_SELECT: case NFA_RW_OP_I93_RESET_TO_READY: case NFA_RW_OP_I93_WRITE_AFI: case NFA_RW_OP_I93_LOCK_AFI: case NFA_RW_OP_I93_WRITE_DSFID: case NFA_RW_OP_I93_LOCK_DSFID: case NFA_RW_OP_I93_GET_SYS_INFO: case NFA_RW_OP_I93_GET_MULTI_BLOCK_STATUS: event = NFA_I93_CMD_CPLT_EVT; break; default: return (freebuf); } nfa_dm_act_conn_cback_notify(event, &conn_evt_data); return (freebuf); } /******************************************************************************* ** ** Function nfa_rw_op_req_while_inactive ** ** Description Handle operation request while inactive ** ** Returns TRUE if caller should free p_data ** FALSE if caller does not need to free p_data ** *******************************************************************************/ static bool nfa_rw_op_req_while_inactive(tNFA_RW_MSG* p_data) { bool freebuf = true; tNFA_CONN_EVT_DATA conn_evt_data; uint8_t event; LOG(ERROR) << StringPrintf( "nfa_rw_op_req_while_inactive: unable to handle API"); /* Return appropriate event for requested API, with status=REJECTED */ conn_evt_data.status = NFA_STATUS_REJECTED; switch (p_data->op_req.op) { case NFA_RW_OP_DETECT_NDEF: conn_evt_data.ndef_detect.cur_size = 0; conn_evt_data.ndef_detect.max_size = 0; conn_evt_data.ndef_detect.flags = RW_NDEF_FL_UNKNOWN; event = NFA_NDEF_DETECT_EVT; break; case NFA_RW_OP_READ_NDEF: case NFA_RW_OP_T1T_RID: case NFA_RW_OP_T1T_RALL: case NFA_RW_OP_T1T_READ: case NFA_RW_OP_T1T_RSEG: case NFA_RW_OP_T1T_READ8: case NFA_RW_OP_T2T_READ: case NFA_RW_OP_T3T_READ: event = NFA_READ_CPLT_EVT; break; case NFA_RW_OP_WRITE_NDEF: case NFA_RW_OP_T1T_WRITE: case NFA_RW_OP_T1T_WRITE8: case NFA_RW_OP_T2T_WRITE: case NFA_RW_OP_T3T_WRITE: event = NFA_WRITE_CPLT_EVT; break; case NFA_RW_OP_FORMAT_TAG: event = NFA_FORMAT_CPLT_EVT; break; case NFA_RW_OP_DETECT_LOCK_TLV: case NFA_RW_OP_DETECT_MEM_TLV: event = NFA_TLV_DETECT_EVT; break; case NFA_RW_OP_SET_TAG_RO: event = NFA_SET_TAG_RO_EVT; break; case NFA_RW_OP_T2T_SECTOR_SELECT: event = NFA_SELECT_CPLT_EVT; break; case NFA_RW_OP_I93_INVENTORY: case NFA_RW_OP_I93_STAY_QUIET: case NFA_RW_OP_I93_READ_SINGLE_BLOCK: case NFA_RW_OP_I93_WRITE_SINGLE_BLOCK: case NFA_RW_OP_I93_LOCK_BLOCK: case NFA_RW_OP_I93_READ_MULTI_BLOCK: case NFA_RW_OP_I93_WRITE_MULTI_BLOCK: case NFA_RW_OP_I93_SELECT: case NFA_RW_OP_I93_RESET_TO_READY: case NFA_RW_OP_I93_WRITE_AFI: case NFA_RW_OP_I93_LOCK_AFI: case NFA_RW_OP_I93_WRITE_DSFID: case NFA_RW_OP_I93_LOCK_DSFID: case NFA_RW_OP_I93_GET_SYS_INFO: case NFA_RW_OP_I93_GET_MULTI_BLOCK_STATUS: event = NFA_I93_CMD_CPLT_EVT; break; default: return (freebuf); } nfa_dm_act_conn_cback_notify(event, &conn_evt_data); return (freebuf); } /******************************************************************************* ** ** Function nfa_rw_command_complete ** ** Description Handle command complete: clear the busy flag, ** and start the presence check timer if applicable. ** ** Returns None ** *******************************************************************************/ void nfa_rw_command_complete(void) { /* Clear the busy flag */ nfa_rw_cb.flags &= ~NFA_RW_FL_API_BUSY; /* Restart presence_check timer */ nfa_rw_check_start_presence_check_timer(NFA_RW_PRESENCE_CHECK_INTERVAL); }