Merge SQ1A.220205.002
Bug: 213904741
Merged-In: I224eb0018f557ca82d092a2ca9b2f29f5e68b39b
Change-Id: I8935b917776490c90a9460485cb3c7267f94eb05
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..788c364 100644
--- a/src/Android.bp
+++ b/src/Android.bp
@@ -18,7 +18,6 @@
"libcutils",
"liblog",
"libdl",
- "libhardware",
"libz",
"libchrome",
"libbase",
@@ -30,6 +29,9 @@
"android.hardware.nfc@1.0",
"android.hardware.nfc@1.1",
"android.hardware.nfc@1.2",
+ // Add for AIDL
+ "android.hardware.nfc-V1-ndk",
+ "libbinder_ndk",
],
static_libs: [
"libnfcutils",
@@ -128,6 +130,7 @@
srcs: [
"nfc/nci/*.cc",
"nfc/nfc/*.cc",
+ "adaptation/debug_lmrt.cc",
"gki/common/*.cc",
"gki/ulinux/*.cc",
"fuzzers/*.cc",
@@ -185,3 +188,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..8524a17 100644
--- a/src/adaptation/NfcAdaptation.cc
+++ b/src/adaptation/NfcAdaptation.cc
@@ -15,6 +15,18 @@
* limitations under the License.
*
******************************************************************************/
+#include <aidl/android/hardware/nfc/BnNfc.h>
+#include <aidl/android/hardware/nfc/BnNfcClientCallback.h>
+#include <aidl/android/hardware/nfc/INfc.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+// syslog.h and base/logging.h both try to #define LOG_INFO and LOG_WARNING.
+// We need to #undef these two before including base/logging.h.
+// libchrome => logging.h
+// aidl => syslog.h
+#undef LOG_INFO
+#undef LOG_WARNING
#include <android-base/stringprintf.h>
#include <android/hardware/nfc/1.1/INfc.h>
#include <android/hardware/nfc/1.2/INfc.h>
@@ -50,6 +62,18 @@
using NfcVendorConfigV1_2 = android::hardware::nfc::V1_2::NfcConfig;
using android::hardware::nfc::V1_1::INfcClientCallback;
using android::hardware::hidl_vec;
+using INfcAidl = ::aidl::android::hardware::nfc::INfc;
+using NfcAidlConfig = ::aidl::android::hardware::nfc::NfcConfig;
+using AidlPresenceCheckAlgorithm =
+ ::aidl::android::hardware::nfc::PresenceCheckAlgorithm;
+using INfcAidlClientCallback =
+ ::aidl::android::hardware::nfc::INfcClientCallback;
+using NfcAidlEvent = ::aidl::android::hardware::nfc::NfcEvent;
+using NfcAidlStatus = ::aidl::android::hardware::nfc::NfcStatus;
+using ::aidl::android::hardware::nfc::NfcCloseType;
+using Status = ::ndk::ScopedAStatus;
+
+std::string NFC_AIDL_HAL_SERVICE_NAME = "android.hardware.nfc.INfc/default";
extern bool nfc_debug_enabled;
@@ -59,14 +83,15 @@
NfcAdaptation* NfcAdaptation::mpInstance = nullptr;
ThreadMutex NfcAdaptation::sLock;
-tHAL_NFC_CBACK* NfcAdaptation::mHalCallback = nullptr;
-tHAL_NFC_DATA_CBACK* NfcAdaptation::mHalDataCallback = nullptr;
ThreadCondVar NfcAdaptation::mHalOpenCompletedEvent;
ThreadCondVar NfcAdaptation::mHalCloseCompletedEvent;
sp<INfc> NfcAdaptation::mHal;
sp<INfcV1_1> NfcAdaptation::mHal_1_1;
sp<INfcV1_2> NfcAdaptation::mHal_1_2;
INfcClientCallback* NfcAdaptation::mCallback;
+std::shared_ptr<INfcAidlClientCallback> mAidlCallback;
+::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+std::shared_ptr<INfcAidl> mAidlHal;
bool nfc_debug_enabled = false;
std::string nfc_storage_path;
@@ -82,21 +107,16 @@
// Whitelist for hosts allowed to create a pipe
// See ADM_CREATE_PIPE command in the ETSI test specification
// ETSI TS 102 622, section 6.1.3.1
-static std::vector<uint8_t> host_whitelist;
+static std::vector<uint8_t> host_allowlist;
namespace {
void initializeGlobalDebugEnabledFlag() {
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 +167,88 @@
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;
+ }
+};
+
+class NfcAidlClientCallback
+ : public ::aidl::android::hardware::nfc::BnNfcClientCallback {
+ public:
+ NfcAidlClientCallback(tHAL_NFC_CBACK* eventCallback,
+ tHAL_NFC_DATA_CBACK dataCallback) {
+ mEventCallback = eventCallback;
+ mDataCallback = dataCallback;
+ };
+ virtual ~NfcAidlClientCallback() = default;
+
+ ::ndk::ScopedAStatus sendEvent(NfcAidlEvent event,
+ NfcAidlStatus event_status) override {
+ uint8_t e_num;
+ uint8_t s_num;
+ switch (event) {
+ case NfcAidlEvent::OPEN_CPLT:
+ e_num = HAL_NFC_OPEN_CPLT_EVT;
+ break;
+ case NfcAidlEvent::CLOSE_CPLT:
+ e_num = HAL_NFC_CLOSE_CPLT_EVT;
+ break;
+ case NfcAidlEvent::POST_INIT_CPLT:
+ e_num = HAL_NFC_POST_INIT_CPLT_EVT;
+ break;
+ case NfcAidlEvent::PRE_DISCOVER_CPLT:
+ e_num = HAL_NFC_PRE_DISCOVER_CPLT_EVT;
+ break;
+ case NfcAidlEvent::HCI_NETWORK_RESET:
+ e_num = HAL_HCI_NETWORK_RESET;
+ break;
+ case NfcAidlEvent::ERROR:
+ default:
+ e_num = HAL_NFC_ERROR_EVT;
+ }
+ switch (event_status) {
+ case NfcAidlStatus::OK:
+ s_num = HAL_NFC_STATUS_OK;
+ break;
+ case NfcAidlStatus::FAILED:
+ s_num = HAL_NFC_STATUS_FAILED;
+ break;
+ case NfcAidlStatus::ERR_TRANSPORT:
+ s_num = HAL_NFC_STATUS_ERR_TRANSPORT;
+ break;
+ case NfcAidlStatus::ERR_CMD_TIMEOUT:
+ s_num = HAL_NFC_STATUS_ERR_CMD_TIMEOUT;
+ break;
+ default:
+ s_num = HAL_NFC_STATUS_FAILED;
+ }
+ mEventCallback(e_num, (tHAL_NFC_STATUS)s_num);
+ return ::ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus sendData(const std::vector<uint8_t>& data) override {
+ std::vector<uint8_t> copy = data;
+ mDataCallback(copy.size(), ©[0]);
+ return ::ndk::ScopedAStatus::ok();
+ };
+
+ private:
+ tHAL_NFC_CBACK* mEventCallback;
+ tHAL_NFC_DATA_CBACK* mDataCallback;
};
/*******************************************************************************
@@ -166,8 +261,9 @@
**
*******************************************************************************/
NfcAdaptation::NfcAdaptation() {
- mNfcHalDeathRecipient = new NfcHalDeathRecipient(mHal);
memset(&mHalEntryFuncs, 0, sizeof(mHalEntryFuncs));
+ mDeathRecipient = ::ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(NfcAdaptation::HalAidlBinderDied));
}
/*******************************************************************************
@@ -203,7 +299,10 @@
void NfcAdaptation::GetVendorConfigs(
std::map<std::string, ConfigValue>& configMap) {
NfcVendorConfigV1_2 configValue;
- if (mHal_1_2) {
+ NfcAidlConfig aidlConfigValue;
+ if (mAidlHal) {
+ mAidlHal->getConfig(&aidlConfigValue);
+ } else if (mHal_1_2) {
mHal_1_2->getConfig_1_2(
[&configValue](NfcVendorConfigV1_2 config) { configValue = config; });
} else if (mHal_1_1) {
@@ -213,7 +312,61 @@
});
}
- if (mHal_1_1 || mHal_1_2) {
+ if (mAidlHal) {
+ std::vector<int8_t> nfaPropCfg = {
+ aidlConfigValue.nfaProprietaryCfg.protocol18092Active,
+ aidlConfigValue.nfaProprietaryCfg.protocolBPrime,
+ aidlConfigValue.nfaProprietaryCfg.protocolDual,
+ aidlConfigValue.nfaProprietaryCfg.protocol15693,
+ aidlConfigValue.nfaProprietaryCfg.protocolKovio,
+ aidlConfigValue.nfaProprietaryCfg.protocolMifare,
+ aidlConfigValue.nfaProprietaryCfg.discoveryPollKovio,
+ aidlConfigValue.nfaProprietaryCfg.discoveryPollBPrime,
+ aidlConfigValue.nfaProprietaryCfg.discoveryListenBPrime};
+ configMap.emplace(NAME_NFA_PROPRIETARY_CFG, ConfigValue(nfaPropCfg));
+ configMap.emplace(NAME_NFA_POLL_BAIL_OUT_MODE,
+ ConfigValue(aidlConfigValue.nfaPollBailOutMode ? 1 : 0));
+ configMap.emplace(NAME_DEFAULT_OFFHOST_ROUTE,
+ ConfigValue(aidlConfigValue.defaultOffHostRoute));
+ if (configValue.offHostRouteUicc.size() != 0) {
+ configMap.emplace(NAME_OFFHOST_ROUTE_UICC,
+ ConfigValue(aidlConfigValue.offHostRouteUicc));
+ }
+ if (configValue.offHostRouteEse.size() != 0) {
+ configMap.emplace(NAME_OFFHOST_ROUTE_ESE,
+ ConfigValue(aidlConfigValue.offHostRouteEse));
+ }
+ configMap.emplace(NAME_DEFAULT_ROUTE,
+ ConfigValue(aidlConfigValue.defaultRoute));
+ configMap.emplace(NAME_DEFAULT_NFCF_ROUTE,
+ ConfigValue(aidlConfigValue.defaultOffHostRouteFelica));
+ configMap.emplace(NAME_DEFAULT_ISODEP_ROUTE,
+ ConfigValue(aidlConfigValue.defaultIsoDepRoute));
+ configMap.emplace(NAME_DEFAULT_SYS_CODE_ROUTE,
+ ConfigValue(aidlConfigValue.defaultSystemCodeRoute));
+ configMap.emplace(NAME_DEFAULT_SYS_CODE_PWR_STATE,
+ ConfigValue(aidlConfigValue.defaultSystemCodePowerState));
+ configMap.emplace(NAME_OFF_HOST_SIM_PIPE_ID,
+ ConfigValue(aidlConfigValue.offHostSIMPipeId));
+ configMap.emplace(NAME_OFF_HOST_ESE_PIPE_ID,
+ ConfigValue(aidlConfigValue.offHostESEPipeId));
+ configMap.emplace(NAME_ISO_DEP_MAX_TRANSCEIVE,
+ ConfigValue(aidlConfigValue.maxIsoDepTransceiveLength));
+ if (aidlConfigValue.hostAllowlist.size() != 0) {
+ configMap.emplace(NAME_DEVICE_HOST_ALLOW_LIST,
+ ConfigValue(aidlConfigValue.hostAllowlist));
+ }
+ /* For Backwards compatibility */
+ if (aidlConfigValue.presenceCheckAlgorithm ==
+ AidlPresenceCheckAlgorithm::ISO_DEP_NAK) {
+ configMap.emplace(NAME_PRESENCE_CHECK_ALGORITHM,
+ ConfigValue((uint32_t)NFA_RW_PRES_CHK_ISO_DEP_NAK));
+ } else {
+ configMap.emplace(
+ NAME_PRESENCE_CHECK_ALGORITHM,
+ ConfigValue((uint32_t)aidlConfigValue.presenceCheckAlgorithm));
+ }
+ } else if (mHal_1_1 || mHal_1_2) {
std::vector<uint8_t> nfaPropCfg = {
configValue.v1_1.nfaProprietaryCfg.protocol18092Active,
configValue.v1_1.nfaProprietaryCfg.protocolBPrime,
@@ -255,7 +408,7 @@
configMap.emplace(NAME_ISO_DEP_MAX_TRANSCEIVE,
ConfigValue(configValue.v1_1.maxIsoDepTransceiveLength));
if (configValue.v1_1.hostWhitelist.size() != 0) {
- configMap.emplace(NAME_DEVICE_HOST_WHITE_LIST,
+ configMap.emplace(NAME_DEVICE_HOST_ALLOW_LIST,
ConfigValue(configValue.v1_1.hostWhitelist));
}
/* For Backwards compatibility */
@@ -300,9 +453,9 @@
if (dm_config.size() > 1) nfa_dm_cfg.auto_read_ndef = dm_config[1];
if (dm_config.size() > 2) nfa_dm_cfg.auto_presence_check = dm_config[2];
if (dm_config.size() > 3) nfa_dm_cfg.presence_check_option = dm_config[3];
- // NOTE: The timeout value is not configurable here because the endianess
+ // NOTE: The timeout value is not configurable here because the endianness
// of a byte array is ambiguous and needlessly difficult to configure.
- // If this value needs to be configgurable, a numeric config option should
+ // If this value needs to be configurable, a numeric config option should
// be used.
}
@@ -343,12 +496,12 @@
nfa_proprietary_cfg.pro_discovery_b_prime_listen = p_config[8];
}
- // Configure whitelist of HCI host ID's
+ // Configure allowlist of HCI host ID's
// See specification: ETSI TS 102 622, section 6.1.3.1
- if (NfcConfig::hasKey(NAME_DEVICE_HOST_WHITE_LIST)) {
- host_whitelist = NfcConfig::getBytes(NAME_DEVICE_HOST_WHITE_LIST);
- nfa_hci_cfg.num_whitelist_host = host_whitelist.size();
- nfa_hci_cfg.p_whitelist = &host_whitelist[0];
+ if (NfcConfig::hasKey(NAME_DEVICE_HOST_ALLOW_LIST)) {
+ host_allowlist = NfcConfig::getBytes(NAME_DEVICE_HOST_ALLOW_LIST);
+ nfa_hci_cfg.num_allowlist_host = host_allowlist.size();
+ nfa_hci_cfg.p_allowlist = &host_allowlist[0];
}
verify_stack_non_volatile_store();
@@ -393,12 +546,17 @@
NfcConfig::clear();
+ if (mHal != nullptr) {
+ mNfcHalDeathRecipient->finalize();
+ }
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", func);
delete this;
}
void NfcAdaptation::FactoryReset() {
- if (mHal_1_2 != nullptr) {
+ if (mAidlHal != nullptr) {
+ mAidlHal->factoryReset();
+ } else if (mHal_1_2 != nullptr) {
mHal_1_2->factoryReset();
} else if (mHal_1_1 != nullptr) {
mHal_1_1->factoryReset();
@@ -406,13 +564,19 @@
}
void NfcAdaptation::DeviceShutdown() {
- if (mHal_1_2 != nullptr) {
- mHal_1_2->closeForPowerOffCase();
- } else if (mHal_1_1 != nullptr) {
- mHal_1_1->closeForPowerOffCase();
- }
- if (mHal) {
- mHal->unlinkToDeath(mNfcHalDeathRecipient);
+ if (mAidlHal != nullptr) {
+ mAidlHal->close(NfcCloseType::HOST_SWITCHED_OFF);
+ AIBinder_unlinkToDeath(mAidlHal->asBinder().get(), mDeathRecipient.get(),
+ this);
+ } else {
+ if (mHal_1_2 != nullptr) {
+ mHal_1_2->closeForPowerOffCase();
+ } else if (mHal_1_1 != nullptr) {
+ mHal_1_1->closeForPowerOffCase();
+ }
+ if (mHal != nullptr) {
+ mHal->unlinkToDeath(mNfcHalDeathRecipient);
+ }
}
}
@@ -498,7 +662,7 @@
**
** Function: NfcAdaptation::InitializeHalDeviceContext
**
-** Description: Ask the generic Android HAL to find the Broadcom-specific HAL.
+** Description: Check validity of current handle to the nfc HAL service
**
** Returns: None.
**
@@ -517,6 +681,7 @@
mHalEntryFuncs.power_cycle = HalPowerCycle;
mHalEntryFuncs.get_max_ee = HalGetMaxNfcee;
LOG(INFO) << StringPrintf("%s: INfc::getService()", func);
+ // TODO: Try get the NFC HIDL first before vendor AIDL impl complete
mHal = mHal_1_1 = mHal_1_2 = INfcV1_2::getService();
if (mHal_1_2 == nullptr) {
mHal = mHal_1_1 = INfcV1_1::getService();
@@ -524,11 +689,23 @@
mHal = INfc::getService();
}
}
- LOG_FATAL_IF(mHal == nullptr, "Failed to retrieve the NFC HAL!");
- LOG(INFO) << StringPrintf("%s: INfc::getService() returned %p (%s)", func,
- mHal.get(),
- (mHal->isRemote() ? "remote" : "local"));
- if (mHal) {
+ if (mHal == nullptr) {
+ // Try get AIDL
+ ::ndk::SpAIBinder binder(
+ AServiceManager_getService(NFC_AIDL_HAL_SERVICE_NAME.c_str()));
+ mAidlHal = INfcAidl::fromBinder(binder);
+ if (mAidlHal != nullptr) {
+ AIBinder_linkToDeath(mAidlHal->asBinder().get(), mDeathRecipient.get(),
+ this /* cookie */);
+ mHal = mHal_1_1 = mHal_1_2 = nullptr;
+ LOG(INFO) << StringPrintf("%s: INfcAidl::fromBinder returned", func);
+ }
+ LOG_FATAL_IF(mAidlHal == nullptr, "Failed to retrieve the NFC AIDL!");
+ } else {
+ LOG(INFO) << StringPrintf("%s: INfc::getService() returned %p (%s)", func,
+ mHal.get(),
+ (mHal->isRemote() ? "remote" : "local"));
+ mNfcHalDeathRecipient = new NfcHalDeathRecipient(mHal);
mHal->linkToDeath(mNfcHalDeathRecipient, 0);
}
}
@@ -576,10 +753,22 @@
tHAL_NFC_DATA_CBACK* p_data_cback) {
const char* func = "NfcAdaptation::HalOpen";
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", func);
- mCallback = new NfcClientCallback(p_hal_cback, p_data_cback);
- if (mHal_1_1 != nullptr) {
+
+ if (mAidlHal != nullptr) {
+ mAidlCallback = ::ndk::SharedRefBase::make<NfcAidlClientCallback>(
+ p_hal_cback, p_data_cback);
+ Status status = mAidlHal->open(mAidlCallback);
+ if (!status.isOk()) {
+ LOG(ERROR) << "Open Error: "
+ << ::aidl::android::hardware::nfc::toString(
+ static_cast<NfcAidlStatus>(
+ status.getServiceSpecificError()));
+ }
+ } else if (mHal_1_1 != nullptr) {
+ mCallback = new NfcClientCallback(p_hal_cback, p_data_cback);
mHal_1_1->open_1_1(mCallback);
} else {
+ mCallback = new NfcClientCallback(p_hal_cback, p_data_cback);
mHal->open(mCallback);
}
}
@@ -596,42 +785,11 @@
void NfcAdaptation::HalClose() {
const char* func = "NfcAdaptation::HalClose";
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", func);
- mHal->close();
-}
-
-/*******************************************************************************
-**
-** Function: NfcAdaptation::HalDeviceContextCallback
-**
-** Description: Translate generic Android HAL's callback into Broadcom-specific
-** callback function.
-**
-** Returns: None.
-**
-*******************************************************************************/
-void NfcAdaptation::HalDeviceContextCallback(nfc_event_t event,
- nfc_status_t event_status) {
- const char* func = "NfcAdaptation::HalDeviceContextCallback";
- DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: event=%u", func, event);
- if (mHalCallback) mHalCallback(event, (tHAL_NFC_STATUS)event_status);
-}
-
-/*******************************************************************************
-**
-** Function: NfcAdaptation::HalDeviceContextDataCallback
-**
-** Description: Translate generic Android HAL's callback into Broadcom-specific
-** callback function.
-**
-** Returns: None.
-**
-*******************************************************************************/
-void NfcAdaptation::HalDeviceContextDataCallback(uint16_t data_len,
- uint8_t* p_data) {
- const char* func = "NfcAdaptation::HalDeviceContextDataCallback";
- DLOG_IF(INFO, nfc_debug_enabled)
- << StringPrintf("%s: len=%u", func, data_len);
- if (mHalDataCallback) mHalDataCallback(data_len, p_data);
+ if (mAidlHal != nullptr) {
+ mAidlHal->close(NfcCloseType::DISABLE);
+ } else {
+ mHal->close();
+ }
}
/*******************************************************************************
@@ -646,9 +804,16 @@
void NfcAdaptation::HalWrite(uint16_t data_len, uint8_t* p_data) {
const char* func = "NfcAdaptation::HalWrite";
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", func);
- ::android::hardware::nfc::V1_0::NfcData data;
- data.setToExternal(p_data, data_len);
- mHal->write(data);
+
+ if (mAidlHal != nullptr) {
+ int ret;
+ std::vector<uint8_t> aidl_data(p_data, p_data + data_len);
+ mAidlHal->write(aidl_data, &ret);
+ } else {
+ ::android::hardware::nfc::V1_0::NfcData data;
+ data.setToExternal(p_data, data_len);
+ mHal->write(data);
+ }
}
/*******************************************************************************
@@ -664,10 +829,14 @@
uint8_t* p_core_init_rsp_params) {
const char* func = "NfcAdaptation::HalCoreInitialized";
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", func);
- hidl_vec<uint8_t> data;
- data.setToExternal(p_core_init_rsp_params, data_len);
-
- mHal->coreInitialized(data);
+ if (mAidlHal != nullptr) {
+ // AIDL coreInitialized doesn't send data to HAL.
+ mAidlHal->coreInitialized();
+ } else {
+ hidl_vec<uint8_t> data;
+ data.setToExternal(p_core_init_rsp_params, data_len);
+ mHal->coreInitialized(data);
+ }
}
/*******************************************************************************
@@ -687,9 +856,18 @@
bool NfcAdaptation::HalPrediscover() {
const char* func = "NfcAdaptation::HalPrediscover";
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", func);
- bool retval = FALSE;
- mHal->prediscover();
- return retval;
+ if (mAidlHal != nullptr) {
+ Status status = mAidlHal->preDiscover();
+ if (status.isOk()) {
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s wait for NFC_PRE_DISCOVER_CPLT_EVT", func);
+ return true;
+ }
+ } else {
+ mHal->prediscover();
+ }
+
+ return false;
}
/*******************************************************************************
@@ -708,7 +886,11 @@
void NfcAdaptation::HalControlGranted() {
const char* func = "NfcAdaptation::HalControlGranted";
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", func);
- mHal->controlGranted();
+ if (mAidlHal != nullptr) {
+ LOG(ERROR) << StringPrintf("Unsupported function %s", func);
+ } else {
+ mHal->controlGranted();
+ }
}
/*******************************************************************************
@@ -723,7 +905,11 @@
void NfcAdaptation::HalPowerCycle() {
const char* func = "NfcAdaptation::HalPowerCycle";
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", func);
- mHal->powerCycle();
+ if (mAidlHal != nullptr) {
+ mAidlHal->powerCycle();
+ } else {
+ mHal->powerCycle();
+ }
}
/*******************************************************************************
@@ -818,6 +1004,31 @@
/*******************************************************************************
**
+** Function: NfcAdaptation::HalAidlBinderDiedImpl
+**
+** Description: Abort nfc service when AIDL process died.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void NfcAdaptation::HalAidlBinderDiedImpl() {
+ LOG(WARNING) << __func__ << "INfc aidl hal died, resetting the state";
+ if (mAidlHal != nullptr) {
+ AIBinder_unlinkToDeath(mAidlHal->asBinder().get(), mDeathRecipient.get(),
+ this);
+ mAidlHal = nullptr;
+ }
+ abort();
+}
+
+// static
+void NfcAdaptation::HalAidlBinderDied(void* cookie) {
+ auto thiz = static_cast<NfcAdaptation*>(cookie);
+ thiz->HalAidlBinderDiedImpl();
+}
+
+/*******************************************************************************
+**
** Function: ThreadMutex::ThreadMutex()
**
** Description: class constructor
diff --git a/src/adaptation/debug_lmrt.cc b/src/adaptation/debug_lmrt.cc
new file mode 100644
index 0000000..1ef3c7a
--- /dev/null
+++ b/src/adaptation/debug_lmrt.cc
@@ -0,0 +1,156 @@
+/**
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/debug_lmrt.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+using android::base::StringPrintf;
+
+extern bool nfc_debug_enabled;
+
+/* The payload of each RF_SET_LISTEN_MODE_ROUTING_CMD when commit routing */
+lmrt_payload_t lmrt_payloads;
+
+/* The committed routing table stored in tlv form */
+std::vector<uint8_t> committed_lmrt_tlvs(0);
+
+/*******************************************************************************
+**
+** Function debug_lmrt_init
+**
+** Description initialize the lmrt_payloads
+**
+** Returns None
+**
+*******************************************************************************/
+void debug_lmrt_init(void) {
+ std::vector<uint8_t> empty_more(0);
+ std::vector<uint8_t> empty_entry_count(0);
+ std::vector<std::vector<uint8_t>> empty_tlvs(0);
+
+ lmrt_payloads.more.swap(empty_more);
+ lmrt_payloads.entry_count.swap(empty_entry_count);
+ lmrt_payloads.tlvs.swap(empty_tlvs);
+}
+
+/*******************************************************************************
+**
+** Function lmrt_log
+**
+** Description print the listen mode routing configuration for debug use
+**
+** Returns None
+**
+*******************************************************************************/
+void lmrt_log(void) {
+ if (!nfc_debug_enabled) return;
+
+ static const char hexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+ for (int i = 0; i < lmrt_payloads.more.size(); i++) {
+ std::string tlvs_str;
+ for (uint8_t byte : lmrt_payloads.tlvs[i]) {
+ tlvs_str.push_back(hexmap[byte >> 4]);
+ tlvs_str.push_back(hexmap[byte & 0x0F]);
+ }
+
+ LOG(INFO) << StringPrintf("lmrt_log: Packet %d/%d, %d more packet", i + 1,
+ (int)lmrt_payloads.more.size(),
+ lmrt_payloads.more[i]);
+ LOG(INFO) << StringPrintf("lmrt_log: %d entries in this packet",
+ lmrt_payloads.entry_count[i]);
+
+ LOG(INFO) << StringPrintf("lmrt_log: tlv: %s", tlvs_str.c_str());
+ }
+}
+
+/*******************************************************************************
+**
+** Function lmrt_capture
+**
+** Description record the last RF_SET_LISTEN_MODE_ROUTING_CMD
+**
+** Returns None
+**
+*******************************************************************************/
+void lmrt_capture(uint8_t* buf, uint8_t buf_size) {
+ if (buf == nullptr || buf_size < 5) return;
+
+ if (lmrt_payloads.more.size() > 0) {
+ if (lmrt_payloads.more.back() == 0) {
+ /* if the MORE setting of the last lmrt command is 0x00,
+ * that means the data in lmrt_payloads are obsolete, empty it */
+ debug_lmrt_init();
+ }
+ }
+
+ /* push_back the last lmrt command to lmrt_payloads */
+ lmrt_payloads.more.push_back(buf[3]);
+ lmrt_payloads.entry_count.push_back(buf[4]);
+ if (buf_size == 5) {
+ lmrt_payloads.tlvs.push_back(std::vector<uint8_t>(0));
+ } else {
+ lmrt_payloads.tlvs.push_back(std::vector<uint8_t>(buf + 5, buf + buf_size));
+ }
+}
+
+/*******************************************************************************
+**
+** Function lmrt_update
+**
+** Description Update the committed tlvs to committed_lmrt_tlvs
+**
+** Returns None
+**
+*******************************************************************************/
+void lmrt_update(void) {
+ lmrt_log();
+ std::vector<uint8_t> temp(0);
+
+ /* combine all tlvs in lmrt_payloads.tlvs */
+ for (auto tlv : lmrt_payloads.tlvs) {
+ temp.insert(temp.end(), tlv.begin(), tlv.end());
+ }
+
+ committed_lmrt_tlvs.swap(temp);
+}
+
+/*******************************************************************************
+**
+** Function lmrt_get_max_size
+**
+** Description This function is used to get the max size of the routing
+** table from cache
+**
+** Returns Max Routing Table Size
+**
+*******************************************************************************/
+int lmrt_get_max_size(void) { return nfc_cb.max_ce_table; }
+
+/*******************************************************************************
+**
+** Function lmrt_get_tlvs
+**
+** Description This function is used to get the committed listen mode
+** routing configuration command
+**
+** Returns The committed listen mode routing configuration command
+**
+*******************************************************************************/
+std::vector<uint8_t>* lmrt_get_tlvs() { return &committed_lmrt_tlvs; }
diff --git a/src/gki/ulinux/gki_ulinux.cc b/src/gki/ulinux/gki_ulinux.cc
index 7262b5f..8a7eea1 100644
--- a/src/gki/ulinux/gki_ulinux.cc
+++ b/src/gki/ulinux/gki_ulinux.cc
@@ -125,7 +125,7 @@
pthread_mutexattr_init(&attr);
#ifndef __CYGWIN__
- pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
#endif
p_os = &gki_cb.os;
pthread_mutex_init(&p_os->GKI_mutex, &attr);
@@ -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,7 +627,7 @@
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 */
@@ -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/include/NfcAdaptation.h b/src/include/NfcAdaptation.h
index df12a44..8bbb9c2 100644
--- a/src/include/NfcAdaptation.h
+++ b/src/include/NfcAdaptation.h
@@ -16,14 +16,14 @@
*
******************************************************************************/
#pragma once
+
#include <pthread.h>
+#include <utils/RefBase.h>
#include "config.h"
#include "nfc_hal_api.h"
#include "nfc_target.h"
-#include <utils/RefBase.h>
-
using ::android::sp;
namespace android {
@@ -138,4 +138,9 @@
nfc_status_t event_status);
static void HalDownloadFirmwareDataCallback(uint16_t data_len,
uint8_t* p_data);
+
+ // Death recipient callback that is called when INfcAidl dies.
+ // The cookie is a pointer to a NfcAdaptation object.
+ static void HalAidlBinderDied(void* cookie);
+ void HalAidlBinderDiedImpl();
};
diff --git a/src/include/debug_lmrt.h b/src/include/debug_lmrt.h
new file mode 100644
index 0000000..b050285
--- /dev/null
+++ b/src/include/debug_lmrt.h
@@ -0,0 +1,102 @@
+/**
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _DEBUG_LMRT_
+#define _DEBUG_LMRT_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "nfc_int.h"
+
+/* The type definition of a group of RF_SET_LISTEN_MODE_ROUTING_CMD(s) */
+typedef struct lmrt_payload_t {
+ std::vector<uint8_t> more;
+ std::vector<uint8_t> entry_count;
+ std::vector<std::vector<uint8_t>> tlvs;
+} __attribute__((__packed__)) lmrt_payload_t;
+
+/*******************************************************************************
+**
+** Function debug_lmrt_init
+**
+** Description initialize the lmrt_payloads
+**
+** Returns None
+**
+*******************************************************************************/
+void debug_lmrt_init(void);
+
+/*******************************************************************************
+**
+** Function lmrt_log
+**
+** Description print the listen mode routing configuration for debug use
+**
+** Returns None
+**
+*******************************************************************************/
+void lmrt_log(void);
+
+/*******************************************************************************
+**
+** Function lmrt_capture
+**
+** Description record the last RF_SET_LISTEN_MODE_ROUTING_CMD
+**
+** Returns None
+**
+*******************************************************************************/
+void lmrt_capture(uint8_t* buf, uint8_t buf_size);
+
+/*******************************************************************************
+**
+** Function lmrt_update
+**
+** Description Update the committed tlvs to committed_lmrt_tlvs
+**
+** Returns None
+**
+*******************************************************************************/
+void lmrt_update(void);
+
+/*******************************************************************************
+**
+** Function lmrt_get_max_size
+**
+** Description This function is used to get the max size of the routing
+** table from cache
+**
+** Returns Max Routing Table Size
+**
+*******************************************************************************/
+int lmrt_get_max_size(void);
+
+/*******************************************************************************
+**
+** Function lmrt_get_tlvs
+**
+** Description This function is used to get the committed listen mode
+** routing configuration command
+**
+** Returns The committed listen mode routing configuration command
+**
+*******************************************************************************/
+std::vector<uint8_t>* lmrt_get_tlvs();
+
+#endif /* _DEBUG_LMRT_ */
diff --git a/src/include/hardware_nfc.h b/src/include/hardware_nfc.h
new file mode 100644
index 0000000..b266541
--- /dev/null
+++ b/src/include/hardware_nfc.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+typedef uint8_t nfc_event_t;
+typedef uint8_t nfc_status_t;
+
+/*
+ * The callback passed in from the NFC stack that the HAL
+ * can use to pass events back to the stack.
+ */
+typedef void(nfc_stack_callback_t)(nfc_event_t event,
+ nfc_status_t event_status);
+
+/*
+ * The callback passed in from the NFC stack that the HAL
+ * can use to pass incomming data to the stack.
+ */
+typedef void(nfc_stack_data_callback_t)(uint16_t data_len, uint8_t* p_data);
+
+enum {
+ HAL_NFC_OPEN_CPLT_EVT = 0u,
+ HAL_NFC_CLOSE_CPLT_EVT = 1u,
+ HAL_NFC_POST_INIT_CPLT_EVT = 2u,
+ HAL_NFC_PRE_DISCOVER_CPLT_EVT = 3u,
+ HAL_NFC_REQUEST_CONTROL_EVT = 4u,
+ HAL_NFC_RELEASE_CONTROL_EVT = 5u,
+ HAL_NFC_ERROR_EVT = 6u,
+ HAL_HCI_NETWORK_RESET = 7u,
+};
+
+enum {
+ HAL_NFC_STATUS_OK = 0u,
+ HAL_NFC_STATUS_FAILED = 1u,
+ HAL_NFC_STATUS_ERR_TRANSPORT = 2u,
+ HAL_NFC_STATUS_ERR_CMD_TIMEOUT = 3u,
+ HAL_NFC_STATUS_REFUSED = 4u,
+};
diff --git a/src/include/nfc_config.h b/src/include/nfc_config.h
index aa7ac66..4731e97 100644
--- a/src/include/nfc_config.h
+++ b/src/include/nfc_config.h
@@ -57,7 +57,7 @@
#define NAME_OFF_HOST_ESE_PIPE_ID "OFF_HOST_ESE_PIPE_ID"
#define NAME_OFF_HOST_SIM_PIPE_ID "OFF_HOST_SIM_PIPE_ID"
#define NAME_ISO_DEP_MAX_TRANSCEIVE "ISO_DEP_MAX_TRANSCEIVE"
-#define NAME_DEVICE_HOST_WHITE_LIST "DEVICE_HOST_WHITE_LIST"
+#define NAME_DEVICE_HOST_ALLOW_LIST "DEVICE_HOST_ALLOW_LIST"
#define NAME_DEFAULT_ISODEP_ROUTE "DEFAULT_ISODEP_ROUTE"
class NfcConfig {
diff --git a/src/include/nfc_hal_api.h b/src/include/nfc_hal_api.h
index 205c6f7..8934a63 100644
--- a/src/include/nfc_hal_api.h
+++ b/src/include/nfc_hal_api.h
@@ -23,8 +23,8 @@
******************************************************************************/
#ifndef NFC_HAL_API_H
#define NFC_HAL_API_H
-#include <hardware/nfc.h>
#include "data_types.h"
+#include "hardware_nfc.h"
#include "nfc_hal_target.h"
typedef uint8_t tHAL_NFC_STATUS;
diff --git a/src/nci_packets.pdl b/src/nci_packets.pdl
new file mode 100644
index 0000000..6fea6e0
--- /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_enable : 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/ee/nfa_ee_act.cc b/src/nfa/ee/nfa_ee_act.cc
index 8b637d6..94fc4db 100644
--- a/src/nfa/ee/nfa_ee_act.cc
+++ b/src/nfa/ee/nfa_ee_act.cc
@@ -21,20 +21,19 @@
* This file contains the action functions for NFA-EE
*
******************************************************************************/
-#include <string.h>
-
#include <android-base/stringprintf.h>
#include <base/logging.h>
+#include <statslog.h>
+#include <string.h>
+#include "include/debug_lmrt.h"
+#include "metrics.h"
#include "nfa_api.h"
#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"
-
using android::base::StringPrintf;
extern bool nfc_debug_enabled;
@@ -646,8 +645,8 @@
int* p_offset, int* p_entry) {
int xx, yy, aid_len_offset, offset;
tNFA_EE_ECB *p_ret = nullptr, *p_ecb;
-
- p_ecb = &nfa_ee_cb.ecb[NFA_EE_CB_4_DH];
+ /* NFA_EE_CB_4_DH + Empty aid ECB */
+ p_ecb = &nfa_ee_cb.ecb[NFA_EE_CB_4_DH + 1];
aid_len_offset = 1; /* skip the tag */
for (yy = 0; yy <= nfa_ee_cb.cur_ee; yy++) {
if (p_ecb->aid_entries) {
@@ -2251,7 +2250,9 @@
if (nfa_ee_cb.ee_wait_evt & NFA_EE_WAIT_UPDATE) {
nfa_ee_cb.ee_wait_evt &= ~NFA_EE_WAIT_UPDATE;
- /* finished updating NFCC; report NFA_EE_UPDATED_EVT now */
+ /* finished updating NFCC; record the committed listen mode routing
+ * configuration command; report NFA_EE_UPDATED_EVT now */
+ lmrt_update();
evt_data.status = NFA_STATUS_OK;
nfa_ee_report_event(nullptr, NFA_EE_UPDATED_EVT, &evt_data);
}
@@ -2859,6 +2860,16 @@
<< StringPrintf("%s --add the routing for DH!!", __func__);
nfa_ee_route_add_one_ecb_by_route_order(&nfa_ee_cb.ecb[NFA_EE_CB_4_DH], rt,
&max_len, more, p, &cur_offset);
+
+ if (rt == NCI_ROUTE_ORDER_AID) {
+ p_cb = &nfa_ee_cb.ecb[NFA_EE_EMPTY_AID_ECB];
+ if (p_cb->ee_status == NFC_NFCEE_STATUS_ACTIVE) {
+ DLOG_IF(INFO, nfc_debug_enabled)
+ << StringPrintf("%s --add the routing for Empty Aid!!", __func__);
+ nfa_ee_route_add_one_ecb_by_route_order(p_cb, rt, &max_len, more, p,
+ &cur_offset);
+ }
+ }
}
GKI_freebuf(p);
diff --git a/src/nfa/ee/nfa_ee_api.cc b/src/nfa/ee/nfa_ee_api.cc
index 4881261..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;
@@ -558,7 +561,11 @@
tNFA_EE_ECB* p_cb;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("handle:<0x%x>", ee_handle);
- p_cb = nfa_ee_find_ecb(nfcee_id);
+ if (aid_len == 0) {
+ p_cb = &nfa_ee_cb.ecb[NFA_EE_EMPTY_AID_ECB];
+ } else {
+ p_cb = nfa_ee_find_ecb(nfcee_id);
+ }
/* validate parameters - make sure the AID is in valid length range */
if ((p_cb == nullptr) ||
@@ -570,6 +577,7 @@
LOG(ERROR) << StringPrintf("Bad ee_handle or AID (len=%d)", aid_len);
status = NFA_STATUS_INVALID_PARAM;
} else {
+ p_cb->nfcee_id = nfcee_id;
p_msg = (tNFA_EE_API_ADD_AID*)GKI_getbuf(size);
if (p_msg != nullptr) {
if (p_aid != nullptr)
diff --git a/src/nfa/hci/nfa_hci_act.cc b/src/nfa/hci/nfa_hci_act.cc
index 70c519c..ae9c3b1 100644
--- a/src/nfa/hci/nfa_hci_act.cc
+++ b/src/nfa/hci/nfa_hci_act.cc
@@ -1356,7 +1356,7 @@
/* Set WHITELIST */
nfa_hciu_send_set_param_cmd(
NFA_HCI_ADMIN_PIPE, NFA_HCI_WHITELIST_INDEX,
- p_nfa_hci_cfg->num_whitelist_host, p_nfa_hci_cfg->p_whitelist);
+ p_nfa_hci_cfg->num_allowlist_host, p_nfa_hci_cfg->p_allowlist);
} else if (nfa_hci_cb.param_in_use == NFA_HCI_WHITELIST_INDEX) {
if ((nfa_hci_cb.hci_state == NFA_HCI_STATE_STARTUP) ||
(nfa_hci_cb.hci_state == NFA_HCI_STATE_RESTORE))
@@ -1408,7 +1408,7 @@
/* Session has not changed, Set WHITELIST */
nfa_hciu_send_set_param_cmd(
NFA_HCI_ADMIN_PIPE, NFA_HCI_WHITELIST_INDEX,
- p_nfa_hci_cfg->num_whitelist_host, p_nfa_hci_cfg->p_whitelist);
+ p_nfa_hci_cfg->num_allowlist_host, p_nfa_hci_cfg->p_allowlist);
} else {
/* Something wrong, NVRAM data could be corrupt or first start with
* default session id */
diff --git a/src/nfa/include/nfa_api.h b/src/nfa/include/nfa_api.h
index d89c6f3..b94f45e 100755
--- a/src/nfa/include/nfa_api.h
+++ b/src/nfa/include/nfa_api.h
@@ -573,10 +573,10 @@
uint16_t hci_netwk_enable_timeout;
/* Maximum time to wait for EE DISC REQ NTF(s) after HOT PLUG EVT(s) */
uint16_t hcp_response_timeout;
- /* Number of host in the whitelist of Terminal host */
- uint8_t num_whitelist_host;
- /* Whitelist of Terminal Host */
- uint8_t* p_whitelist;
+ /* Number of host in the allowlist of Terminal host */
+ uint8_t num_allowlist_host;
+ /* Allowlist of Terminal Host */
+ uint8_t* p_allowlist;
} tNFA_HCI_CFG;
/*
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/include/nfa_ee_int.h b/src/nfa/include/nfa_ee_int.h
index cf1781a..b280562 100644
--- a/src/nfa/include/nfa_ee_int.h
+++ b/src/nfa/include/nfa_ee_int.h
@@ -30,10 +30,12 @@
/*****************************************************************************
** Constants and data types
*****************************************************************************/
-/* the number of tNFA_EE_ECBs (for NFCEEs and DH) */
-#define NFA_EE_NUM_ECBS (NFA_EE_MAX_EE_SUPPORTED + 1)
+/* the number of tNFA_EE_ECBs (for NFCEEs and DH) + Empty aid ECB */
+#define NFA_EE_NUM_ECBS (NFA_EE_MAX_EE_SUPPORTED + 2)
/* The index for DH in nfa_ee_cb.ee_cb[] */
#define NFA_EE_CB_4_DH NFA_EE_MAX_EE_SUPPORTED
+/* The index for Empty aid in nfa_ee_cb.ee_cb[] */
+#define NFA_EE_EMPTY_AID_ECB (NFA_EE_CB_4_DH + 1)
#define NFA_EE_INVALID 0xFF
/* only A, B, F, Bprime are supported by UICC now */
#define NFA_EE_MAX_TECH_ROUTE 4
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/nci/nci_hmsgs.cc b/src/nfc/nci/nci_hmsgs.cc
index 885ebaa..ed7caaa 100644
--- a/src/nfc/nci/nci_hmsgs.cc
+++ b/src/nfc/nci/nci_hmsgs.cc
@@ -22,13 +22,15 @@
* commands (for DH).
*
******************************************************************************/
-#include <string.h>
-#include "nfc_target.h"
-
-#include "nci_defs.h"
#include "nci_hmsgs.h"
+
+#include <string.h>
+
+#include "include/debug_lmrt.h"
+#include "nci_defs.h"
#include "nfc_api.h"
#include "nfc_int.h"
+#include "nfc_target.h"
/*******************************************************************************
**
@@ -655,6 +657,10 @@
UINT8_TO_STREAM(pp, num_tlv);
ARRAY_TO_STREAM(pp, p_param_tlvs, tlv_size);
}
+
+ uint8_t* lmrt_head_ptr = (uint8_t*)(p + 1) + p->offset;
+ lmrt_capture(lmrt_head_ptr, size + 3);
+
nfc_ncif_send_cmd(p);
return (NCI_STATUS_OK);
diff --git a/src/nfc/nci/nci_hrcv.cc b/src/nfc/nci/nci_hrcv.cc
index 50a6297..7be4c21 100644
--- a/src/nfc/nci/nci_hrcv.cc
+++ b/src/nfc/nci/nci_hrcv.cc
@@ -333,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;
@@ -412,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_main.cc b/src/nfc/nfc/nfc_main.cc
index a03fa7a..1b25eeb 100644
--- a/src/nfc/nfc/nfc_main.cc
+++ b/src/nfc/nfc/nfc_main.cc
@@ -148,7 +148,7 @@
return "HAL_NFC_RELEASE_CONTROL_EVT";
case HAL_NFC_ERROR_EVT:
return "HAL_NFC_ERROR_EVT";
- case (uint32_t)NfcEvent::HCI_NETWORK_RESET:
+ case HAL_HCI_NETWORK_RESET:
return "HCI_NETWORK_RESET";
default:
return "???? UNKNOWN EVENT";
@@ -526,7 +526,7 @@
}
break;
- case (uint32_t)NfcEvent::HCI_NETWORK_RESET:
+ case HAL_HCI_NETWORK_RESET:
delete_stack_non_volatile_store(true);
break;
@@ -630,7 +630,7 @@
case HAL_NFC_REQUEST_CONTROL_EVT:
case HAL_NFC_RELEASE_CONTROL_EVT:
case HAL_NFC_ERROR_EVT:
- case (uint32_t)NfcEvent::HCI_NETWORK_RESET:
+ case HAL_HCI_NETWORK_RESET:
nfc_main_post_hal_evt(event, status);
break;
diff --git a/src/nfc/nfc/nfc_ncif.cc b/src/nfc/nfc/nfc_ncif.cc
index 1eb8d82..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;
@@ -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 5bf9afc..d4391d2 100644
--- a/src/nfc/tags/rw_i93.cc
+++ b/src/nfc/tags/rw_i93.cc
@@ -2287,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 */
diff --git a/src/nfc/tags/rw_mfc.cc b/src/nfc/tags/rw_mfc.cc
index 649f333..8803f2d 100644
--- a/src/nfc/tags/rw_mfc.cc
+++ b/src/nfc/tags/rw_mfc.cc
@@ -694,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;
}
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..fd4ae32
--- /dev/null
+++ b/src/rust/hal/hal.rs
@@ -0,0 +1,146 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! 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 std::collections::HashMap;
+use std::sync::Arc;
+use thiserror::Error;
+use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
+use tokio::sync::{oneshot, Mutex};
+
+#[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 events
+ pub hal_events: HalEventRegistry,
+ /// 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
+}
+
+/// NFC HAL specific events
+#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
+pub enum HalEvent {
+ /// HAL CLOSE_CPLT event
+ CloseComplete,
+}
+
+/// Status of a NFC HAL event
+#[derive(Debug)]
+pub enum HalEventStatus {
+ /// HAL OK status
+ Success,
+ /// HAL FAILED status
+ Failed,
+ /// HAL ERR_TRANSPORT status
+ TransportError,
+ /// HAL ERR_CMD_TIMEOUT status
+ Timeout,
+ /// HAL REFUSED status
+ Refused,
+}
+
+/// Provides ability to register and unregister for HAL event notifications
+#[derive(Clone)]
+pub struct HalEventRegistry {
+ handlers: Arc<Mutex<HashMap<HalEvent, oneshot::Sender<HalEventStatus>>>>,
+}
+
+impl HalEventRegistry {
+ /// Indicate interest in specific HAL event
+ pub async fn register(&mut self, event: HalEvent, sender: oneshot::Sender<HalEventStatus>) {
+ assert!(
+ self.handlers.lock().await.insert(event, sender).is_none(),
+ "A handler for {:?} is already registered",
+ event
+ );
+ }
+
+ /// Remove interest in specific HAL event
+ pub async fn unregister(&mut self, event: HalEvent) -> Option<oneshot::Sender<HalEventStatus>> {
+ self.handlers.lock().await.remove(&event)
+ }
+}
+
+mod internal {
+ use crate::{Hal, HalEventRegistry};
+ use nfc_packets::nci::{DataPacket, NciPacket};
+ use std::collections::HashMap;
+ use std::sync::Arc;
+ use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
+ use tokio::sync::Mutex;
+
+ 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();
+ let handlers = Arc::new(Mutex::new(HashMap::new()));
+ let hal_events = HalEventRegistry { handlers };
+ (
+ Hal { hal_events, 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..91e67ef
--- /dev/null
+++ b/src/rust/hal/hidl_hal.rs
@@ -0,0 +1,174 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! 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, HalEvent, HalEventRegistry, HalEventStatus, Result};
+use lazy_static::lazy_static;
+use log::{debug, error};
+use nfc_packets::nci::{DataPacket, NciPacket, Packet};
+use std::sync::Mutex;
+use tokio::select;
+use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
+use tokio::sync::oneshot;
+
+/// Initialize the module
+pub async fn init() -> Hal {
+ let (raw_hal, inner_hal) = InnerHal::new();
+ let (hal_open_evt_tx, hal_open_evt_rx) = oneshot::channel::<ffi::NfcStatus>();
+ let (hal_close_evt_tx, hal_close_evt_rx) = oneshot::channel::<ffi::NfcStatus>();
+ *CALLBACKS.lock().unwrap() = Some(Callbacks {
+ hal_open_evt_tx: Some(hal_open_evt_tx),
+ hal_close_evt_tx: Some(hal_close_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.await.unwrap();
+
+ tokio::spawn(dispatch_outgoing(
+ raw_hal.hal_events.clone(),
+ inner_hal.out_cmd_rx,
+ inner_hal.out_data_rx,
+ hal_close_evt_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]);
+ }
+}
+
+impl From<ffi::NfcStatus> for HalEventStatus {
+ fn from(ffi_nfc_status: ffi::NfcStatus) -> Self {
+ match ffi_nfc_status {
+ ffi::NfcStatus::OK => HalEventStatus::Success,
+ ffi::NfcStatus::FAILED => HalEventStatus::Failed,
+ ffi::NfcStatus::ERR_TRANSPORT => HalEventStatus::TransportError,
+ ffi::NfcStatus::ERR_CMD_TIMEOUT => HalEventStatus::Timeout,
+ ffi::NfcStatus::REFUSED => HalEventStatus::Refused,
+ _ => HalEventStatus::Failed,
+ }
+ }
+}
+
+struct Callbacks {
+ hal_open_evt_tx: Option<oneshot::Sender<ffi::NfcStatus>>,
+ hal_close_evt_tx: Option<oneshot::Sender<ffi::NfcStatus>>,
+ 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) {
+ debug!("got event: {:?} with status {:?}", evt, status);
+ let mut callbacks = CALLBACKS.lock().unwrap();
+ match evt {
+ ffi::NfcEvent::OPEN_CPLT => {
+ if let Some(evt_tx) = callbacks.as_mut().unwrap().hal_open_evt_tx.take() {
+ evt_tx.send(status).unwrap();
+ }
+ }
+ ffi::NfcEvent::CLOSE_CPLT => {
+ if let Some(evt_tx) = callbacks.as_mut().unwrap().hal_close_evt_tx.take() {
+ evt_tx.send(status).unwrap();
+ }
+ }
+ _ => error!("Unhandled HAL event {:?}", evt),
+ }
+}
+
+fn on_data(data: &[u8]) {
+ debug!("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 hal_events: HalEventRegistry,
+ mut out_cmd_rx: UnboundedReceiver<NciPacket>,
+ mut out_data_rx: UnboundedReceiver<DataPacket>,
+ hal_close_evt_rx: oneshot::Receiver<ffi::NfcStatus>,
+) {
+ 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,
+ }
+ }
+ ffi::stop_hal();
+ let status = hal_close_evt_rx.await.unwrap();
+ if let Some(evt) = hal_events.unregister(HalEvent::CloseComplete).await {
+ evt.send(HalEventStatus::from(status)).unwrap();
+ }
+}
diff --git a/src/rust/hal/rootcanal_hal.rs b/src/rust/hal/rootcanal_hal.rs
new file mode 100644
index 0000000..b52154d
--- /dev/null
+++ b/src/rust/hal/rootcanal_hal.rs
@@ -0,0 +1,128 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! 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, HalEvent, HalEventRegistry, HalEventStatus, 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(
+ raw_hal.hal_events.clone(),
+ 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) => {
+ if in_cmd_tx.send(p).is_err() {
+ break;
+ }
+ }
+ Err(e) => error!("dropping invalid cmd event packet: {}: {:02x}", e, frozen),
+ }
+ } else {
+ match DataPacket::parse(&frozen) {
+ Ok(p) => {
+ if in_data_tx.send(p).is_err() {
+ break;
+ }
+ }
+ Err(e) => error!("dropping invalid data event packet: {}: {:02x}", e, frozen),
+ }
+ }
+ }
+ debug!("Dispatch incoming finished.");
+ Ok(())
+}
+
+/// Send commands received from the NCI later to rootcanal
+async fn dispatch_outgoing<W>(
+ mut hal_events: HalEventRegistry,
+ 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,
+ }
+ }
+
+ writer.shutdown().await?;
+ if let Some(evt) = hal_events.unregister(HalEvent::CloseComplete).await {
+ evt.send(HalEventStatus::Success).unwrap();
+ }
+ debug!("Dispatch outgoing finished.");
+ 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/api.rs b/src/rust/nci/api.rs
new file mode 100644
index 0000000..2bd4ae6
--- /dev/null
+++ b/src/rust/nci/api.rs
@@ -0,0 +1,137 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! NCI API module
+
+use crate::{CommandSender, Result};
+use log::debug;
+use nfc_hal::{HalEvent, HalEventRegistry, HalEventStatus};
+use nfc_packets::nci::{FeatureEnable, PacketBoundaryFlag, ResetType};
+use nfc_packets::nci::{InitCommandBuilder, ResetCommandBuilder};
+use tokio::sync::oneshot;
+
+/// NCI API object to manage static API data
+pub struct NciApi {
+ /// Command Sender external interface
+ commands: Option<CommandSender>,
+ /// The NFC response callback
+ callback: Option<fn(u16, &[u8])>,
+ /// HalEventRegistry is used to register for HAL events
+ hal_events: Option<HalEventRegistry>,
+}
+
+impl NciApi {
+ /// NciApi constructor
+ pub fn new() -> NciApi {
+ NciApi { commands: None, callback: None, hal_events: None }
+ }
+
+ /** ****************************************************************************
+ **
+ ** Function nfc_enable
+ **
+ ** Description This function enables NFC. Prior to calling NFC_Enable:
+ ** - the NFCC must be powered up, and ready to receive
+ ** commands.
+ **
+ ** This function opens the NCI transport (if applicable),
+ ** resets the NFC controller, and initializes the NFC
+ ** subsystems.
+ **
+ ** When the NFC startup procedure is completed, an
+ ** NFC_ENABLE_REVT is returned to the application using the
+ ** tNFC_RESPONSE_CBACK.
+ **
+ ** Returns tNFC_STATUS
+ **
+ *******************************************************************************/
+ /// extern tNFC_STATUS NFC_Enable(tNFC_RESPONSE_CBACK* p_cback);
+ pub async fn nfc_enable(&mut self, callback: fn(u16, &[u8])) {
+ let nci = crate::init().await;
+
+ self.commands = Some(nci.commands);
+ self.callback = Some(callback);
+ self.hal_events = Some(nci.hal_events);
+ }
+ /** ****************************************************************************
+ **
+ ** Function NFC_Disable
+ **
+ ** Description This function performs clean up routines for shutting down
+ ** NFC and closes the NCI transport (if using dedicated NCI
+ ** transport).
+ **
+ ** When the NFC shutdown procedure is completed, an
+ ** NFC_DISABLED_REVT is returned to the application using the
+ ** tNFC_RESPONSE_CBACK.
+ **
+ ** Returns nothing
+ **
+ *******************************************************************************/
+ // extern void NFC_Disable(void);
+ pub async fn nfc_disable(&mut self) {
+ let (tx, rx) = oneshot::channel::<HalEventStatus>();
+ if let Some(mut hr) = self.hal_events.take() {
+ hr.register(HalEvent::CloseComplete, tx).await;
+
+ if let Some(cmd) = self.commands.take() {
+ drop(cmd);
+ }
+ let status = rx.await.unwrap();
+ debug!("Shutdown complete {:?}.", status);
+
+ if let Some(cb) = self.callback.take() {
+ cb(1, &[]);
+ }
+ }
+ }
+
+ /** ****************************************************************************
+ **
+ ** Function NFC_Init
+ **
+ ** Description This function initializes control blocks for NFC
+ **
+ ** Returns nothing
+ **
+ *******************************************************************************/
+ /// extern void NFC_Init(tHAL_NFC_ENTRY* p_hal_entry_tbl);
+ pub async fn nfc_init(&mut self) -> Result<()> {
+ let pbf = PacketBoundaryFlag::CompleteOrFinal;
+ if let Some(cmd) = self.commands.as_mut() {
+ let reset = cmd
+ .send_and_notify(
+ ResetCommandBuilder { gid: 0, pbf, reset_type: ResetType::ResetConfig }
+ .build()
+ .into(),
+ )
+ .await?;
+ let _notification_packet = reset.notification.await?;
+ let _init = cmd
+ .send(
+ InitCommandBuilder { gid: 0, pbf, feature_enable: FeatureEnable::Rfu }
+ .build()
+ .into(),
+ )
+ .await?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for NciApi {
+ fn default() -> Self {
+ Self::new()
+ }
+}
diff --git a/src/rust/nci/nci.rs b/src/rust/nci/nci.rs
new file mode 100644
index 0000000..d0743f1
--- /dev/null
+++ b/src/rust/nci/nci.rs
@@ -0,0 +1,231 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! NCI Protocol Abstraction Layer
+//! Supports sending NCI commands to the HAL and receiving
+//! NCI messages back
+
+use log::{debug, error};
+use nfc_hal::{Hal, HalEventRegistry};
+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};
+
+pub mod api;
+
+/// 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 hal_events = hc.hal_events.clone();
+
+ let notifications = EventRegistry { handlers: Arc::new(Mutex::new(HashMap::new())) };
+
+ tokio::spawn(dispatch(notifications, hc, ic, cmd_rx));
+ Nci { hal_events, commands, out_data_ext, in_data_ext }
+}
+
+/// NCI module external interface
+pub struct Nci {
+ /// HAL events
+ pub hal_events: HalEventRegistry,
+ /// 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 })
+ }
+}
+
+impl Drop for CommandSender {
+ fn drop(&mut self) {
+ debug!("CommandSender is dropped");
+ }
+}
+
+/// 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);
+ // The max_deadline is used to set the sleep() deadline to a very distant moment in
+ // the future, when the notification from the timer is not required.
+ 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),
+ }
+ },
+ qc = cmd_rx.recv(), if pending.is_none() => if let Some(queued) = qc {
+ debug!("cmd_rx got a q");
+ 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);
+ } else {
+ break;
+ },
+ () = &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.unwrap(),
+ Some(data) = ic.out_data_int.recv() => hc.out_data_tx.send(data).unwrap(),
+ else => {
+ debug!("Select is done");
+ break;
+ },
+ }
+ }
+ debug!("NCI dispatch is terminated.");
+ 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..e7d20a4
--- /dev/null
+++ b/src/rust/rootcanal/main.rs
@@ -0,0 +1,185 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! This 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, ErrorKind};
+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?;
+
+ for _ in 0..2 {
+ 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,
+ RootcanalError::IoError(e) => {
+ if e.kind() == ErrorKind::UnexpectedEof {
+ 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..aa01629
--- /dev/null
+++ b/src/rust/test/main.rs
@@ -0,0 +1,43 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Rootcanal HAL
+//! This connects to "rootcanal" which provides a simulated
+//! Nfc chip as well as a simulated environment.
+
+use log::{debug, Level};
+use logger::{self, Config};
+use nfc_rnci::api::NciApi;
+
+/// Result type
+type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
+
+/// The NFC response callback
+pub fn nfc_callback(kind: u16, _val: &[u8]) {
+ debug!("Callback {} received", kind);
+}
+
+#[tokio::main]
+async fn main() -> Result<()> {
+ logger::init(Config::default().with_tag_on_device("lnfc").with_min_level(Level::Trace));
+
+ let mut nci = NciApi::new();
+ nci.nfc_enable(nfc_callback).await;
+ nci.nfc_init().await?;
+ nci.nfc_disable().await;
+ nci.nfc_enable(nfc_callback).await;
+ nci.nfc_init().await?;
+ nci.nfc_disable().await;
+ Ok(())
+}
diff --git a/utils/config.cc b/utils/config.cc
index 6354a2e..40be00f 100644
--- a/utils/config.cc
+++ b/utils/config.cc
@@ -59,6 +59,13 @@
value_unsigned_ = value;
}
+ConfigValue::ConfigValue(std::vector<int8_t> value) {
+ CHECK(!(value.empty()));
+ type_ = BYTES;
+ value_bytes_ = std::vector<uint8_t>(value.begin(), value.end());
+ value_unsigned_ = 0;
+}
+
ConfigValue::ConfigValue(std::vector<uint8_t> value) {
CHECK(!(value.empty()));
type_ = BYTES;
diff --git a/utils/include/config.h b/utils/include/config.h
index f4bcdec..e48717b 100644
--- a/utils/include/config.h
+++ b/utils/include/config.h
@@ -27,6 +27,7 @@
explicit ConfigValue(std::string);
explicit ConfigValue(unsigned);
explicit ConfigValue(std::vector<uint8_t>);
+ explicit ConfigValue(std::vector<int8_t>);
Type getType() const;
std::string getString() const;
unsigned getUnsigned() const;
diff --git a/utils/include/ringbuffer.h b/utils/include/ringbuffer.h
index d2c310a..35cc023 100644
--- a/utils/include/ringbuffer.h
+++ b/utils/include/ringbuffer.h
@@ -19,6 +19,7 @@
#pragma once
#include <stdint.h>
+#include <sys/types.h>
typedef struct ringbuffer_t ringbuffer_t;