| /* |
| * Copyright (C) 2013 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. |
| */ |
| |
| /* |
| * Manage the listen-mode routing table. |
| */ |
| |
| #include "RoutingManager.h" |
| // Redefined by android-base headers. |
| #undef ATTRIBUTE_UNUSED |
| |
| #include <android-base/logging.h> |
| #include <android-base/stringprintf.h> |
| #include <nativehelper/JNIHelp.h> |
| #include <nativehelper/ScopedLocalRef.h> |
| |
| #include "JavaClassConstants.h" |
| #include "nfa_ce_api.h" |
| #include "nfa_ee_api.h" |
| #include "nfc_config.h" |
| |
| using android::base::StringPrintf; |
| |
| extern bool gActivated; |
| extern SyncEvent gDeactivatedEvent; |
| |
| const JNINativeMethod RoutingManager::sMethods[] = { |
| {"doGetDefaultRouteDestination", "()I", |
| (void*)RoutingManager:: |
| com_android_nfc_cardemulation_doGetDefaultRouteDestination}, |
| {"doGetDefaultOffHostRouteDestination", "()I", |
| (void*)RoutingManager:: |
| com_android_nfc_cardemulation_doGetDefaultOffHostRouteDestination}, |
| {"doGetDefaultFelicaRouteDestination", "()I", |
| (void*)RoutingManager:: |
| com_android_nfc_cardemulation_doGetDefaultFelicaRouteDestination}, |
| {"doGetOffHostUiccDestination", "()[B", |
| (void*)RoutingManager:: |
| com_android_nfc_cardemulation_doGetOffHostUiccDestination}, |
| {"doGetOffHostEseDestination", "()[B", |
| (void*)RoutingManager:: |
| com_android_nfc_cardemulation_doGetOffHostEseDestination}, |
| {"doGetAidMatchingMode", "()I", |
| (void*)RoutingManager::com_android_nfc_cardemulation_doGetAidMatchingMode}, |
| {"doGetDefaultIsoDepRouteDestination", "()I", |
| (void*)RoutingManager:: |
| com_android_nfc_cardemulation_doGetDefaultIsoDepRouteDestination}, |
| {"doGetDefaultScRouteDestination", "()I", |
| (void*)RoutingManager:: |
| com_android_nfc_cardemulation_doGetDefaultScRouteDestination}, |
| {"doGetEuiccMepMode", "()I", |
| (void*)RoutingManager::com_android_nfc_cardemulation_doGetEuiccMepMode}}; |
| |
| static const int MAX_NUM_EE = 5; |
| // SCBR from host works only when App is in foreground |
| static const uint8_t SYS_CODE_PWR_STATE_HOST = 0x01; |
| static const uint16_t DEFAULT_SYS_CODE = 0xFEFE; |
| |
| static const uint8_t AID_ROUTE_QUAL_PREFIX = 0x10; |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: RoutingManager |
| ** |
| ** Description: Constructor |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| RoutingManager::RoutingManager() |
| : mSecureNfcEnabled(false), |
| mNativeData(NULL), |
| mAidRoutingConfigured(false) { |
| static const char fn[] = "RoutingManager::RoutingManager()"; |
| |
| mDefaultOffHostRoute = |
| NfcConfig::getUnsigned(NAME_DEFAULT_OFFHOST_ROUTE, 0x00); |
| |
| if (NfcConfig::hasKey(NAME_OFFHOST_ROUTE_UICC)) { |
| mOffHostRouteUicc = NfcConfig::getBytes(NAME_OFFHOST_ROUTE_UICC); |
| } |
| |
| if (NfcConfig::hasKey(NAME_OFFHOST_ROUTE_ESE)) { |
| mOffHostRouteEse = NfcConfig::getBytes(NAME_OFFHOST_ROUTE_ESE); |
| } |
| |
| mDefaultFelicaRoute = NfcConfig::getUnsigned(NAME_DEFAULT_NFCF_ROUTE, 0x00); |
| LOG(DEBUG) << StringPrintf("%s: Active SE for Nfc-F is 0x%02X", fn, |
| mDefaultFelicaRoute); |
| |
| mDefaultEe = NfcConfig::getUnsigned(NAME_DEFAULT_ROUTE, 0x00); |
| LOG(DEBUG) << StringPrintf("%s: default route is 0x%02X", fn, mDefaultEe); |
| |
| mAidMatchingMode = |
| NfcConfig::getUnsigned(NAME_AID_MATCHING_MODE, AID_MATCHING_EXACT_ONLY); |
| |
| mDefaultSysCodeRoute = |
| NfcConfig::getUnsigned(NAME_DEFAULT_SYS_CODE_ROUTE, 0xC0); |
| |
| mDefaultSysCodePowerstate = |
| NfcConfig::getUnsigned(NAME_DEFAULT_SYS_CODE_PWR_STATE, 0x19); |
| |
| mDefaultSysCode = DEFAULT_SYS_CODE; |
| if (NfcConfig::hasKey(NAME_DEFAULT_SYS_CODE)) { |
| std::vector<uint8_t> pSysCode = NfcConfig::getBytes(NAME_DEFAULT_SYS_CODE); |
| if (pSysCode.size() == 0x02) { |
| mDefaultSysCode = ((pSysCode[0] << 8) | ((int)pSysCode[1] << 0)); |
| LOG(DEBUG) << StringPrintf("%s: DEFAULT_SYS_CODE=0x%02X", __func__, |
| mDefaultSysCode); |
| } |
| } |
| |
| mOffHostAidRoutingPowerState = |
| NfcConfig::getUnsigned(NAME_OFFHOST_AID_ROUTE_PWR_STATE, 0x01); |
| |
| mDefaultIsoDepRoute = NfcConfig::getUnsigned(NAME_DEFAULT_ISODEP_ROUTE, 0x0); |
| |
| mHostListenTechMask = |
| NfcConfig::getUnsigned(NAME_HOST_LISTEN_TECH_MASK, |
| NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_F); |
| |
| mOffHostListenTechMask = NfcConfig::getUnsigned( |
| NAME_OFFHOST_LISTEN_TECH_MASK, |
| NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B | NFA_TECHNOLOGY_MASK_F); |
| |
| mEuiccMepMode= NfcConfig::getUnsigned(NAME_EUICC_MEP_MODE, 0x0); |
| |
| if (NfcConfig::hasKey(NAME_NFCEE_EVENT_RF_DISCOVERY_OPTION)) { |
| mIsRFDiscoveryOptimized = |
| (NfcConfig::getUnsigned(NAME_NFCEE_EVENT_RF_DISCOVERY_OPTION) == 0x01 |
| ? true |
| : false); |
| LOG(VERBOSE) << StringPrintf( |
| "%s: NAME_NFCEE_EVENT_RF_DISCOVERY_OPTION found=%d", fn, |
| mIsRFDiscoveryOptimized); |
| } else { |
| mIsRFDiscoveryOptimized = false; |
| LOG(VERBOSE) << StringPrintf( |
| "%s: NAME_NFCEE_EVENT_RF_DISCOVERY_OPTION not found=%d", fn, |
| mIsRFDiscoveryOptimized); |
| } |
| |
| memset(&mEeInfo, 0, sizeof(mEeInfo)); |
| mReceivedEeInfo = false; |
| mSeTechMask = 0x00; |
| mIsScbrSupported = false; |
| |
| mNfcFOnDhHandle = NFA_HANDLE_INVALID; |
| |
| mDeinitializing = false; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: RoutingManager |
| ** |
| ** Description: Destructor |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| RoutingManager::~RoutingManager() {} |
| |
| /******************************************************************************* |
| ** |
| ** Function: initialize |
| ** |
| ** Description: Initialize the object |
| ** |
| ** Returns: true if OK |
| ** false if failed |
| ** |
| *******************************************************************************/ |
| bool RoutingManager::initialize(nfc_jni_native_data* native) { |
| static const char fn[] = "RoutingManager::initialize()"; |
| mNativeData = native; |
| mRxDataBuffer.clear(); |
| |
| { |
| SyncEventGuard guard(mEeRegisterEvent); |
| LOG(DEBUG) << fn << ": try ee register"; |
| tNFA_STATUS nfaStat = NFA_EeRegister(nfaEeCallback); |
| if (nfaStat != NFA_STATUS_OK) { |
| LOG(ERROR) << StringPrintf("%s: fail ee register; error=0x%X", fn, |
| nfaStat); |
| return false; |
| } |
| mEeRegisterEvent.wait(); |
| } |
| |
| if ((mDefaultOffHostRoute != 0) || (mDefaultFelicaRoute != 0)) { |
| // Wait for EE info if needed |
| SyncEventGuard guard(mEeInfoEvent); |
| if (!mReceivedEeInfo) { |
| LOG(INFO) << fn << ": Waiting for EE info"; |
| mEeInfoEvent.wait(); |
| } |
| } |
| |
| // Set the host-routing Tech |
| tNFA_STATUS nfaStat = NFA_CeSetIsoDepListenTech( |
| mHostListenTechMask & (NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B)); |
| |
| if (nfaStat != NFA_STATUS_OK) |
| LOG(ERROR) << StringPrintf("%s: Failed to configure CE IsoDep technologies", |
| fn); |
| |
| // Register a wild-card for AIDs routed to the host |
| nfaStat = NFA_CeRegisterAidOnDH(NULL, 0, stackCallback); |
| if (nfaStat != NFA_STATUS_OK) |
| LOG(ERROR) << fn << ": Failed to register wildcard AID for DH"; |
| |
| // Trigger RT update |
| mEeInfoChanged = true; |
| mDefaultAidRouteAdded = false; |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: getInstance |
| ** |
| ** Description: Get an instance of RoutingManager object |
| ** |
| ** Returns: handle to object |
| ** |
| *******************************************************************************/ |
| RoutingManager& RoutingManager::getInstance() { |
| static RoutingManager manager; |
| return manager; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: isTypeATypeBTechSupportedInEe |
| ** |
| ** Description: receive eeHandle |
| ** |
| ** Returns: true : if EE support protocol type A/B |
| ** false : if EE doesn't protocol type A/B |
| ** |
| *******************************************************************************/ |
| bool RoutingManager::isTypeATypeBTechSupportedInEe(tNFA_HANDLE eeHandle) { |
| static const char fn[] = "RoutingManager::isTypeATypeBTechSupportedInEe"; |
| uint8_t actualNbEe = MAX_NUM_EE; |
| tNFA_EE_INFO eeInfo[actualNbEe]; |
| |
| memset(&eeInfo, 0, actualNbEe * sizeof(tNFA_EE_INFO)); |
| tNFA_STATUS nfaStat = NFA_EeGetInfo(&actualNbEe, eeInfo); |
| if (nfaStat != NFA_STATUS_OK) { |
| return false; |
| } |
| for (auto i = 0; i < actualNbEe; i++) { |
| if (eeHandle == eeInfo[i].ee_handle) { |
| if (eeInfo[i].la_protocol || eeInfo[i].lb_protocol) { |
| return true; |
| } |
| } |
| } |
| |
| if (mEuiccMepMode) { |
| memset(&eeInfo, 0, MAX_NUM_EE * sizeof(tNFA_EE_INFO)); |
| nfaStat = NFA_EeGetMepInfo(&actualNbEe, eeInfo); |
| if (nfaStat != NFA_STATUS_OK) { |
| return false; |
| } |
| for (auto i = 0; i < actualNbEe; i++) { |
| if (eeHandle == eeInfo[i].ee_handle) { |
| if (eeInfo[i].la_protocol || eeInfo[i].lb_protocol) { |
| return true; |
| } |
| } |
| } |
| } |
| |
| LOG(WARNING) << StringPrintf( |
| "%s: Route does not support A/B, using DH as default", fn); |
| return false; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: addAidRouting |
| ** |
| ** Description: Add an AID to be programmed in routing table. |
| ** |
| ** Returns: true if procedure OK |
| ** false if procedure failed |
| ** |
| *******************************************************************************/ |
| bool RoutingManager::addAidRouting(const uint8_t* aid, uint8_t aidLen, |
| int route, int aidInfo, int power) { |
| static const char fn[] = "RoutingManager::addAidRouting"; |
| uint8_t powerState = 0x01; |
| |
| if (route != NFC_DH_ID && |
| !isTypeATypeBTechSupportedInEe(route | NFA_HANDLE_GROUP_EE)) { |
| route = NFC_DH_ID; |
| } |
| |
| if (!mSecureNfcEnabled) { |
| if (power == 0x00) { |
| powerState = (route != 0x00) ? mOffHostAidRoutingPowerState : 0x11; |
| } else { |
| powerState = |
| (route != 0x00) ? mOffHostAidRoutingPowerState & power : power; |
| } |
| } |
| |
| if (aidLen == 0) { |
| LOG(DEBUG) << StringPrintf( |
| "%s: default AID on route=%02x, aidInfo=%02x, power=%02x", fn, route, |
| aidInfo, power); |
| mDefaultAidRouteAdded = true; |
| } else { |
| LOG(DEBUG) << StringPrintf( |
| "%s: aidLen =%02X, route=%02x, aidInfo=%02x, power=%02x", fn, aidLen, |
| route, aidInfo, power); |
| } |
| |
| SyncEventGuard guard(mAidAddRemoveEvent); |
| mAidRoutingConfigured = false; |
| tNFA_STATUS nfaStat = |
| NFA_EeAddAidRouting(route, aidLen, (uint8_t*)aid, powerState, aidInfo); |
| if (nfaStat == NFA_STATUS_OK) { |
| mAidAddRemoveEvent.wait(); |
| } |
| if (mAidRoutingConfigured) { |
| return true; |
| } else { |
| LOG(ERROR) << fn << ": failed to route AID"; |
| return false; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: removeAidRouting |
| ** |
| ** Description: Removes an AID from the routing table |
| ** |
| ** Returns: true if procedure OK |
| ** false if procedure failed |
| ** |
| *******************************************************************************/ |
| bool RoutingManager::removeAidRouting(const uint8_t* aid, uint8_t aidLen) { |
| static const char fn[] = "RoutingManager::removeAidRouting"; |
| |
| if (aidLen != 0) { |
| LOG(DEBUG) << StringPrintf("%s: len=%d, 0x%x 0x%x 0x%x 0x%x 0x%x", __func__, |
| aidLen, *(aid), *(aid + 1), *(aid + 2), |
| *(aid + 3), *(aid + 4)); |
| } else { |
| LOG(DEBUG) << fn << ": Remove Empty aid"; |
| } |
| |
| SyncEventGuard guard(mAidAddRemoveEvent); |
| mAidRoutingConfigured = false; |
| tNFA_STATUS nfaStat = NFA_EeRemoveAidRouting(aidLen, (uint8_t*)aid); |
| if (nfaStat == NFA_STATUS_OK) { |
| mAidAddRemoveEvent.wait(); |
| } |
| if (mAidRoutingConfigured) { |
| return true; |
| } else { |
| LOG(WARNING) << fn << ": failed to remove AID"; |
| return false; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: commitRouting |
| ** |
| ** Description: Ask for routing table update |
| ** |
| ** Returns: true if procedure OK |
| ** false if procedure failed |
| ** |
| *******************************************************************************/ |
| tNFA_STATUS RoutingManager::commitRouting() { |
| static const char fn[] = "RoutingManager::commitRouting"; |
| tNFA_STATUS nfaStat = 0; |
| if (mAidRoutingConfigured || mEeInfoChanged) { |
| LOG(DEBUG) << StringPrintf("%s: RT update needed", fn); |
| if (mEeInfoChanged) { |
| clearRoutingEntry(CLEAR_PROTOCOL_ENTRIES | CLEAR_TECHNOLOGY_ENTRIES); |
| updateRoutingTable(); |
| mEeInfoChanged = false; |
| } |
| { |
| SyncEventGuard guard(mEeUpdateEvent); |
| nfaStat = NFA_EeUpdateNow(); |
| if (nfaStat == NFA_STATUS_OK) { |
| mEeUpdateEvent.wait(); // wait for NFA_EE_UPDATED_EVT |
| } |
| } |
| } |
| return nfaStat; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: onNfccShutdown |
| ** |
| ** Description: performs tasks for NFC shutdown |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::onNfccShutdown() { |
| static const char fn[] = "RoutingManager:onNfccShutdown"; |
| if (mDefaultOffHostRoute == 0x00 && mDefaultFelicaRoute == 0x00) return; |
| |
| tNFA_STATUS nfaStat = NFA_STATUS_FAILED; |
| uint8_t actualNumEe = MAX_NUM_EE; |
| tNFA_EE_INFO eeInfo[MAX_NUM_EE]; |
| mDeinitializing = true; |
| |
| memset(&eeInfo, 0, sizeof(eeInfo)); |
| if ((nfaStat = NFA_EeGetInfo(&actualNumEe, eeInfo)) != NFA_STATUS_OK) { |
| LOG(ERROR) << StringPrintf("%s: fail get info; error=0x%X", fn, nfaStat); |
| return; |
| } |
| if (actualNumEe != 0) { |
| for (uint8_t xx = 0; xx < actualNumEe; xx++) { |
| bool bIsOffHostEEPresent = |
| (NFC_GetNCIVersion() < NCI_VERSION_2_0) |
| ? (eeInfo[xx].num_interface != 0) |
| : (eeInfo[xx].ee_interface[0] != |
| NCI_NFCEE_INTERFACE_HCI_ACCESS) && |
| (eeInfo[xx].ee_status == NFA_EE_STATUS_ACTIVE); |
| if (bIsOffHostEEPresent) { |
| LOG(DEBUG) << StringPrintf( |
| "%s: Handle=0x%04x Change Status Active to Inactive", fn, |
| eeInfo[xx].ee_handle); |
| SyncEventGuard guard(mEeSetModeEvent); |
| if ((nfaStat = NFA_EeModeSet(eeInfo[xx].ee_handle, |
| NFA_EE_MD_DEACTIVATE)) == NFA_STATUS_OK) { |
| mEeSetModeEvent.wait(); // wait for NFA_EE_MODE_SET_EVT |
| } else { |
| LOG(ERROR) << fn << ": Failed to set EE inactive"; |
| } |
| } |
| } |
| } else { |
| LOG(DEBUG) << fn << ": No active EEs found"; |
| } |
| //release waits |
| { |
| SyncEventGuard guard(mEeRegisterEvent); |
| mEeRegisterEvent.notifyOne(); |
| } |
| { |
| SyncEventGuard guard(mRoutingEvent); |
| mRoutingEvent.notifyOne(); |
| } |
| { |
| SyncEventGuard guard(mEeSetModeEvent); |
| mEeSetModeEvent.notifyOne(); |
| } |
| { |
| SyncEventGuard guard(mEePwrAndLinkCtrlEvent); |
| mEePwrAndLinkCtrlEvent.notifyOne(); |
| } |
| { |
| SyncEventGuard guard(mAidAddRemoveEvent); |
| mAidAddRemoveEvent.notifyOne(); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: notifyActivated |
| ** |
| ** Description: Notify upper layers of CE activation |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::notifyActivated(uint8_t technology) { |
| JNIEnv* e = NULL; |
| ScopedAttach attach(mNativeData->vm, &e); |
| if (e == NULL) { |
| LOG(ERROR) << __func__ << ": jni env is null"; |
| return; |
| } |
| |
| e->CallVoidMethod(mNativeData->manager, |
| android::gCachedNfcManagerNotifyHostEmuActivated, |
| (int)technology); |
| if (e->ExceptionCheck()) { |
| e->ExceptionClear(); |
| LOG(ERROR) << __func__ << ": fail notify"; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: getNameOfEe |
| ** |
| ** Description: Translates NFCEE Id into string name, if it exists |
| ** |
| ** Returns: true if handle was found |
| ** false if not |
| ** |
| *******************************************************************************/ |
| bool RoutingManager::getNameOfEe(tNFA_HANDLE ee_handle, std::string& eeName) { |
| if (mOffHostRouteEse.size() == 0) { |
| return false; |
| } |
| ee_handle &= ~NFA_HANDLE_GROUP_EE; |
| |
| for (uint8_t i = 0; i < mOffHostRouteEse.size(); i++) { |
| if (ee_handle == mOffHostRouteEse[i]) { |
| eeName = "eSE" + std::to_string(i + 1); |
| return true; |
| } |
| } |
| for (uint8_t i = 0; i < mOffHostRouteUicc.size(); i++) { |
| if (ee_handle == mOffHostRouteUicc[i]) { |
| eeName = "SIM" + std::to_string(i + 1); |
| return true; |
| } |
| } |
| |
| LOG(WARNING) << __func__ << ": Incorrect EE Id"; |
| return false; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: notifyEeAidSelected |
| ** |
| ** Description: Notify upper layers of RF_NFCEE_ACTION_NTF with trigger |
| ** AID |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::notifyEeAidSelected(tNFC_AID& nfcaid, |
| tNFA_HANDLE ee_handle) { |
| std::vector<uint8_t> aid(nfcaid.aid, nfcaid.aid + nfcaid.len_aid); |
| if (aid.empty()) { |
| return; |
| } |
| |
| JNIEnv* e = NULL; |
| ScopedAttach attach(mNativeData->vm, &e); |
| CHECK(e); |
| |
| ScopedLocalRef<jobject> aidJavaArray(e, e->NewByteArray(aid.size())); |
| CHECK(aidJavaArray.get()); |
| e->SetByteArrayRegion((jbyteArray)aidJavaArray.get(), 0, aid.size(), |
| (jbyte*)&aid[0]); |
| CHECK(!e->ExceptionCheck()); |
| |
| std::string evtSrc; |
| if (!getNameOfEe(ee_handle, evtSrc)) { |
| return; |
| } |
| |
| ScopedLocalRef<jobject> srcJavaString(e, e->NewStringUTF(evtSrc.c_str())); |
| CHECK(srcJavaString.get()); |
| e->CallVoidMethod(mNativeData->manager, |
| android::gCachedNfcManagerNotifyEeAidSelected, |
| aidJavaArray.get(), srcJavaString.get()); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: notifyEeProtocolSelected |
| ** |
| ** Description: Notify upper layers of RF_NFCEE_ACTION_NTF with trigger |
| ** protocol |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::notifyEeProtocolSelected(uint8_t protocol, |
| tNFA_HANDLE ee_handle) { |
| JNIEnv* e = NULL; |
| ScopedAttach attach(mNativeData->vm, &e); |
| CHECK(e); |
| |
| std::string evtSrc; |
| if (!getNameOfEe(ee_handle, evtSrc)) { |
| return; |
| } |
| |
| ScopedLocalRef<jobject> srcJavaString(e, e->NewStringUTF(evtSrc.c_str())); |
| CHECK(srcJavaString.get()); |
| e->CallVoidMethod(mNativeData->manager, |
| android::gCachedNfcManagerNotifyEeProtocolSelected, |
| protocol, srcJavaString.get()); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: notifyEeTechSelected |
| ** |
| ** Description: Notify upper layers of RF_NFCEE_ACTION_NTF with trigger |
| ** technology |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::notifyEeTechSelected(uint8_t tech, tNFA_HANDLE ee_handle) { |
| JNIEnv* e = NULL; |
| ScopedAttach attach(mNativeData->vm, &e); |
| CHECK(e); |
| |
| std::string evtSrc; |
| if (!getNameOfEe(ee_handle, evtSrc)) { |
| return; |
| } |
| |
| ScopedLocalRef<jobject> srcJavaString(e, e->NewStringUTF(evtSrc.c_str())); |
| CHECK(srcJavaString.get()); |
| e->CallVoidMethod(mNativeData->manager, |
| android::gCachedNfcManagerNotifyEeTechSelected, tech, |
| srcJavaString.get()); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: notifyDeactivated |
| ** |
| ** Description: Notify upper layers for CE deactivation |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::notifyDeactivated(uint8_t technology) { |
| mRxDataBuffer.clear(); |
| JNIEnv* e = NULL; |
| ScopedAttach attach(mNativeData->vm, &e); |
| if (e == NULL) { |
| LOG(ERROR) << __func__ << ": jni env is null"; |
| return; |
| } |
| |
| e->CallVoidMethod(mNativeData->manager, |
| android::gCachedNfcManagerNotifyEeListenActivated, |
| JNI_FALSE); |
| if (e->ExceptionCheck()) { |
| e->ExceptionClear(); |
| LOG(ERROR) << StringPrintf("%s: Fail to notify Ee listen active status", |
| __func__); |
| } |
| |
| e->CallVoidMethod(mNativeData->manager, |
| android::gCachedNfcManagerNotifyHostEmuDeactivated, |
| (int)technology); |
| if (e->ExceptionCheck()) { |
| e->ExceptionClear(); |
| LOG(ERROR) << StringPrintf("%s: fail notify", __func__); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: handleData |
| ** |
| ** Description: Notify upper layers of received HCE data |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::handleData(uint8_t technology, const uint8_t* data, |
| uint32_t dataLen, tNFA_STATUS status) { |
| if (status == NFC_STATUS_CONTINUE) { |
| if (dataLen > 0) { |
| mRxDataBuffer.insert(mRxDataBuffer.end(), &data[0], |
| &data[dataLen]); // append data; more to come |
| } |
| return; // expect another NFA_CE_DATA_EVT to come |
| } else if (status == NFA_STATUS_OK) { |
| if (dataLen > 0) { |
| mRxDataBuffer.insert(mRxDataBuffer.end(), &data[0], |
| &data[dataLen]); // append data |
| } |
| // entire data packet has been received; no more NFA_CE_DATA_EVT |
| } else if (status == NFA_STATUS_FAILED) { |
| LOG(ERROR) << __func__ << ": read data fail"; |
| goto TheEnd; |
| } |
| |
| { |
| JNIEnv* e = NULL; |
| ScopedAttach attach(mNativeData->vm, &e); |
| if (e == NULL) { |
| LOG(ERROR) << __func__ << ": jni env is null"; |
| goto TheEnd; |
| } |
| |
| ScopedLocalRef<jobject> dataJavaArray( |
| e, e->NewByteArray(mRxDataBuffer.size())); |
| if (dataJavaArray.get() == NULL) { |
| LOG(ERROR) << __func__ << ": fail allocate array"; |
| goto TheEnd; |
| } |
| |
| e->SetByteArrayRegion((jbyteArray)dataJavaArray.get(), 0, |
| mRxDataBuffer.size(), (jbyte*)(&mRxDataBuffer[0])); |
| if (e->ExceptionCheck()) { |
| e->ExceptionClear(); |
| LOG(ERROR) << __func__ << ": fail fill array"; |
| goto TheEnd; |
| } |
| |
| e->CallVoidMethod(mNativeData->manager, |
| android::gCachedNfcManagerNotifyHostEmuData, |
| (int)technology, dataJavaArray.get()); |
| if (e->ExceptionCheck()) { |
| e->ExceptionClear(); |
| LOG(ERROR) << __func__ << ": fail notify"; |
| } |
| } |
| TheEnd: |
| mRxDataBuffer.clear(); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: notifyEeUpdated |
| ** |
| ** Description: notify upper layers of NFCEE RF capabilities update |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::notifyEeUpdated() { |
| JNIEnv* e = NULL; |
| ScopedAttach attach(mNativeData->vm, &e); |
| if (e == NULL) { |
| LOG(ERROR) << __func__ << ": jni env is null"; |
| return; |
| } |
| |
| e->CallVoidMethod(mNativeData->manager, |
| android::gCachedNfcManagerNotifyEeUpdated); |
| if (e->ExceptionCheck()) { |
| e->ExceptionClear(); |
| LOG(ERROR) << __func__ << ": fail notify"; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: stackCallback |
| ** |
| ** Description: Handles callback for completion of calls to NFA APIs |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::stackCallback(uint8_t event, |
| tNFA_CONN_EVT_DATA* eventData) { |
| static const char fn[] = "RoutingManager::stackCallback"; |
| RoutingManager& routingManager = RoutingManager::getInstance(); |
| |
| switch (event) { |
| case NFA_CE_REGISTERED_EVT: { |
| tNFA_CE_REGISTERED& ce_registered = eventData->ce_registered; |
| LOG(DEBUG) << StringPrintf( |
| "%s: NFA_CE_REGISTERED_EVT; status=0x%X; h=0x%X", fn, |
| ce_registered.status, ce_registered.handle); |
| } break; |
| |
| case NFA_CE_DEREGISTERED_EVT: { |
| tNFA_CE_DEREGISTERED& ce_deregistered = eventData->ce_deregistered; |
| LOG(DEBUG) << StringPrintf("%s: NFA_CE_DEREGISTERED_EVT; h=0x%X", fn, |
| ce_deregistered.handle); |
| } break; |
| |
| case NFA_CE_ACTIVATED_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_CE_ACTIVATED_EVT;", fn); |
| routingManager.notifyActivated(NFA_TECHNOLOGY_MASK_A); |
| } break; |
| |
| case NFA_DEACTIVATED_EVT: |
| case NFA_CE_DEACTIVATED_EVT: { |
| if (event == NFA_DEACTIVATED_EVT) { |
| LOG(DEBUG) << StringPrintf("%s: NFA_DEACTIVATED_EVT", fn); |
| } else { |
| LOG(DEBUG) << StringPrintf("%s: NFA_CE_DEACTIVATED_EVT", fn); |
| } |
| routingManager.notifyDeactivated(NFA_TECHNOLOGY_MASK_A); |
| SyncEventGuard g(gDeactivatedEvent); |
| gActivated = false; // guard this variable from multi-threaded access |
| gDeactivatedEvent.notifyOne(); |
| } break; |
| |
| case NFA_CE_DATA_EVT: { |
| tNFA_CE_DATA& ce_data = eventData->ce_data; |
| LOG(DEBUG) << StringPrintf( |
| "%s: NFA_CE_DATA_EVT; stat=0x%X; h=0x%X; data len=%u", fn, |
| ce_data.status, ce_data.handle, ce_data.len); |
| getInstance().handleData(NFA_TECHNOLOGY_MASK_A, ce_data.p_data, |
| ce_data.len, ce_data.status); |
| } break; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: updateRoutingTable |
| ** |
| ** Description: Receive execution environment-related events from stack. |
| ** event: Event code. |
| ** eventData: Event data. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::updateRoutingTable() { |
| static const char fn[] = "RoutingManager::updateRoutingTable"; |
| LOG(DEBUG) << fn << ":(enter)"; |
| mSeTechMask = updateEeTechRouteSetting(); |
| updateDefaultRoute(); |
| updateDefaultProtocolRoute(); |
| LOG(DEBUG) << fn << ":(exit)"; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: updateIsoDepProtocolRoute |
| ** |
| ** Description: Updates the route for ISO-DEP protocol |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::updateIsoDepProtocolRoute(int route) { |
| static const char fn[] = "RoutingManager::updateIsoDepProtocolRoute"; |
| LOG(DEBUG) << StringPrintf("%s: New default ISO-DEP route=0x%x", fn, route); |
| mEeInfoChanged = true; |
| mDefaultIsoDepRoute = route; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: updateSystemCodeRoute |
| ** |
| ** Description: Updates the route for System Code |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::updateSystemCodeRoute(int route) { |
| static const char fn[] = "RoutingManager::updateSystemCodeRoute"; |
| LOG(DEBUG) << StringPrintf("%s: New default SC route=0x%x", fn, route); |
| mEeInfoChanged = true; |
| mDefaultSysCodeRoute = route; |
| updateDefaultRoute(); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: updateDefaultProtocolRoute |
| ** |
| ** Description: Updates the default protocol routes |
| ** |
| ** Returns: |
| ** |
| *******************************************************************************/ |
| void RoutingManager::updateDefaultProtocolRoute() { |
| static const char fn[] = "RoutingManager::updateDefaultProtocolRoute"; |
| |
| LOG(DEBUG) << StringPrintf("%s: Default ISO-DEP route=0x%x", fn, |
| mDefaultIsoDepRoute); |
| // Default Routing for ISO-DEP |
| tNFA_PROTOCOL_MASK protoMask = NFA_PROTOCOL_MASK_ISO_DEP; |
| tNFA_STATUS nfaStat; |
| if (mDefaultIsoDepRoute != NFC_DH_ID && |
| isTypeATypeBTechSupportedInEe(mDefaultIsoDepRoute | |
| NFA_HANDLE_GROUP_EE)) { |
| nfaStat = NFA_EeSetDefaultProtoRouting( |
| mDefaultIsoDepRoute, protoMask, mSecureNfcEnabled ? 0 : protoMask, 0, |
| mSecureNfcEnabled ? 0 : protoMask, mSecureNfcEnabled ? 0 : protoMask, |
| mSecureNfcEnabled ? 0 : protoMask); |
| } else { |
| nfaStat = NFA_EeSetDefaultProtoRouting( |
| NFC_DH_ID, protoMask, 0, 0, mSecureNfcEnabled ? 0 : protoMask, 0, 0); |
| mDefaultIsoDepRoute = NFC_DH_ID; |
| } |
| if (nfaStat != NFA_STATUS_OK) |
| LOG(ERROR) << fn << ": failed to register default ISO-DEP route"; |
| |
| // Default routing for T3T protocol |
| if (!mIsScbrSupported) { |
| SyncEventGuard guard(mRoutingEvent); |
| tNFA_PROTOCOL_MASK protoMask = NFA_PROTOCOL_MASK_T3T; |
| if (mDefaultEe == NFC_DH_ID) { |
| nfaStat = |
| NFA_EeSetDefaultProtoRouting(NFC_DH_ID, protoMask, 0, 0, 0, 0, 0); |
| } else { |
| nfaStat = NFA_EeSetDefaultProtoRouting( |
| mDefaultEe, protoMask, 0, 0, mSecureNfcEnabled ? 0 : protoMask, |
| mSecureNfcEnabled ? 0 : protoMask, mSecureNfcEnabled ? 0 : protoMask); |
| } |
| if (nfaStat == NFA_STATUS_OK) |
| mRoutingEvent.wait(); |
| else |
| LOG(ERROR) << fn << ": Fail to set default proto routing for T3T"; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: updateDefaultRoute |
| ** |
| ** Description: Updating default AID and SC (T3T) routes |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::updateDefaultRoute() { |
| static const char fn[] = "RoutingManager::updateDefaultRoute"; |
| int defaultAidRoute = mDefaultEe; |
| |
| if (NFC_GetNCIVersion() != NCI_VERSION_2_0) return; |
| |
| LOG(DEBUG) << StringPrintf("%s: Default SC route=0x%x", fn, |
| mDefaultSysCodeRoute); |
| |
| // Register System Code for routing |
| SyncEventGuard guard(mRoutingEvent); |
| tNFA_STATUS nfaStat = NFA_EeAddSystemCodeRouting( |
| mDefaultSysCode, mDefaultSysCodeRoute, |
| mSecureNfcEnabled ? 0x01 : mDefaultSysCodePowerstate); |
| if (nfaStat == NFA_STATUS_NOT_SUPPORTED) { |
| mIsScbrSupported = false; |
| LOG(ERROR) << fn << ": SCBR not supported"; |
| } else if (nfaStat == NFA_STATUS_OK) { |
| mIsScbrSupported = true; |
| mRoutingEvent.wait(); |
| } else { |
| LOG(ERROR) << fn << ": Fail to register system code"; |
| // still support SCBR routing for other NFCEEs |
| mIsScbrSupported = true; |
| } |
| |
| // Check if default AID was already added or not |
| if (!mDefaultAidRouteAdded) { |
| LOG(DEBUG) << StringPrintf("%s: Default AID route=0x%x", fn, |
| defaultAidRoute); |
| |
| // Register zero lengthy Aid for default Aid Routing |
| if ((defaultAidRoute != NFC_DH_ID) && |
| (!isTypeATypeBTechSupportedInEe(defaultAidRoute | |
| NFA_HANDLE_GROUP_EE))) { |
| defaultAidRoute = NFC_DH_ID; |
| } |
| |
| // Default AID route should be added only if different from ISO-DEP route |
| if ((defaultAidRoute != mDefaultIsoDepRoute) || |
| (mDefaultIsoDepRoute == NFC_DH_ID)) { |
| removeAidRouting(nullptr, 0); |
| uint8_t powerState = 0x01; |
| if (!mSecureNfcEnabled) |
| powerState = |
| (defaultAidRoute != 0x00) ? mOffHostAidRoutingPowerState : 0x11; |
| nfaStat = NFA_EeAddAidRouting(defaultAidRoute, 0, NULL, powerState, |
| AID_ROUTE_QUAL_PREFIX); |
| if (nfaStat != NFA_STATUS_OK) |
| LOG(ERROR) << fn << ": failed to register zero length AID"; |
| else |
| mDefaultAidRouteAdded = true; |
| } |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: updateTechnologyABFRoute |
| ** |
| ** Description: Updating default A/B/F routes |
| ** |
| ** Returns: bitmask of routed technologies |
| ** |
| *******************************************************************************/ |
| tNFA_TECHNOLOGY_MASK RoutingManager::updateTechnologyABFRoute(int route, |
| int felicaRoute) { |
| static const char fn[] = "RoutingManager::updateTechnologyABFRoute"; |
| LOG(DEBUG) << StringPrintf("%s: New default A/B route=0x%x", fn, route); |
| LOG(DEBUG) << StringPrintf("%s: New default F route=0x%x", fn, felicaRoute); |
| mEeInfoChanged = true; |
| mDefaultFelicaRoute = felicaRoute; |
| mDefaultOffHostRoute = route; |
| return mSeTechMask; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: updateEeTechRouteSetting |
| ** |
| ** Description: Update the route of listen A/B/F technologies |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| tNFA_TECHNOLOGY_MASK RoutingManager::updateEeTechRouteSetting() { |
| static const char fn[] = "RoutingManager::updateEeTechRouteSetting"; |
| tNFA_TECHNOLOGY_MASK allSeTechMask = 0x00, hostTechMask = 0x00; |
| |
| LOG(DEBUG) << StringPrintf("%s: Default route A/B=0x%x", fn, |
| mDefaultOffHostRoute); |
| LOG(DEBUG) << StringPrintf("%s: Default route F=0x%x", fn, |
| mDefaultFelicaRoute); |
| |
| LOG(DEBUG) << StringPrintf("%s: Nb NFCEE=%d", fn, mEeInfo.num_ee); |
| |
| tNFA_STATUS nfaStat; |
| |
| for (uint8_t i = 0; i < mEeInfo.num_ee; i++) { |
| tNFA_HANDLE eeHandle = mEeInfo.ee_disc_info[i].ee_handle; |
| tNFA_TECHNOLOGY_MASK seTechMask = 0; |
| |
| LOG(DEBUG) << StringPrintf( |
| "%s EE[%u] Handle=0x%04x techA=0x%02x techB=0x%02x techF=0x%02x " |
| "techBprime=0x%02x", |
| fn, i, eeHandle, mEeInfo.ee_disc_info[i].la_protocol, |
| mEeInfo.ee_disc_info[i].lb_protocol, |
| mEeInfo.ee_disc_info[i].lf_protocol, |
| mEeInfo.ee_disc_info[i].lbp_protocol); |
| |
| if ((mDefaultOffHostRoute != NFC_DH_ID) && |
| (eeHandle == (mDefaultOffHostRoute | NFA_HANDLE_GROUP_EE))) { |
| if (mEeInfo.ee_disc_info[i].la_protocol != 0) { |
| seTechMask |= NFA_TECHNOLOGY_MASK_A; |
| } |
| if (mEeInfo.ee_disc_info[i].lb_protocol != 0) { |
| seTechMask |= NFA_TECHNOLOGY_MASK_B; |
| } |
| } |
| |
| if ((mDefaultFelicaRoute != NFC_DH_ID) && |
| (eeHandle == (mDefaultFelicaRoute | NFA_HANDLE_GROUP_EE))) { |
| if (mEeInfo.ee_disc_info[i].lf_protocol != 0) { |
| seTechMask |= NFA_TECHNOLOGY_MASK_F; |
| } |
| } |
| |
| // If OFFHOST_LISTEN_TECH_MASK exists, |
| // filter out the unspecified technologies |
| seTechMask &= mOffHostListenTechMask; |
| |
| LOG(DEBUG) << StringPrintf("%s: seTechMask[%u]=0x%02x", fn, i, seTechMask); |
| if (seTechMask != 0x00) { |
| LOG(DEBUG) << StringPrintf( |
| "%s: Configuring tech mask 0x%02x on EE 0x%04x", fn, seTechMask, |
| eeHandle); |
| |
| nfaStat = NFA_CeConfigureUiccListenTech(eeHandle, seTechMask); |
| if (nfaStat != NFA_STATUS_OK) |
| LOG(ERROR) << fn << ": Failed to configure UICC listen technologies."; |
| |
| nfaStat = NFA_EeSetDefaultTechRouting( |
| eeHandle, seTechMask, mSecureNfcEnabled ? 0 : seTechMask, 0, |
| mSecureNfcEnabled ? 0 : seTechMask, |
| mSecureNfcEnabled ? 0 : seTechMask, |
| mSecureNfcEnabled ? 0 : seTechMask); |
| if (nfaStat != NFA_STATUS_OK) |
| LOG(ERROR) << StringPrintf( |
| "%s: Failed to configure 0x%x technology routing", fn, eeHandle); |
| |
| allSeTechMask |= seTechMask; |
| } |
| } |
| |
| // Check if some tech should be routed to DH |
| if (!(allSeTechMask & NFA_TECHNOLOGY_MASK_A) && |
| (mHostListenTechMask & NFA_TECHNOLOGY_MASK_A)) { |
| hostTechMask |= NFA_TECHNOLOGY_MASK_A; |
| } |
| // Check if some tech should be routed to DH |
| if (!(allSeTechMask & NFA_TECHNOLOGY_MASK_B) && |
| (mHostListenTechMask & NFA_TECHNOLOGY_MASK_B)) { |
| hostTechMask |= NFA_TECHNOLOGY_MASK_B; |
| } |
| // Check if some tech should be routed to DH |
| if (!(allSeTechMask & NFA_TECHNOLOGY_MASK_F) && |
| (mHostListenTechMask & NFA_TECHNOLOGY_MASK_F)) { |
| hostTechMask |= NFA_TECHNOLOGY_MASK_F; |
| } |
| |
| if (hostTechMask) { |
| nfaStat = NFA_EeSetDefaultTechRouting(NFC_DH_ID, hostTechMask, 0, 0, |
| mSecureNfcEnabled ? 0 : hostTechMask, |
| mSecureNfcEnabled ? 0 : hostTechMask, |
| mSecureNfcEnabled ? 0 : hostTechMask); |
| if (nfaStat != NFA_STATUS_OK) |
| LOG(ERROR) << fn << ": Failed to configure DH technology routing."; |
| } |
| |
| return allSeTechMask; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nfaEeCallback |
| ** |
| ** Description: Receive execution environment-related events from stack. |
| ** event: Event code. |
| ** eventData: Event data. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::nfaEeCallback(tNFA_EE_EVT event, |
| tNFA_EE_CBACK_DATA* eventData) { |
| static const char fn[] = "RoutingManager::nfaEeCallback"; |
| |
| RoutingManager& routingManager = RoutingManager::getInstance(); |
| if (!eventData) { |
| LOG(ERROR) << fn << ": eventData is null"; |
| return; |
| } |
| routingManager.mCbEventData = *eventData; |
| switch (event) { |
| case NFA_EE_REGISTER_EVT: { |
| SyncEventGuard guard(routingManager.mEeRegisterEvent); |
| LOG(DEBUG) << StringPrintf("%s: NFA_EE_REGISTER_EVT; status=%u", fn, |
| eventData->ee_register); |
| routingManager.mEeRegisterEvent.notifyOne(); |
| } break; |
| |
| case NFA_EE_DEREGISTER_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_EE_DEREGISTER_EVT; status=0x%X", fn, |
| eventData->status); |
| routingManager.mReceivedEeInfo = false; |
| routingManager.mDeinitializing = false; |
| } break; |
| |
| case NFA_EE_MODE_SET_EVT: { |
| SyncEventGuard guard(routingManager.mEeSetModeEvent); |
| LOG(DEBUG) << StringPrintf( |
| "%s: NFA_EE_MODE_SET_EVT; status=0x%04X handle=0x%04X ", fn, |
| eventData->mode_set.status, eventData->mode_set.ee_handle); |
| routingManager.mEeSetModeEvent.notifyOne(); |
| } break; |
| |
| case NFA_EE_SET_TECH_CFG_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_EE_SET_TECH_CFG_EVT; status=0x%X", fn, |
| eventData->status); |
| } break; |
| |
| case NFA_EE_CLEAR_TECH_CFG_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_EE_CLEAR_TECH_CFG_EVT; status=0x%X", |
| fn, eventData->status); |
| } break; |
| |
| case NFA_EE_SET_PROTO_CFG_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_EE_SET_PROTO_CFG_EVT; status=0x%X", |
| fn, eventData->status); |
| if (!routingManager.mIsScbrSupported) { |
| SyncEventGuard guard(routingManager.mRoutingEvent); |
| routingManager.mRoutingEvent.notifyOne(); |
| } |
| } break; |
| |
| case NFA_EE_CLEAR_PROTO_CFG_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_EE_CLEAR_PROTO_CFG_EVT; status=0x%X", |
| fn, eventData->status); |
| } break; |
| |
| case NFA_EE_ACTION_EVT: { |
| tNFA_EE_ACTION& action = eventData->action; |
| if (action.trigger == NFC_EE_TRIG_SELECT) { |
| tNFC_AID& aid = action.param.aid; |
| LOG(DEBUG) << StringPrintf( |
| "%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=select (0x%X)", fn, |
| action.ee_handle, action.trigger); |
| routingManager.notifyEeAidSelected(aid, action.ee_handle); |
| } else if (action.trigger == NFC_EE_TRIG_APP_INIT) { |
| tNFC_APP_INIT& app_init = action.param.app_init; |
| LOG(DEBUG) << StringPrintf( |
| "%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=app-init " |
| "(0x%X); aid len=%u; data len=%u", |
| fn, action.ee_handle, action.trigger, app_init.len_aid, |
| app_init.len_data); |
| } else if (action.trigger == NFC_EE_TRIG_RF_PROTOCOL) { |
| LOG(DEBUG) << StringPrintf( |
| "%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=rf protocol (0x%X)", fn, |
| action.ee_handle, action.trigger); |
| routingManager.notifyEeProtocolSelected(action.param.protocol, |
| action.ee_handle); |
| } else if (action.trigger == NFC_EE_TRIG_RF_TECHNOLOGY) { |
| LOG(DEBUG) << StringPrintf( |
| "%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=rf tech (0x%X)", fn, |
| action.ee_handle, action.trigger); |
| routingManager.notifyEeTechSelected(action.param.technology, |
| action.ee_handle); |
| } else |
| LOG(DEBUG) << StringPrintf( |
| "%s: NFA_EE_ACTION_EVT; h=0x%X; unknown trigger (0x%X)", fn, |
| action.ee_handle, action.trigger); |
| } break; |
| |
| case NFA_EE_DISCOVER_REQ_EVT: { |
| SyncEventGuard guard(routingManager.mEeInfoEvent); |
| memcpy(&routingManager.mEeInfo, &eventData->discover_req, |
| sizeof(routingManager.mEeInfo)); |
| for (int i = 0; i < eventData->discover_req.num_ee; i++) { |
| LOG(DEBUG) << StringPrintf( |
| "%s; NFA_EE_DISCOVER_REQ_EVT; nfceeId=0x%X; la_proto=0x%X, " |
| "lb_proto=0x%x, lf_proto=0x%x", |
| fn, eventData->discover_req.ee_disc_info[i].ee_handle, |
| eventData->discover_req.ee_disc_info[i].la_protocol, |
| eventData->discover_req.ee_disc_info[i].lb_protocol, |
| eventData->discover_req.ee_disc_info[i].lf_protocol); |
| } |
| if (!routingManager.mIsRFDiscoveryOptimized) { |
| if (routingManager.mReceivedEeInfo && !routingManager.mDeinitializing) { |
| routingManager.mEeInfoChanged = true; |
| routingManager.notifyEeUpdated(); |
| } |
| } |
| routingManager.mReceivedEeInfo = true; |
| routingManager.mEeInfoEvent.notifyOne(); |
| } break; |
| |
| case NFA_EE_ENABLED_EVT: { |
| LOG(DEBUG) << StringPrintf( |
| "%s: NFA_EE_ENABLED_EVT; status=0x%X; num ee=%u", __func__, |
| eventData->discover_req.status, eventData->discover_req.num_ee); |
| if (routingManager.mIsRFDiscoveryOptimized) { |
| if (routingManager.mReceivedEeInfo && !routingManager.mDeinitializing) { |
| routingManager.mEeInfoChanged = true; |
| routingManager.notifyEeUpdated(); |
| } |
| } |
| } break; |
| |
| case NFA_EE_NO_CB_ERR_EVT: |
| LOG(DEBUG) << StringPrintf("%s: NFA_EE_NO_CB_ERR_EVT status=%u", fn, |
| eventData->status); |
| break; |
| |
| case NFA_EE_ADD_AID_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_EE_ADD_AID_EVT status=%u", fn, |
| eventData->status); |
| SyncEventGuard guard(routingManager.mAidAddRemoveEvent); |
| routingManager.mAidRoutingConfigured = |
| (eventData->status == NFA_STATUS_OK); |
| routingManager.mAidAddRemoveEvent.notifyOne(); |
| } break; |
| |
| case NFA_EE_ADD_SYSCODE_EVT: { |
| SyncEventGuard guard(routingManager.mRoutingEvent); |
| routingManager.mRoutingEvent.notifyOne(); |
| LOG(DEBUG) << StringPrintf("%s: NFA_EE_ADD_SYSCODE_EVT status=%u", fn, |
| eventData->status); |
| } break; |
| |
| case NFA_EE_REMOVE_SYSCODE_EVT: { |
| SyncEventGuard guard(routingManager.mRoutingEvent); |
| routingManager.mRoutingEvent.notifyOne(); |
| LOG(DEBUG) << StringPrintf("%s: NFA_EE_REMOVE_SYSCODE_EVT status=%u", fn, |
| eventData->status); |
| } break; |
| |
| case NFA_EE_REMOVE_AID_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_EE_REMOVE_AID_EVT status=%u", fn, |
| eventData->status); |
| SyncEventGuard guard(routingManager.mAidAddRemoveEvent); |
| routingManager.mAidRoutingConfigured = |
| (eventData->status == NFA_STATUS_OK); |
| routingManager.mAidAddRemoveEvent.notifyOne(); |
| } break; |
| |
| case NFA_EE_NEW_EE_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_EE_NEW_EE_EVT h=0x%X; status=%u", fn, |
| eventData->new_ee.ee_handle, |
| eventData->new_ee.ee_status); |
| } break; |
| |
| case NFA_EE_UPDATED_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_EE_UPDATED_EVT", fn); |
| routingManager.mAidRoutingConfigured = false; |
| SyncEventGuard guard(routingManager.mEeUpdateEvent); |
| routingManager.mEeUpdateEvent.notifyOne(); |
| } break; |
| |
| case NFA_EE_PWR_AND_LINK_CTRL_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_EE_PWR_AND_LINK_CTRL_EVT", fn); |
| SyncEventGuard guard(routingManager.mEePwrAndLinkCtrlEvent); |
| routingManager.mEePwrAndLinkCtrlEvent.notifyOne(); |
| } break; |
| |
| default: |
| LOG(DEBUG) << StringPrintf("%s: unknown event=%u ????", fn, event); |
| break; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: registerT3tIdentifier |
| ** |
| ** Description: register a t3T identifier for HCE-F purposes |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| int RoutingManager::registerT3tIdentifier(uint8_t* t3tId, uint8_t t3tIdLen) { |
| static const char fn[] = "RoutingManager::registerT3tIdentifier"; |
| |
| LOG(DEBUG) << fn << ": Start to register NFC-F system on DH"; |
| |
| if (t3tIdLen != (2 + NCI_RF_F_UID_LEN + NCI_T3T_PMM_LEN)) { |
| LOG(ERROR) << fn << ": Invalid length of T3T Identifier"; |
| return NFA_HANDLE_INVALID; |
| } |
| |
| mNfcFOnDhHandle = NFA_HANDLE_INVALID; |
| |
| uint16_t systemCode; |
| uint8_t nfcid2[NCI_RF_F_UID_LEN]; |
| uint8_t t3tPmm[NCI_T3T_PMM_LEN]; |
| |
| systemCode = (((int)t3tId[0] << 8) | ((int)t3tId[1] << 0)); |
| memcpy(nfcid2, t3tId + 2, NCI_RF_F_UID_LEN); |
| memcpy(t3tPmm, t3tId + 10, NCI_T3T_PMM_LEN); |
| { |
| SyncEventGuard guard(mRoutingEvent); |
| tNFA_STATUS nfaStat = NFA_CeRegisterFelicaSystemCodeOnDH( |
| systemCode, nfcid2, t3tPmm, nfcFCeCallback); |
| if (nfaStat == NFA_STATUS_OK) { |
| mRoutingEvent.wait(); |
| } else { |
| LOG(ERROR) << fn << ": Fail to register NFC-F system on DH"; |
| return NFA_HANDLE_INVALID; |
| } |
| } |
| LOG(DEBUG) << fn << ": Succeed to register NFC-F system on DH"; |
| |
| // Register System Code for routing |
| if (mIsScbrSupported) { |
| SyncEventGuard guard(mRoutingEvent); |
| tNFA_STATUS nfaStat = NFA_EeAddSystemCodeRouting(systemCode, NCI_DH_ID, |
| SYS_CODE_PWR_STATE_HOST); |
| if (nfaStat == NFA_STATUS_OK) { |
| mRoutingEvent.wait(); |
| } |
| if ((nfaStat != NFA_STATUS_OK) || (mCbEventData.status != NFA_STATUS_OK)) { |
| LOG(ERROR) << StringPrintf("%s: Fail to register system code on DH", fn); |
| return NFA_HANDLE_INVALID; |
| } |
| LOG(DEBUG) << StringPrintf("%s: Succeed to register system code on DH", fn); |
| mEeInfoChanged = true; |
| // add handle and system code pair to the map |
| mMapScbrHandle.emplace(mNfcFOnDhHandle, systemCode); |
| } else { |
| LOG(ERROR) << StringPrintf("%s: SCBR Not supported", fn); |
| } |
| |
| return mNfcFOnDhHandle; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: deregisterT3tIdentifier |
| ** |
| ** Description: Deregisters the T3T identifier used for HCE-F purposes |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::deregisterT3tIdentifier(int handle) { |
| static const char fn[] = "RoutingManager::deregisterT3tIdentifier"; |
| |
| LOG(DEBUG) << StringPrintf("%s: Start to deregister NFC-F system on DH", fn); |
| { |
| SyncEventGuard guard(mRoutingEvent); |
| tNFA_STATUS nfaStat = NFA_CeDeregisterFelicaSystemCodeOnDH(handle); |
| if (nfaStat == NFA_STATUS_OK) { |
| mRoutingEvent.wait(); |
| LOG(DEBUG) << StringPrintf( |
| "%s: Succeeded in deregistering NFC-F system on DH", fn); |
| } else { |
| LOG(ERROR) << StringPrintf("%s: Fail to deregister NFC-F system on DH", |
| fn); |
| } |
| } |
| if (mIsScbrSupported) { |
| map<int, uint16_t>::iterator it = mMapScbrHandle.find(handle); |
| // find system code for given handle |
| if (it != mMapScbrHandle.end()) { |
| uint16_t systemCode = it->second; |
| mMapScbrHandle.erase(handle); |
| if (systemCode != 0) { |
| SyncEventGuard guard(mRoutingEvent); |
| tNFA_STATUS nfaStat = NFA_EeRemoveSystemCodeRouting(systemCode); |
| if (nfaStat == NFA_STATUS_OK) { |
| mRoutingEvent.wait(); |
| mEeInfoChanged = true; |
| LOG(DEBUG) << StringPrintf( |
| "%s: Succeeded in deregistering system Code on DH", fn); |
| } else { |
| LOG(ERROR) << StringPrintf("%s: Fail to deregister system Code on DH", |
| fn); |
| } |
| } |
| } |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nfcFCeCallback |
| ** |
| ** Description: Receive execution environment-related events from stack. |
| ** event: Event code. |
| ** eventData: Event data. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::nfcFCeCallback(uint8_t event, |
| tNFA_CONN_EVT_DATA* eventData) { |
| static const char fn[] = "RoutingManager::nfcFCeCallback"; |
| RoutingManager& routingManager = RoutingManager::getInstance(); |
| |
| switch (event) { |
| case NFA_CE_REGISTERED_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_CE_REGISTERED_EVT", fn); |
| routingManager.mNfcFOnDhHandle = eventData->ce_registered.handle; |
| SyncEventGuard guard(routingManager.mRoutingEvent); |
| routingManager.mRoutingEvent.notifyOne(); |
| } break; |
| case NFA_CE_DEREGISTERED_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_CE_DEREGISTERED_EVT", fn); |
| SyncEventGuard guard(routingManager.mRoutingEvent); |
| routingManager.mRoutingEvent.notifyOne(); |
| } break; |
| case NFA_CE_ACTIVATED_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_CE_ACTIVATED_EVT", fn); |
| routingManager.notifyActivated(NFA_TECHNOLOGY_MASK_F); |
| } break; |
| case NFA_CE_DEACTIVATED_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_CE_DEACTIVATED_EVT", fn); |
| routingManager.notifyDeactivated(NFA_TECHNOLOGY_MASK_F); |
| } break; |
| case NFA_CE_DATA_EVT: { |
| LOG(DEBUG) << StringPrintf("%s: NFA_CE_DATA_EVT", fn); |
| tNFA_CE_DATA& ce_data = eventData->ce_data; |
| routingManager.handleData(NFA_TECHNOLOGY_MASK_F, ce_data.p_data, |
| ce_data.len, ce_data.status); |
| } break; |
| default: { |
| LOG(DEBUG) << StringPrintf("%s: unknown event=%u ????", fn, event); |
| } break; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: setNfcSecure |
| ** |
| ** Description: set the NFC secure status |
| ** |
| ** Returns: true |
| ** |
| *******************************************************************************/ |
| bool RoutingManager::setNfcSecure(bool enable) { |
| mSecureNfcEnabled = enable; |
| LOG(INFO) << __func__ << ": enable= " << enable; |
| NFA_SetNfcSecure(enable); |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: eeSetPwrAndLinkCtrl |
| ** |
| ** Description: Programs the NCI command NFCEE_POWER_AND_LINK_CTRL_CMD |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::eeSetPwrAndLinkCtrl(uint8_t config) { |
| static const char fn[] = "RoutingManager::eeSetPwrAndLinkCtrl"; |
| tNFA_STATUS status = NFA_STATUS_OK; |
| |
| if (mOffHostRouteEse.size() > 0) { |
| LOG(DEBUG) << StringPrintf("%s: nfceeId=0x%02X, config=0x%02X", fn, |
| mOffHostRouteEse[0], config); |
| |
| SyncEventGuard guard(mEePwrAndLinkCtrlEvent); |
| status = |
| NFA_EePowerAndLinkCtrl( |
| ((uint8_t)mOffHostRouteEse[0] | NFA_HANDLE_GROUP_EE), config); |
| if (status != NFA_STATUS_OK) { |
| LOG(ERROR) << StringPrintf("%s: fail NFA_EePowerAndLinkCtrl; error=0x%X", |
| fn, status); |
| return; |
| } else { |
| mEePwrAndLinkCtrlEvent.wait(); |
| } |
| } else { |
| LOG(ERROR) << StringPrintf("%s: No ESE specified", fn); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: clearRoutingEntry |
| ** |
| ** Description: Receive execution environment-related events from stack. |
| ** event: Event code. |
| ** eventData: Event data. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::clearRoutingEntry(int clearFlags) { |
| static const char fn[] = "RoutingManager::clearRoutingEntry"; |
| |
| LOG(DEBUG) << StringPrintf("%s: clearFlags = %x", fn, clearFlags); |
| tNFA_STATUS nfaStat = NFA_STATUS_FAILED; |
| bool clear_tech = false, clear_proto = false, clear_sc = false; |
| |
| if (clearFlags & CLEAR_AID_ENTRIES) { |
| LOG(DEBUG) << StringPrintf("%s: clear all of aid based routing", fn); |
| RoutingManager::getInstance().removeAidRouting((uint8_t*)NFA_REMOVE_ALL_AID, |
| NFA_REMOVE_ALL_AID_LEN); |
| mDefaultAidRouteAdded = false; |
| } |
| |
| if (clearFlags & CLEAR_PROTOCOL_ENTRIES) { |
| clear_proto = true; |
| } |
| |
| if (clearFlags & CLEAR_TECHNOLOGY_ENTRIES) { |
| clear_tech = true; |
| } |
| |
| if (clearFlags & CLEAR_SC_ENTRIES) { |
| clear_sc = true; |
| } |
| |
| if (clearFlags > CLEAR_AID_ENTRIES) { |
| NFA_EeClearRoutingTable(clear_tech, clear_proto, clear_sc); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: setEeTechRouteUpdateRequired |
| ** |
| ** Description: Set flag EeInfoChanged so that tech route will be updated |
| ** when applying route table. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::setEeTechRouteUpdateRequired() { |
| static const char fn[] = "RoutingManager::setEeTechRouteUpdateRequired"; |
| |
| LOG(DEBUG) << StringPrintf("%s", fn); |
| |
| // Setting flag for Ee info changed so that |
| // routing table can be updated |
| mEeInfoChanged = true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: deinitialize |
| ** |
| ** Description: Called for NFC disable |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void RoutingManager::deinitialize() { |
| onNfccShutdown(); |
| NFA_EeDeregister(nfaEeCallback); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: registerJniFunctions |
| ** |
| ** Description: called at object creation to register JNI function |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| int RoutingManager::registerJniFunctions(JNIEnv* e) { |
| static const char fn[] = "RoutingManager::registerJniFunctions"; |
| LOG(DEBUG) << StringPrintf("%s", fn); |
| return jniRegisterNativeMethods( |
| e, "com/android/nfc/cardemulation/RoutingOptionManager", sMethods, |
| NELEM(sMethods)); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: com_android_nfc_cardemulation_doGetDefaultRouteDestination |
| ** |
| ** Description: Retrieves the default NFCEE route |
| ** |
| ** Returns: default NFCEE route |
| ** |
| *******************************************************************************/ |
| int RoutingManager::com_android_nfc_cardemulation_doGetDefaultRouteDestination( |
| JNIEnv*) { |
| return getInstance().mDefaultEe; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: com_android_nfc_cardemulation_doGetDefaultOffHostRouteDestination |
| ** |
| ** Description: retrieves the default off host route |
| ** |
| ** Returns: off host route |
| ** |
| *******************************************************************************/ |
| int RoutingManager:: |
| com_android_nfc_cardemulation_doGetDefaultOffHostRouteDestination(JNIEnv*) { |
| return getInstance().mDefaultOffHostRoute; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: com_android_nfc_cardemulation_doGetDefaultFelicaRouteDestination |
| ** |
| ** Description: retrieves the default Felica route |
| ** |
| ** Returns: felica route |
| ** |
| *******************************************************************************/ |
| int RoutingManager:: |
| com_android_nfc_cardemulation_doGetDefaultFelicaRouteDestination(JNIEnv*) { |
| return getInstance().mDefaultFelicaRoute; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: com_android_nfc_cardemulation_doGetEuiccMepMode |
| ** |
| ** Description: retrieves mep mode of euicc |
| ** |
| ** Returns: mep mode |
| ** |
| *******************************************************************************/ |
| |
| int RoutingManager::com_android_nfc_cardemulation_doGetEuiccMepMode(JNIEnv*) { |
| return getInstance().mEuiccMepMode; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: com_android_nfc_cardemulation_doGetOffHostUiccDestination |
| ** |
| ** Description: retrieves the default UICC NFCEE-ID |
| ** |
| ** Returns: areay of NFCEE Id for UICC |
| ** |
| *******************************************************************************/ |
| jbyteArray |
| RoutingManager::com_android_nfc_cardemulation_doGetOffHostUiccDestination( |
| JNIEnv* e) { |
| std::vector<uint8_t> uicc = getInstance().mOffHostRouteUicc; |
| if (uicc.size() == 0) { |
| return NULL; |
| } |
| CHECK(e); |
| jbyteArray uiccJavaArray = e->NewByteArray(uicc.size()); |
| CHECK(uiccJavaArray); |
| e->SetByteArrayRegion(uiccJavaArray, 0, uicc.size(), (jbyte*)&uicc[0]); |
| return uiccJavaArray; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: com_android_nfc_cardemulation_doGetOffHostEseDestination |
| ** |
| ** Description: Retrieves the NFCEE id for eSE |
| ** |
| ** Returns: array of NFCEE Ids |
| |
| ** |
| *******************************************************************************/ |
| jbyteArray |
| RoutingManager::com_android_nfc_cardemulation_doGetOffHostEseDestination( |
| JNIEnv * e) { |
| std::vector<uint8_t> ese = getInstance().mOffHostRouteEse; |
| if (ese.size() == 0) { |
| return NULL; |
| } |
| CHECK(e); |
| jbyteArray eseJavaArray = e->NewByteArray(ese.size()); |
| CHECK(eseJavaArray); |
| e->SetByteArrayRegion(eseJavaArray, 0, ese.size(), (jbyte*)&ese[0]); |
| return eseJavaArray; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: com_android_nfc_cardemulation_doGetAidMatchingMode |
| ** |
| ** Description: Retrieves the AID matching mode |
| ** |
| ** Returns: matching mode |
| ** |
| *******************************************************************************/ |
| int RoutingManager::com_android_nfc_cardemulation_doGetAidMatchingMode( |
| JNIEnv*) { |
| return getInstance().mAidMatchingMode; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: com_android_nfc_cardemulation_doGetDefaultIsoDepRouteDestination |
| ** |
| ** Description: Retrieves the route for ISO-DEP |
| ** |
| ** Returns: ISO-DEP route |
| |
| ** |
| *******************************************************************************/ |
| int RoutingManager:: |
| com_android_nfc_cardemulation_doGetDefaultIsoDepRouteDestination(JNIEnv*) { |
| return getInstance().mDefaultIsoDepRoute; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: com_android_nfc_cardemulation_doGetDefaultScRouteDestination |
| ** |
| ** Description: Retrieves the default NFCEE route |
| ** |
| ** Returns: default NFCEE route |
| ** |
| *******************************************************************************/ |
| int RoutingManager::com_android_nfc_cardemulation_doGetDefaultScRouteDestination( |
| JNIEnv*) { |
| return getInstance().mDefaultSysCodeRoute; |
| } |