Merge "Add empty aid as the last entry of aid routing"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 7fb1636..657c8df 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -3,4 +3,8 @@
[Builtin Hooks]
clang_format = true
+rustfmt = true
+
+[Builtin Hooks Options]
+rustfmt = --config-path=rustfmt.toml
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 100644
index 0000000..617d425
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1,5 @@
+# Android Format Style
+
+edition = "2018"
+use_small_heuristics = "Max"
+newline_style = "Unix"
diff --git a/src/Android.bp b/src/Android.bp
index f691c4a..b16696a 100644
--- a/src/Android.bp
+++ b/src/Android.bp
@@ -185,3 +185,46 @@
"fuzzers/llcp/*.cc",
],
}
+
+genrule {
+ name: "NfcGeneratedPackets_rust",
+ tools: [
+ "bluetooth_packetgen",
+ ],
+ cmd: "$(location bluetooth_packetgen) --include=system/nfc/src --out=$(genDir) $(in) --rust",
+ srcs: [
+ "nci_packets.pdl",
+ ],
+ out: [
+ "nci_packets.rs",
+ ],
+}
+
+rust_library {
+ name: "libnfc_packets",
+ defaults: ["nfc_rust_defaults"],
+ crate_name: "nfc_packets",
+ srcs: ["rust/packets/lib.rs", ":NfcGeneratedPackets_rust"],
+ host_supported: true,
+ proc_macros: ["libnum_derive"],
+ rustlibs: [
+ "libbytes",
+ "libnum_traits",
+ "libthiserror",
+ "liblog_rust",
+ ],
+}
+
+rust_test_host {
+ name: "libnfc_packets_test",
+ defaults: ["nfc_rust_defaults"],
+ srcs: ["rust/packets/lib.rs", ":NfcGeneratedPackets_rust"],
+ test_suites: ["general-tests"],
+ proc_macros: ["libnum_derive"],
+ rustlibs: [
+ "libbytes",
+ "libnum_traits",
+ "libthiserror",
+ "liblog_rust",
+ ],
+}
diff --git a/src/adaptation/NfcAdaptation.cc b/src/adaptation/NfcAdaptation.cc
index 7c6a857..1567b0c 100644
--- a/src/adaptation/NfcAdaptation.cc
+++ b/src/adaptation/NfcAdaptation.cc
@@ -89,14 +89,9 @@
nfc_debug_enabled =
(NfcConfig::getUnsigned(NAME_NFC_DEBUG_ENABLED, 0) != 0) ? true : false;
- char valueStr[PROPERTY_VALUE_MAX] = {0};
- int len = property_get("nfc.debug_enabled", valueStr, "");
- if (len > 0) {
- // let Android property override .conf variable
- unsigned debug_enabled = 0;
- sscanf(valueStr, "%u", &debug_enabled);
- nfc_debug_enabled = (debug_enabled == 0) ? false : true;
- }
+ bool debug_enabled = property_get_bool("persist.nfc.debug_enabled", false);
+
+ nfc_debug_enabled = (nfc_debug_enabled || debug_enabled);
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("%s: level=%u", __func__, nfc_debug_enabled);
@@ -147,13 +142,24 @@
const wp<::android::hidl::base::V1_0::IBase>& /* who */) {
ALOGE(
"NfcHalDeathRecipient::serviceDied - Nfc-Hal service died. Killing "
- "NfcServie");
+ "NfcService");
if (mNfcDeathHal) {
mNfcDeathHal->unlinkToDeath(this);
}
mNfcDeathHal = NULL;
abort();
}
+ void finalize() {
+ if (mNfcDeathHal) {
+ mNfcDeathHal->unlinkToDeath(this);
+ } else {
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s: mNfcDeathHal is not set", __func__);
+ }
+
+ ALOGI("NfcHalDeathRecipient::destructor - NfcService");
+ mNfcDeathHal = NULL;
+ }
};
/*******************************************************************************
@@ -166,7 +172,6 @@
**
*******************************************************************************/
NfcAdaptation::NfcAdaptation() {
- mNfcHalDeathRecipient = new NfcHalDeathRecipient(mHal);
memset(&mHalEntryFuncs, 0, sizeof(mHalEntryFuncs));
}
@@ -393,6 +398,7 @@
NfcConfig::clear();
+ mNfcHalDeathRecipient->finalize();
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", func);
delete this;
}
@@ -529,6 +535,7 @@
mHal.get(),
(mHal->isRemote() ? "remote" : "local"));
if (mHal) {
+ mNfcHalDeathRecipient = new NfcHalDeathRecipient(mHal);
mHal->linkToDeath(mNfcHalDeathRecipient, 0);
}
}
diff --git a/src/fuzzers/ce/t3t.cc b/src/fuzzers/ce/t3t.cc
index 490f6b7..e774df7 100644
--- a/src/fuzzers/ce/t3t.cc
+++ b/src/fuzzers/ce/t3t.cc
@@ -93,13 +93,13 @@
for (auto it = ctx.Data.cbegin(); it != ctx.Data.cend(); ++it) {
NFC_HDR* p_msg;
p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR) + it->size());
- if (p_msg == nullptr) {
+ if (p_msg == nullptr || it->size() < 1) {
FUZZLOG(MODULE_NAME ": GKI_getbuf returns null, size=%zu", it->size());
return;
}
/* Initialize NFC_HDR */
- p_msg->len = it->size();
+ p_msg->len = it->size() - 1;
p_msg->offset = 0;
uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
diff --git a/src/fuzzers/rw/t1t.cc b/src/fuzzers/rw/t1t.cc
index 94670fd..f2c4f80 100644
--- a/src/fuzzers/rw/t1t.cc
+++ b/src/fuzzers/rw/t1t.cc
@@ -213,13 +213,13 @@
for (auto it = ctx.Data.cbegin() + 1; it != ctx.Data.cend(); ++it) {
NFC_HDR* p_msg;
p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR) + it->size());
- if (p_msg == nullptr) {
+ if (p_msg == nullptr || it->size() < 1) {
FUZZLOG(MODULE_NAME ": GKI_getbuf returns null, size=%zu", it->size());
return;
}
/* Initialize NFC_HDR */
- p_msg->len = it->size();
+ p_msg->len = it->size() - 1;
p_msg->offset = 0;
uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
diff --git a/src/fuzzers/rw/t2t.cc b/src/fuzzers/rw/t2t.cc
index 57ddb0f..f829e35 100644
--- a/src/fuzzers/rw/t2t.cc
+++ b/src/fuzzers/rw/t2t.cc
@@ -172,13 +172,13 @@
for (auto it = ctx.Data.cbegin() + 1; it != ctx.Data.cend(); ++it) {
NFC_HDR* p_msg;
p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR) + it->size());
- if (p_msg == nullptr) {
+ if (p_msg == nullptr || it->size() < 1) {
FUZZLOG(MODULE_NAME ": GKI_getbuf returns null, size=%zu", it->size());
return;
}
/* Initialize NFC_HDR */
- p_msg->len = it->size();
+ p_msg->len = it->size() - 1;
p_msg->offset = 0;
uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
diff --git a/src/fuzzers/rw/t3t.cc b/src/fuzzers/rw/t3t.cc
index b64ffc5..8853cf7 100644
--- a/src/fuzzers/rw/t3t.cc
+++ b/src/fuzzers/rw/t3t.cc
@@ -251,6 +251,11 @@
.status = NFC_STATUS_OK,
.p_data = p_msg,
}};
+ if (p_msg->len < 1) {
+ FUZZLOG(MODULE_NAME ": Ivalid message length=%hu", p_msg->len);
+ return;
+ }
+ p_msg->len--;
rf_cback(NFC_RF_CONN_ID, NFC_DATA_CEVT, &conn);
}
diff --git a/src/fuzzers/rw/t5t.cc b/src/fuzzers/rw/t5t.cc
index 1358bed..bd61f66 100644
--- a/src/fuzzers/rw/t5t.cc
+++ b/src/fuzzers/rw/t5t.cc
@@ -290,13 +290,13 @@
for (auto it = ctx.Data.cbegin() + 1; it != ctx.Data.cend(); ++it) {
NFC_HDR* p_msg;
p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR) + it->size());
- if (p_msg == nullptr) {
+ if (p_msg == nullptr || it->size() < 1) {
FUZZLOG(MODULE_NAME ": GKI_getbuf returns null, size=%zu", it->size());
return;
}
/* Initialize NFC_HDR */
- p_msg->len = it->size();
+ p_msg->len = it->size() - 1;
p_msg->offset = 0;
uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
diff --git a/src/gki/common/gki_buffer.cc b/src/gki/common/gki_buffer.cc
index 0ad8427..1aeb3ae 100644
--- a/src/gki/common/gki_buffer.cc
+++ b/src/gki/common/gki_buffer.cc
@@ -1306,10 +1306,35 @@
**
*******************************************************************************/
uint16_t GKI_get_pool_bufsize(uint8_t pool_id) {
+#if defined(DYN_ALLOC) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
+ uint16_t size = 0;
+ switch (pool_id) {
+ case GKI_POOL_ID_0:
+ size = GKI_BUF0_SIZE;
+ break;
+ case GKI_POOL_ID_1:
+ size = GKI_BUF1_SIZE;
+ break;
+ case GKI_POOL_ID_2:
+ size = GKI_BUF2_SIZE;
+ break;
+ case GKI_POOL_ID_3:
+ size = GKI_BUF3_SIZE;
+ break;
+ /* Here could be more pool ids, but they are not used in the current
+ * implementation */
+ default:
+ LOG(ERROR) << StringPrintf("Unknown pool ID: %d", pool_id);
+ return (0);
+ break;
+ }
+ return (size);
+#else
if (pool_id < GKI_NUM_TOTAL_BUF_POOLS)
return (gki_cb.com.freeq[pool_id].size);
return (0);
+#endif
}
/*******************************************************************************
diff --git a/src/gki/ulinux/gki_ulinux.cc b/src/gki/ulinux/gki_ulinux.cc
index 57c2402..64983fd 100644
--- a/src/gki/ulinux/gki_ulinux.cc
+++ b/src/gki/ulinux/gki_ulinux.cc
@@ -95,8 +95,8 @@
/* Call the actual thread entry point */
(p_pthread_info->task_entry)(p_pthread_info->params);
- LOG(ERROR) << StringPrintf("gki_task task_id=%i terminating",
- p_pthread_info->task_id);
+ LOG(WARNING) << StringPrintf("gki_task task_id=%i terminating",
+ p_pthread_info->task_id);
gki_cb.os.thread_id[p_pthread_info->task_id] = 0;
return nullptr;
@@ -290,8 +290,6 @@
* GKI_exception problem due to btu->hci sleep request events */
for (task_id = GKI_MAX_TASKS; task_id > 0; task_id--) {
if (gki_cb.com.OSRdyTbl[task_id - 1] != TASK_DEAD) {
- gki_cb.com.OSRdyTbl[task_id - 1] = TASK_DEAD;
-
/* paranoi settings, make sure that we do not execute any mailbox events
*/
gki_cb.com.OSWaitEvt[task_id - 1] &=
@@ -629,13 +627,13 @@
if (gki_cb.com.OSTaskQFirst[rtask][3])
gki_cb.com.OSWaitEvt[rtask] |= TASK_MBOX_3_EVT_MASK;
- if (gki_cb.com.OSRdyTbl[rtask] == TASK_DEAD) {
+ if (gki_cb.com.OSWaitEvt[rtask] == EVENT_MASK(GKI_SHUTDOWN_EVT)) {
gki_cb.com.OSWaitEvt[rtask] = 0;
/* unlock thread_evt_mutex as pthread_cond_wait() does auto lock when cond
* is met */
pthread_mutex_unlock(&gki_cb.os.thread_evt_mutex[rtask]);
- LOG(ERROR) << StringPrintf("GKI TASK_DEAD received. exit thread %d...",
- rtask);
+ LOG(WARNING) << StringPrintf("GKI TASK_DEAD received. exit thread %d...",
+ rtask);
gki_cb.os.thread_id[rtask] = 0;
return (EVENT_MASK(GKI_SHUTDOWN_EVT));
@@ -1073,6 +1071,11 @@
return;
}
GKI_disable();
+ if (gki_cb.com.OSRdyTbl[task_id] == TASK_DEAD) {
+ GKI_enable();
+ LOG(WARNING) << StringPrintf("%s: task_id %d was already stopped.", __func__, task_id);
+ return;
+ }
gki_cb.com.OSRdyTbl[task_id] = TASK_DEAD;
/* Destroy mutex and condition variable objects */
diff --git a/src/nci_packets.pdl b/src/nci_packets.pdl
new file mode 100644
index 0000000..f94a35d
--- /dev/null
+++ b/src/nci_packets.pdl
@@ -0,0 +1,441 @@
+little_endian_packets
+
+enum PacketBoundaryFlag : 1 {
+ COMPLETE_OR_FINAL = 0,
+ INCOMPLETE = 1,
+}
+
+enum NciMsgType : 3 {
+ DATA = 0,
+ COMMAND = 1,
+ RESPONSE = 2,
+ NOTIFICATION = 3,
+}
+
+enum Opcode : 8 {
+ CORE_RESET = 0x0,
+ CORE_INIT = 0x1,
+ CORE_SET_CONFIG = 0x2,
+ CORE_GET_CONFIG = 0x3,
+ CORE_CONN_CREATE = 0x4,
+ CORE_CONN_CLOSE = 0x5,
+ CORE_CONN_CREDITS = 0x6,
+ CORE_GENERIC_ERROR = 0x7,
+ CORE_INTERFACE_ERROR = 0x8,
+ CORE_SET_POWER_SUBSTATE = 0x9,
+ RF_DISCOVER_MAP = 0x40,
+ RF_SET_LISTEN_MODE_ROUTING = 0x41,
+ RF_GET_LISTEN_MODE_ROUTING = 0x42,
+ RF_DISCOVER = 0x43,
+ RF_DISCOVER_SELECT = 0x44,
+ RF_INTF_ACTIVATED = 0x45,
+ RF_DIACTIVATE = 0x46,
+ RF_FIELD_INFO = 0x47,
+ RF_T3T_POLLING = 0x48,
+ RF_NFCEE_ACTION = 0x49,
+ RF_NFCEE_DISCOVERY_REQ = 0x4A,
+ RF_PARAMETER_UPDATE = 0x4B,
+ RF_INTF_EXT_START = 0x4C,
+ RF_INTF_EXT_STOP = 0x4D,
+ RF_EXT_AGG_ABORT = 0x4E,
+ RF_NDEF_ABORT = 0x4F,
+ RF_ISO_DEP_NAK_PRESENCE = 0x50,
+ RF_SET_FORCED_NFCEE_ROUTING_CMD = 0x51,
+}
+
+enum Status : 8 {
+ OK = 0x00,
+ REJECTED = 0x01,
+ FAILED = 0x03,
+ NOT_INITIALIZED = 0x04,
+ SYNTAX_ERROR = 0x05,
+ SEMANTIC_ERROR = 0x06,
+ INVALID_PARAM = 0x09,
+ MESSAGE_SIZE_EXCEEDED = 0x0A,
+ OK_1_BIT = 0x11,
+ OK_2_BIT = 0x12,
+ OK_3_BIT = 0x13,
+ OK_4_BIT = 0x14,
+ OK_5_BIT = 0x15,
+ OK_6_BIT = 0x16,
+ OK_7_BIT = 0x17,
+ DISCOVERY_ALREADY_STARTED = 0xA0,
+ DISCOVERY_TARGET_ACTIVATION_FAILED = 0xA1,
+ DISCOVERY_TEAR_DOWN = 0xA2,
+ RF_FRAME_CORRUPTED = 0x02,
+ RF_TRANSMISSION_EXCEPTION = 0xB0,
+ RF_PROTOCOL_EXCEPTION = 0xB1,
+ RF_TIMEOUT_EXCEPTION = 0xB2,
+ RF_UNEXPECTED_DATA = 0xB3,
+ NFCEE_INTERFACE_ACTIVATION_FAILED = 0xC0,
+ NFCEE_TRANSMISSION_ERROR = 0xC1,
+ NFCEE_PROTOCOL_ERROR = 0xC2,
+ NFCEE_TIMEOUT_ERROR = 0xC3,
+}
+
+packet Nci {
+ gid : 4,
+ pbf : PacketBoundaryFlag,
+ mt : NciMsgType,
+ _payload_,
+}
+
+packet Command : Nci (mt = COMMAND) {
+ op : Opcode,
+ _size_(_payload_) : 8,
+ _payload_,
+}
+
+packet Response : Nci (mt = RESPONSE) {
+ cmd_op : Opcode,
+ _size_(_payload_) : 8,
+ _payload_,
+}
+
+packet Notification : Nci (mt = NOTIFICATION) {
+ cmd_op : Opcode,
+ _size_(_payload_) : 8,
+ _payload_,
+}
+
+packet Data {
+ conn_id : 4,
+ pbf : PacketBoundaryFlag,
+ _fixed_ = 0x0 : 3,
+ cr : 8,
+ _size_(_payload_) : 8,
+ _payload_,
+}
+
+enum ResetType : 8 {
+ KEEP_CONFIG = 0,
+ RESET_CONFIG = 1,
+}
+
+packet ResetCommand : Command (op = CORE_RESET) {
+ reset_type: ResetType,
+}
+
+test ResetCommand {
+ "\x20\x00\x01\x01",
+}
+
+packet ResetResponse : Response (cmd_op = CORE_RESET) {
+ status: Status,
+}
+
+test ResetResponse {
+ "\x40\x00\x01\x00",
+}
+
+enum ResetTrigger : 8 {
+ UNRECOVERABLE_ERROR = 0,
+ POWER_ON = 1,
+ RESET_COMMAND = 2,
+}
+
+enum NciVersion : 8 {
+ VERSION_1_0 = 0x10,
+ VERSION_1_1 = 0x11,
+ VERSION_2_0 = 0x20,
+}
+
+enum ConfigStatus : 8 {
+ CONFIG_KEPT = 0x00,
+ CONFIG_RESET = 0x01,
+}
+
+packet ResetNotification : Notification (cmd_op = CORE_RESET) {
+ trigger : ResetTrigger,
+ config_status : ConfigStatus,
+ nci_version : NciVersion,
+ manufacturer_id: 8,
+ _size_(mfsi) : 8,
+ mfsi : 8[],
+}
+
+test ResetNotification {
+ "\x60\x00\x1f\x02\x01\x20\x02\x1a\x05\x03\x03\x06\x88\x97\x01\x06\x00\x00\x44\x64\xd6\x00\x00\xec\x10\x00\x00\x00\x01\x00\x00\xee\xe7\x02",
+}
+
+enum FeatureEnable : 16 {
+ RFU = 0,
+}
+
+
+enum DiscConfMode : 2 {
+ DH_ONLY = 0x0,
+ DH_AND_EE = 0x1,
+}
+
+enum FeatureState : 1 {
+ DISABLED = 0,
+ AVAILABLE = 1,
+}
+
+struct PropCaps {
+ b7 : 1,
+ b6 : 1,
+ b5 : 1,
+ b4 : 1,
+ b3 : 1,
+ b2 : 1,
+ b1 : 1,
+ b0 : 1,
+}
+
+struct NfccFeatures {
+ disc_freq_conf : FeatureState,
+ disc_conf_mode : DiscConfMode,
+ hci_net_support : FeatureState,
+ active_comm_mode : FeatureState,
+ _reserved_ : 3,
+ _reserved_: 1,
+ tech_routing : FeatureState,
+ proto_routing : FeatureState,
+ aid_routing : FeatureState,
+ syc_code_routing : FeatureState,
+ apdu_pttn_routing : FeatureState,
+ forced_nfcee_routing : FeatureState,
+ _reserved_ : 1,
+ batt_off_st : FeatureState,
+ soff_st : FeatureState,
+ swon_subst : FeatureState,
+ rf_conf_soff: FeatureState,
+ _reserved_ : 4,
+ prop_caps: PropCaps,
+}
+
+enum Intf : 8 {
+ NFCEE_DIRECT_RF = 0x00,
+ FRAME_RF = 0x01,
+ ISO_DEP_RF = 0x02,
+ NFC_DEP_RF = 0x03,
+ NDEF_RF = 0x06,
+}
+
+enum Extns : 8 {
+ FR_AGREG_RF_EXT = 0x00,
+ LLCP_SYM_RF_EXT = 0x01,
+}
+
+struct ExtList {
+ ext : Extns,
+}
+
+struct RfInterface {
+ intf : 8,
+ _size_(extns) : 8,
+ extns : 8[],
+}
+
+packet InitCommand : Command (op = CORE_INIT) {
+ feature_eneble : FeatureEnable,
+}
+
+test InitCommand {
+ "\x20\x01\x02\x00\x00",
+}
+
+packet InitResponse : Response (cmd_op = CORE_INIT) {
+ status : Status,
+ nfcc_features : NfccFeatures,
+ max_log_conns : 4, //TODO set max to 0x0E
+ _reserved_ : 4,
+ max_rout_tbls_size : 16,
+ max_ctrl_payload : 8, //TODO 32 <= val <= 255
+ max_data_payload : 8,
+ num_of_credits : 8,
+ max_nfcv_rf_frame_sz : 16,
+ _count_(rf_interface) : 8,
+ rf_interface: RfInterface[],
+}
+
+test InitResponse {
+ "\x40\x01\x18\x00\x1a\x7e\x06\x00\x01\x00\x04\xff\xff\x00\x0c\x01\x05\x01\x00\x02\x00\x03\x00\x00\x00\x90\x00",
+}
+
+enum ParamIds : 8 {
+ TOTAL_DURATION = 0x00,
+ CON_DISCOVERY_PARAM = 0x02,
+ POWER_STATE = 0x03,
+ PA_BAIL_OUT = 0x08,
+ PA_DEVICES_LIMIT = 0x09,
+ PB_AFI = 0x10,
+ PB_BAIL_OUT = 0x11,
+ PB_ATTRIB_PARAM1 = 0x12,
+ PB_SENSB_REQ_PARAM = 0x13,
+ PB_DEVICES_LIMIT = 0x14,
+ PF_BIT_RATE = 0x18,
+ PF_BAIL_OUT = 0x19,
+ PF_DEVICES_LIMIT = 0x1A,
+ PI_B_H_INFO = 0x20,
+ PI_BIT_RATE = 0x21,
+ PN_NFC_DEP_PSL = 0x28,
+ PN_ATR_REQ_GEN_BYTES = 0x29,
+ PN_ATR_REQ_CONFIG = 0x2A,
+ PV_DEVICES_LIMIT = 0x2F,
+ LA_BIT_FRAME_SDD = 0x30,
+ LA_PLATFORM_CONFIG = 0x31,
+ LA_SEL_INFO = 0x32,
+ LA_NFCID1 = 0x33,
+ LB_SENSB_INFO = 0x38,
+ LB_NFCID0 = 0x39,
+ LB_APPLICATION_DATA = 0x3A,
+ LB_SFGI = 0x3B,
+ LB_FWI_ADC_FO = 0x3C,
+ LB_BIT_RATE = 0x3E,
+ LF_T3T_IDENTIFIERS_1 = 0x40,
+ LF_T3T_IDENTIFIERS_2 = 0x41,
+ LF_T3T_IDENTIFIERS_3 = 0x42,
+ LF_T3T_IDENTIFIERS_4 = 0x43,
+ LF_T3T_IDENTIFIERS_5 = 0x44,
+ LF_T3T_IDENTIFIERS_6 = 0x45,
+ LF_T3T_IDENTIFIERS_7 = 0x46,
+ LF_T3T_IDENTIFIERS_8 = 0x47,
+ LF_T3T_IDENTIFIERS_9 = 0x48,
+ LF_T3T_IDENTIFIERS_10 = 0x49,
+ LF_T3T_IDENTIFIERS_11 = 0x4A,
+ LF_T3T_IDENTIFIERS_12 = 0x4B,
+ LF_T3T_IDENTIFIERS_13 = 0x4C,
+ LF_T3T_IDENTIFIERS_14 = 0x4D,
+ LF_T3T_IDENTIFIERS_15 = 0x4E,
+ LF_T3T_IDENTIFIERS_16 = 0x4F,
+ LF_T3T_MAX = 0x52,
+ LF_T3T_FLAGS = 0x53,
+ LF_T3T_RD_ALLOWED = 0x55,
+ LF_PROTOCOL_TYPE = 0x50,
+ LI_A_RATS_TB1 = 0x58,
+ LI_A_HIST_BY = 0x59,
+ LI_B_H_INFO_RESP = 0x5A,
+ LI_A_BIT_RATE = 0x5B,
+ LI_A_RATS_TC1 = 0x5C,
+ LN_WT = 0x60,
+ LN_ATR_RES_GEN_BYTES = 0x61,
+ LN_ATR_RES_CONFIG = 0x62,
+ PACM_BIT_RATE = 0x68,
+ RF_FIELD_INFO = 0x80,
+ RF_NFCEE_ACTION = 0x81,
+ NFCDEP_OP = 0x82,
+ LLCP_VERSION = 0x83,
+ NFCC_CONFIG_CONTROL = 0x85,
+}
+
+struct ConfigParams {
+ paramid : ParamIds,
+ _size_(valm) : 8,
+ valm : 8[],
+}
+
+struct ParamList {
+ pids : ParamIds,
+}
+
+packet SetConfigCommand : Command (op = CORE_SET_CONFIG) {
+ _count_(params) : 8,
+ params : ConfigParams[],
+}
+
+packet SetConfigResponse : Response (cmd_op = CORE_SET_CONFIG) {
+ status : Status,
+ _count_(paramids) : 8,
+ paramids : ParamList[],
+}
+
+packet GetConfigCommand : Command (op = CORE_GET_CONFIG) {
+ _count_(paramids) : 8,
+ paramids : ParamList[],
+}
+
+packet GetConfigResponse : Response (cmd_op = CORE_GET_CONFIG) {
+ status : Status,
+ _count_(params) : 8,
+ params : ConfigParams[],
+}
+
+enum RfProtocols : 8 {
+ PROTOCOL_UNDETERMINED = 0x00,
+ PROTOCOL_T1T = 0x01,
+ PROTOCOL_T2T = 0x02,
+ PROTOCOL_T3T = 0x03,
+ PROTOCOL_ISO_DEP = 0x04,
+ PROTOCOL_NFC_DEP = 0x05,
+ PROTOCOL_T5T = 0x06,
+ PROTOCOL_NDEF = 0x07,
+}
+
+enum NfceeProtocols : 8 {
+ APDU = 0x00,
+ RFU = 0x01,
+ T3CS = 0x02,
+ TRANSPARENT = 0x04,
+}
+
+enum DestTypes : 8 {
+ RFU = 0x00,
+ NFCC_LPBK = 0x01,
+ REMOTE = 0x02,
+ NFCEE = 0x03,
+}
+
+enum DestParamTypes : 8 {
+ RF_DISC = 0x00,
+ NFCEE = 0x01,
+}
+
+struct RfDiscType {
+ id : 8,
+ proto: RfProtocols,
+}
+
+struct NfceeType {
+ id : 8,
+ proto : NfceeProtocols,
+}
+
+struct DestParams {
+ ptype : DestParamTypes,
+ _size_(valdsp) : 8,
+ valdsp : 8[],
+}
+
+packet ConnCreateCommand : Command (op = CORE_CONN_CREATE) {
+ dt : DestTypes,
+ _count_(destparams) : 8,
+ destparams : DestParams[],
+}
+
+packet ConnCreateResponse : Response (cmd_op = CORE_CONN_CREATE) {
+ status : Status,
+ mpps : 8,
+ ncreds : 8,
+ conn_id : 8,
+}
+
+packet ConnCloseCommand : Command (op = CORE_CONN_CLOSE) {
+ conn_id : 8,
+}
+
+packet ConnCloseResponse : Response (cmd_op = CORE_CONN_CLOSE) {
+ status : Status,
+}
+
+struct CreditsPerConn {
+ conn_id : 8,
+ ncredits : 8,
+}
+
+packet ConnCreditsNotification : Notification (cmd_op = CORE_CONN_CREDITS) {
+ _count_(conns) : 8,
+ conns : CreditsPerConn[],
+}
+
+packet GenericError : Notification (cmd_op = CORE_GENERIC_ERROR) {
+ status : Status,
+}
+
+packet InterfaceError : Notification (cmd_op = CORE_INTERFACE_ERROR) {
+ status : Status,
+ conn_id : 8,
+}
+
diff --git a/src/nfa/dm/nfa_dm_act.cc b/src/nfa/dm/nfa_dm_act.cc
index e89ff94..51c841d 100644
--- a/src/nfa/dm/nfa_dm_act.cc
+++ b/src/nfa/dm/nfa_dm_act.cc
@@ -36,9 +36,10 @@
#if (NFC_NFCEE_INCLUDED == TRUE)
#include "nfa_ee_int.h"
-
#endif
+#include "nfc_int.h"
+
#if (NFA_SNEP_INCLUDED == TRUE)
#include "nfa_snep_int.h"
#endif
@@ -950,6 +951,14 @@
poll_disc_mask |= NFA_DM_DISC_MASK_P_KOVIO;
}
+ if (!(nfc_cb.nci_interfaces & (1 << NCI_INTERFACE_NFC_DEP))) {
+ /* Remove NFC-DEP related Discovery mask, if NFC_DEP interface is not
+ * supported */
+ poll_disc_mask &=
+ ~(NFA_DM_DISC_MASK_PACM_NFC_DEP | NFA_DM_DISC_MASK_PAA_NFC_DEP |
+ NFA_DM_DISC_MASK_PFA_NFC_DEP | NFA_DM_DISC_MASK_PF_NFC_DEP);
+ }
+
nfa_dm_cb.poll_disc_handle = nfa_dm_add_rf_discover(
poll_disc_mask, NFA_DM_DISC_HOST_ID_DH, nfa_dm_poll_disc_cback);
diff --git a/src/nfa/dm/nfa_dm_api.cc b/src/nfa/dm/nfa_dm_api.cc
index 20b1730..87f6e80 100644
--- a/src/nfa/dm/nfa_dm_api.cc
+++ b/src/nfa/dm/nfa_dm_api.cc
@@ -760,7 +760,8 @@
DLOG_IF(INFO, nfc_debug_enabled) << __func__;
/* Post the API message */
- p_msg = (tNFA_DM_API_SET_RF_DISC_DUR*)GKI_getbuf(sizeof(NFC_HDR));
+ p_msg = (tNFA_DM_API_SET_RF_DISC_DUR*)GKI_getbuf(
+ sizeof(tNFA_DM_API_SET_RF_DISC_DUR));
if (p_msg != nullptr) {
p_msg->hdr.event = NFA_DM_API_SET_RF_DISC_DURATION_EVT;
diff --git a/src/nfa/ee/nfa_ee_act.cc b/src/nfa/ee/nfa_ee_act.cc
index 5d22fb5..cc2c904 100644
--- a/src/nfa/ee/nfa_ee_act.cc
+++ b/src/nfa/ee/nfa_ee_act.cc
@@ -30,6 +30,7 @@
#include "nfa_dm_int.h"
#include "nfa_ee_int.h"
#include "nfa_hci_int.h"
+#include "nfc_int.h"
#include <statslog.h>
#include "metrics.h"
@@ -383,11 +384,16 @@
}
if (p_cb->nfcee_id == NFC_DH_ID &&
nfa_ee_proto_mask_list[xx] == NFA_PROTOCOL_MASK_NFC_DEP) {
- /* add NFC-DEP routing to HOST */
- add_route_tech_proto_tlv(&pp, NFC_ROUTE_TAG_PROTO, NFC_DH_ID,
- NCI_ROUTE_PWR_STATE_ON, NFC_PROTOCOL_NFC_DEP);
- DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf("%s - NFC DEP added for DH!!!", __func__);
+ /* add NFC-DEP routing to HOST if NFC_DEP interface is supported */
+ if (nfc_cb.nci_interfaces & (1 << NCI_INTERFACE_NFC_DEP)) {
+ add_route_tech_proto_tlv(&pp, NFC_ROUTE_TAG_PROTO, NFC_DH_ID,
+ NCI_ROUTE_PWR_STATE_ON,
+ NFC_PROTOCOL_NFC_DEP);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - NFC DEP added for DH!!!", __func__);
+ } else {
+ continue;
+ }
} else {
add_route_tech_proto_tlv(&pp, proto_tag, p_cb->nfcee_id, power_cfg,
nfa_ee_proto_list[xx]);
@@ -1310,7 +1316,7 @@
/* report NFA_EE_REMOVE_AID_EVT to the callback associated the NFCEE */
p_cback = p_cb->p_ee_cback;
} else {
- LOG(ERROR) << StringPrintf(
+ LOG(WARNING) << StringPrintf(
"nfa_ee_api_remove_aid The AID entry is not in the database");
evt_data.status = NFA_STATUS_INVALID_PARAM;
}
@@ -2165,8 +2171,8 @@
/* Start routing table update debounce timer */
nfa_ee_start_timer();
}
- LOG(ERROR) << StringPrintf("%s p_rsp->status:0x%02x", __func__,
- p_rsp->status);
+ LOG(WARNING) << StringPrintf("%s p_rsp->status:0x%02x", __func__,
+ p_rsp->status);
if (p_rsp->status == NFA_STATUS_OK) {
if (p_rsp->mode == NFA_EE_MD_ACTIVATE) {
p_cb->ee_status = NFC_NFCEE_STATUS_ACTIVE;
diff --git a/src/nfa/ee/nfa_ee_api.cc b/src/nfa/ee/nfa_ee_api.cc
index 12b5844..428ac21 100644
--- a/src/nfa/ee/nfa_ee_api.cc
+++ b/src/nfa/ee/nfa_ee_api.cc
@@ -127,6 +127,9 @@
p_info->ee_status = p_cb->ee_status;
p_info->num_interface = p_cb->num_interface;
p_info->num_tlvs = p_cb->num_tlvs;
+ p_info->la_protocol = p_cb->la_protocol;
+ p_info->lb_protocol = p_cb->lb_protocol;
+ p_info->lf_protocol = p_cb->lf_protocol;
memcpy(p_info->ee_interface, p_cb->ee_interface, p_cb->num_interface);
memcpy(p_info->ee_tlv, p_cb->ee_tlv, p_cb->num_tlvs * sizeof(tNFA_EE_TLV));
p_info->ee_power_supply_status = p_cb->ee_power_supply_status;
diff --git a/src/nfa/include/nfa_ee_api.h b/src/nfa/include/nfa_ee_api.h
index 30a0867..ec9b20a 100644
--- a/src/nfa/include/nfa_ee_api.h
+++ b/src/nfa/include/nfa_ee_api.h
@@ -119,6 +119,9 @@
uint8_t num_tlvs; /* number of TLVs */
tNFA_EE_TLV ee_tlv[NFC_MAX_EE_TLVS]; /* the TLV */
uint8_t ee_power_supply_status; /* The NFCEE Power supply */
+ tNFA_NFC_PROTOCOL la_protocol; /* Listen A protocol */
+ tNFA_NFC_PROTOCOL lb_protocol; /* Listen B protocol */
+ tNFA_NFC_PROTOCOL lf_protocol; /* Listen F protocol */
} tNFA_EE_INFO;
typedef struct {
diff --git a/src/nfa/rw/nfa_rw_act.cc b/src/nfa/rw/nfa_rw_act.cc
index 3ed8c7c..4721b68 100644
--- a/src/nfa/rw/nfa_rw_act.cc
+++ b/src/nfa/rw/nfa_rw_act.cc
@@ -776,7 +776,7 @@
break;
case RW_T2T_TLV_DETECT_EVT: /* Lock control/Mem/Prop tlv detection complete
- */
+ */
nfa_rw_handle_tlv_detect(p_rw_data);
break;
@@ -1699,8 +1699,7 @@
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);
+ status = RW_T4tUpdateNDef(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,
@@ -1793,8 +1792,8 @@
} 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 */
+ * 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 */
@@ -2715,8 +2714,23 @@
/* 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 */
+ if (!appl_dta_mode_flag) {
+ 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;
+ }
+ } else {
nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING;
activate_notify = true;
@@ -2725,10 +2739,6 @@
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;
}
}
}
diff --git a/src/nfc/include/nfc_int.h b/src/nfc/include/nfc_int.h
index f357965..5ecc879 100644
--- a/src/nfc/include/nfc_int.h
+++ b/src/nfc/include/nfc_int.h
@@ -199,6 +199,8 @@
bool reassembly; /* Reassemble fragmented data pkt */
uint8_t last_hdr[NFC_SAVED_HDR_SIZE]; /* part of last NCI command header */
uint8_t last_cmd[NFC_SAVED_CMD_SIZE]; /* part of last NCI command payload */
+ uint8_t
+ last_nfcee_cmd[NFC_SAVED_CMD_SIZE]; /* part of last NCI command payload */
void* p_vsc_cback; /* the callback function for last VSC command */
BUFFER_Q nci_cmd_xmit_q; /* NCI command queue */
TIMER_LIST_ENT
diff --git a/src/nfc/include/rw_api.h b/src/nfc/include/rw_api.h
index 91382e3..242b568 100644
--- a/src/nfc/include/rw_api.h
+++ b/src/nfc/include/rw_api.h
@@ -936,7 +936,7 @@
** NFC_STATUS_FAILED if T4T is busy or other error
**
*******************************************************************************/
-extern tNFC_STATUS RW_T4tUpdateNDef(uint16_t length, uint8_t* p_data);
+extern tNFC_STATUS RW_T4tUpdateNDef(uint32_t length, uint8_t* p_data);
/*****************************************************************************
**
diff --git a/src/nfc/include/rw_int.h b/src/nfc/include/rw_int.h
index 9bc861a..e25f48e 100644
--- a/src/nfc/include/rw_int.h
+++ b/src/nfc/include/rw_int.h
@@ -492,6 +492,8 @@
#define RW_T3T_FL_W4_FMT_FELICA_LITE_POLL_RSP 0x10
/* Waiting for POLL response for RW_T3tSetReadOnly */
#define RW_T3T_FL_W4_SRO_FELICA_LITE_POLL_RSP 0x20
+/* Waiting for POLL response for RW_T3tPoll */
+#define RW_T3T_FL_W4_USER_POLL_RSP 0x40
typedef struct {
uint32_t cur_tout; /* Current command timeout */
@@ -538,16 +540,34 @@
/* Max data size using a single UpdateBinary. 6 bytes are for CLA, INS, P1, P2,
* Lc */
+/* Use worst case where Extended Field Coding and ODO format are used */
#define RW_T4T_MAX_DATA_PER_WRITE \
(NFC_RW_POOL_BUF_SIZE - NFC_HDR_SIZE - NCI_MSG_OFFSET_SIZE - \
- NCI_DATA_HDR_SIZE - T4T_CMD_MAX_HDR_SIZE)
+ NCI_DATA_HDR_SIZE - T4T_CMD_MAX_EXT_HDR_SIZE)
+#define RW_T4T_EXT_FIELD_CODING 0x01
+#define RW_T4T_DDO_LC_FIELD_CODING 0x02
+
+#define RW_T4T_BER_TLV_LENGTH_1_BYTE 0x01
+#define RW_T4T_BER_TLV_LENGTH_2_BYTES 0x02
+#define RW_T4T_BER_TLV_LENGTH_3_BYTES 0x03
+
+/* Minimum data header in command APDU data:
+ * ODO: 54 00 xxyyzz: tag '54' with 3-byte offset xxyyzz
+ * DDO: 53 Ld {data to be written to the ENDEF File}
+ * Ld (data length) can be 1, 2 or 3 bytes
+ */
+#define RW_T4T_ODO_DDO_HEADER_MIN_LENGTH 0x06 /* ODO + tag '53' */
+/* Ld encoded on two bytes with '81' tag and N=0 to 255
+ * for data field length coded on one byte */
+#define RW_T4T_ODO_DDO_HEADER_2BYTES_LENGTH 8 /* ODO + tag '53' + '81' + N */
/* Mandatory NDEF file control */
typedef struct {
uint16_t file_id; /* File Identifier */
- uint16_t max_file_size; /* Max NDEF file size */
+ uint32_t max_file_size; /* Max NDEF file size */
uint8_t read_access; /* read access condition */
uint8_t write_access; /* write access condition */
+ uint8_t nlen_size; /* (E)NLEN size (2 or 4 bytes) */
} tRW_T4T_NDEF_FC;
/* Capability Container */
@@ -569,10 +589,11 @@
uint8_t version; /* currently effective version */
TIMER_LIST_ENT timer; /* timeout for each API call */
- uint16_t ndef_length; /* length of NDEF data */
- uint8_t* p_update_data; /* pointer of data to update */
- uint16_t rw_length; /* remaining bytes to read/write */
- uint16_t rw_offset; /* remaining offset to read/write */
+ uint32_t ndef_length; /* length of NDEF data */
+ uint8_t* p_update_data; /* pointer of data to update */
+ uint32_t rw_length; /* remaining bytes to read/write */
+ uint32_t rw_offset; /* remaining offset to read/write */
+
NFC_HDR* p_data_to_free; /* GKI buffet to delete after done */
tRW_T4T_CC cc_file; /* Capability Container File */
@@ -589,6 +610,7 @@
uint16_t max_update_size; /* max updating size per a command */
uint16_t card_size;
uint8_t card_type;
+ uint8_t intl_flags; /* flags for internal information */
} tRW_T4T_CB;
/* RW retransmission statistics */
@@ -738,6 +760,7 @@
RW_I93_STM_M24LR64_R, /* STM M24LR64-R */
RW_I93_STM_M24LR04E_R, /* STM M24LR04E-R */
RW_I93_STM_M24LR16E_R, /* STM M24LR16E-R */
+ RW_I93_STM_M24LR16D_W, /* STM M24LR16D-W */
RW_I93_STM_M24LR64E_R, /* STM M24LR64E-R */
RW_I93_STM_ST25DV04K, /* STM ST25DV04K */
RW_I93_STM_ST25DVHIK, /* STM ST25DV 16K OR 64K */
diff --git a/src/nfc/include/tags_defs.h b/src/nfc/include/tags_defs.h
index a9b5df2..9572286 100644
--- a/src/nfc/include/tags_defs.h
+++ b/src/nfc/include/tags_defs.h
@@ -366,15 +366,24 @@
#define T4T_CMD_MIN_HDR_SIZE 4 /* CLA, INS, P1, P2 */
#define T4T_CMD_MAX_HDR_SIZE 5 /* CLA, INS, P1, P2, Lc */
+/* CLA, INS, P1, P2, Data ODO */
+#define T4T_CMD_MIN_EXT_HDR_SIZE 9
+/* CLA, INS, P1, P2, Lc, Data ODO, Le
+ * with Lc and Le coded using Extended Field Coding */
+#define T4T_CMD_MAX_EXT_HDR_SIZE 15
+
+#define T4T_VERSION_3_0 0x30 /* version 3.0 */
#define T4T_VERSION_2_0 0x20 /* version 2.0 */
#define T4T_VERSION_1_0 0x10 /* version 1.0 */
-#define T4T_MY_VERSION T4T_VERSION_2_0
+#define T4T_MY_VERSION T4T_VERSION_3_0
#define T4T_GET_MAJOR_VERSION(x) ((x) >> 4)
#define T4T_CMD_CLASS 0x00
#define T4T_CMD_INS_SELECT 0xA4
#define T4T_CMD_INS_READ_BINARY 0xB0
#define T4T_CMD_INS_UPDATE_BINARY 0xD6
+#define T4T_CMD_INS_READ_BINARY_ODO 0xB1
+#define T4T_CMD_INS_UPDATE_BINARY_ODO 0xD7
#define T4T_CMD_DES_CLASS 0x90
#define T4T_CMD_INS_GET_HW_VERSION 0x60
#define T4T_CMD_CREATE_AID 0xCA
@@ -415,6 +424,8 @@
#define T4T_VERSION_OFFSET_IN_CC 0x02
#define T4T_FC_TLV_OFFSET_IN_CC 0x07
+/* size of T(1),L(1),V(8) for extended NDEF file control */
+#define T4T_ENDEF_FC_V_FIELD_OFFSET 0x09
/* Offset of Write access byte from type field in CC */
#define T4T_FC_WRITE_ACCESS_OFFSET_IN_TLV 0x07
@@ -425,8 +436,18 @@
/* size of V(6) for file control */
#define T4T_FILE_CONTROL_LENGTH 0x06
+#define T4T_ENDEF_FILE_CONTROL_TYPE 0x06 /* Extended NDEF File Control Type */
+/* size of T(1),L(1),V(8) for extended NDEF file control */
+#define T4T_ENDEF_FILE_CONTROL_TLV_SIZE 0x0A
+/* size of V(8) for extended NDEF file control */
+#define T4T_ENDEF_FILE_CONTROL_LENGTH 0x08
+
/* read access granted without any security */
#define T4T_FC_READ_ACCESS 0x00
+/* no read access granted at all */
+#define T4T_FC_NO_READ_ACCESS 0xFF
+/* proprietary read access range start */
+#define T4T_FC_READ_ACCESS_PROP_START 0x80
/* write access granted without any security */
#define T4T_FC_WRITE_ACCESS 0x00
/* proprietary write access range start */
@@ -435,6 +456,7 @@
#define T4T_FC_NO_WRITE_ACCESS 0xFF
#define T4T_FILE_LENGTH_SIZE 0x02
+#define T4T_EFILE_LENGTH_SIZE 0x04
#define T4T_ADDI_FRAME_RESP 0xAFU
#define T4T_DES_GET_VERSION_LEN 0x09
#define T4T_SIZE_IDENTIFIER_2K 0x16U
@@ -660,7 +682,10 @@
/* IC Reference for M24LR16E-R: 01001110(b), blockSize: 4, numberBlocks: 0x200
*/
#define I93_IC_REF_STM_M24LR16E_R 0x4E
-/* IC Reference for M24LR64E-R: 01011110(b), blockSize: 4, numberBlocks: 0x800
+/* IC Reference for M24LR16D-W: 01001101(b), blockSize: 4, numberBlocks: 0x200
+ */
+#define I93_IC_REF_STM_M24LR16D_W 0x4D
+/* IC Reference for M24LR64D-W: 01011110(b), blockSize: 4, numberBlocks: 0x800
*/
#define I93_IC_REF_STM_M24LR64E_R 0x5E
/* IC Reference for ST25DV04K: 00100100(b), blockSize: 4, numberBlocks: 0x80
diff --git a/src/nfc/nci/nci_hrcv.cc b/src/nfc/nci/nci_hrcv.cc
index 6dc1ae4..7be4c21 100644
--- a/src/nfc/nci/nci_hrcv.cc
+++ b/src/nfc/nci/nci_hrcv.cc
@@ -275,6 +275,10 @@
break;
case NCI_MSG_RF_FIELD:
+ if (p_msg->len < 4) {
+ android_errorWriteLog(0x534e4554, "176582502");
+ return;
+ }
nfc_ncif_proc_rf_field_ntf(*pp);
break;
@@ -299,6 +303,10 @@
#endif
#endif
case NCI_MSG_RF_ISO_DEP_NAK_PRESENCE:
+ if (p_msg->len < 4) {
+ android_errorWriteLog(0x534e4554, "176582502");
+ return;
+ }
nfc_ncif_proc_isodep_nak_presence_check_status(*pp, true);
break;
default:
@@ -325,7 +333,7 @@
tNFC_RESPONSE_CBACK* p_cback = nfc_cb.p_resp_cback;
tNFC_RESPONSE nfc_response;
tNFC_RESPONSE_EVT event = NFC_NFCEE_INFO_REVT;
- uint8_t* p_old = nfc_cb.last_cmd;
+ uint8_t* p_old = nfc_cb.last_nfcee_cmd;
/* find the start of the NCI message and parse the NCI header */
p = (uint8_t*)(p_msg + 1) + p_msg->offset;
@@ -356,6 +364,8 @@
nfc_response.mode_set.status = *pp;
} else {
nfc_response.mode_set.status = NFC_STATUS_FAILED;
+ android_errorWriteLog(0x534e4554, "176203800");
+ return;
}
nfc_response.mode_set.nfcee_id = *p_old++;
nfc_response.mode_set.mode = *p_old++;
@@ -402,7 +412,7 @@
tNFC_RESPONSE_CBACK* p_cback = nfc_cb.p_resp_cback;
tNFC_RESPONSE nfc_response;
tNFC_RESPONSE_EVT event = NFC_NFCEE_INFO_REVT;
- uint8_t* p_old = nfc_cb.last_cmd;
+ uint8_t* p_old = nfc_cb.last_nfcee_cmd;
uint8_t xx;
uint8_t yy;
tNFC_NFCEE_TLV* p_tlv;
diff --git a/src/nfc/nfc/nfc_ncif.cc b/src/nfc/nfc/nfc_ncif.cc
index c786af1..0fc0fbf 100644
--- a/src/nfc/nfc/nfc_ncif.cc
+++ b/src/nfc/nfc/nfc_ncif.cc
@@ -282,6 +282,11 @@
ps = (uint8_t*)(p_buf + 1) + p_buf->offset;
memcpy(nfc_cb.last_hdr, ps, NFC_SAVED_HDR_SIZE);
memcpy(nfc_cb.last_cmd, ps + NCI_MSG_HDR_SIZE, NFC_SAVED_CMD_SIZE);
+ // Check first byte to check if this is an NFCEE command
+ if (*ps == ((NCI_MT_CMD << NCI_MT_SHIFT) | NCI_GID_EE_MANAGE)) {
+ memcpy(nfc_cb.last_nfcee_cmd, ps + NCI_MSG_HDR_SIZE,
+ NFC_SAVED_CMD_SIZE);
+ }
if (p_buf->layer_specific == NFC_WAIT_RSP_VSC) {
/* save the callback for NCI VSCs) */
nfc_cb.p_vsc_cback = (void*)((tNFC_NCI_VS_MSG*)p_buf)->p_cback;
@@ -1647,7 +1652,7 @@
status = *p_len > 0 ? *p++ : NCI_STATUS_FAILED;
if (*p_len > 2 && is_ntf) {
- LOG(ERROR) << StringPrintf("reset notification!!:0x%x ", status);
+ LOG(WARNING) << StringPrintf("reset notification!!:0x%x ", status);
/* clean up, if the state is OPEN
* FW does not report reset ntf right now */
if (status == NCI2_0_RESET_TRIGGER_TYPE_CORE_RESET_CMD_RECEIVED ||
@@ -1663,7 +1668,7 @@
status = NCI_STATUS_OK;
} else {
/* CORE_RESET_NTF received error case , trigger recovery*/
- DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ LOG(ERROR) << StringPrintf(
"CORE_RESET_NTF Received status nfc_state : 0x%x : 0x%x", status,
nfc_cb.nfc_state);
nfc_ncif_cmd_timeout();
@@ -2046,7 +2051,7 @@
LOG(ERROR) << StringPrintf("%s", __func__);
tNFC_RESPONSE nfc_response;
nfc_response.mode_set.status = NCI_STATUS_FAILED;
- nfc_response.mode_set.nfcee_id = *nfc_cb.last_cmd;
+ nfc_response.mode_set.nfcee_id = *nfc_cb.last_nfcee_cmd;
nfc_response.mode_set.mode = NCI_NFCEE_MD_DEACTIVATE;
tNFC_RESPONSE_CBACK* p_cback = nfc_cb.p_resp_cback;
diff --git a/src/nfc/tags/rw_i93.cc b/src/nfc/tags/rw_i93.cc
index de48f95..d4391d2 100644
--- a/src/nfc/tags/rw_i93.cc
+++ b/src/nfc/tags/rw_i93.cc
@@ -39,6 +39,7 @@
using android::base::StringPrintf;
extern bool nfc_debug_enabled;
+extern unsigned char appl_dta_mode_flag;
/* Response timeout */
#define RW_I93_TOUT_RESP 1000
@@ -109,6 +110,8 @@
p_i93->product_version = RW_I93_STM_M24LR04E_R;
else if (p_i93->ic_reference == I93_IC_REF_STM_M24LR16E_R)
p_i93->product_version = RW_I93_STM_M24LR16E_R;
+ else if (p_i93->ic_reference == I93_IC_REF_STM_M24LR16D_W)
+ p_i93->product_version = RW_I93_STM_M24LR16D_W;
else if (p_i93->ic_reference == I93_IC_REF_STM_M24LR64E_R)
p_i93->product_version = RW_I93_STM_M24LR64E_R;
else if (p_i93->ic_reference == I93_IC_REF_STM_ST25DVHIK)
@@ -361,12 +364,14 @@
** M24LR64-R: 001011xx(b), blockSize: 4, numberBlocks: 0x800
** M24LR04E-R: 01011010(b), blockSize: 4, numberBlocks: 0x80
** M24LR16E-R: 01001110(b), blockSize: 4, numberBlocks: 0x200
+ ** M24LR16D-W: 01001101(b), blockSize: 4, numberBlocks: 0x200
** M24LR64E-R: 01011110(b), blockSize: 4, numberBlocks: 0x800
*/
if ((p_i93->product_version == RW_I93_STM_M24LR16E_R) ||
+ (p_i93->product_version == RW_I93_STM_M24LR16D_W) ||
(p_i93->product_version == RW_I93_STM_M24LR64E_R)) {
/*
- ** M24LR16E-R or M24LR64E-R returns system information
+ ** M24LR16E-R or M24LR16D-W or M24LR64E-R returns system information
** without memory size, if option flag is not set.
** LRIS64K and M24LR64-R return error if option flag is not
** set.
@@ -652,11 +657,17 @@
rw_cb.tcb.i93.p_retry_cmd = nullptr;
}
+ uint16_t msg_size = sizeof(NFC_HDR) + p_msg->offset + p_msg->len;
+
rw_cb.tcb.i93.p_retry_cmd = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
- if (rw_cb.tcb.i93.p_retry_cmd) {
- memcpy(rw_cb.tcb.i93.p_retry_cmd, p_msg,
- sizeof(NFC_HDR) + p_msg->offset + p_msg->len);
+ if (rw_cb.tcb.i93.p_retry_cmd &&
+ GKI_get_pool_bufsize(NFC_RW_POOL_ID) >= msg_size) {
+ memcpy(rw_cb.tcb.i93.p_retry_cmd, p_msg, msg_size);
+ } else {
+ LOG(ERROR) << StringPrintf("Memory allocation error");
+ android_errorWriteLog(0x534e4554, "157650357");
+ return false;
}
if (NFC_SendData(NFC_RF_CONN_ID, p_msg) != NFC_STATUS_OK) {
@@ -960,8 +971,8 @@
**
** Description Send Lock Block Request to VICC
**
-** STM LRIS64K, M24LR64-R, M24LR04E-R, M24LR16E-R, M24LR64E-R
-** do not support.
+** STM LRIS64K, M24LR64-R, M24LR04E-R, M24LR16E-R, M24LR64E-R,
+** M24LR16D-W do not support.
**
** Returns tNFC_STATUS
**
@@ -1678,7 +1689,8 @@
}
if (p_i93->uid[1] == I93_UID_IC_MFG_CODE_STM) {
- /* LRIS64K, M24LR64-R, M24LR04E-R, M24LR16E-R, M24LR64E-R requires
+ /* LRIS64K, M24LR64-R, M24LR04E-R, M24LR16E-R, M24LR16D-W, M24LR64E-R
+ ** require
** - The max number of blocks is 32 and they are all located in the
** same sector.
** - The sector is 32 blocks of 4 bytes.
@@ -1687,6 +1699,7 @@
(p_i93->product_version == RW_I93_STM_M24LR64_R) ||
(p_i93->product_version == RW_I93_STM_M24LR04E_R) ||
(p_i93->product_version == RW_I93_STM_M24LR16E_R) ||
+ (p_i93->product_version == RW_I93_STM_M24LR16D_W) ||
(p_i93->product_version == RW_I93_STM_M24LR64E_R)) {
if (num_block > I93_STM_MAX_BLOCKS_PER_READ)
num_block = I93_STM_MAX_BLOCKS_PER_READ;
@@ -2274,6 +2287,9 @@
if (p_resp->len > 0) {
(*(rw_cb.p_cback))(RW_I93_NDEF_READ_EVT, &rw_data);
+ } else {
+ // free buffer, if len == 0
+ GKI_freebuf(p_resp);
}
/* this will make read data from next block */
@@ -3957,8 +3973,10 @@
if (rw_cb.tcb.i93.uid[0] != I93_UID_FIRST_BYTE) {
status = rw_i93_send_cmd_inventory(nullptr, false, 0x00);
sub_state = RW_I93_SUBSTATE_WAIT_UID;
- } else if ((rw_cb.tcb.i93.num_block == 0) ||
- (rw_cb.tcb.i93.block_size == 0)) {
+
+ } else if (((rw_cb.tcb.i93.num_block == 0) ||
+ (rw_cb.tcb.i93.block_size == 0)) &&
+ (!appl_dta_mode_flag)) {
status =
rw_i93_send_cmd_get_sys_info(rw_cb.tcb.i93.uid, I93_FLAG_PROT_EXT_NO);
sub_state = RW_I93_SUBSTATE_WAIT_SYS_INFO;
@@ -4417,6 +4435,8 @@
return "M24LR04E";
case RW_I93_STM_M24LR16E_R:
return "M24LR16E";
+ case RW_I93_STM_M24LR16D_W:
+ return "M24LR16D-W";
case RW_I93_STM_M24LR64E_R:
return "M24LR64E";
case RW_I93_STM_ST25DV04K:
diff --git a/src/nfc/tags/rw_main.cc b/src/nfc/tags/rw_main.cc
index 071b966..abd8bbe 100644
--- a/src/nfc/tags/rw_main.cc
+++ b/src/nfc/tags/rw_main.cc
@@ -34,6 +34,7 @@
#include "bt_types.h"
#include "nci_hmsgs.h"
#include "nfc_api.h"
+#include "nfc_int.h"
#include "rw_api.h"
#include "rw_int.h"
@@ -220,6 +221,38 @@
return (NFC_STATUS_FAILED);
}
+ switch (rw_cb.tcb_type) {
+ case RW_CB_TYPE_T1T: {
+ nfc_stop_quick_timer(&rw_cb.tcb.t1t.timer);
+ break;
+ }
+ case RW_CB_TYPE_T2T: {
+ nfc_stop_quick_timer(&rw_cb.tcb.t2t.t2_timer);
+ break;
+ }
+ case RW_CB_TYPE_T3T: {
+ nfc_stop_quick_timer(&rw_cb.tcb.t3t.timer);
+ nfc_stop_quick_timer(&rw_cb.tcb.t3t.poll_timer);
+ break;
+ }
+ case RW_CB_TYPE_T4T: {
+ nfc_stop_quick_timer(&rw_cb.tcb.t4t.timer);
+ break;
+ }
+ case RW_CB_TYPE_T5T: {
+ nfc_stop_quick_timer(&rw_cb.tcb.i93.timer);
+ break;
+ }
+ case RW_CB_TYPE_MIFARE: {
+ nfc_stop_quick_timer(&rw_cb.tcb.mfc.timer);
+ nfc_stop_quick_timer(&rw_cb.tcb.mfc.mfc_timer);
+ break;
+ }
+ case RW_CB_TYPE_UNKNOWN: {
+ break;
+ }
+ }
+
/* Reset tag-specific area of control block */
memset(&rw_cb.tcb, 0, sizeof(tRW_TCB));
diff --git a/src/nfc/tags/rw_mfc.cc b/src/nfc/tags/rw_mfc.cc
index a77ac63..8803f2d 100644
--- a/src/nfc/tags/rw_mfc.cc
+++ b/src/nfc/tags/rw_mfc.cc
@@ -22,6 +22,7 @@
******************************************************************************/
#include <android-base/stringprintf.h>
#include <base/logging.h>
+#include <log/log.h>
#include <string.h>
#include "bt_types.h"
#include "nfc_target.h"
@@ -693,7 +694,9 @@
}
if ((p_mfc->state != RW_MFC_STATE_IDLE) && (mfc_data == NULL)) {
- LOG(ERROR) << StringPrintf("%s NULL pointer", __func__);
+ if (p_mfc->state != RW_MFC_STATE_NOT_ACTIVATED) {
+ LOG(ERROR) << StringPrintf("%s NULL pointer", __func__);
+ }
return;
}
@@ -1004,6 +1007,7 @@
NFC_HDR* mfc_data;
uint16_t len;
uint16_t offset;
+ uint16_t saved_length;
bool failed = false;
bool done = false;
tRW_READ_DATA evt_data;
@@ -1025,6 +1029,7 @@
/* On the first read, adjust for any partial block offset */
offset = 0;
len = RW_MFC_1K_BLOCK_SIZE;
+ saved_length = p_mfc->ndef_length;
if (p_mfc->work_offset == 0) {
/* The Ndef Message offset may be present in the read 16 bytes */
@@ -1036,14 +1041,18 @@
}
}
- /* Skip all reserved and lock bytes */
- while ((offset < len) && (p_mfc->work_offset < p_mfc->ndef_length))
+ if (!failed && saved_length >= p_mfc->ndef_length) {
+ /* Skip all reserved and lock bytes */
+ while ((offset < len) && (p_mfc->work_offset < p_mfc->ndef_length))
- {
- /* Collect the NDEF Message */
- p_mfc->p_ndef_buffer[p_mfc->work_offset] = p[offset];
- p_mfc->work_offset++;
- offset++;
+ {
+ /* Collect the NDEF Message */
+ p_mfc->p_ndef_buffer[p_mfc->work_offset] = p[offset];
+ p_mfc->work_offset++;
+ offset++;
+ }
+ } else {
+ android_errorWriteLog(0x534e4554, "178725766");
}
if (p_mfc->work_offset >= p_mfc->ndef_length) {
diff --git a/src/nfc/tags/rw_t3t.cc b/src/nfc/tags/rw_t3t.cc
index 7a4f9a4..0e91498 100644
--- a/src/nfc/tags/rw_t3t.cc
+++ b/src/nfc/tags/rw_t3t.cc
@@ -248,6 +248,14 @@
/* For GetSystemCode: tag did not respond to requested POLL */
rw_t3t_handle_get_system_codes_cplt();
return;
+ } else if ((p_cb->flags & (RW_T3T_FL_W4_PRESENCE_CHECK_POLL_RSP |
+ RW_T3T_FL_W4_GET_SC_POLL_RSP |
+ RW_T3T_FL_W4_FMT_FELICA_LITE_POLL_RSP |
+ RW_T3T_FL_W4_SRO_FELICA_LITE_POLL_RSP |
+ RW_T3T_FL_W4_NDEF_DETECT_POLL_RSP |
+ RW_T3T_FL_W4_USER_POLL_RSP))) {
+ /* Tag did not respond correctly to requested POLL */
+ return;
}
/* Retry sending command if retry-count < max */
else if (rw_cb.cur_retry < RW_MAX_RETRIES) {
@@ -271,8 +279,7 @@
p_cb->cur_tout);
return;
} else {
- /* failure - could not send buffer */
- GKI_freebuf(p_cmd_buf);
+ android_errorWriteLog(0x534e4554, "179687208");
}
}
} else {
@@ -368,6 +375,7 @@
rw_t3t_handle_ndef_detect_poll_rsp(p_cb, nci_status, num_responses);
} else {
/* Handle POLL ntf in response to RW_T3tPoll */
+ p_cb->flags &= ~RW_T3T_FL_W4_USER_POLL_RSP;
evt_data.t3t_poll.status = nci_status;
if (evt_data.t3t_poll.status == NCI_STATUS_OK) {
evt_data.t3t_poll.rc = p_cb->cur_poll_rc;
@@ -2844,6 +2852,7 @@
/* start timer for waiting for responses */
p_cb->cur_poll_rc = rc;
p_cb->rw_state = RW_T3T_STATE_COMMAND_PENDING;
+ p_cb->flags |= RW_T3T_FL_W4_USER_POLL_RSP;
rw_t3t_start_poll_timer(p_cb);
}
diff --git a/src/nfc/tags/rw_t4t.cc b/src/nfc/tags/rw_t4t.cc
index b7b6144..e5d3ef2 100644
--- a/src/nfc/tags/rw_t4t.cc
+++ b/src/nfc/tags/rw_t4t.cc
@@ -39,6 +39,7 @@
using android::base::StringPrintf;
extern bool nfc_debug_enabled;
+extern unsigned char appl_dta_mode_flag;
/* main state */
/* T4T is not activated */
@@ -78,7 +79,8 @@
#define RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN 0x07
/* waiting for response of updating CC */
#define RW_T4T_SUBSTATE_WAIT_UPDATE_CC 0x08
-
+/* waiting for response of reading CC */
+#define RW_T4T_SUBSTATE_WAIT_ENDEF_FILE_CTRL_TLV 0x11
#define RW_T4T_SUBSTATE_WAIT_GET_HW_VERSION 0x09
#define RW_T4T_SUBSTATE_WAIT_GET_SW_VERSION 0x0A
#define RW_T4T_SUBSTATE_WAIT_GET_UID 0x0B
@@ -93,9 +95,9 @@
static bool rw_t4t_send_to_lower(NFC_HDR* p_c_apdu);
static bool rw_t4t_select_file(uint16_t file_id);
-static bool rw_t4t_read_file(uint16_t offset, uint16_t length,
+static bool rw_t4t_read_file(uint32_t offset, uint32_t length,
bool is_continue);
-static bool rw_t4t_update_nlen(uint16_t ndef_len);
+static bool rw_t4t_update_nlen(uint32_t ndef_len);
static bool rw_t4t_update_file(void);
static bool rw_t4t_update_cc_to_readonly(void);
static bool rw_t4t_select_application(uint8_t version);
@@ -141,6 +143,159 @@
/*******************************************************************************
**
+** Function rw_t4t_set_ber_tlv
+**
+** Description Send UpdateBinary Command with ODO and DDO
+**
+** Returns TRUE if success
+**
+*******************************************************************************/
+static bool rw_t4t_set_ber_tlv(NFC_HDR* p_c_apdu, uint8_t* p, uint32_t length) {
+ tRW_T4T_CB* p_t4t = &rw_cb.tcb.t4t;
+ uint32_t data_length, tmp_length, tmp_offset;
+ uint8_t length_size, data_header = 0;
+
+ p_c_apdu->len = T4T_CMD_MIN_EXT_HDR_SIZE + 1; /* tag 53 */
+ /* Remove min data header for encoding offset and data length */
+ /* length is Lc data length */
+ /* data_length is the length of the data to be written to the ENDEF
+ * File */
+ data_length = length;
+ if (length <= 0x7F) {
+ /* Default Short Field Coding can be used */
+ /* BER-TLV length coded on one byte */
+ length_size = RW_T4T_BER_TLV_LENGTH_1_BYTE;
+
+ } else if ((length + RW_T4T_ODO_DDO_HEADER_2BYTES_LENGTH) <= 0xFF) {
+ /* Default Short Field Coding can be used */
+ /* BER-TLV length coded on two bytes: (81h+N) with N=0 to 255 */
+ length_size = RW_T4T_BER_TLV_LENGTH_2_BYTES;
+
+ } else {
+ if (p_t4t->intl_flags & RW_T4T_EXT_FIELD_CODING) {
+ /* Extended Field Coding can be used */
+ if (length <= 0xFF) {
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - Extended Field Coding used, 2-byte coding "
+ "for BER-TLV",
+ __func__);
+ /* BER-TLV length coded on two bytes still possible */
+ length_size = RW_T4T_BER_TLV_LENGTH_2_BYTES;
+
+ } else {
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - Extended Field Coding used, 3-byte coding "
+ "for BER-TLV",
+ __func__);
+ /* BER-TLV length coded on three bytes:
+ * (82h+N) with N=0 to 65535 */
+ length_size = RW_T4T_BER_TLV_LENGTH_3_BYTES;
+ }
+ } else {
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - Short Field Coding used", __func__);
+ /* Only Short Field Coding can be used */
+ /* Write a max of 255 bytes in data field,
+ * as Lc=00 is reserved for Extended Field coding */
+ /* BER-TLV length coded on two bytes */
+ length_size = RW_T4T_BER_TLV_LENGTH_2_BYTES;
+ length = 0;
+ }
+ }
+
+ data_header = RW_T4T_ODO_DDO_HEADER_MIN_LENGTH + length_size;
+ if (length == 0) {
+ length = T4T_MAX_LENGTH_LC;
+ if (length <= p_t4t->max_update_size) {
+ data_length = T4T_MAX_LENGTH_LC - data_header;
+ } else {
+ /* Realign with MLc (taking into account header now) */
+ length = p_t4t->max_update_size;
+ data_length = p_t4t->max_update_size - data_header;
+ }
+ } else {
+ if ((length + data_header) <= p_t4t->max_update_size) {
+ length += data_header;
+ } else {
+ /* Realign with MLc (taking into account header now) */
+ length = p_t4t->max_update_size;
+ data_length = p_t4t->max_update_size - data_header;
+ }
+ }
+
+ UINT8_TO_BE_STREAM(p, T4T_CMD_CLASS);
+ UINT8_TO_BE_STREAM(p, T4T_CMD_INS_UPDATE_BINARY_ODO);
+ /* P1 P2 field */
+ UINT16_TO_BE_STREAM(p, 0x0000);
+ /* Lc field */
+ if (p_t4t->intl_flags & RW_T4T_EXT_FIELD_CODING) {
+ /* Coded over three bytes */
+ UINT8_TO_BE_STREAM(p, 0x00);
+ tmp_length = length;
+ tmp_length >>= 8;
+ UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_length));
+ tmp_length = length;
+ UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_length));
+ p_c_apdu->len += 3;
+ } else {
+ /* Coded over 1 byte */
+ UINT8_TO_BE_STREAM(p, ((uint8_t)length));
+ p_c_apdu->len += 1;
+ }
+
+ /* Data field containing data offset coded over 3 bytes
+ * followed by data to be written to the ENDEF File */
+ UINT16_TO_BE_STREAM(p, 0x5403);
+ tmp_offset = p_t4t->rw_offset;
+ tmp_offset >>= 16;
+ UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_offset));
+ tmp_offset = p_t4t->rw_offset;
+ tmp_offset >>= 8;
+ UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_offset));
+ tmp_offset = p_t4t->rw_offset;
+ UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_offset));
+
+ UINT8_TO_BE_STREAM(p, 0x53);
+ /* Data length */
+ if (length_size == RW_T4T_BER_TLV_LENGTH_1_BYTE) {
+ /* Length coded over 1 byte */
+ UINT8_TO_BE_STREAM(p, data_length);
+ p_c_apdu->len += 1;
+ } else if (length_size == RW_T4T_BER_TLV_LENGTH_2_BYTES) {
+ UINT8_TO_BE_STREAM(p, 0x81);
+ UINT8_TO_BE_STREAM(p, data_length);
+ p_c_apdu->len += 2;
+ } else if ((length_size == RW_T4T_BER_TLV_LENGTH_3_BYTES) &&
+ (data_length <= 0xFFFF)) {
+ /* Length coded over 3 bytes */
+ UINT8_TO_BE_STREAM(p, 0x82);
+ UINT16_TO_BE_STREAM(p, (uint16_t)data_length);
+ p_c_apdu->len += 3;
+ } else {
+ LOG(ERROR) << StringPrintf(
+ "%s - Data to be written to MV3.0 tag exceeds 0xFFFF", __func__);
+ return false;
+ }
+
+ memcpy(p, p_t4t->p_update_data, data_length);
+
+ p_c_apdu->len += data_length;
+
+ if (!rw_t4t_send_to_lower(p_c_apdu)) {
+ return false;
+ }
+ /* Le field not present */
+
+ /* adjust offset, length and pointer for remaining data */
+ p_t4t->rw_offset += data_length;
+ p_t4t->rw_length -= data_length;
+ p_t4t->p_update_data += data_length;
+
+ return true;
+}
+
+/*******************************************************************************
+**
** Function rw_t4t_get_hw_version
**
** Description Send get hw version cmd to peer
@@ -610,12 +765,13 @@
NFC_HDR* p_c_apdu;
uint8_t* p;
- DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("File ID:0x%04X", file_id);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - File ID:0x%04X", __func__, file_id);
p_c_apdu = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
if (!p_c_apdu) {
- LOG(ERROR) << StringPrintf("Cannot allocate buffer");
+ LOG(ERROR) << StringPrintf("%s - Cannot allocate buffer", __func__);
return false;
}
@@ -627,7 +783,8 @@
UINT8_TO_BE_STREAM(p, T4T_CMD_P1_SELECT_BY_FILE_ID);
/* if current version mapping is V2.0 */
- if (rw_cb.tcb.t4t.version == T4T_VERSION_2_0) {
+ if ((rw_cb.tcb.t4t.version == T4T_VERSION_2_0) ||
+ (rw_cb.tcb.t4t.version == T4T_VERSION_3_0)) {
UINT8_TO_BE_STREAM(p, T4T_CMD_P2_FIRST_OR_ONLY_0CH);
} else /* version 1.0 */
{
@@ -655,19 +812,21 @@
** Returns TRUE if success
**
*******************************************************************************/
-static bool rw_t4t_read_file(uint16_t offset, uint16_t length,
+static bool rw_t4t_read_file(uint32_t offset, uint32_t length,
bool is_continue) {
tRW_T4T_CB* p_t4t = &rw_cb.tcb.t4t;
NFC_HDR* p_c_apdu;
uint8_t* p;
+ uint32_t tmp_offset;
- DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
- "offset:%d, length:%d, is_continue:%d, ", offset, length, is_continue);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - offset:%d, length:%d, is_continue:%d, ", __func__,
+ offset, length, is_continue);
p_c_apdu = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
if (!p_c_apdu) {
- LOG(ERROR) << StringPrintf("Cannot allocate buffer");
+ LOG(ERROR) << StringPrintf("%s - Cannot allocate buffer", __func__);
return false;
}
@@ -682,18 +841,97 @@
/* adjust reading length if payload is bigger than max size per single command
*/
if (length > p_t4t->max_read_size) {
- length = (uint8_t)(p_t4t->max_read_size);
+ length = (uint32_t)(p_t4t->max_read_size);
}
p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
p = (uint8_t*)(p_c_apdu + 1) + p_c_apdu->offset;
UINT8_TO_BE_STREAM(p, (T4T_CMD_CLASS | rw_cb.tcb.t4t.channel));
- UINT8_TO_BE_STREAM(p, T4T_CMD_INS_READ_BINARY);
- UINT16_TO_BE_STREAM(p, offset);
- UINT8_TO_BE_STREAM(p, length); /* Le */
+ if ((p_t4t->rw_offset + p_t4t->rw_length) > 0x7FFF) {
+ /* ReadBinary with ODO must be used */
+ if (p_t4t->cc_file.version >= T4T_VERSION_3_0) {
+ /* MV 3.0 tag */
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - Read above 0x7FFF address offset detected", __func__);
- p_c_apdu->len = T4T_CMD_MIN_HDR_SIZE + 1; /* adding Le */
+ p_c_apdu->len = T4T_CMD_MIN_EXT_HDR_SIZE;
+
+ UINT8_TO_BE_STREAM(p, T4T_CMD_INS_READ_BINARY_ODO);
+ /* P1 P2 field */
+ UINT16_TO_BE_STREAM(p, 0x0000);
+ /* Lc field */
+ if (p_t4t->intl_flags & RW_T4T_EXT_FIELD_CODING) {
+ /* Coded over three bytes */
+ UINT16_TO_BE_STREAM(p, 0x0000);
+ UINT8_TO_BE_STREAM(p, 0x05);
+ p_c_apdu->len += 3;
+ } else {
+ /* Coded over 1 byte */
+ UINT8_TO_BE_STREAM(p, 0x05);
+ p_c_apdu->len += 1;
+ }
+ p_t4t->intl_flags |= RW_T4T_DDO_LC_FIELD_CODING;
+
+ /* Data field containing address offset */
+ UINT16_TO_BE_STREAM(p, 0x5403);
+ tmp_offset = offset;
+ tmp_offset >>= 16;
+ UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_offset));
+ tmp_offset = offset;
+ tmp_offset >>= 8;
+ UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_offset));
+ tmp_offset = offset;
+ UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_offset));
+
+ /* Le field */
+ if (length < p_t4t->max_read_size) {
+ /* For the last R-APDU, must consider the DDO '53h' tag and data length
+ * size in the response. As difficult to know which coding will be used
+ * for BER-TLV, safer to request the remaining maximum number of bytes
+ * the tag can send */
+ length = 0x0000;
+ }
+ if (p_t4t->intl_flags & RW_T4T_EXT_FIELD_CODING) {
+ /* If Lc is coded over 3 bytes, Le is coded over 2 bytes */
+ p_c_apdu->len += 2;
+ UINT16_TO_BE_STREAM(p, length);
+ } else {
+ /* Coded over 1 byte */
+ p_c_apdu->len += 1;
+ UINT8_TO_BE_STREAM(p, length);
+ }
+ } else {
+ LOG(ERROR) << StringPrintf("%s - Cannot read above 0x7FFF for MV2.0",
+ __func__);
+ return false;
+ }
+ } else {
+ /* MV 2.0 tag or MV 3.0 tag read below 32kB */
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - Read below 0x8000 address offset detected", __func__);
+
+ UINT8_TO_BE_STREAM(p, T4T_CMD_INS_READ_BINARY);
+ /* Lc and Data fields absent */
+ UINT16_TO_BE_STREAM(p, offset);
+ if (p_t4t->intl_flags & RW_T4T_EXT_FIELD_CODING) {
+ /* Coded over three bytes with first one null */
+ p_c_apdu->len = T4T_CMD_MIN_HDR_SIZE + 3; /* adding Le */
+ UINT8_TO_BE_STREAM(p, 0x00);
+ UINT16_TO_BE_STREAM(p, length); /* Le */
+ } else {
+ /* If MLe=256 bytes, using UINT8_TO_BE_STREAM casts the length
+ * to Le=0x00 which is accepted by the specifications but not
+ * by all tags in the field. Force Le to 255 bytes to read the
+ * remaining bytes in two times
+ */
+ if (length == (T4T_MAX_LENGTH_LE + 1)) {
+ length = T4T_MAX_LENGTH_LE;
+ }
+ p_c_apdu->len = T4T_CMD_MIN_HDR_SIZE + 1; /* adding Le */
+ UINT8_TO_BE_STREAM(p, length); /* Le */
+ }
+ }
if (!rw_t4t_send_to_lower(p_c_apdu)) {
return false;
@@ -711,16 +949,18 @@
** Returns TRUE if success
**
*******************************************************************************/
-static bool rw_t4t_update_nlen(uint16_t ndef_len) {
+static bool rw_t4t_update_nlen(uint32_t ndef_len) {
+ tRW_T4T_CB* p_t4t = &rw_cb.tcb.t4t;
NFC_HDR* p_c_apdu;
uint8_t* p;
- DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("NLEN:%d", ndef_len);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - NLEN:%d", __func__, ndef_len);
p_c_apdu = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
if (!p_c_apdu) {
- LOG(ERROR) << StringPrintf("Cannot allocate buffer");
+ LOG(ERROR) << StringPrintf("%s - Cannot allocate buffer", __func__);
return false;
}
@@ -730,10 +970,14 @@
UINT8_TO_BE_STREAM(p, T4T_CMD_CLASS);
UINT8_TO_BE_STREAM(p, T4T_CMD_INS_UPDATE_BINARY);
UINT16_TO_BE_STREAM(p, 0x0000); /* offset for NLEN */
- UINT8_TO_BE_STREAM(p, T4T_FILE_LENGTH_SIZE);
- UINT16_TO_BE_STREAM(p, ndef_len);
+ UINT8_TO_BE_STREAM(p, p_t4t->cc_file.ndef_fc.nlen_size);
+ if (p_t4t->cc_file.ndef_fc.nlen_size == T4T_FILE_LENGTH_SIZE) {
+ UINT16_TO_BE_STREAM(p, ndef_len);
+ } else {
+ UINT32_TO_BE_STREAM(p, ndef_len);
+ }
- p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + T4T_FILE_LENGTH_SIZE;
+ p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + p_t4t->cc_file.ndef_fc.nlen_size;
if (!rw_t4t_send_to_lower(p_c_apdu)) {
return false;
@@ -755,48 +999,83 @@
tRW_T4T_CB* p_t4t = &rw_cb.tcb.t4t;
NFC_HDR* p_c_apdu;
uint8_t* p;
- uint16_t length;
+ uint32_t length;
- DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
- "rw_offset:%d, rw_length:%d", p_t4t->rw_offset, p_t4t->rw_length);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - rw_offset:%d, rw_length:%d", __func__,
+ p_t4t->rw_offset, p_t4t->rw_length);
p_c_apdu = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
if (!p_c_apdu) {
- LOG(ERROR) << StringPrintf("Cannot allocate buffer");
+ LOG(ERROR) << StringPrintf("%s - Cannot allocate buffer", __func__);
return false;
}
/* try to send all of remaining data */
length = p_t4t->rw_length;
+ if (length == 0) {
+ LOG(ERROR) << StringPrintf("%s - Length to write can not be null",
+ __func__);
+ return false;
+ }
+
/* adjust updating length if payload is bigger than max size per single
* command */
if (length > p_t4t->max_update_size) {
- length = (uint8_t)(p_t4t->max_update_size);
+ length = (uint32_t)(p_t4t->max_update_size);
}
p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
p = (uint8_t*)(p_c_apdu + 1) + p_c_apdu->offset;
- UINT8_TO_BE_STREAM(p, T4T_CMD_CLASS);
- UINT8_TO_BE_STREAM(p, T4T_CMD_INS_UPDATE_BINARY);
- UINT16_TO_BE_STREAM(p, p_t4t->rw_offset);
- UINT8_TO_BE_STREAM(p, length);
+ if ((p_t4t->rw_offset + p_t4t->rw_length) > 0x7FFF) {
+ /* UpdateBinary with ODO and DDO */
+ if (p_t4t->cc_file.version >= T4T_VERSION_3_0) {
+ /* MV 3.0 tag */
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - MV 3.0 detected, update NDEF Message size > 0x7FFF", __func__);
- memcpy(p, p_t4t->p_update_data, length);
+ return rw_t4t_set_ber_tlv(p_c_apdu, p, length);
- p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + length;
+ } else {
+ LOG(ERROR) << StringPrintf("%s - Cannot write above 0x7FFF for MV2.0",
+ __func__);
+ return false;
+ }
+ } else {
+ /* MV 2.0 or MV 3.0 tag */
+ /* ReadBinary with Standard Data structure used */
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - NDEF Message to write < 0x8000, MV2.0 or MV3.0 tag", __func__);
- if (!rw_t4t_send_to_lower(p_c_apdu)) {
- return false;
+ UINT8_TO_BE_STREAM(p, T4T_CMD_CLASS);
+ UINT8_TO_BE_STREAM(p, T4T_CMD_INS_UPDATE_BINARY);
+ UINT16_TO_BE_STREAM(p, p_t4t->rw_offset);
+
+ /* Lc field encoded using Short Field Coding */
+ if (length > T4T_MAX_LENGTH_LC) {
+ /* Write a max of 255 bytes,
+ * as Lc=00 is reserved for Extended Field coding */
+ length = T4T_MAX_LENGTH_LC;
+ }
+ UINT8_TO_BE_STREAM(p, length);
+
+ memcpy(p, p_t4t->p_update_data, length);
+
+ p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + length;
+
+ if (!rw_t4t_send_to_lower(p_c_apdu)) {
+ return false;
+ }
+
+ /* adjust offset, length and pointer for remaining data */
+ p_t4t->rw_offset += length;
+ p_t4t->rw_length -= length;
+ p_t4t->p_update_data += length;
}
- /* adjust offset, length and pointer for remaining data */
- p_t4t->rw_offset += length;
- p_t4t->rw_length -= length;
- p_t4t->p_update_data += length;
-
return true;
}
@@ -814,12 +1093,12 @@
uint8_t* p;
DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf("Remove Write access from CC");
+ << StringPrintf("%s - Remove Write access from CC", __func__);
p_c_apdu = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
if (!p_c_apdu) {
- LOG(ERROR) << StringPrintf("Cannot allocate buffer");
+ LOG(ERROR) << StringPrintf("%s - Cannot allocate buffer", __func__);
return false;
}
@@ -859,6 +1138,7 @@
** CLA INS P1 P2 Lc Data(AID) Le
** V1.0: 00 A4 04 00 07 D2760000850100 -
** V2.0: 00 A4 04 00 07 D2760000850101 00
+** V3.0: 00 A4 04 00 07 D2760000850101 00
**
** Returns TRUE if success
**
@@ -867,12 +1147,13 @@
NFC_HDR* p_c_apdu;
uint8_t* p;
- DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("version:0x%X", version);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - version:0x%X", __func__, version);
p_c_apdu = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
if (!p_c_apdu) {
- LOG(ERROR) << StringPrintf("Cannot allocate buffer");
+ LOG(ERROR) << StringPrintf("%s - Cannot allocate buffer", __func__);
return false;
}
@@ -891,7 +1172,8 @@
memcpy(p, t4t_v10_ndef_tag_aid, T4T_V10_NDEF_TAG_AID_LEN);
p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + T4T_V10_NDEF_TAG_AID_LEN;
- } else if (version == T4T_VERSION_2_0) /* this is for V2.0 */
+ } else if ((version == T4T_VERSION_2_0) || /* this is for V2.0 */
+ (version == T4T_VERSION_3_0)) /* this is for V3.0 */
{
UINT8_TO_BE_STREAM(p, T4T_V20_NDEF_TAG_AID_LEN);
@@ -927,61 +1209,71 @@
DLOG_IF(INFO, nfc_debug_enabled) << __func__;
if (p_t4t->cc_file.cclen < T4T_CC_FILE_MIN_LEN) {
- LOG(ERROR) << StringPrintf("CCLEN (%d) is too short", p_t4t->cc_file.cclen);
+ LOG(ERROR) << StringPrintf("%s - CCLEN (%d) is too short", __func__,
+ p_t4t->cc_file.cclen);
return false;
}
- if (T4T_GET_MAJOR_VERSION(p_t4t->cc_file.version) !=
+ if (T4T_GET_MAJOR_VERSION(p_t4t->cc_file.version) >
T4T_GET_MAJOR_VERSION(p_t4t->version)) {
LOG(ERROR) << StringPrintf(
- "Peer version (0x%02X) is matched to ours "
+ "%s - Peer version (0x%02X) mismatched to ours "
"(0x%02X)",
- p_t4t->cc_file.version, p_t4t->version);
+ __func__, p_t4t->cc_file.version, p_t4t->version);
+
return false;
}
if (p_t4t->cc_file.max_le < 0x000F) {
- LOG(ERROR) << StringPrintf("MaxLe (%d) is too small",
+ LOG(ERROR) << StringPrintf("%s - MaxLe (%d) is too small", __func__,
p_t4t->cc_file.max_le);
return false;
}
- if (p_t4t->cc_file.max_lc < 0x0001) {
- LOG(ERROR) << StringPrintf("MaxLc (%d) is too small",
+ if (p_t4t->cc_file.max_lc < 0x0001 ||
+ ((p_t4t->cc_file.max_lc < 0x000D) && appl_dta_mode_flag)) {
+ LOG(ERROR) << StringPrintf("%s - MaxLc (%d) is too small", __func__,
p_t4t->cc_file.max_lc);
return false;
}
if ((p_t4t->cc_file.ndef_fc.file_id == T4T_CC_FILE_ID) ||
(p_t4t->cc_file.ndef_fc.file_id == 0xE102) ||
- (p_t4t->cc_file.ndef_fc.file_id == 0xE103) ||
((p_t4t->cc_file.ndef_fc.file_id == 0x0000) &&
- (p_t4t->cc_file.version == 0x20)) ||
+ ((p_t4t->cc_file.version == 0x20) ||
+ (p_t4t->cc_file.version == 0x30))) ||
(p_t4t->cc_file.ndef_fc.file_id == 0x3F00) ||
(p_t4t->cc_file.ndef_fc.file_id == 0x3FFF) ||
(p_t4t->cc_file.ndef_fc.file_id == 0xFFFF)) {
- LOG(ERROR) << StringPrintf("File ID (0x%04X) is invalid",
+ LOG(ERROR) << StringPrintf("%s - File ID (0x%04X) is invalid", __func__,
p_t4t->cc_file.ndef_fc.file_id);
return false;
}
- if ((p_t4t->cc_file.ndef_fc.max_file_size < 0x0005) ||
- (p_t4t->cc_file.ndef_fc.max_file_size == 0xFFFF)) {
- LOG(ERROR) << StringPrintf("max_file_size (%d) is reserved",
+ if (((p_t4t->cc_file.version == 0x20) &&
+ ((p_t4t->cc_file.ndef_fc.max_file_size < 0x0005) ||
+ (p_t4t->cc_file.ndef_fc.max_file_size > 0x7FFF))) ||
+ ((p_t4t->cc_file.version == 0x30) &&
+ ((p_t4t->cc_file.ndef_fc.max_file_size < 0x00000007) ||
+ (p_t4t->cc_file.ndef_fc.max_file_size == 0xFFFFFFFF)))) {
+ LOG(ERROR) << StringPrintf("%s - max_file_size (%d) is reserved", __func__,
p_t4t->cc_file.ndef_fc.max_file_size);
return false;
}
- if (p_t4t->cc_file.ndef_fc.read_access != T4T_FC_READ_ACCESS) {
- LOG(ERROR) << StringPrintf("Read Access (0x%02X) is invalid",
+ if (((p_t4t->cc_file.ndef_fc.read_access > T4T_FC_READ_ACCESS) &&
+ (p_t4t->cc_file.ndef_fc.read_access < T4T_FC_READ_ACCESS_PROP_START)) ||
+ (p_t4t->cc_file.ndef_fc.read_access == T4T_FC_NO_READ_ACCESS)) {
+ LOG(ERROR) << StringPrintf("%s - Read Access (0x%02X) is invalid", __func__,
p_t4t->cc_file.ndef_fc.read_access);
return false;
}
- if ((p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS) &&
- (p_t4t->cc_file.ndef_fc.write_access < T4T_FC_WRITE_ACCESS_PROP_START)) {
- LOG(ERROR) << StringPrintf("Write Access (0x%02X) is invalid",
- p_t4t->cc_file.ndef_fc.write_access);
+ if (((p_t4t->cc_file.ndef_fc.write_access > T4T_FC_WRITE_ACCESS) &&
+ (p_t4t->cc_file.ndef_fc.write_access <
+ T4T_FC_WRITE_ACCESS_PROP_START))) {
+ LOG(ERROR) << StringPrintf("%s - Write Access (0x%02X) is invalid",
+ __func__, p_t4t->cc_file.ndef_fc.write_access);
return false;
}
@@ -1003,9 +1295,9 @@
tRW_EVENT event;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
- "status:0x%02X, sw1:0x%02X, sw2:0x%02X, "
+ "%s - status:0x%02X, sw1:0x%02X, sw2:0x%02X, "
"state:0x%X",
- status, sw1, sw2, p_t4t->state);
+ __func__, status, sw1, sw2, p_t4t->state);
nfc_stop_quick_timer(&p_t4t->timer);
@@ -1252,12 +1544,15 @@
static void rw_t4t_sm_detect_ndef(NFC_HDR* p_r_apdu) {
tRW_T4T_CB* p_t4t = &rw_cb.tcb.t4t;
uint8_t *p, type, length;
- uint16_t status_words, nlen;
+ uint32_t nlen;
+ uint32_t cc_file_offset = 0x00;
+ uint16_t status_words;
+ uint8_t cc_file_rsp_len = T4T_CC_FILE_MIN_LEN;
tRW_DATA rw_data;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
- "sub_state:%s (%d)", rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(),
- p_t4t->sub_state);
+ "%s - sub_state:%s (%d)", __func__,
+ rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(), p_t4t->sub_state);
/* get status words */
p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
@@ -1265,13 +1560,14 @@
BE_STREAM_TO_UINT16(status_words, p);
if (status_words != T4T_RSP_CMD_CMPLTED) {
- /* try V1.0 after failing of V2.0 */
+ /* try V1.0 after failing of V2.0 or V3.0 */
if ((p_t4t->sub_state == RW_T4T_SUBSTATE_WAIT_SELECT_APP) &&
- (p_t4t->version == T4T_VERSION_2_0)) {
+ ((p_t4t->version == T4T_VERSION_2_0) ||
+ (p_t4t->version == T4T_VERSION_3_0))) {
p_t4t->version = T4T_VERSION_1_0;
- DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf("retry with version=0x%02X", p_t4t->version);
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - retry with version=0x%02X", __func__, p_t4t->version);
if (!rw_t4t_select_application(T4T_VERSION_1_0)) {
rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
@@ -1298,7 +1594,8 @@
case RW_T4T_SUBSTATE_WAIT_SELECT_CC:
/* CC file has been selected then read mandatory part of CC file */
- if (!rw_t4t_read_file(0x00, T4T_CC_FILE_MIN_LEN, false)) {
+ cc_file_offset = 0x00;
+ if (!rw_t4t_read_file(cc_file_offset, cc_file_rsp_len, false)) {
rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
} else {
p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_CC_FILE;
@@ -1308,7 +1605,7 @@
case RW_T4T_SUBSTATE_WAIT_CC_FILE:
/* CC file has been read then validate and select mandatory NDEF file */
- if (p_r_apdu->len >= T4T_CC_FILE_MIN_LEN + T4T_RSP_STATUS_WORDS_SIZE) {
+ if (p_r_apdu->len >= cc_file_rsp_len + T4T_RSP_STATUS_WORDS_SIZE) {
p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
BE_STREAM_TO_UINT16(p_t4t->cc_file.cclen, p);
@@ -1327,34 +1624,107 @@
BE_STREAM_TO_UINT8(p_t4t->cc_file.ndef_fc.write_access, p);
DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf("Capability Container (CC) file");
- DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf(" CCLEN: 0x%04X", p_t4t->cc_file.cclen);
- DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf(" Version:0x%02X", p_t4t->cc_file.version);
- DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf(" MaxLe: 0x%04X", p_t4t->cc_file.max_le);
- DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf(" MaxLc: 0x%04X", p_t4t->cc_file.max_lc);
- DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf(" NDEF File Control TLV");
+ << StringPrintf("%s - Capability Container (CC) file", __func__);
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
- " FileID: 0x%04X", p_t4t->cc_file.ndef_fc.file_id);
+ "%s - CCLEN: 0x%04X", __func__, p_t4t->cc_file.cclen);
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
- " MaxFileSize: 0x%04X", p_t4t->cc_file.ndef_fc.max_file_size);
+ "%s - Version:0x%02X", __func__, p_t4t->cc_file.version);
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
- " ReadAccess: 0x%02X", p_t4t->cc_file.ndef_fc.read_access);
+ "%s - MaxLe: 0x%04X", __func__, p_t4t->cc_file.max_le);
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
- " WriteAccess: 0x%02X", p_t4t->cc_file.ndef_fc.write_access);
+ "%s - MaxLc: 0x%04X", __func__, p_t4t->cc_file.max_lc);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - NDEF File Control TLV", __func__);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - FileID: 0x%04X", __func__,
+ p_t4t->cc_file.ndef_fc.file_id);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - MaxFileSize: 0x%04X", __func__,
+ p_t4t->cc_file.ndef_fc.max_file_size);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - ReadAccess: 0x%02X", __func__,
+ p_t4t->cc_file.ndef_fc.read_access);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - WriteAccess: 0x%02X", __func__,
+ p_t4t->cc_file.ndef_fc.write_access);
if (rw_t4t_validate_cc_file()) {
if (!rw_t4t_select_file(p_t4t->cc_file.ndef_fc.file_id)) {
rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
} else {
+ p_t4t->cc_file.ndef_fc.nlen_size = T4T_FILE_LENGTH_SIZE;
p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE;
}
break;
}
+ } else if ((type == T4T_ENDEF_FILE_CONTROL_TYPE) &&
+ (length == T4T_ENDEF_FILE_CONTROL_LENGTH)) {
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - Capability Container (CC) file", __func__);
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - CCLEN: 0x%04X", __func__, p_t4t->cc_file.cclen);
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - Version:0x%02X", __func__, p_t4t->cc_file.version);
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - MaxLe: 0x%04X", __func__, p_t4t->cc_file.max_le);
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - MaxLc: 0x%04X", __func__, p_t4t->cc_file.max_lc);
+
+ cc_file_offset = T4T_ENDEF_FC_V_FIELD_OFFSET;
+ cc_file_rsp_len = T4T_ENDEF_FILE_CONTROL_TLV_SIZE - 2;
+
+ /* CC file has been selected then now read from control TLV area part
+ * of CC file */
+ /* assume ENDEF Ctrl TLV is the first one */
+ /* read again the TLV as 2 bytes missing */
+ if (!rw_t4t_read_file(cc_file_offset, cc_file_rsp_len, false)) {
+ rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
+ } else {
+ p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_ENDEF_FILE_CTRL_TLV;
+ }
+ break;
+ }
+ }
+
+ /* invalid response or CC file */
+ p_t4t->ndef_status &= ~(RW_T4T_NDEF_STATUS_NDEF_DETECTED);
+ rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+ break;
+
+ case RW_T4T_SUBSTATE_WAIT_ENDEF_FILE_CTRL_TLV:
+
+ if (p_r_apdu->len >=
+ T4T_ENDEF_FILE_CONTROL_LENGTH + T4T_RSP_STATUS_WORDS_SIZE) {
+ p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
+
+ BE_STREAM_TO_UINT16(p_t4t->cc_file.ndef_fc.file_id, p);
+ BE_STREAM_TO_UINT32(p_t4t->cc_file.ndef_fc.max_file_size, p);
+ BE_STREAM_TO_UINT8(p_t4t->cc_file.ndef_fc.read_access, p);
+ BE_STREAM_TO_UINT8(p_t4t->cc_file.ndef_fc.write_access, p);
+
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - ENDEF File Control TLV", __func__);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - FileID: 0x%04X", __func__,
+ p_t4t->cc_file.ndef_fc.file_id);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - MaxFileSize: 0x%08X", __func__,
+ p_t4t->cc_file.ndef_fc.max_file_size);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - ReadAccess: 0x%02X", __func__,
+ p_t4t->cc_file.ndef_fc.read_access);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - WriteAccess: 0x%02X", __func__,
+ p_t4t->cc_file.ndef_fc.write_access);
+
+ if (rw_t4t_validate_cc_file()) {
+ if (!rw_t4t_select_file(p_t4t->cc_file.ndef_fc.file_id)) {
+ rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
+ } else {
+ p_t4t->cc_file.ndef_fc.nlen_size = T4T_EFILE_LENGTH_SIZE;
+ p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE;
+ }
+ break;
}
}
@@ -1366,7 +1736,7 @@
case RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE:
/* NDEF file has been selected then read the first 2 bytes (NLEN) */
- if (!rw_t4t_read_file(0, T4T_FILE_LENGTH_SIZE, false)) {
+ if (!rw_t4t_read_file(0, p_t4t->cc_file.ndef_fc.nlen_size, false)) {
rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
} else {
p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_READ_NLEN;
@@ -1376,16 +1746,21 @@
case RW_T4T_SUBSTATE_WAIT_READ_NLEN:
/* NLEN has been read then report upper layer */
- if (p_r_apdu->len == T4T_FILE_LENGTH_SIZE + T4T_RSP_STATUS_WORDS_SIZE) {
+ if (p_r_apdu->len ==
+ p_t4t->cc_file.ndef_fc.nlen_size + T4T_RSP_STATUS_WORDS_SIZE) {
/* get length of NDEF */
p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
- BE_STREAM_TO_UINT16(nlen, p);
+ if (p_t4t->cc_file.ndef_fc.nlen_size == T4T_FILE_LENGTH_SIZE) {
+ BE_STREAM_TO_UINT16(nlen, p);
+ } else {
+ BE_STREAM_TO_UINT32(nlen, p);
+ }
- if (nlen <=
- p_t4t->cc_file.ndef_fc.max_file_size - T4T_FILE_LENGTH_SIZE) {
+ if (nlen <= p_t4t->cc_file.ndef_fc.max_file_size -
+ p_t4t->cc_file.ndef_fc.nlen_size) {
p_t4t->ndef_status = RW_T4T_NDEF_STATUS_NDEF_DETECTED;
- if (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS) {
+ if (p_t4t->cc_file.ndef_fc.write_access == T4T_FC_NO_WRITE_ACCESS) {
p_t4t->ndef_status |= RW_T4T_NDEF_STATUS_NDEF_READ_ONLY;
}
@@ -1396,9 +1771,14 @@
p_t4t->max_read_size = p_t4t->cc_file.max_le;
}
- /* Le: valid range is 0x01 to 0xFF */
- if (p_t4t->max_read_size >= T4T_MAX_LENGTH_LE) {
- p_t4t->max_read_size = T4T_MAX_LENGTH_LE;
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - max_read_size: 0x%04X", __func__,
+ p_t4t->max_read_size);
+
+ /* Le: valid range is 0x0001 to 0xFFFF */
+ if (p_t4t->max_read_size > T4T_MAX_LENGTH_LE + 1) {
+ /* Extended Field Coding supported by the tag */
+ p_t4t->intl_flags |= RW_T4T_EXT_FIELD_CODING;
}
/* Get max bytes to update per command */
@@ -1408,9 +1788,10 @@
p_t4t->max_update_size = p_t4t->cc_file.max_lc;
}
- /* Lc: valid range is 0x01 to 0xFF */
- if (p_t4t->max_update_size >= T4T_MAX_LENGTH_LC) {
- p_t4t->max_update_size = T4T_MAX_LENGTH_LC;
+ /* Lc: valid range is 0x0001 to 0xFFFF */
+ if (p_t4t->max_update_size > T4T_MAX_LENGTH_LC) {
+ /* Extended Field Coding supported by the tag */
+ p_t4t->intl_flags |= RW_T4T_EXT_FIELD_CODING;
}
p_t4t->ndef_length = nlen;
@@ -1421,7 +1802,7 @@
rw_data.ndef.protocol = NFC_PROTOCOL_ISO_DEP;
rw_data.ndef.max_size =
(uint32_t)(p_t4t->cc_file.ndef_fc.max_file_size -
- (uint16_t)T4T_FILE_LENGTH_SIZE);
+ (uint16_t)p_t4t->cc_file.ndef_fc.nlen_size);
rw_data.ndef.cur_size = nlen;
rw_data.ndef.flags = RW_NDEF_FL_SUPPORTED | RW_NDEF_FL_FORMATED;
if (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS) {
@@ -1431,23 +1812,23 @@
(*(rw_cb.p_cback))(RW_T4T_NDEF_DETECT_EVT, &rw_data);
DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf("Sent RW_T4T_NDEF_DETECT_EVT");
+ << StringPrintf("%s - Sent RW_T4T_NDEF_DETECT_EVT", __func__);
}
} else {
/* NLEN should be less than max file size */
LOG(ERROR) << StringPrintf(
- "NLEN (%d) + 2 must be <= max file "
+ "%s - NLEN (%d) + 2 must be <= max file "
"size (%d)",
- nlen, p_t4t->cc_file.ndef_fc.max_file_size);
+ __func__, nlen, p_t4t->cc_file.ndef_fc.max_file_size);
p_t4t->ndef_status &= ~(RW_T4T_NDEF_STATUS_NDEF_DETECTED);
rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
}
} else {
- /* response payload size should be T4T_FILE_LENGTH_SIZE */
+ /* response payload size should be T4T_(E)FILE_LENGTH_SIZE */
LOG(ERROR) << StringPrintf(
- "Length (%d) of R-APDU must be %d", p_r_apdu->len,
- T4T_FILE_LENGTH_SIZE + T4T_RSP_STATUS_WORDS_SIZE);
+ "%s - Length (%d) of R-APDU must be %d", __func__, p_r_apdu->len,
+ p_t4t->cc_file.ndef_fc.nlen_size + T4T_RSP_STATUS_WORDS_SIZE);
p_t4t->ndef_status &= ~(RW_T4T_NDEF_STATUS_NDEF_DETECTED);
rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
@@ -1455,7 +1836,8 @@
break;
default:
- LOG(ERROR) << StringPrintf("unknown sub_state=%d", p_t4t->sub_state);
+ LOG(ERROR) << StringPrintf("%s - unknown sub_state=%d", __func__,
+ p_t4t->sub_state);
rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
break;
}
@@ -1474,11 +1856,12 @@
tRW_T4T_CB* p_t4t = &rw_cb.tcb.t4t;
uint8_t* p;
uint16_t status_words;
+ uint16_t r_apdu_len;
tRW_DATA rw_data;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
- "sub_state:%s (%d)", rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(),
- p_t4t->sub_state);
+ "%s - sub_state:%s (%d)", __func__,
+ rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(), p_t4t->sub_state);
/* get status words */
p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
@@ -1497,46 +1880,141 @@
/* Read partial or complete data */
p_r_apdu->len -= T4T_RSP_STATUS_WORDS_SIZE;
- if ((p_r_apdu->len > 0) && (p_r_apdu->len <= p_t4t->rw_length)) {
- p_t4t->rw_length -= p_r_apdu->len;
- p_t4t->rw_offset += p_r_apdu->len;
-
- if (rw_cb.p_cback) {
- rw_data.data.status = NFC_STATUS_OK;
- rw_data.data.p_data = p_r_apdu;
-
- /* if need to read more data */
- if (p_t4t->rw_length > 0) {
- (*(rw_cb.p_cback))(RW_T4T_NDEF_READ_EVT, &rw_data);
-
- if (!rw_t4t_read_file(p_t4t->rw_offset, p_t4t->rw_length, true)) {
- rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
+ p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
+ if (p_t4t->intl_flags & RW_T4T_DDO_LC_FIELD_CODING) {
+ if (*p == 0x53) {
+ /* ReadBinary command with ODO */
+ if (*(p + 1) <= 0x7F) {
+ p_r_apdu->len -= 2;
+ p_r_apdu->offset += 2;
+ /* Content read length coded over 1 byte in 1st byte
+ * of BER-TLV length field */
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - Content read length expected: 0x%02X, returned: 0x%02X",
+ __func__, *(p + 1), p_r_apdu->len);
+ if (*(p + 1) == p_r_apdu->len) {
+ if ((p_r_apdu->len > 0) && (p_r_apdu->len <= p_t4t->rw_length)) {
+ p_t4t->rw_length -= p_r_apdu->len;
+ p_t4t->rw_offset += p_r_apdu->len;
+ }
+ } else {
+ LOG(ERROR) << StringPrintf(
+ "%s - invalid payload length (%d), rw_length (%d)", __func__,
+ p_r_apdu->len, p_t4t->rw_length);
+ rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+ break;
+ }
+ } else if (*(p + 1) == 0x81) {
+ if (*(p + 2) <= 0xFD) {
+ p_r_apdu->len -= 3;
+ p_r_apdu->offset += 3;
+ /* Content read length coded over 1 byte in 2nd byte
+ * of BER-TLV length field */
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - Content read length expected: 0x%02X, returned: 0x%02X",
+ __func__, *(p + 2), p_r_apdu->len);
+ if (*(p + 2) == p_r_apdu->len) {
+ if ((p_r_apdu->len > 0) &&
+ (p_r_apdu->len <= p_t4t->rw_length)) {
+ p_t4t->rw_length -= p_r_apdu->len;
+ p_t4t->rw_offset += p_r_apdu->len;
+ }
+ } else {
+ LOG(ERROR) << StringPrintf(
+ "%s - invalid payload length (%d), rw_length "
+ "(%d)",
+ __func__, p_r_apdu->len, p_t4t->rw_length);
+ rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+ break;
+ }
+ } else {
+ LOG(ERROR) << StringPrintf(
+ "%s - invalid DDO length content length received (1)",
+ __func__);
+ rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+ break;
+ }
+ } else if (*(p + 1) == 0x82) {
+ /* Content read length coded over 2 bytes in 2nd and 3rd bytes
+ * of BER-TLV length field*/
+ r_apdu_len = (uint16_t)(*(p + 2) << 8);
+ r_apdu_len |= (uint8_t) * (p + 3);
+ if (r_apdu_len <= (p_t4t->max_read_size - 4)) {
+ p_r_apdu->len -= 4;
+ p_r_apdu->offset += 4;
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - Content read length expected: 0x%02X%02X, returned: "
+ "0x%02X%02X ",
+ __func__, *(p + 3), *(p + 2), (uint8_t)(p_r_apdu->len >> 8),
+ (uint8_t)p_r_apdu->len);
+ if (r_apdu_len == p_r_apdu->len) {
+ if ((p_r_apdu->len > 0) &&
+ (p_r_apdu->len <= p_t4t->rw_length)) {
+ p_t4t->rw_length -= p_r_apdu->len;
+ p_t4t->rw_offset += p_r_apdu->len;
+ }
+ } else {
+ LOG(ERROR) << StringPrintf(
+ "%s - invalid payload length (%d), rw_length "
+ "(%d)",
+ __func__, p_r_apdu->len, p_t4t->rw_length);
+ rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+ break;
+ }
}
} else {
- p_t4t->state = RW_T4T_STATE_IDLE;
-
- (*(rw_cb.p_cback))(RW_T4T_NDEF_READ_CPLT_EVT, &rw_data);
-
- DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf("Sent RW_T4T_NDEF_READ_CPLT_EVT");
+ LOG(ERROR) << StringPrintf(
+ "%s - invalid DDO length content length received (2)",
+ __func__);
+ rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+ break;
}
-
- p_r_apdu = nullptr;
} else {
- p_t4t->rw_length = 0;
- p_t4t->state = RW_T4T_STATE_IDLE;
+ LOG(ERROR) << StringPrintf("%s - invalid DDO tag", __func__);
+ rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+ break;
}
+ } else if ((p_r_apdu->len > 0) && (p_r_apdu->len <= p_t4t->rw_length)) {
+ p_t4t->rw_length -= p_r_apdu->len;
+ p_t4t->rw_offset += p_r_apdu->len;
} else {
LOG(ERROR) << StringPrintf(
- "invalid payload length (%d), rw_length "
+ "%s - invalid payload length (%d), rw_length "
"(%d)",
- p_r_apdu->len, p_t4t->rw_length);
+ __func__, p_r_apdu->len, p_t4t->rw_length);
rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+ break;
+ }
+ if (rw_cb.p_cback) {
+ rw_data.data.status = NFC_STATUS_OK;
+ rw_data.data.p_data = p_r_apdu;
+
+ /* if need to read more data */
+ if (p_t4t->rw_length > 0) {
+ (*(rw_cb.p_cback))(RW_T4T_NDEF_READ_EVT, &rw_data);
+
+ if (!rw_t4t_read_file(p_t4t->rw_offset, p_t4t->rw_length, true)) {
+ rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
+ }
+ } else {
+ p_t4t->state = RW_T4T_STATE_IDLE;
+
+ (*(rw_cb.p_cback))(RW_T4T_NDEF_READ_CPLT_EVT, &rw_data);
+
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - Sent RW_T4T_NDEF_READ_CPLT_EVT", __func__);
+ }
+
+ p_r_apdu = nullptr;
+ } else {
+ p_t4t->rw_length = 0;
+ p_t4t->state = RW_T4T_STATE_IDLE;
}
break;
default:
- LOG(ERROR) << StringPrintf("unknown sub_state = %d", p_t4t->sub_state);
+ LOG(ERROR) << StringPrintf("%s - unknown sub_state = %d", __func__,
+ p_t4t->sub_state);
rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
break;
}
@@ -1560,8 +2038,8 @@
tRW_DATA rw_data;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
- "sub_state:%s (%d)", rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(),
- p_t4t->sub_state);
+ "%s - sub_state:%s (%d)", __func__,
+ rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(), p_t4t->sub_state);
/* Get status words */
p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
@@ -1593,8 +2071,8 @@
rw_data.status = NFC_STATUS_OK;
(*(rw_cb.p_cback))(RW_T4T_NDEF_UPDATE_CPLT_EVT, &rw_data);
- DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf("Sent RW_T4T_NDEF_UPDATE_CPLT_EVT");
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+ "%s - Sent RW_T4T_NDEF_UPDATE_CPLT_EVT", __func__);
}
}
break;
@@ -1620,7 +2098,8 @@
break;
default:
- LOG(ERROR) << StringPrintf("unknown sub_state = %d", p_t4t->sub_state);
+ LOG(ERROR) << StringPrintf("%s - unknown sub_state = %d", __func__,
+ p_t4t->sub_state);
rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
break;
}
@@ -1642,8 +2121,8 @@
tRW_DATA rw_data;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
- "sub_state:%s (%d)", rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(),
- p_t4t->sub_state);
+ "%s - sub_state:%s (%d)", __func__,
+ rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(), p_t4t->sub_state);
/* Get status words */
p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
@@ -1687,13 +2166,14 @@
rw_data.status = NFC_STATUS_OK;
DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf("Sent RW_T4T_SET_TO_RO_EVT");
+ << StringPrintf("%s - Sent RW_T4T_SET_TO_RO_EVT", __func__);
(*(rw_cb.p_cback))(RW_T4T_SET_TO_RO_EVT, &rw_data);
}
break;
default:
- LOG(ERROR) << StringPrintf("unknown sub_state = %d", p_t4t->sub_state);
+ LOG(ERROR) << StringPrintf("%s - unknown sub_state = %d", __func__,
+ p_t4t->sub_state);
rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
break;
}
@@ -1757,7 +2237,8 @@
uint8_t begin_state = p_t4t->state;
- DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("event = 0x%X", event);
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - event = 0x%X", __func__, event);
nfc_stop_quick_timer(&p_t4t->timer);
switch (event) {
@@ -1794,8 +2275,8 @@
}
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
- "RW T4T state: <%s (%d)>", rw_t4t_get_state_name(p_t4t->state).c_str(),
- p_t4t->state);
+ "%s - RW T4T state: <%s (%d)>", __func__,
+ rw_t4t_get_state_name(p_t4t->state).c_str(), p_t4t->state);
if (p_t4t->state != RW_T4T_STATE_IDLE &&
p_t4t->state != RW_T4T_STATE_PRESENCE_CHECK &&
@@ -1812,8 +2293,8 @@
/* Unexpected R-APDU, it should be raw frame response */
/* forward to upper layer without parsing */
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
- "RW T4T Raw Frame: Len [0x%X] Status [%s]", p_r_apdu->len,
- NFC_GetStatusName(p_data->data.status).c_str());
+ "%s - RW T4T Raw Frame: Len [0x%X] Status [%s]", __func__,
+ p_r_apdu->len, NFC_GetStatusName(p_data->data.status).c_str());
if (rw_cb.p_cback) {
rw_data.raw_frame.status = p_data->data.status;
rw_data.raw_frame.p_data = p_r_apdu;
@@ -1851,14 +2332,15 @@
GKI_freebuf(p_r_apdu);
break;
default:
- LOG(ERROR) << StringPrintf("invalid state=%d", p_t4t->state);
+ LOG(ERROR) << StringPrintf("%s - invalid state=%d", __func__,
+ p_t4t->state);
GKI_freebuf(p_r_apdu);
break;
}
if (begin_state != p_t4t->state) {
DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf("RW T4T state changed:<%s> -> <%s>",
+ << StringPrintf("%s - RW T4T state changed:<%s> -> <%s>", __func__,
rw_t4t_get_state_name(begin_state).c_str(),
rw_t4t_get_state_name(p_t4t->state).c_str());
}
@@ -1939,8 +2421,8 @@
DLOG_IF(INFO, nfc_debug_enabled) << __func__;
if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE) {
- LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
- rw_cb.tcb.t4t.state);
+ LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+ __func__, rw_cb.tcb.t4t.state);
return NFC_STATUS_FAILED;
}
@@ -1984,16 +2466,16 @@
DLOG_IF(INFO, nfc_debug_enabled) << __func__;
if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE) {
- LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
- rw_cb.tcb.t4t.state);
+ LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+ __func__, rw_cb.tcb.t4t.state);
return NFC_STATUS_FAILED;
}
/* if NDEF has been detected */
if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED) {
/* start reading NDEF */
- if (!rw_t4t_read_file(T4T_FILE_LENGTH_SIZE, rw_cb.tcb.t4t.ndef_length,
- false)) {
+ if (!rw_t4t_read_file(rw_cb.tcb.t4t.cc_file.ndef_fc.nlen_size,
+ rw_cb.tcb.t4t.ndef_length, false)) {
return NFC_STATUS_FAILED;
}
@@ -2002,7 +2484,7 @@
return NFC_STATUS_OK;
} else {
- LOG(ERROR) << StringPrintf("No NDEF detected");
+ LOG(ERROR) << StringPrintf("%s - No NDEF detected", __func__);
return NFC_STATUS_FAILED;
}
}
@@ -2024,12 +2506,13 @@
** NFC_STATUS_FAILED if T4T is busy or other error
**
*******************************************************************************/
-tNFC_STATUS RW_T4tUpdateNDef(uint16_t length, uint8_t* p_data) {
- DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("length:%d", length);
+tNFC_STATUS RW_T4tUpdateNDef(uint32_t length, uint8_t* p_data) {
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s - length:%d", __func__, length);
if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE) {
- LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
- rw_cb.tcb.t4t.state);
+ LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+ __func__, rw_cb.tcb.t4t.state);
return NFC_STATUS_FAILED;
}
@@ -2037,16 +2520,16 @@
if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED) {
/* if read-only */
if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_READ_ONLY) {
- LOG(ERROR) << StringPrintf("NDEF is read-only");
+ LOG(ERROR) << StringPrintf("%s - NDEF is read-only", __func__);
return NFC_STATUS_FAILED;
}
if (rw_cb.tcb.t4t.cc_file.ndef_fc.max_file_size <
- length + T4T_FILE_LENGTH_SIZE) {
+ length + rw_cb.tcb.t4t.cc_file.ndef_fc.nlen_size) {
LOG(ERROR) << StringPrintf(
- "data (%d bytes) plus NLEN is more than max file "
+ "%s - data (%d bytes) plus NLEN is more than max file "
"size (%d)",
- length, rw_cb.tcb.t4t.cc_file.ndef_fc.max_file_size);
+ __func__, length, rw_cb.tcb.t4t.cc_file.ndef_fc.max_file_size);
return NFC_STATUS_FAILED;
}
@@ -2054,7 +2537,7 @@
rw_cb.tcb.t4t.ndef_length = length;
rw_cb.tcb.t4t.p_update_data = p_data;
- rw_cb.tcb.t4t.rw_offset = T4T_FILE_LENGTH_SIZE;
+ rw_cb.tcb.t4t.rw_offset = rw_cb.tcb.t4t.cc_file.ndef_fc.nlen_size;
rw_cb.tcb.t4t.rw_length = length;
/* set NLEN to 0x0000 for the first step */
@@ -2067,7 +2550,7 @@
return NFC_STATUS_OK;
} else {
- LOG(ERROR) << StringPrintf("No NDEF detected");
+ LOG(ERROR) << StringPrintf("%s - No NDEF detected", __func__);
return NFC_STATUS_FAILED;
}
}
@@ -2096,7 +2579,7 @@
bool status;
NFC_HDR* p_data;
- DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%d", option);
+ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s - %d", __func__, option);
/* If RW_SelectTagType was not called (no conn_callback) return failure */
if (!rw_cb.p_cback) {
@@ -2158,8 +2641,8 @@
DLOG_IF(INFO, nfc_debug_enabled) << __func__;
if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE) {
- LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
- rw_cb.tcb.t4t.state);
+ LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+ __func__, rw_cb.tcb.t4t.state);
return NFC_STATUS_FAILED;
}
@@ -2168,7 +2651,7 @@
/* if read-only */
if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_READ_ONLY) {
DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf("NDEF is already read-only");
+ << StringPrintf("%s - NDEF is already read-only", __func__);
evt_data.status = NFC_STATUS_OK;
(*rw_cb.p_cback)(RW_T4T_SET_TO_RO_EVT, &evt_data);
@@ -2185,7 +2668,7 @@
return NFC_STATUS_OK;
} else {
- LOG(ERROR) << StringPrintf("No NDEF detected");
+ LOG(ERROR) << StringPrintf("%s - No NDEF detected", __func__);
return NFC_STATUS_FAILED;
}
return (retval);
@@ -2268,6 +2751,8 @@
return "WAIT_WRITE_CC";
case RW_T4T_SUBSTATE_WAIT_WRITE_NDEF:
return "WAIT_WRITE_NDEF";
+ case RW_T4T_SUBSTATE_WAIT_ENDEF_FILE_CTRL_TLV:
+ return "WAIT_ENDEF_FILE_CTRL_TLV";
default:
return "???? UNKNOWN SUBSTATE";
}
diff --git a/src/rust/Android.bp b/src/rust/Android.bp
new file mode 100644
index 0000000..f91266d
--- /dev/null
+++ b/src/rust/Android.bp
@@ -0,0 +1,106 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "system_nfc_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["system_nfc_license"],
+}
+
+rust_defaults {
+ name: "nfc_rust_defaults",
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ host_supported: true,
+}
+
+cc_defaults {
+ name: "nfc_ffi_defaults",
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+rust_library {
+ name: "libnfc_rnci",
+ defaults: ["nfc_rust_defaults"],
+ crate_name: "nfc_rnci",
+ srcs: ["nci/nci.rs"],
+ host_supported: true,
+ rustlibs: [
+ "libnfc_packets",
+ "libnfc_hal",
+ "libtokio",
+ "libcxx",
+ "liblazy_static",
+ "liblog_rust",
+ ],
+ proc_macros: ["libnum_derive"],
+}
+
+rust_library {
+ name: "libnfc_hal",
+ defaults: ["nfc_rust_defaults"],
+ crate_name: "nfc_hal",
+ srcs: ["hal/hal.rs"],
+ host_supported: true,
+ rustlibs: [
+ "libnfc_packets",
+ "libbytes",
+ "libthiserror",
+ "libtokio",
+ "libcxx",
+ "liblazy_static",
+ "liblog_rust",
+ ],
+ proc_macros: ["libnum_derive"],
+ target: {
+ android: {
+ whole_static_libs: ["libnfc_hidl_hal_cxx"],
+ shared_libs: [
+ "android.hardware.nfc@1.0",
+ "android.hardware.nfc@1.1",
+ "android.hardware.nfc@1.2",
+ "libhidlbase",
+ "libutils",
+ ],
+ },
+ },
+}
+
+genrule {
+ name: "libnfc_hidl_hal_bridge_header",
+ tools: ["cxxbridge"],
+ cmd: "$(location cxxbridge) $(in) --header > $(out)",
+ srcs: ["hal/hidl_hal.rs"],
+ out: ["hal/hidl_hal.rs.h"],
+}
+
+genrule {
+ name: "libnfc_hidl_hal_bridge_code",
+ tools: ["cxxbridge"],
+ cmd: "$(location cxxbridge) $(in) >> $(out)",
+ srcs: ["hal/hidl_hal.rs"],
+ out: ["hidl_hal_generated.cc"],
+}
+
+cc_library_static {
+ name: "libnfc_hidl_hal_cxx",
+ defaults: ["nfc_ffi_defaults"],
+ srcs: ["hal/ffi/hidl.cc"],
+ local_include_dirs: ["hal/ffi"],
+ generated_headers: ["libnfc_hidl_hal_bridge_header", "cxx-bridge-header"],
+ generated_sources: ["libnfc_hidl_hal_bridge_code"],
+ shared_libs: [
+ "android.hardware.nfc@1.0",
+ "android.hardware.nfc@1.1",
+ "android.hardware.nfc@1.2",
+ "libhidlbase",
+ "libutils",
+ ],
+}
diff --git a/src/rust/hal/ffi/hidl.cc b/src/rust/hal/ffi/hidl.cc
new file mode 100644
index 0000000..fb3b5b3
--- /dev/null
+++ b/src/rust/hal/ffi/hidl.cc
@@ -0,0 +1,115 @@
+#include "hal/ffi/hidl.h"
+
+#include <log/log.h>
+#include <stdlib.h>
+
+using ::android::wp;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hidl::base::V1_0::IBase;
+
+using android::OK;
+using android::sp;
+using android::status_t;
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using android::hardware::nfc::V1_0::INfc;
+using INfcV1_1 = android::hardware::nfc::V1_1::INfc;
+using INfcV1_2 = android::hardware::nfc::V1_2::INfc;
+using android::hardware::nfc::V1_1::INfcClientCallback;
+
+namespace nfc {
+namespace hal {
+namespace {
+
+class NfcHalDeathRecipient : public hidl_death_recipient {
+ public:
+ virtual void serviceDied(
+ uint64_t /*cookie*/,
+ const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+ LOG_FATAL("Nfc HAL service died!");
+ abort();
+ }
+};
+
+class NfcCallbackTrampoline : public INfcClientCallback {
+ public:
+ NfcCallbackTrampoline() {}
+
+ Return<void> sendEvent_1_1(
+ ::android::hardware::nfc::V1_1::NfcEvent event,
+ ::android::hardware::nfc::V1_0::NfcStatus event_status) override {
+ on_event(event, event_status);
+ return Void();
+ }
+ Return<void> sendEvent(
+ ::android::hardware::nfc::V1_0::NfcEvent event,
+ ::android::hardware::nfc::V1_0::NfcStatus event_status) override {
+ on_event((::android::hardware::nfc::V1_1::NfcEvent)event, event_status);
+ return Void();
+ }
+
+ Return<void> sendData(const ::android::hardware::nfc::V1_0::NfcData& data) {
+ on_data(rust::Slice(&data[0], data.size()));
+ return Void();
+ }
+};
+
+android::sp<NfcHalDeathRecipient> nfc_death_recipient_;
+android::sp<INfc> nci_;
+android::sp<INfcV1_1> nci_1_1_;
+android::sp<INfcV1_2> nci_1_2_;
+android::sp<NfcCallbackTrampoline> trampoline_;
+
+} // namespace
+
+void start_hal() {
+ ALOG_ASSERT(nci_ != nullptr, "Stale value of the NCI port");
+
+ nci_ = nci_1_1_ = nci_1_2_ = INfcV1_2::getService();
+ if (nci_1_2_ == nullptr) {
+ nci_ = nci_1_1_ = INfcV1_1::getService();
+ if (nci_1_1_ == nullptr) {
+ nci_ = INfc::getService();
+ }
+ }
+ LOG_FATAL_IF(nci_ == nullptr, "Failed to retrieve the NFC HAL!");
+ ALOGI("%s: INfc::getService() returned %p (%s)", __func__, nci_.get(),
+ (nci_->isRemote() ? "remote" : "local"));
+ if (nci_) {
+ nfc_death_recipient_ = new NfcHalDeathRecipient();
+ auto death_link = nci_->linkToDeath(nfc_death_recipient_, 0);
+ ALOG_ASSERT(death_link.isOk(),
+ "Unable to set the death recipient for the Nfc HAL");
+ }
+
+ trampoline_ = new NfcCallbackTrampoline();
+ if (nci_1_1_ != nullptr) {
+ nci_1_1_->open_1_1(trampoline_);
+ } else {
+ nci_->open(trampoline_);
+ }
+}
+
+void stop_hal() {
+ ALOG_ASSERT(nci_ == nullptr, "The NCI communication was already closed");
+
+ auto death_unlink = nci_->unlinkToDeath(nfc_death_recipient_);
+ if (!death_unlink.isOk()) {
+ ALOGE("Error unlinking death recipient from the Bluetooth HAL");
+ }
+ nci_->close();
+ nci_ = nullptr;
+ nci_1_1_ = nullptr;
+ nci_1_2_ = nullptr;
+ trampoline_ = nullptr;
+}
+
+void send_command(rust::Slice<const uint8_t> data) {
+ ALOG_ASSERT(nci_ == nullptr, "The NCI communication was already closed");
+ nci_->write(hidl_vec<uint8_t>(data.data(), data.data() + data.length()));
+}
+
+} // namespace hal
+} // namespace nfc
diff --git a/src/rust/hal/ffi/hidl.h b/src/rust/hal/ffi/hidl.h
new file mode 100644
index 0000000..b4b7761
--- /dev/null
+++ b/src/rust/hal/ffi/hidl.h
@@ -0,0 +1,25 @@
+#pragma once
+#include <android/hardware/nfc/1.0/INfc.h>
+#include <android/hardware/nfc/1.1/INfc.h>
+#include <android/hardware/nfc/1.2/INfc.h>
+
+namespace nfc {
+namespace hal {
+
+using android::hardware::nfc::V1_0::NfcStatus;
+using android::hardware::nfc::V1_1::NfcEvent;
+
+} // namespace hal
+} // namespace nfc
+
+#include "hal/hidl_hal.rs.h"
+
+namespace nfc {
+namespace hal {
+
+void start_hal();
+void stop_hal();
+void send_command(rust::Slice<const uint8_t> data);
+
+} // namespace hal
+} // namespace nfc
diff --git a/src/rust/hal/hal.rs b/src/rust/hal/hal.rs
new file mode 100644
index 0000000..a1689b3
--- /dev/null
+++ b/src/rust/hal/hal.rs
@@ -0,0 +1,78 @@
+//! NCI Hardware Abstraction Layer
+//! Supports sending NCI commands to the HAL and receiving
+//! NCI events from the HAL
+
+use nfc_packets::nci::{DataPacket, NciPacket};
+use thiserror::Error;
+use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
+
+#[cfg(target_os = "android")]
+#[path = "hidl_hal.rs"]
+pub mod ihal;
+
+#[cfg(not(target_os = "android"))]
+#[path = "rootcanal_hal.rs"]
+pub mod ihal;
+
+/// HAL module interface
+pub struct Hal {
+ /// HAL outbound channel for Command messages
+ pub out_cmd_tx: UnboundedSender<NciPacket>,
+ /// HAL inbound channel for Response and Notification messages
+ pub in_cmd_rx: UnboundedReceiver<NciPacket>,
+ /// HAL outbound channel for Data messages
+ pub out_data_tx: UnboundedSender<DataPacket>,
+ /// HAL inbound channel for Data messages
+ pub in_data_rx: UnboundedReceiver<DataPacket>,
+}
+
+/// Initialize the module and connect the channels
+pub async fn init() -> Hal {
+ ihal::init().await
+}
+
+mod internal {
+ use crate::Hal;
+ use nfc_packets::nci::{DataPacket, NciPacket};
+ use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
+
+ pub struct InnerHal {
+ pub out_cmd_rx: UnboundedReceiver<NciPacket>,
+ pub in_cmd_tx: UnboundedSender<NciPacket>,
+ pub out_data_rx: UnboundedReceiver<DataPacket>,
+ pub in_data_tx: UnboundedSender<DataPacket>,
+ }
+
+ impl InnerHal {
+ pub fn new() -> (Hal, Self) {
+ let (out_cmd_tx, out_cmd_rx) = unbounded_channel();
+ let (in_cmd_tx, in_cmd_rx) = unbounded_channel();
+ let (out_data_tx, out_data_rx) = unbounded_channel();
+ let (in_data_tx, in_data_rx) = unbounded_channel();
+ (
+ Hal { out_cmd_tx, in_cmd_rx, out_data_tx, in_data_rx },
+ Self { out_cmd_rx, in_cmd_tx, out_data_rx, in_data_tx },
+ )
+ }
+ }
+}
+
+/// Is this NCI control stream or data response
+pub fn is_control_packet(data: &[u8]) -> bool {
+ // Check the MT bits
+ (data[0] >> 5) & 0x7 != 0
+}
+
+/// Result type
+type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
+
+/// Errors that can be encountered while dealing with the HAL
+#[derive(Error, Debug)]
+pub enum HalError {
+ /// Invalid rootcanal host error
+ #[error("Invalid rootcanal host")]
+ InvalidAddressError,
+ /// Error while connecting to rootcanal
+ #[error("Connection to rootcanal failed: {0}")]
+ RootcanalConnectError(#[from] tokio::io::Error),
+}
diff --git a/src/rust/hal/hidl_hal.rs b/src/rust/hal/hidl_hal.rs
new file mode 100644
index 0000000..feb3913
--- /dev/null
+++ b/src/rust/hal/hidl_hal.rs
@@ -0,0 +1,121 @@
+//! Implementation of the HAl that talks to NFC controller over Android's HIDL
+use crate::internal::InnerHal;
+#[allow(unused)]
+use crate::{is_control_packet, Hal, Result};
+use lazy_static::lazy_static;
+use log::error;
+use nfc_packets::nci::{DataPacket, NciPacket, Packet};
+use std::sync::Mutex;
+use tokio::select;
+use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
+
+/// Initialize the module
+pub async fn init() -> Hal {
+ let (raw_hal, inner_hal) = InnerHal::new();
+ let (hal_open_evt_tx, mut hal_open_evt_rx) = unbounded_channel();
+ *CALLBACKS.lock().unwrap() = Some(Callbacks {
+ hal_open_evt_tx,
+ in_cmd_tx: inner_hal.in_cmd_tx,
+ in_data_tx: inner_hal.in_data_tx,
+ });
+ ffi::start_hal();
+ hal_open_evt_rx.recv().await.unwrap();
+
+ tokio::spawn(dispatch_outgoing(inner_hal.out_cmd_rx, inner_hal.out_data_rx));
+
+ raw_hal
+}
+
+#[cxx::bridge(namespace = nfc::hal)]
+// TODO Either use or remove these functions, this shouldn't be the long term state
+#[allow(dead_code)]
+mod ffi {
+
+ #[repr(u32)]
+ #[derive(Debug)]
+ enum NfcEvent {
+ OPEN_CPLT = 0,
+ CLOSE_CPLT = 1,
+ POST_INIT_CPLT = 2,
+ PRE_DISCOVER_CPLT = 3,
+ REQUEST_CONTROL = 4,
+ RELEASE_CONTROL = 5,
+ ERROR = 6,
+ HCI_NETWORK_RESET = 7,
+ }
+
+ #[repr(u32)]
+ #[derive(Debug)]
+ enum NfcStatus {
+ OK = 0,
+ FAILED = 1,
+ ERR_TRANSPORT = 2,
+ ERR_CMD_TIMEOUT = 3,
+ REFUSED = 4,
+ }
+
+ unsafe extern "C++" {
+ include!("hal/ffi/hidl.h");
+ fn start_hal();
+ fn stop_hal();
+ fn send_command(data: &[u8]);
+
+ #[namespace = "android::hardware::nfc::V1_1"]
+ type NfcEvent;
+
+ #[namespace = "android::hardware::nfc::V1_0"]
+ type NfcStatus;
+ }
+
+ extern "Rust" {
+ fn on_event(evt: NfcEvent, status: NfcStatus);
+ fn on_data(data: &[u8]);
+ }
+}
+
+struct Callbacks {
+ hal_open_evt_tx: UnboundedSender<()>,
+ in_cmd_tx: UnboundedSender<NciPacket>,
+ in_data_tx: UnboundedSender<DataPacket>,
+}
+
+lazy_static! {
+ static ref CALLBACKS: Mutex<Option<Callbacks>> = Mutex::new(None);
+}
+
+fn on_event(evt: ffi::NfcEvent, status: ffi::NfcStatus) {
+ error!("got event: {:?} with status {:?}", evt, status);
+ let callbacks = CALLBACKS.lock().unwrap();
+ if evt == ffi::NfcEvent::OPEN_CPLT {
+ callbacks.as_ref().unwrap().hal_open_evt_tx.send(()).unwrap();
+ }
+}
+
+fn on_data(data: &[u8]) {
+ error!("got packet: {:02x?}", data);
+ let callbacks = CALLBACKS.lock().unwrap();
+ if is_control_packet(data) {
+ match NciPacket::parse(data) {
+ Ok(p) => callbacks.as_ref().unwrap().in_cmd_tx.send(p).unwrap(),
+ Err(e) => error!("failure to parse response: {:?} data: {:02x?}", e, data),
+ }
+ } else {
+ match DataPacket::parse(data) {
+ Ok(p) => callbacks.as_ref().unwrap().in_data_tx.send(p).unwrap(),
+ Err(e) => error!("failure to parse response: {:?} data: {:02x?}", e, data),
+ }
+ }
+}
+
+async fn dispatch_outgoing(
+ mut out_cmd_rx: UnboundedReceiver<NciPacket>,
+ mut out_data_rx: UnboundedReceiver<DataPacket>,
+) {
+ loop {
+ select! {
+ Some(cmd) = out_cmd_rx.recv() => ffi::send_command(&cmd.to_bytes()),
+ Some(data) = out_data_rx.recv() => ffi::send_command(&data.to_bytes()),
+ else => break,
+ }
+ }
+}
diff --git a/src/rust/hal/rootcanal_hal.rs b/src/rust/hal/rootcanal_hal.rs
new file mode 100644
index 0000000..ec4abbf
--- /dev/null
+++ b/src/rust/hal/rootcanal_hal.rs
@@ -0,0 +1,93 @@
+//! Rootcanal HAL
+//! This connects to "rootcanal" which provides a simulated
+//! Nfc chip as well as a simulated environment.
+
+use crate::internal::InnerHal;
+use crate::{is_control_packet, Hal, Result};
+use bytes::{BufMut, BytesMut};
+use log::{debug, error};
+use nfc_packets::nci::{DataPacket, NciPacket, Packet};
+use std::convert::TryInto;
+use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader};
+use tokio::net::TcpStream;
+use tokio::select;
+use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
+
+/// Initialize the module
+pub async fn init() -> Hal {
+ let (raw_hal, inner_hal) = InnerHal::new();
+ let (reader, writer) = TcpStream::connect("127.0.0.1:54323")
+ .await
+ .expect("unable to create stream to rootcanal")
+ .into_split();
+
+ let reader = BufReader::new(reader);
+ tokio::spawn(dispatch_incoming(inner_hal.in_cmd_tx, inner_hal.in_data_tx, reader));
+ tokio::spawn(dispatch_outgoing(inner_hal.out_cmd_rx, inner_hal.out_data_rx, writer));
+
+ raw_hal
+}
+
+/// Send NCI events received from the HAL to the NCI layer
+async fn dispatch_incoming<R>(
+ in_cmd_tx: UnboundedSender<NciPacket>,
+ in_data_tx: UnboundedSender<DataPacket>,
+ mut reader: R,
+) -> Result<()>
+where
+ R: AsyncReadExt + Unpin,
+{
+ loop {
+ let mut buffer = BytesMut::with_capacity(1024);
+ let len: usize = reader.read_u16().await?.into();
+ buffer.resize(len, 0);
+ reader.read_exact(&mut buffer).await?;
+ let frozen = buffer.freeze();
+ debug!("{:?}", &frozen);
+ if is_control_packet(&frozen[..]) {
+ match NciPacket::parse(&frozen) {
+ Ok(p) => in_cmd_tx.send(p)?,
+ Err(e) => error!("dropping invalid cmd event packet: {}: {:02x}", e, frozen),
+ }
+ } else {
+ match DataPacket::parse(&frozen) {
+ Ok(p) => in_data_tx.send(p)?,
+ Err(e) => error!("dropping invalid data event packet: {}: {:02x}", e, frozen),
+ }
+ }
+ }
+}
+
+/// Send commands received from the NCI later to rootcanal
+async fn dispatch_outgoing<W>(
+ mut out_cmd_rx: UnboundedReceiver<NciPacket>,
+ mut out_data_rx: UnboundedReceiver<DataPacket>,
+ mut writer: W,
+) -> Result<()>
+where
+ W: AsyncWriteExt + Unpin,
+{
+ loop {
+ select! {
+ Some(cmd) = out_cmd_rx.recv() => write_nci(&mut writer, cmd).await?,
+ Some(data) = out_data_rx.recv() => write_nci(&mut writer, data).await?,
+ else => break,
+ }
+ }
+
+ Ok(())
+}
+
+async fn write_nci<W, P>(writer: &mut W, cmd: P) -> Result<()>
+where
+ W: AsyncWriteExt + Unpin,
+ P: Packet,
+{
+ let b = cmd.to_bytes();
+ let mut data = BytesMut::with_capacity(b.len() + 2);
+ data.put_u16(b.len().try_into().unwrap());
+ data.extend(b);
+ writer.write_all(&data[..]).await?;
+ debug!("Sent {:?}", data);
+ Ok(())
+}
diff --git a/src/rust/nci/nci.rs b/src/rust/nci/nci.rs
new file mode 100644
index 0000000..47685e4
--- /dev/null
+++ b/src/rust/nci/nci.rs
@@ -0,0 +1,197 @@
+//! NCI Protocol Abstraction Layer
+//! Supports sending NCI commands to the HAL and receiving
+//! NCI messages back
+
+use log::error;
+use nfc_hal::Hal;
+use nfc_packets::nci::NciChild::{Notification, Response};
+use nfc_packets::nci::{CommandPacket, DataPacket, NotificationPacket, Opcode, ResponsePacket};
+use std::collections::HashMap;
+use std::sync::Arc;
+use tokio::select;
+use tokio::sync::mpsc::{channel, Receiver, Sender};
+use tokio::sync::{oneshot, Mutex};
+use tokio::time::{sleep, Duration, Instant};
+
+/// Result type
+type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
+
+/// Initialize the module and connect the channels
+pub async fn init() -> Nci {
+ let hc = nfc_hal::init().await;
+ // Channel to handle data downstream messages
+ let (out_data_ext, out_data_int) = channel::<DataPacket>(10);
+ // Channel to handle data upstream messages
+ let (in_data_int, in_data_ext) = channel::<DataPacket>(10);
+ // Internal data channels
+ let ic = InternalChannels { out_data_int, in_data_int };
+
+ let (cmd_tx, cmd_rx) = channel::<QueuedCommand>(10);
+ let commands = CommandSender { cmd_tx };
+
+ let notifications = EventRegistry { handlers: Arc::new(Mutex::new(HashMap::new())) };
+
+ tokio::spawn(dispatch(notifications, hc, ic, cmd_rx));
+ Nci { commands, out_data_ext, in_data_ext }
+}
+
+/// NCI module external interface
+pub struct Nci {
+ /// NCI command communication interface
+ pub commands: CommandSender,
+ /// NCI outbound channel for Data messages
+ pub out_data_ext: Sender<DataPacket>,
+ /// NCI inbound channel for Data messages
+ pub in_data_ext: Receiver<DataPacket>,
+}
+
+struct InternalChannels {
+ out_data_int: Receiver<DataPacket>,
+ in_data_int: Sender<DataPacket>,
+}
+
+#[derive(Debug)]
+struct PendingCommand {
+ cmd: CommandPacket,
+ response: oneshot::Sender<ResponsePacket>,
+}
+
+#[derive(Debug)]
+struct QueuedCommand {
+ pending: PendingCommand,
+ notification: Option<oneshot::Sender<NotificationPacket>>,
+}
+
+/// Sends raw commands. Only useful for facades & shims, or wrapped as a CommandSender.
+#[derive(Clone)]
+pub struct CommandSender {
+ cmd_tx: Sender<QueuedCommand>,
+}
+
+/// The data returned by send_notify() method.
+pub struct ResponsePendingNotification {
+ /// Command response
+ pub response: ResponsePacket,
+ /// Pending notification receiver
+ pub notification: oneshot::Receiver<NotificationPacket>,
+}
+
+impl CommandSender {
+ /// Send a command, but do not expect notification to be returned
+ pub async fn send(&mut self, cmd: CommandPacket) -> Result<ResponsePacket> {
+ let (tx, rx) = oneshot::channel::<ResponsePacket>();
+ self.cmd_tx
+ .send(QueuedCommand {
+ pending: PendingCommand { cmd, response: tx },
+ notification: None,
+ })
+ .await?;
+ let event = rx.await?;
+ Ok(event)
+ }
+ /// Send a command which expects notification as a result
+ pub async fn send_and_notify(
+ &mut self,
+ cmd: CommandPacket,
+ ) -> Result<ResponsePendingNotification> {
+ let (tx, rx) = oneshot::channel::<ResponsePacket>();
+ let (ntx, nrx) = oneshot::channel::<NotificationPacket>();
+ self.cmd_tx
+ .send(QueuedCommand {
+ pending: PendingCommand { cmd, response: tx },
+ notification: Some(ntx),
+ })
+ .await?;
+ let event = rx.await?;
+ Ok(ResponsePendingNotification { response: event, notification: nrx })
+ }
+}
+
+/// Provides ability to register and unregister for NCI notifications
+#[derive(Clone)]
+pub struct EventRegistry {
+ handlers: Arc<Mutex<HashMap<Opcode, oneshot::Sender<NotificationPacket>>>>,
+}
+
+impl EventRegistry {
+ /// Indicate interest in specific NCI notification
+ pub async fn register(&mut self, code: Opcode, sender: oneshot::Sender<NotificationPacket>) {
+ assert!(
+ self.handlers.lock().await.insert(code, sender).is_none(),
+ "A handler for {:?} is already registered",
+ code
+ );
+ }
+
+ /// Remove interest in specific NCI notification
+ pub async fn unregister(
+ &mut self,
+ code: Opcode,
+ ) -> Option<oneshot::Sender<NotificationPacket>> {
+ self.handlers.lock().await.remove(&code)
+ }
+}
+
+async fn dispatch(
+ mut ntfs: EventRegistry,
+ mut hc: Hal,
+ mut ic: InternalChannels,
+ mut cmd_rx: Receiver<QueuedCommand>,
+) -> Result<()> {
+ let mut pending: Option<PendingCommand> = None;
+ let timeout = sleep(Duration::MAX);
+ let max_deadline = timeout.deadline();
+ tokio::pin!(timeout);
+ loop {
+ select! {
+ Some(cmd) = hc.in_cmd_rx.recv() => {
+ match cmd.specialize() {
+ Response(rsp) => {
+ timeout.as_mut().reset(max_deadline);
+ let this_opcode = rsp.get_cmd_op();
+ match pending.take() {
+ Some(PendingCommand{cmd, response}) if cmd.get_op() == this_opcode => {
+ if let Err(e) = response.send(rsp) {
+ error!("failure dispatching command status {:?}", e);
+ }
+ },
+ Some(PendingCommand{cmd, ..}) => panic!("Waiting for {}, got {}", cmd.get_op(), this_opcode),
+ None => panic!("Unexpected status event with opcode {}", this_opcode),
+ }
+ }
+ Notification(ntfy) => {
+ let code = ntfy.get_cmd_op();
+ match ntfs.unregister(code).await {
+ Some(sender) => {
+ if let Err(e) = sender.send(ntfy) {
+ error!("notification channel closed {:?}", e);
+ }
+ },
+ None => panic!("Unhandled notification {:?}", code),
+ }
+ }
+ _ => error!("Unexpected NCI data received {:?}", cmd),
+ }
+ }
+ Some(queued) = cmd_rx.recv(), if pending.is_none() => {
+ if let Some(nsender) = queued.notification {
+ ntfs.register(queued.pending.cmd.get_op(), nsender).await;
+ }
+ if let Err(e) = hc.out_cmd_tx.send(queued.pending.cmd.clone().into()) {
+ error!("command queue closed: {:?}", e);
+ }
+ timeout.as_mut().reset(Instant::now() + Duration::from_millis(20));
+ pending = Some(queued.pending);
+ },
+ () = &mut timeout => {
+ error!("Command processing timeout");
+ timeout.as_mut().reset(max_deadline);
+ pending = None;
+ }
+ Some(data) = hc.in_data_rx.recv() => ic.in_data_int.send(data).await?,
+ Some(data) = ic.out_data_int.recv() => hc.out_data_tx.send(data)?,
+ else => break,
+ }
+ }
+ Ok(())
+}
diff --git a/src/rust/packets/lib.rs b/src/rust/packets/lib.rs
new file mode 100644
index 0000000..c459c75
--- /dev/null
+++ b/src/rust/packets/lib.rs
@@ -0,0 +1,9 @@
+//! reimport of generated packets (to go away once rust_genrule exists)
+
+#![allow(clippy::all)]
+#![allow(unused)]
+#![allow(missing_docs)]
+
+pub mod nci {
+ include!(concat!(env!("OUT_DIR"), "/nci_packets.rs"));
+}
diff --git a/src/rust/rootcanal/Android.bp b/src/rust/rootcanal/Android.bp
new file mode 100644
index 0000000..8673273
--- /dev/null
+++ b/src/rust/rootcanal/Android.bp
@@ -0,0 +1,23 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "system_nfc_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["system_nfc_license"],
+}
+
+rust_binary {
+ name: "nfc_rootcanal",
+ defaults: ["nfc_rust_defaults"],
+ srcs: ["main.rs"],
+ rustlibs: [
+ "libnfc_packets",
+ "libbytes",
+ "libthiserror",
+ "liblogger",
+ "liblog_rust",
+ "libtokio",
+ ],
+ proc_macros: ["libnum_derive"],
+}
diff --git a/src/rust/rootcanal/main.rs b/src/rust/rootcanal/main.rs
new file mode 100644
index 0000000..c023a11
--- /dev/null
+++ b/src/rust/rootcanal/main.rs
@@ -0,0 +1,164 @@
+//! This connects to "rootcanal" and provides a simulated
+//! Nfc chip as well as a simulated environment.
+
+use bytes::{BufMut, BytesMut};
+use log::{debug, Level};
+use logger::{self, Config};
+use nfc_packets::nci;
+use nfc_packets::nci::{CommandChild, NciChild};
+use nfc_packets::nci::{
+ ConfigStatus, NciVersion, ResetNotificationBuilder, ResetResponseBuilder, ResetTrigger,
+ ResetType,
+};
+use nfc_packets::nci::{InitResponseBuilder, NfccFeatures, RfInterface};
+use nfc_packets::nci::{NciMsgType, NciPacket, Packet, PacketBoundaryFlag};
+use std::convert::TryInto;
+use thiserror::Error;
+use tokio::io;
+use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader};
+use tokio::net::TcpListener;
+
+/// Result type
+type Result<T> = std::result::Result<T, RootcanalError>;
+
+#[derive(Debug, Error)]
+enum RootcanalError {
+ #[error("Termination request")]
+ TerminateTask,
+ #[error("Socket error")]
+ IoError(#[from] io::Error),
+ #[error("Unsupported command packet")]
+ UnsupportedCommand,
+ #[error("Packet did not parse correctly")]
+ InvalidPacket,
+ #[error("Packet type not supported")]
+ UnsupportedPacket,
+}
+
+const TERMINATION: u8 = 4u8;
+
+#[tokio::main]
+async fn main() -> io::Result<()> {
+ logger::init(Config::default().with_tag_on_device("nfc-rc").with_min_level(Level::Trace));
+
+ let listener = TcpListener::bind("127.0.0.1:54323").await?;
+
+ let (mut sock, _) = listener.accept().await?;
+
+ tokio::spawn(async move {
+ let (rd, mut wr) = sock.split();
+ let mut rd = BufReader::new(rd);
+ loop {
+ if let Err(e) = process(&mut rd, &mut wr).await {
+ match e {
+ RootcanalError::TerminateTask => break,
+ _ => panic!("Communication error: {:?}", e),
+ }
+ }
+ }
+ })
+ .await?;
+ Ok(())
+}
+
+async fn process<R, W>(reader: &mut R, writer: &mut W) -> Result<()>
+where
+ R: AsyncReadExt + Unpin,
+ W: AsyncWriteExt + Unpin,
+{
+ let mut buffer = BytesMut::with_capacity(1024);
+ let len: usize = reader.read_u16().await?.into();
+ buffer.resize(len, 0);
+ reader.read_exact(&mut buffer).await?;
+ let frozen = buffer.freeze();
+ debug!("{:?}", &frozen);
+ let pkt_type = (frozen[0] >> 5) & 0x7;
+ debug!("packet {} received len={}", &pkt_type, &len);
+ if pkt_type == NciMsgType::Command as u8 {
+ match NciPacket::parse(&frozen) {
+ Ok(p) => command_response(writer, p).await,
+ Err(_) => Err(RootcanalError::InvalidPacket),
+ }
+ } else if pkt_type == TERMINATION {
+ Err(RootcanalError::TerminateTask)
+ } else {
+ Err(RootcanalError::UnsupportedPacket)
+ }
+}
+
+async fn command_response<W>(out: &mut W, cmd: NciPacket) -> Result<()>
+where
+ W: AsyncWriteExt + Unpin,
+{
+ let pbf = PacketBoundaryFlag::CompleteOrFinal;
+ let gid = 0u8;
+ match cmd.specialize() {
+ NciChild::Command(cmd) => match cmd.specialize() {
+ CommandChild::ResetCommand(rst) => {
+ write_nci(
+ out,
+ (ResetResponseBuilder { gid, pbf, status: nci::Status::Ok }).build(),
+ )
+ .await?;
+ write_nci(
+ out,
+ (ResetNotificationBuilder {
+ gid,
+ pbf,
+ trigger: ResetTrigger::ResetCommand,
+ config_status: if rst.get_reset_type() == ResetType::KeepConfig {
+ ConfigStatus::ConfigKept
+ } else {
+ ConfigStatus::ConfigReset
+ },
+ nci_version: NciVersion::Version20,
+ manufacturer_id: 0,
+ mfsi: Vec::new(),
+ })
+ .build(),
+ )
+ .await
+ }
+ CommandChild::InitCommand(_) => {
+ let nfcc_feat = [0u8; 5];
+ let rf_int = [0u8; 2];
+ write_nci(
+ out,
+ (InitResponseBuilder {
+ gid,
+ pbf,
+ status: nci::Status::Ok,
+ nfcc_features: NfccFeatures::parse(&nfcc_feat).unwrap(),
+ max_log_conns: 0,
+ max_rout_tbls_size: 0x0000,
+ max_ctrl_payload: 255,
+ max_data_payload: 255,
+ num_of_credits: 0,
+ max_nfcv_rf_frame_sz: 64,
+ rf_interface: vec![RfInterface::parse(&rf_int).unwrap(); 1],
+ })
+ .build(),
+ )
+ .await
+ }
+ _ => Err(RootcanalError::UnsupportedCommand),
+ },
+ _ => Err(RootcanalError::InvalidPacket),
+ }
+}
+
+async fn write_nci<W, T>(writer: &mut W, rsp: T) -> Result<()>
+where
+ W: AsyncWriteExt + Unpin,
+ T: Into<NciPacket>,
+{
+ let pkt = rsp.into();
+ let b = pkt.to_bytes();
+ let mut data = BytesMut::with_capacity(b.len() + 2);
+ data.put_u16(b.len().try_into().unwrap());
+ data.extend(b);
+ let frozen = data.freeze();
+ writer.write_all(frozen.as_ref()).await?;
+ debug!("command written");
+ Ok(())
+}
diff --git a/src/rust/test/Android.bp b/src/rust/test/Android.bp
new file mode 100644
index 0000000..138d551
--- /dev/null
+++ b/src/rust/test/Android.bp
@@ -0,0 +1,24 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "system_nfc_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["system_nfc_license"],
+}
+
+rust_binary {
+ name: "nfc_rootcanal_test",
+ defaults: ["nfc_rust_defaults"],
+ srcs: ["main.rs"],
+ rustlibs: [
+ "libnfc_packets",
+ "libnfc_rnci",
+ "libbytes",
+ "libthiserror",
+ "liblogger",
+ "liblog_rust",
+ "libtokio",
+ ],
+ proc_macros: ["libnum_derive"],
+}
diff --git a/src/rust/test/main.rs b/src/rust/test/main.rs
new file mode 100644
index 0000000..aa66dc4
--- /dev/null
+++ b/src/rust/test/main.rs
@@ -0,0 +1,44 @@
+//! Rootcanal HAL
+//! This connects to "rootcanal" which provides a simulated
+//! Nfc chip as well as a simulated environment.
+
+use log::{debug, error, Level};
+use logger::{self, Config};
+use nfc_packets::nci::CommandPacket;
+use nfc_packets::nci::Opcode::{self, CoreInit, CoreReset};
+use nfc_packets::nci::{FeatureEnable, PacketBoundaryFlag, ResetType};
+use nfc_packets::nci::{InitCommandBuilder, ResetCommandBuilder};
+
+/// Result type
+type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
+
+#[tokio::main]
+async fn main() -> Result<()> {
+ logger::init(Config::default().with_tag_on_device("lnfc").with_min_level(Level::Trace));
+ let mut nci = nfc_rnci::init().await;
+ let reset = nci.commands.send_and_notify(build_cmd(CoreReset).unwrap()).await?;
+ let init = nci.commands.send(build_cmd(CoreInit).unwrap()).await?;
+ let reset_response_packet = reset.response.specialize();
+ debug!("Received {:?}", reset_response_packet);
+ let init_response_packet = init.specialize();
+ debug!("Received {:?}", init_response_packet);
+ let notification_packet = reset.notification.await?;
+ debug!("Received {:?}", notification_packet.specialize());
+ Ok(())
+}
+
+fn build_cmd(cmd_op_code: Opcode) -> Option<CommandPacket> {
+ let pbf = PacketBoundaryFlag::CompleteOrFinal;
+ match cmd_op_code {
+ CoreReset => Some(
+ ResetCommandBuilder { gid: 0, pbf, reset_type: ResetType::ResetConfig }.build().into(),
+ ),
+ CoreInit => Some(
+ InitCommandBuilder { gid: 0, pbf, feature_eneble: FeatureEnable::Rfu }.build().into(),
+ ),
+ _ => {
+ error!("Unsupported command: {}", cmd_op_code);
+ None
+ }
+ }
+}