| /****************************************************************************** |
| * |
| * Copyright (c) 2016, The Linux Foundation. All rights reserved. |
| * Not a Contribution. |
| * |
| * Copyright (C) 2015-2019 NXP Semiconductors |
| * The original Work has been changed by NXP Semiconductors. |
| * |
| * Copyright (C) 2012 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 <android-base/stringprintf.h> |
| #include <base/logging.h> |
| #include <errno.h> |
| #include <nativehelper/ScopedLocalRef.h> |
| #include <nativehelper/ScopedPrimitiveArray.h> |
| #include <semaphore.h> |
| #include <signal.h> |
| #include <time.h> |
| #include <string> |
| #include "IntervalTimer.h" |
| #include "JavaClassConstants.h" |
| #include "Mutex.h" |
| #include "NfcJniUtil.h" |
| #include "NfcTag.h" |
| #include "TransactionController.h" |
| #include "ndef_utils.h" |
| #include "nfa_api.h" |
| #include "nfa_rw_api.h" |
| #include "nfc_brcm_defs.h" |
| #include "phNxpExtns.h" |
| #include "rw_api.h" |
| using android::base::StringPrintf; |
| |
| namespace android { |
| extern nfc_jni_native_data* getNative(JNIEnv* e, jobject o); |
| extern bool nfcManager_isNfcActive(); |
| extern uint16_t getrfDiscoveryDuration(); |
| } // namespace android |
| |
| extern bool gActivated; |
| extern SyncEvent gDeactivatedEvent; |
| extern bool nfc_debug_enabled; |
| extern bool legacy_mfc_reader; |
| |
| /***************************************************************************** |
| ** |
| ** public variables and functions |
| ** |
| *****************************************************************************/ |
| namespace android { |
| bool gIsTagDeactivating = false; // flag for nfa callback indicating we are |
| // deactivating for RF interface switch |
| bool gIsSelectingRfInterface = false; // flag for nfa callback indicating we |
| // are selecting for RF interface switch |
| #if (NXP_EXTNS == TRUE) |
| bool gIsWaiting4Deact2SleepNtf = false; |
| bool gGotDeact2IdleNtf = false; |
| #endif |
| bool fNeedToSwitchBack = false; |
| void nativeNfcTag_acquireRfInterfaceMutexLock(); |
| void nativeNfcTag_releaseRfInterfaceMutexLock(); |
| } // namespace android |
| |
| /***************************************************************************** |
| ** |
| ** private variables and functions |
| ** |
| *****************************************************************************/ |
| namespace android { |
| |
| // Pre-defined tag type values. These must match the values in |
| // framework Ndef.java for Google public NFC API. |
| #define NDEF_UNKNOWN_TYPE (-1) |
| #define NDEF_TYPE1_TAG 1 |
| #define NDEF_TYPE2_TAG 2 |
| #define NDEF_TYPE3_TAG 3 |
| #define NDEF_TYPE4_TAG 4 |
| #define NDEF_MIFARE_CLASSIC_TAG 101 |
| |
| /*Below #defines are made to make libnfc-nci as AOSP*/ |
| #ifndef NCI_INTERFACE_MIFARE |
| #define NCI_INTERFACE_MIFARE 0x80 |
| #endif |
| #undef NCI_PROTOCOL_MIFARE |
| #define NCI_PROTOCOL_MIFARE 0x80 |
| |
| #define STATUS_CODE_TARGET_LOST 146 // this error code comes from the service |
| |
| static uint32_t sCheckNdefCurrentSize = 0; |
| static tNFA_STATUS sCheckNdefStatus = |
| 0; // whether tag already contains a NDEF message |
| static bool sCheckNdefCapable = false; // whether tag has NDEF capability |
| static tNFA_HANDLE sNdefTypeHandlerHandle = NFA_HANDLE_INVALID; |
| static tNFA_INTF_TYPE sCurrentRfInterface = NFA_INTERFACE_ISO_DEP; |
| static tNFA_INTF_TYPE sCurrentActivatedProtocl = NFC_PROTOCOL_UNKNOWN; |
| static std::basic_string<uint8_t> sRxDataBuffer; |
| static tNFA_STATUS sRxDataStatus = NFA_STATUS_OK; |
| static bool sWaitingForTransceive = false; |
| static bool sTransceiveRfTimeout = false; |
| static Mutex sRfInterfaceMutex; |
| static uint32_t sReadDataLen = 0; |
| static tNFA_STATUS sReadStatus; |
| static uint8_t* sReadData = NULL; |
| static bool sIsReadingNdefMessage = false; |
| static SyncEvent sReadEvent; |
| static sem_t sWriteSem; |
| static sem_t sFormatSem; |
| static SyncEvent sTransceiveEvent; |
| static SyncEvent sReconnectEvent; |
| static sem_t sCheckNdefSem; |
| static SyncEvent sPresenceCheckEvent; |
| static sem_t sMakeReadonlySem; |
| static IntervalTimer sSwitchBackTimer; // timer used to tell us to switch back |
| // to ISO_DEP frame interface |
| uint8_t RW_TAG_SLP_REQ[] = {0x50, 0x00}; |
| uint8_t RW_DESELECT_REQ[] = {0xC2}; |
| static IntervalTimer |
| sPresenceCheckTimer; // timer used for presence cmd notification timeout. |
| static IntervalTimer sReconnectNtfTimer; |
| static jboolean sWriteOk = JNI_FALSE; |
| static jboolean sWriteWaitingForComplete = JNI_FALSE; |
| static bool sFormatOk = false; |
| #if (NXP_EXTNS == TRUE && NFC_NXP_NON_STD_CARD == TRUE) |
| static bool sNeedToSwitchRf = false; |
| #endif |
| static jboolean sConnectOk = JNI_FALSE; |
| static jboolean sConnectWaitingForComplete = JNI_FALSE; |
| static bool sGotDeactivate = false; |
| static uint32_t sCheckNdefMaxSize = 0; |
| static bool sCheckNdefCardReadOnly = false; |
| static jboolean sCheckNdefWaitingForComplete = JNI_FALSE; |
| static bool sIsTagPresent = true; |
| static tNFA_STATUS sMakeReadonlyStatus = NFA_STATUS_FAILED; |
| static jboolean sMakeReadonlyWaitingForComplete = JNI_FALSE; |
| static int sCurrentConnectedTargetType = TARGET_TYPE_UNKNOWN; |
| static int sCurrentConnectedTargetProtocol = NFC_PROTOCOL_UNKNOWN; |
| static int sCurrentConnectedHandle; |
| static SyncEvent sNfaVSCResponseEvent; |
| static SyncEvent sNfaVSCNotificationEvent; |
| static bool sIsTagInField; |
| static bool sVSCRsp; |
| static bool sReconnectFlag = false; |
| static int reSelect(tNFA_INTF_TYPE rfInterface, bool fSwitchIfNeeded); |
| static bool switchRfInterface(tNFA_INTF_TYPE rfInterface); |
| static bool setNdefDetectionTimeoutIfTagAbsent(JNIEnv* e, jobject o, |
| tNFC_PROTOCOL protocol); |
| static void setNdefDetectionTimeout(); |
| static jboolean nativeNfcTag_doPresenceCheck(JNIEnv*, jobject); |
| #if (NXP_EXTNS == TRUE) |
| uint8_t key1[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; |
| uint8_t key2[6] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7}; |
| bool isMifare = false; |
| static uint8_t Presence_check_TypeB[] = {0xB2}; |
| #if (NFC_NXP_NON_STD_CARD == TRUE) |
| static uint16_t NON_NCI_CARD_TIMER_OFFSET = 700; |
| static IntervalTimer sNonNciCardDetectionTimer; |
| static IntervalTimer sNonNciMultiCardDetectionTimer; |
| struct sNonNciCard { |
| bool chinaTransp_Card; |
| bool Changan_Card; |
| uint8_t sProtocolType; |
| uint8_t srfInterfaceType; |
| uint32_t uidlen; |
| uint8_t uid[12]; |
| } sNonNciCard_t; |
| bool scoreGenericNtf = false; |
| void nativeNfcTag_cacheNonNciCardDetection(); |
| void nativeNfcTag_handleNonNciCardDetection(tNFA_CONN_EVT_DATA* eventData); |
| void nativeNfcTag_handleNonNciMultiCardDetection(uint8_t connEvent, |
| tNFA_CONN_EVT_DATA* eventData); |
| static void nonNciCardTimerProc(union sigval); |
| uint8_t checkTagNtf = 0; |
| uint8_t checkCmdSent = 0; |
| #endif |
| #endif |
| static bool sIsReconnecting = false; |
| static int doReconnectFlag = 0x00; |
| static bool sIsCheckingNDef = false; |
| |
| static void nfaVSCCallback(uint8_t event, uint16_t param_len, uint8_t* p_param); |
| static void nfaVSCNtfCallback(uint8_t event, uint16_t param_len, |
| uint8_t* p_param); |
| static void presenceCheckTimerProc(union sigval); |
| static void sReconnectTimerProc(union sigval); |
| |
| static void nfaVSCNtfCallback(uint8_t event, uint16_t param_len, |
| uint8_t* p_param) { |
| (void)event; |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); |
| if (param_len == 4 && p_param[3] == 0x01) { |
| sIsTagInField = true; |
| } else { |
| sIsTagInField = false; |
| } |
| |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s is Tag in Field = %d", __func__, sIsTagInField); |
| usleep(100 * 1000); |
| SyncEventGuard guard(sNfaVSCNotificationEvent); |
| sNfaVSCNotificationEvent.notifyOne(); |
| } |
| |
| static void nfaVSCCallback(uint8_t event, uint16_t param_len, |
| uint8_t* p_param) { |
| (void)event; |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s param_len = %d ", __func__, param_len); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s p_param = %d ", __func__, *p_param); |
| |
| if (param_len == 4 && p_param[3] == 0x00) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s sVSCRsp = true", __func__); |
| |
| sVSCRsp = true; |
| } else { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s sVSCRsp = false", __func__); |
| |
| sVSCRsp = false; |
| } |
| |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s sVSCRsp = %d", __func__, sVSCRsp); |
| |
| SyncEventGuard guard(sNfaVSCResponseEvent); |
| sNfaVSCResponseEvent.notifyOne(); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_abortWaits |
| ** |
| ** Description: Unblock all thread synchronization objects. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_abortWaits() { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); |
| { |
| SyncEventGuard g(sReadEvent); |
| sReadEvent.notifyOne(); |
| } |
| sem_post(&sWriteSem); |
| sem_post(&sFormatSem); |
| { |
| SyncEventGuard g(sTransceiveEvent); |
| sTransceiveEvent.notifyOne(); |
| } |
| { |
| SyncEventGuard g(sReconnectEvent); |
| sReconnectEvent.notifyOne(); |
| } |
| |
| sem_post(&sCheckNdefSem); |
| { |
| SyncEventGuard guard(sPresenceCheckEvent); |
| sPresenceCheckEvent.notifyOne(); |
| } |
| sem_post(&sMakeReadonlySem); |
| sCurrentRfInterface = NFA_INTERFACE_ISO_DEP; |
| sCurrentActivatedProtocl = NFC_PROTOCOL_UNKNOWN; |
| sCurrentConnectedTargetType = TARGET_TYPE_UNKNOWN; |
| sCurrentConnectedTargetProtocol = NFC_PROTOCOL_UNKNOWN; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doReadCompleted |
| ** |
| ** Description: Receive the completion status of read operation. Called by |
| ** NFA_READ_CPLT_EVT. |
| ** status: Status of operation. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_doReadCompleted(tNFA_STATUS status) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: status=0x%X; is reading=%u", __func__, status, |
| sIsReadingNdefMessage); |
| |
| if (sIsReadingNdefMessage == false) |
| return; // not reading NDEF message right now, so just return |
| |
| sReadStatus = status; |
| if (status != NFA_STATUS_OK) { |
| sReadDataLen = 0; |
| if (sReadData) free(sReadData); |
| sReadData = NULL; |
| } |
| SyncEventGuard g(sReadEvent); |
| sReadEvent.notifyOne(); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_setRfInterface |
| ** |
| ** Description: Set rf interface. |
| ** |
| ** Returns: void |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_setRfInterface(tNFA_INTF_TYPE rfInterface) { |
| sCurrentRfInterface = rfInterface; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_setRfProtocol |
| ** |
| ** Description: Set rf Activated Protocol. |
| ** |
| ** Returns: void |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_setRfProtocol(tNFA_INTF_TYPE rfProtocol) { |
| sCurrentActivatedProtocl = rfProtocol; |
| } |
| /******************************************************************************* |
| ** |
| ** Function: ndefHandlerCallback |
| ** |
| ** Description: Receive NDEF-message related events from stack. |
| ** event: Event code. |
| ** p_data: Event data. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| static void ndefHandlerCallback(tNFA_NDEF_EVT event, |
| tNFA_NDEF_EVT_DATA* eventData) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: event=%u, eventData=%p", __func__, event, eventData); |
| |
| switch (event) { |
| case NFA_NDEF_REGISTER_EVT: { |
| tNFA_NDEF_REGISTER& ndef_reg = eventData->ndef_reg; |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: NFA_NDEF_REGISTER_EVT; status=0x%X; h=0x%X", |
| __func__, ndef_reg.status, ndef_reg.ndef_type_handle); |
| sNdefTypeHandlerHandle = ndef_reg.ndef_type_handle; |
| } break; |
| |
| case NFA_NDEF_DATA_EVT: { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: NFA_NDEF_DATA_EVT; data_len = %u", __func__, |
| eventData->ndef_data.len); |
| sReadDataLen = eventData->ndef_data.len; |
| sReadData = (uint8_t*)malloc(sReadDataLen); |
| if (sReadData != NULL) |
| memcpy(sReadData, eventData->ndef_data.p_data, |
| eventData->ndef_data.len); |
| } break; |
| |
| default: |
| LOG(ERROR) << StringPrintf("%s: Unknown event %u ????", __func__, event); |
| break; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doRead |
| ** |
| ** Description: Read the NDEF message on the tag. |
| ** e: JVM environment. |
| ** o: Java object. |
| ** |
| ** Returns: NDEF message. |
| ** |
| *******************************************************************************/ |
| static jbyteArray nativeNfcTag_doRead(JNIEnv* e, jobject o) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__); |
| tNFA_STATUS status = NFA_STATUS_FAILED; |
| jbyteArray buf = NULL; |
| |
| sReadStatus = NFA_STATUS_OK; |
| sReadDataLen = 0; |
| if (sReadData != NULL) { |
| free(sReadData); |
| sReadData = NULL; |
| } |
| |
| if (sCheckNdefCurrentSize > 0) { |
| { |
| SyncEventGuard g(sReadEvent); |
| sIsReadingNdefMessage = true; |
| if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && |
| legacy_mfc_reader) { |
| status = EXTNS_MfcReadNDef(); |
| } else { |
| status = NFA_RwReadNDef(); |
| } |
| sReadEvent.wait(); // wait for NFA_READ_CPLT_EVT |
| } |
| sIsReadingNdefMessage = false; |
| |
| if (sReadDataLen > 0) // if stack actually read data from the tag |
| { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: read %u bytes", __func__, sReadDataLen); |
| buf = e->NewByteArray(sReadDataLen); |
| e->SetByteArrayRegion(buf, 0, sReadDataLen, (jbyte*)sReadData); |
| } |
| if (sReadStatus == NFA_STATUS_TIMEOUT) |
| setNdefDetectionTimeout(); |
| else if (sReadStatus == NFA_STATUS_FAILED) |
| (void)setNdefDetectionTimeoutIfTagAbsent(e, o, NFA_PROTOCOL_T5T); |
| } else { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: create empty buffer", __func__); |
| sReadDataLen = 0; |
| sReadData = (uint8_t*)malloc(1); |
| buf = e->NewByteArray(sReadDataLen); |
| e->SetByteArrayRegion(buf, 0, sReadDataLen, (jbyte*)sReadData); |
| } |
| |
| if (sReadData) { |
| free(sReadData); |
| sReadData = NULL; |
| } |
| sReadDataLen = 0; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); |
| return buf; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doWriteStatus |
| ** |
| ** Description: Receive the completion status of write operation. Called |
| ** by NFA_WRITE_CPLT_EVT. |
| ** isWriteOk: Status of operation. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_doWriteStatus(jboolean isWriteOk) { |
| if (sWriteWaitingForComplete != JNI_FALSE) { |
| sWriteWaitingForComplete = JNI_FALSE; |
| sWriteOk = isWriteOk; |
| sem_post(&sWriteSem); |
| } |
| } |
| #if (NXP_EXTNS == TRUE && NFC_NXP_NON_STD_CARD == TRUE) |
| /******************************************************************************* |
| ** |
| ** Function: nonNciCardTimerProc |
| ** |
| ** Description: CallBack timer for Non nci card detection. |
| ** |
| ** |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nonNciCardTimerProc(union sigval) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter ", __func__); |
| memset(&sNonNciCard_t, 0, sizeof(sNonNciCard)); |
| scoreGenericNtf = false; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_cacheChinaBeijingCardDetection |
| ** |
| ** Description: Store the China Beijing Card detection parameters |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_cacheNonNciCardDetection() { |
| NfcTag& natTag = NfcTag::getInstance(); |
| static uint32_t cardDetectTimeout = 0; |
| static uint8_t* uid; |
| scoreGenericNtf = true; |
| NfcTag::getInstance().getTypeATagUID(&uid, &sNonNciCard_t.uidlen); |
| memcpy(sNonNciCard_t.uid, uid, sNonNciCard_t.uidlen); |
| sNonNciCard_t.sProtocolType = |
| natTag.mTechLibNfcTypes[sCurrentConnectedHandle]; |
| sNonNciCard_t.srfInterfaceType = sCurrentRfInterface; |
| cardDetectTimeout = |
| NON_NCI_CARD_TIMER_OFFSET + android::getrfDiscoveryDuration(); |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: cardDetectTimeout = %d", |
| __func__, cardDetectTimeout); |
| sNonNciCardDetectionTimer.set(cardDetectTimeout, nonNciCardTimerProc); |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: sNonNciCard_t.sProtocolType=0x%x sNonNciCard_t.srfInterfaceType " |
| "=0x%x ", |
| __func__, sNonNciCard_t.sProtocolType, sNonNciCard_t.srfInterfaceType); |
| } |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_handleChinaBeijingCardDetection |
| ** |
| ** Description: China Beijing Card activation |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_handleNonNciCardDetection(tNFA_CONN_EVT_DATA* eventData) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter ", __func__); |
| sNonNciCardDetectionTimer.kill(); |
| static uint32_t tempUidLen = 0x00; |
| static uint8_t* tempUid; |
| NfcTag::getInstance().getTypeATagUID(&tempUid, &tempUidLen); |
| if ((eventData->activated.activate_ntf.intf_param.type == |
| sNonNciCard_t.srfInterfaceType) && |
| (eventData->activated.activate_ntf.protocol == |
| sNonNciCard_t.sProtocolType)) { |
| if ((tempUidLen == sNonNciCard_t.uidlen) && |
| (memcmp(tempUid, sNonNciCard_t.uid, tempUidLen) == 0x00)) { |
| sNonNciCard_t.chinaTransp_Card = true; |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: sNonNciCard_t.chinaTransp_Card = true", __func__); |
| } |
| } else if ((sNonNciCard_t.srfInterfaceType == NFC_INTERFACE_FRAME) && |
| (eventData->activated.activate_ntf.protocol == |
| sNonNciCard_t.sProtocolType)) { |
| if ((tempUidLen == sNonNciCard_t.uidlen) && |
| (memcmp(tempUid, sNonNciCard_t.uid, tempUidLen) == 0x00)) { |
| sNonNciCard_t.Changan_Card = true; |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: sNonNciCard_t.Changan_Card = true", __func__); |
| } |
| } |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: eventData->activated.activate_ntf.protocol =0x%x " |
| "eventData->activated.activate_ntf.intf_param.type =0x%x", |
| __func__, eventData->activated.activate_ntf.protocol, |
| eventData->activated.activate_ntf.intf_param.type); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_handleChinaMultiCardDetection |
| ** |
| ** Description: Multiprotocol Card activation |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_handleNonNciMultiCardDetection( |
| uint8_t connEvent, tNFA_CONN_EVT_DATA* eventData) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter ", __func__); |
| if (NfcTag::getInstance().mNumDiscNtf) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: check_tag_ntf = %d, check_cmd_sent = %d", __func__, |
| checkTagNtf, checkCmdSent); |
| if (checkTagNtf == 0) { |
| NfcTag::getInstance().connectionEventHandler(connEvent, eventData); |
| NFA_Deactivate(true); |
| checkCmdSent = 1; |
| sNonNciMultiCardDetectionTimer.set(NON_NCI_CARD_TIMER_OFFSET, |
| nonNciCardTimerProc); |
| } else if (checkTagNtf == 1) { |
| NfcTag::getInstance().mNumDiscNtf = 0; |
| checkTagNtf = 0; |
| checkCmdSent = 0; |
| NfcTag::getInstance().connectionEventHandler(connEvent, eventData); |
| } |
| } else { |
| NfcTag::getInstance().connectionEventHandler(connEvent, eventData); |
| } |
| } |
| /******************************************************************************* |
| ** |
| ** Function: switchBackTimerProc |
| ** |
| ** Description: Callback function for interval timer. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| static void switchBackTimerProc(union sigval) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); |
| switchRfInterface(NFA_INTERFACE_ISO_DEP); |
| } |
| #endif |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_formatStatus |
| ** |
| ** Description: Receive the completion status of format operation. Called |
| ** by NFA_FORMAT_CPLT_EVT. |
| ** isOk: Status of operation. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_formatStatus(bool isOk) { |
| sFormatOk = isOk; |
| sem_post(&sFormatSem); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doWrite |
| ** |
| ** Description: Write a NDEF message to the tag. |
| ** e: JVM environment. |
| ** o: Java object. |
| ** buf: Contains a NDEF message. |
| ** |
| ** Returns: True if ok. |
| ** |
| *******************************************************************************/ |
| static jboolean nativeNfcTag_doWrite(JNIEnv* e, jobject, jbyteArray buf) { |
| jboolean result = JNI_FALSE; |
| tNFA_STATUS status = 0; |
| const int maxBufferSize = 1024; |
| uint8_t buffer[maxBufferSize] = {0}; |
| uint32_t curDataSize = 0; |
| |
| ScopedByteArrayRO bytes(e, buf); |
| uint8_t* p_data = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>( |
| &bytes[0])); // TODO: const-ness API bug in NFA_RwWriteNDef! |
| |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: enter; len = %zu", __func__, bytes.size()); |
| |
| /* Create the write semaphore */ |
| if (sem_init(&sWriteSem, 0, 0) == -1) { |
| LOG(ERROR) << StringPrintf("%s: semaphore creation failed (errno=0x%08x)", |
| __func__, errno); |
| return JNI_FALSE; |
| } |
| |
| sWriteWaitingForComplete = JNI_TRUE; |
| if (sCheckNdefStatus == NFA_STATUS_FAILED) { |
| // if tag does not contain a NDEF message |
| // and tag is capable of storing NDEF message |
| if (sCheckNdefCapable) { |
| #if (NXP_EXTNS == TRUE) |
| isMifare = false; |
| #endif |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: try format", __func__); |
| sem_init(&sFormatSem, 0, 0); |
| sFormatOk = false; |
| if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && |
| legacy_mfc_reader) { |
| #if (NXP_EXTNS == TRUE) |
| isMifare = true; |
| status = EXTNS_MfcFormatTag(key1, sizeof(key1)); |
| #endif |
| } else { |
| status = NFA_RwFormatTag(); |
| if (status != NFA_STATUS_OK) { |
| LOG(ERROR) << StringPrintf("%s: can't format mifare classic tag", |
| __func__); |
| sem_destroy(&sFormatSem); |
| goto TheEnd; |
| } |
| } |
| sem_wait(&sFormatSem); |
| sem_destroy(&sFormatSem); |
| |
| #if (NXP_EXTNS == TRUE) |
| if (isMifare == true && sFormatOk != true) { |
| sem_init(&sFormatSem, 0, 0); |
| |
| status = EXTNS_MfcFormatTag(key2, sizeof(key2)); |
| sem_wait(&sFormatSem); |
| sem_destroy(&sFormatSem); |
| } |
| #endif |
| |
| if (sFormatOk == false) // if format operation failed |
| goto TheEnd; |
| } |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: try write", __func__); |
| status = NFA_RwWriteNDef(p_data, bytes.size()); |
| } else if (bytes.size() == 0) { |
| // if (NXP TagWriter wants to erase tag) then create and write an empty ndef |
| // message |
| NDEF_MsgInit(buffer, maxBufferSize, &curDataSize); |
| status = NDEF_MsgAddRec(buffer, maxBufferSize, &curDataSize, NDEF_TNF_EMPTY, |
| NULL, 0, NULL, 0, NULL, 0); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: create empty ndef msg; status=%u; size=%u", |
| __func__, status, curDataSize); |
| if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && |
| legacy_mfc_reader) { |
| status = EXTNS_MfcWriteNDef(buffer, curDataSize); |
| } else { |
| status = NFA_RwWriteNDef(buffer, curDataSize); |
| } |
| } else { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: NFA_RwWriteNDef", __func__); |
| if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && |
| legacy_mfc_reader) { |
| status = EXTNS_MfcWriteNDef(p_data, bytes.size()); |
| } else { |
| status = NFA_RwWriteNDef(p_data, bytes.size()); |
| } |
| } |
| |
| if (status != NFA_STATUS_OK) { |
| LOG(ERROR) << StringPrintf("%s: write/format error=%d", __func__, status); |
| goto TheEnd; |
| } |
| |
| /* Wait for write completion status */ |
| sWriteOk = false; |
| if (sem_wait(&sWriteSem)) { |
| LOG(ERROR) << StringPrintf("%s: wait semaphore (errno=0x%08x)", __func__, |
| errno); |
| goto TheEnd; |
| } |
| |
| result = sWriteOk; |
| |
| TheEnd: |
| /* Destroy semaphore */ |
| if (sem_destroy(&sWriteSem)) { |
| LOG(ERROR) << StringPrintf("%s: failed destroy semaphore (errno=0x%08x)", |
| __func__, errno); |
| } |
| sWriteWaitingForComplete = JNI_FALSE; |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: exit; result=%d", __func__, result); |
| return result; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: setNdefDetectionTimeoutIfTagAbsent |
| ** |
| ** Description: Check protocol / presence of a tag which cannot detect tag |
| *lost during |
| ** NDEF check. If it is absent, set NDEF detection timed out |
| *state. |
| ** |
| ** Returns: True if a tag is absent and a current protocol matches the |
| *given protocols. |
| ** |
| *******************************************************************************/ |
| static bool setNdefDetectionTimeoutIfTagAbsent(JNIEnv* e, jobject o, |
| tNFC_PROTOCOL protocol) { |
| if (!(NfcTag::getInstance().getProtocol() & protocol)) return false; |
| |
| if (nativeNfcTag_doPresenceCheck(e, o)) return false; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: tag is not present. set NDEF detection timed out", __func__); |
| setNdefDetectionTimeout(); |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: setNdefDetectionTimeout |
| ** |
| ** Description: Set the flag which indicates whether NDEF detection |
| *algorithm |
| ** timed out so that the tag is regarded as lost. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| static void setNdefDetectionTimeout() { |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| |
| conn_evt_data.status = NFA_STATUS_TIMEOUT; |
| conn_evt_data.ndef_detect.cur_size = 0; |
| conn_evt_data.ndef_detect.max_size = 0; |
| conn_evt_data.ndef_detect.flags = RW_NDEF_FL_UNKNOWN; |
| |
| NfcTag::getInstance().connectionEventHandler(NFA_NDEF_DETECT_EVT, |
| &conn_evt_data); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doConnectStatus |
| ** |
| ** Description: Receive the completion status of connect operation. |
| ** isConnectOk: Status of the operation. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_doConnectStatus(jboolean isConnectOk) { |
| if (EXTNS_GetConnectFlag() == true && legacy_mfc_reader) { |
| EXTNS_MfcActivated(); |
| EXTNS_SetConnectFlag(false); |
| return; |
| } |
| |
| if (sConnectWaitingForComplete != JNI_FALSE) { |
| sConnectWaitingForComplete = JNI_FALSE; |
| sConnectOk = isConnectOk; |
| SyncEventGuard g(sReconnectEvent); |
| sReconnectEvent.notifyOne(); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doDeactivateStatus |
| ** |
| ** Description: Receive the completion status of deactivate operation. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_doDeactivateStatus(int status) { |
| if (EXTNS_GetDeactivateFlag() == true && legacy_mfc_reader) { |
| EXTNS_MfcDisconnect(); |
| EXTNS_SetDeactivateFlag(false); |
| return; |
| } |
| |
| sGotDeactivate = (status == 0); |
| |
| SyncEventGuard g(sReconnectEvent); |
| sReconnectEvent.notifyOne(); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doConnect |
| ** |
| ** Description: Connect to the tag in RF field. |
| ** e: JVM environment. |
| ** o: Java object. |
| ** targetHandle: Handle of the tag. |
| ** |
| ** Returns: Must return NXP status code, which NFC service expects. |
| ** |
| *******************************************************************************/ |
| static jint nativeNfcTag_doConnect(JNIEnv*, jobject, jint targetHandle) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: targetHandle = %d", __func__, targetHandle); |
| int i = targetHandle; |
| NfcTag& natTag = NfcTag::getInstance(); |
| int retCode = NFCSTATUS_SUCCESS; |
| if (i >= NfcTag::MAX_NUM_TECHNOLOGY) { |
| LOG(ERROR) << StringPrintf("%s: Handle not found", __func__); |
| retCode = NFCSTATUS_FAILED; |
| goto TheEnd; |
| } |
| sCurrentConnectedTargetType = natTag.mTechList[i]; |
| sCurrentConnectedTargetProtocol = natTag.mTechLibNfcTypes[i]; |
| #if (NXP_EXTNS == TRUE && NFC_NXP_NON_STD_CARD == TRUE) |
| sNeedToSwitchRf = false; |
| #endif |
| if (natTag.getActivationState() != NfcTag::Active) { |
| LOG(ERROR) << StringPrintf("%s: tag already deactivated", __func__); |
| retCode = NFCSTATUS_FAILED; |
| goto TheEnd; |
| } |
| #if (NXP_EXTNS == TRUE) |
| sCurrentConnectedHandle = targetHandle; |
| if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_T3BT) { |
| goto TheEnd; |
| } |
| #endif |
| |
| if (sCurrentConnectedTargetProtocol != NFC_PROTOCOL_ISO_DEP) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s() Nfc type = %d, do nothing for non ISO_DEP", |
| __func__, sCurrentConnectedTargetProtocol); |
| retCode = NFCSTATUS_SUCCESS; |
| goto TheEnd; |
| } |
| /* Switching is required for CTS protocol paramter test case.*/ |
| if (sCurrentConnectedTargetType == TARGET_TYPE_ISO14443_3A || |
| sCurrentConnectedTargetType == TARGET_TYPE_ISO14443_3B) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: switching to tech: %d need to switch rf intf to frame", __func__, |
| sCurrentConnectedTargetType); |
| #if (NXP_EXTNS == TRUE && NFC_NXP_NON_STD_CARD == TRUE) |
| if (sNonNciCard_t.Changan_Card == true) |
| sNeedToSwitchRf = true; |
| else |
| #endif |
| retCode = switchRfInterface(NFA_INTERFACE_FRAME) ? NFA_STATUS_OK |
| : NFA_STATUS_FAILED; |
| } else { |
| retCode = switchRfInterface(NFA_INTERFACE_ISO_DEP) ? NFA_STATUS_OK |
| : NFA_STATUS_FAILED; |
| } |
| |
| TheEnd: |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: exit 0x%X", __func__, retCode); |
| return retCode; |
| } |
| void setReconnectState(bool flag) { |
| sReconnectFlag = flag; |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("setReconnectState = 0x%x", sReconnectFlag); |
| } |
| bool getReconnectState(void) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("getReconnectState = 0x%x", sReconnectFlag); |
| return sReconnectFlag; |
| } |
| /******************************************************************************* |
| ** |
| ** Function: reSelect |
| ** |
| ** Description: Deactivates the tag and re-selects it with the specified |
| ** rf interface. |
| ** |
| ** Returns: status code, 0 on success, 1 on failure, |
| ** 146 (defined in service) on tag lost |
| ** |
| *******************************************************************************/ |
| static int reSelect(tNFA_INTF_TYPE rfInterface, bool fSwitchIfNeeded) { |
| int handle = sCurrentConnectedHandle; |
| int rVal = 1; |
| tNFA_STATUS status = NFA_STATUS_FAILED; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: enter; Requested RF Intf = 0x%0X, Current RF Intf = 0x%0X", __func__, |
| rfInterface, sCurrentRfInterface); |
| |
| sRfInterfaceMutex.lock(); |
| |
| if (fSwitchIfNeeded && (rfInterface == sCurrentRfInterface)) { |
| sRfInterfaceMutex.unlock(); |
| return 0; |
| } |
| |
| NfcTag& natTag = NfcTag::getInstance(); |
| |
| #if (NFC_NXP_NON_STD_CARD == TRUE) |
| uint8_t retry_cnt = 1; |
| #endif |
| |
| do { |
| /* if tag has shutdown, abort this method */ |
| if (natTag.isNdefDetectionTimedOut()) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: NDEF detection timeout; break", __func__); |
| rVal = STATUS_CODE_TARGET_LOST; |
| break; |
| } |
| if ((sCurrentRfInterface == NFA_INTERFACE_FRAME) && |
| (NFC_GetNCIVersion() >= NCI_VERSION_2_0)) { |
| { |
| SyncEventGuard g3(sReconnectEvent); |
| if(sCurrentActivatedProtocl == NFA_PROTOCOL_T2T) { |
| status = NFA_SendRawFrame(RW_TAG_SLP_REQ, sizeof(RW_TAG_SLP_REQ), 0); |
| } else if (sCurrentActivatedProtocl == NFA_PROTOCOL_ISO_DEP) { |
| status = NFA_SendRawFrame(RW_DESELECT_REQ, |
| sizeof(RW_DESELECT_REQ), 0); |
| } |
| sReconnectEvent.wait(4); |
| if (status != NFA_STATUS_OK) { |
| LOG(ERROR) << StringPrintf("%s: send error=%d", __func__, status); |
| break; |
| } |
| } |
| } |
| |
| #if (NFC_NXP_NON_STD_CARD == TRUE) |
| if (!retry_cnt && |
| (natTag.mTechLibNfcTypes[handle] != NFC_PROTOCOL_MIFARE)) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: Cashbee detected", __func__); |
| natTag.mCashbeeDetected = true; |
| } |
| #endif |
| |
| { |
| SyncEventGuard guard1(sReconnectEvent); |
| gIsTagDeactivating = true; |
| sGotDeactivate = false; |
| setReconnectState(false); |
| NFA_SetReconnectState(true); |
| |
| if (natTag.isCashBeeActivated() == true || |
| natTag.isEzLinkTagActivated() == true |
| #if (NXP_EXTNS == TRUE && NFC_NXP_NON_STD_CARD == TRUE) |
| || sNonNciCard_t.chinaTransp_Card == true |
| #endif |
| ) { |
| setReconnectState(true); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: Deactivate to IDLE", __func__); |
| if (NFA_STATUS_OK != (status = NFA_StopRfDiscovery())) { |
| LOG(ERROR) << StringPrintf("%s: Deactivate failed, status = 0x%0X", |
| __func__, status); |
| break; |
| } |
| } else { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: Deactivate to SLEEP", __func__); |
| if (NFA_STATUS_OK != (status = NFA_Deactivate(true))) { |
| LOG(ERROR) << StringPrintf("%s: Deactivate failed, status = 0x%0X", |
| __func__, status); |
| break; |
| } |
| #if (NXP_EXTNS == TRUE) |
| else if (natTag.mIsMultiProtocolTag) { |
| gIsWaiting4Deact2SleepNtf = true; |
| } |
| #endif |
| } |
| |
| if (sReconnectEvent.wait(1000) == false) { |
| LOG(ERROR) << StringPrintf("%s: Timeout waiting for deactivate", |
| __func__); |
| } |
| } |
| |
| #if (NXP_EXTNS == TRUE) |
| if (gIsWaiting4Deact2SleepNtf) { |
| if (gGotDeact2IdleNtf) { |
| LOG(ERROR) << StringPrintf("%s: wrong deactivate ntf; break", __func__); |
| gIsWaiting4Deact2SleepNtf = false; |
| gGotDeact2IdleNtf = false; |
| rVal = STATUS_CODE_TARGET_LOST; |
| break; |
| } |
| } |
| #endif |
| |
| if (natTag.getActivationState() == NfcTag::Idle) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: Tag is in IDLE state", __func__); |
| |
| if (natTag.mActivationParams_t.mTechLibNfcTypes == NFC_PROTOCOL_ISO_DEP) { |
| if (natTag.mActivationParams_t.mTechParams == |
| NFC_DISCOVERY_TYPE_POLL_A) { |
| natTag.mCashbeeDetected = true; |
| } else if (natTag.mActivationParams_t.mTechParams == |
| NFC_DISCOVERY_TYPE_POLL_B) { |
| natTag.mEzLinkTypeTag = true; |
| } |
| } |
| } |
| |
| if (!(natTag.isCashBeeActivated() == true || |
| natTag.isEzLinkTagActivated() == true |
| #if (NXP_EXTNS == TRUE && NFC_NXP_NON_STD_CARD == TRUE) |
| || sNonNciCard_t.chinaTransp_Card == true |
| #endif |
| )) { |
| if (natTag.getActivationState() != NfcTag::Sleep) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: Tag is not in SLEEP", __func__); |
| rVal = STATUS_CODE_TARGET_LOST; |
| #if (NFC_NXP_NON_STD_CARD == TRUE) |
| if (!retry_cnt) |
| #endif |
| break; |
| #if (NFC_NXP_NON_STD_CARD == TRUE) |
| else |
| continue; |
| #endif |
| } |
| } else { |
| setReconnectState(false); |
| } |
| |
| gIsTagDeactivating = false; |
| |
| { |
| SyncEventGuard guard2(sReconnectEvent); |
| gIsSelectingRfInterface = true; |
| sConnectWaitingForComplete = JNI_TRUE; |
| |
| if (natTag.isCashBeeActivated() == true || |
| natTag.isEzLinkTagActivated() == true |
| #if (NXP_EXTNS == TRUE && NFC_NXP_NON_STD_CARD == TRUE) |
| || sNonNciCard_t.chinaTransp_Card == true |
| #endif |
| ) { |
| setReconnectState(true); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: Start RF discovery", __func__); |
| if (NFA_STATUS_OK != (status = NFA_StartRfDiscovery())) { |
| LOG(ERROR) << StringPrintf("%s: deactivate failed, status = 0x%0X", |
| __func__, status); |
| break; |
| } |
| } else { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: Select RF interface = 0x%0X", __func__, rfInterface); |
| if (NFA_STATUS_OK != |
| (status = |
| NFA_Select(natTag.mTechHandles[handle], |
| natTag.mTechLibNfcTypes[handle], rfInterface))) { |
| LOG(ERROR) << StringPrintf("%s: NFA_Select failed, status = 0x%0X", |
| __func__, status); |
| break; |
| } |
| } |
| |
| sConnectOk = false; |
| |
| if (sReconnectEvent.wait(1000) == false) { |
| LOG(ERROR) << StringPrintf("%s: timeout waiting for select", __func__); |
| #if (NXP_EXTNS == TRUE) |
| if (!(natTag.isCashBeeActivated() == true || |
| natTag.isEzLinkTagActivated() == true |
| #if (NFC_NXP_NON_STD_CARD == TRUE) |
| || sNonNciCard_t.chinaTransp_Card == true |
| #endif |
| )) { |
| status = NFA_Deactivate(false); |
| if (status != NFA_STATUS_OK) |
| LOG(ERROR) << StringPrintf( |
| "%s: deactivate failed; error status = 0x%X", __func__, status); |
| } |
| break; |
| #endif |
| } |
| } |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: Select completed; sConnectOk = 0x%0X", __func__, sConnectOk); |
| |
| if (natTag.getActivationState() != NfcTag::Active) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: Tag is not Active", __func__); |
| rVal = STATUS_CODE_TARGET_LOST; |
| |
| #if (NFC_NXP_NON_STD_CARD == TRUE) |
| if ((sCurrentActivatedProtocl & (NFC_PROTOCOL_MIFARE | NFC_PROTOCOL_ISO_DEP)) && |
| !natTag.mIsMultiProtocolTag) |
| break; |
| if (!retry_cnt) |
| #endif |
| break; |
| } |
| if (natTag.isEzLinkTagActivated() == true) { |
| natTag.mEzLinkTypeTag = false; |
| } |
| #if (NFC_NXP_NON_STD_CARD == TRUE) |
| if (natTag.isCashBeeActivated() == true) { |
| natTag.mCashbeeDetected = false; |
| } |
| #endif |
| if (sConnectOk) { |
| rVal = 0; |
| sCurrentRfInterface = rfInterface; |
| #if (NFC_NXP_NON_STD_CARD == TRUE) |
| break; |
| #endif |
| } else { |
| rVal = 1; |
| } |
| } |
| #if (NFC_NXP_NON_STD_CARD == TRUE) |
| while (retry_cnt--); |
| #else |
| while (0); |
| #endif |
| setReconnectState(false); |
| NFA_SetReconnectState(false); |
| sConnectWaitingForComplete = JNI_FALSE; |
| gIsTagDeactivating = false; |
| gIsSelectingRfInterface = false; |
| sRfInterfaceMutex.unlock(); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: exit rVal = 0x%0X", __func__, rVal); |
| return rVal; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: switchRfInterface |
| ** |
| ** Description: Switch controller's RF interface to frame, ISO-DEP, or |
| *NFC-DEP. |
| ** rfInterface: Type of RF interface. |
| ** |
| ** Returns: True if ok. |
| ** |
| *******************************************************************************/ |
| static bool switchRfInterface(tNFA_INTF_TYPE rfInterface) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: rf intf = %d", __func__, rfInterface); |
| |
| if (sCurrentConnectedTargetProtocol != NFC_PROTOCOL_ISO_DEP) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: protocol: %d not ISO_DEP, do nothing", __func__, |
| sCurrentConnectedTargetProtocol); |
| return true; |
| } |
| |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: new rf intf = %d, cur rf intf = %d", __func__, |
| rfInterface, sCurrentRfInterface); |
| |
| bool rVal = true; |
| if (rfInterface != sCurrentRfInterface) { |
| if (0 == reSelect(rfInterface, true)) { |
| sCurrentRfInterface = rfInterface; |
| rVal = true; |
| } else { |
| rVal = false; |
| } |
| } |
| |
| return rVal; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doReconnect |
| ** |
| ** Description: Re-connect to the tag in RF field. |
| ** e: JVM environment. |
| ** o: Java object. |
| ** |
| ** Returns: Status code. |
| ** |
| *******************************************************************************/ |
| static jint nativeNfcTag_doReconnect(JNIEnv*, jobject) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__); |
| int retCode = NFCSTATUS_SUCCESS; |
| NfcTag& natTag = NfcTag::getInstance(); |
| int handle = sCurrentConnectedHandle; |
| |
| uint8_t* uid; |
| uint32_t uid_len; |
| tNFC_STATUS stat; |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: enter; handle=%x", __func__, handle); |
| natTag.getTypeATagUID(&uid, &uid_len); |
| |
| if (natTag.mNfcDisableinProgress) { |
| LOG(ERROR) << StringPrintf("%s: NFC disabling in progress", __func__); |
| retCode = NFCSTATUS_FAILED; |
| goto TheEnd; |
| } |
| |
| if (natTag.getActivationState() != NfcTag::Active) { |
| LOG(ERROR) << StringPrintf("%s: tag already deactivated", __func__); |
| retCode = NFCSTATUS_FAILED; |
| goto TheEnd; |
| } |
| |
| // special case for Kovio |
| if (sCurrentConnectedTargetType == TARGET_TYPE_KOVIO_BARCODE) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: fake out reconnect for Kovio", __func__); |
| goto TheEnd; |
| } |
| |
| if (natTag.isNdefDetectionTimedOut()) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: ndef detection timeout", __func__); |
| retCode = STATUS_CODE_TARGET_LOST; |
| goto TheEnd; |
| } |
| |
| // special case for TypeB and TypeA random UID |
| if ((sCurrentRfInterface != NCI_INTERFACE_FRAME) && |
| ((natTag.mTechLibNfcTypes[handle] == NFA_PROTOCOL_ISO_DEP && |
| true == natTag.isTypeBTag()) || |
| (NfcTag::getInstance().mTechLibNfcTypes[handle] == |
| NFA_PROTOCOL_ISO_DEP && |
| uid_len > 0 && uid[0] == 0x08))) { |
| if (NFA_GetNCIVersion() != NCI_VERSION_2_0) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: reconnect for TypeB / TypeA random uid", __func__); |
| sReconnectNtfTimer.set(500, sReconnectTimerProc); |
| |
| tNFC_STATUS stat = NFA_RegVSCback( |
| true, nfaVSCNtfCallback); // Register CallBack for VS NTF |
| if (NFA_STATUS_OK != stat) { |
| retCode = 0x01; |
| goto TheEnd; |
| } |
| |
| { |
| SyncEventGuard guard(sNfaVSCResponseEvent); |
| stat = NFA_SendVsCommand(0x11, 0x00, NULL, nfaVSCCallback); |
| if (NFA_STATUS_OK == stat) { |
| sIsReconnecting = true; |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: reconnect for TypeB - wait for NFA VS command to finish", |
| __func__); |
| sNfaVSCResponseEvent.wait(); // wait for NFA VS command to finish |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: reconnect for TypeB - Got RSP", __func__); |
| } |
| } |
| |
| if (false == sVSCRsp) { |
| retCode = 0x01; |
| sIsReconnecting = false; |
| } else { |
| { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: reconnect for TypeB - wait for NFA VS NTF to come", |
| __func__); |
| SyncEventGuard guard(sNfaVSCNotificationEvent); |
| sNfaVSCNotificationEvent.wait(); // wait for NFA VS NTF to come |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: reconnect for TypeB - GOT NFA VS NTF", __func__); |
| sReconnectNtfTimer.kill(); |
| sIsReconnecting = false; |
| } |
| |
| if (false == sIsTagInField) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: NxpNci: TAG OUT OF FIELD", __func__); |
| retCode = STATUS_CODE_TARGET_LOST; |
| |
| SyncEventGuard g(gDeactivatedEvent); |
| |
| // Tag not present, deactivate the TAG. |
| stat = NFA_Deactivate(false); |
| if (stat == NFA_STATUS_OK) { |
| gDeactivatedEvent.wait(); |
| } else { |
| LOG(ERROR) << StringPrintf("%s: deactivate failed; error=0x%X", |
| __func__, stat); |
| } |
| } |
| |
| else { |
| retCode = 0x00; |
| } |
| } |
| |
| stat = NFA_RegVSCback( |
| false, nfaVSCNtfCallback); // DeRegister CallBack for VS NTF |
| if (NFA_STATUS_OK != stat) { |
| retCode = 0x01; |
| } |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: reconnect for TypeB - return", __func__); |
| } else { |
| SyncEventGuard guard(sPresenceCheckEvent); |
| stat = NFA_RwPresenceCheck( |
| NfcTag::getInstance().getPresenceCheckAlgorithm()); |
| if (stat == NFA_STATUS_OK) { |
| sPresenceCheckEvent.wait(); |
| retCode = sIsTagPresent ? NCI_STATUS_OK : NCI_STATUS_FAILED; |
| } |
| } |
| goto TheEnd; |
| } |
| // this is only supported for type 2 or 4 (ISO_DEP) tags |
| if (sCurrentConnectedTargetProtocol == NFA_PROTOCOL_ISO_DEP) |
| retCode = reSelect(NFA_INTERFACE_ISO_DEP, false); |
| else if (sCurrentConnectedTargetProtocol == NFA_PROTOCOL_T2T) |
| retCode = reSelect(NFA_INTERFACE_FRAME, false); |
| else if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) |
| retCode = reSelect(NFA_INTERFACE_MIFARE, false); |
| |
| TheEnd: |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: exit 0x%X", __func__, retCode); |
| return retCode; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doHandleReconnect |
| ** |
| ** Description: Re-connect to the tag in RF field. |
| ** e: JVM environment. |
| ** o: Java object. |
| ** targetHandle: Handle of the tag. |
| ** |
| ** Returns: Status code. |
| ** |
| *******************************************************************************/ |
| static jint nativeNfcTag_doHandleReconnect(JNIEnv* e, jobject o, |
| jint targetHandle) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: targetHandle = %d", __func__, targetHandle); |
| if (NfcTag::getInstance().mNfcDisableinProgress) |
| return STATUS_CODE_TARGET_LOST; |
| return nativeNfcTag_doConnect(e, o, targetHandle); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doDisconnect |
| ** |
| ** Description: Deactivate the RF field. |
| ** e: JVM environment. |
| ** o: Java object. |
| ** |
| ** Returns: True if ok. |
| ** |
| *******************************************************************************/ |
| jboolean nativeNfcTag_doDisconnect(JNIEnv*, jobject) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__); |
| tNFA_STATUS nfaStat = NFA_STATUS_OK; |
| |
| NfcTag::getInstance().resetAllTransceiveTimeouts(); |
| #if (NXP_EXTNS == TRUE && NFC_NXP_NON_STD_CARD == TRUE) |
| if (sNonNciCard_t.Changan_Card == true || |
| sNonNciCard_t.chinaTransp_Card == true) { |
| memset(&sNonNciCard_t, 0, sizeof(sNonNciCard)); |
| scoreGenericNtf = false; |
| } |
| #endif |
| if (NfcTag::getInstance().getActivationState() != NfcTag::Active) { |
| LOG(ERROR) << StringPrintf("%s: tag already deactivated", __func__); |
| goto TheEnd; |
| } |
| |
| nfaStat = NFA_Deactivate(false); |
| if (nfaStat != NFA_STATUS_OK) |
| LOG(ERROR) << StringPrintf("%s: deactivate failed; error=0x%X", __func__, |
| nfaStat); |
| |
| TheEnd: |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); |
| return (nfaStat == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doTransceiveStatus |
| ** |
| ** Description: Receive the completion status of transceive operation. |
| ** status: operation status. |
| ** buf: Contains tag's response. |
| ** bufLen: Length of buffer. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_doTransceiveStatus(tNFA_STATUS status, uint8_t* buf, |
| uint32_t bufLen) { |
| SyncEventGuard g(sTransceiveEvent); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: data len=%d, cur connection handle =%d", __func__, |
| bufLen, sCurrentConnectedHandle); |
| |
| if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && |
| legacy_mfc_reader) { |
| if (EXTNS_GetCallBackFlag() == false) { |
| EXTNS_MfcCallBack(buf, bufLen); |
| return; |
| } |
| } |
| |
| if (!sWaitingForTransceive) { |
| LOG(ERROR) << StringPrintf("%s: drop data", __func__); |
| return; |
| } |
| sRxDataStatus = status; |
| if (sRxDataStatus == NFA_STATUS_OK || sRxDataStatus == NFC_STATUS_CONTINUE) |
| sRxDataBuffer.append(buf, bufLen); |
| |
| if (sRxDataStatus == NFA_STATUS_OK) sTransceiveEvent.notifyOne(); |
| } |
| |
| void nativeNfcTag_notifyRfTimeout() { |
| SyncEventGuard g(sTransceiveEvent); |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: waiting for transceive: %d", __func__, sWaitingForTransceive); |
| if (!sWaitingForTransceive) return; |
| |
| sTransceiveRfTimeout = true; |
| |
| sTransceiveEvent.notifyOne(); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doTransceive |
| ** |
| ** Description: Send raw data to the tag; receive tag's response. |
| ** e: JVM environment. |
| ** o: Java object. |
| ** raw: Not used. |
| ** statusTargetLost: Whether tag responds or times out. |
| ** |
| ** Returns: Response from tag. |
| ** |
| *******************************************************************************/ |
| static jbyteArray nativeNfcTag_doTransceive(JNIEnv* e, jobject o, |
| jbyteArray data, jboolean raw, |
| jintArray statusTargetLost) { |
| int timeout = |
| NfcTag::getInstance().getTransceiveTimeout(sCurrentConnectedTargetType); |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: enter; raw=%u; timeout = %d", __func__, raw, timeout); |
| |
| bool waitOk = false; |
| bool isNack = false; |
| jint* targetLost = NULL; |
| tNFA_STATUS status; |
| #if (NXP_EXTNS == TRUE && NFC_NXP_NON_STD_CARD == TRUE) |
| bool fNeedToSwitchBack = false; |
| #endif |
| if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && |
| legacy_mfc_reader) { |
| if (doReconnectFlag == 0) { |
| int retCode = NFCSTATUS_SUCCESS; |
| retCode = nativeNfcTag_doReconnect(e, o); |
| doReconnectFlag = 0x01; |
| } |
| } |
| |
| if (NfcTag::getInstance().getActivationState() != NfcTag::Active) { |
| if (statusTargetLost) { |
| targetLost = e->GetIntArrayElements(statusTargetLost, 0); |
| if (targetLost) |
| *targetLost = 1; // causes NFC service to throw TagLostException |
| e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); |
| } |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: tag not active", __func__); |
| return NULL; |
| } |
| |
| NfcTag& natTag = NfcTag::getInstance(); |
| |
| // get input buffer and length from java call |
| ScopedByteArrayRO bytes(e, data); |
| uint8_t* buf = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>( |
| &bytes[0])); // TODO: API bug; NFA_SendRawFrame should take const*! |
| size_t bufLen = bytes.size(); |
| |
| if (statusTargetLost) { |
| targetLost = e->GetIntArrayElements(statusTargetLost, 0); |
| if (targetLost) *targetLost = 0; // success, tag is still present |
| } |
| |
| sSwitchBackTimer.kill(); |
| ScopedLocalRef<jbyteArray> result(e, NULL); |
| do { |
| #if (NXP_EXTNS == TRUE && NFC_NXP_NON_STD_CARD == TRUE) |
| if (sNeedToSwitchRf) { |
| if (!switchRfInterface(NFA_INTERFACE_FRAME)) // NFA_INTERFACE_ISO_DEP |
| { |
| break; |
| } |
| fNeedToSwitchBack = true; |
| } |
| #endif |
| { |
| SyncEventGuard g(sTransceiveEvent); |
| sTransceiveRfTimeout = false; |
| sWaitingForTransceive = true; |
| sRxDataStatus = NFA_STATUS_OK; |
| sRxDataBuffer.clear(); |
| if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && legacy_mfc_reader) { |
| status = EXTNS_MfcTransceive(buf, bufLen); |
| } else { |
| status = NFA_SendRawFrame(buf, bufLen, |
| NFA_DM_DEFAULT_PRESENCE_CHECK_START_DELAY); |
| } |
| |
| if (status != NFA_STATUS_OK) { |
| LOG(ERROR) << StringPrintf("%s: fail send; error=%d", __func__, status); |
| break; |
| } |
| waitOk = sTransceiveEvent.wait(timeout); |
| } |
| |
| if (waitOk == false || sTransceiveRfTimeout) // if timeout occurred |
| { |
| LOG(ERROR) << StringPrintf("%s: wait response timeout", __func__); |
| if (targetLost) |
| *targetLost = 1; // causes NFC service to throw TagLostException |
| break; |
| } |
| |
| if (NfcTag::getInstance().getActivationState() != NfcTag::Active) { |
| LOG(ERROR) << StringPrintf("%s: already deactivated", __func__); |
| if (targetLost) |
| *targetLost = 1; // causes NFC service to throw TagLostException |
| break; |
| } |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: response %zu bytes", __func__, sRxDataBuffer.size()); |
| |
| if ((natTag.getProtocol() == NFA_PROTOCOL_T2T) && |
| natTag.isT2tNackResponse(sRxDataBuffer.data(), sRxDataBuffer.size())) { |
| isNack = true; |
| } |
| |
| if (sRxDataBuffer.size() > 0) { |
| if (isNack) { |
| // Some Mifare Ultralight C tags enter the HALT state after it |
| // responds with a NACK. Need to perform a "reconnect" operation |
| // to wake it. |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: try reconnect", __func__); |
| nativeNfcTag_doReconnect(NULL, NULL); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: reconnect finish", __func__); |
| } else if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) { |
| uint32_t transDataLen = sRxDataBuffer.size(); |
| uint8_t* transData = (uint8_t*)sRxDataBuffer.data(); |
| bool doReconnect = false; |
| |
| if (legacy_mfc_reader) { |
| doReconnect = (EXTNS_CheckMfcResponse(&transData, &transDataLen) == |
| NFCSTATUS_FAILED) |
| ? true |
| : false; |
| } else { |
| doReconnect = |
| ((transDataLen == 1) && (transData[0] != 0x00)) ? true : false; |
| } |
| |
| if (doReconnect) { |
| nativeNfcTag_doReconnect(e, o); |
| } else { |
| if (transDataLen != 0) { |
| result.reset(e->NewByteArray(transDataLen)); |
| if (result.get() != NULL) { |
| e->SetByteArrayRegion(result.get(), 0, transDataLen, |
| (const jbyte*)transData); |
| } else |
| LOG(ERROR) << StringPrintf( |
| "%s: Failed to allocate java byte array", __func__); |
| } |
| } |
| } else { |
| // marshall data to java for return |
| result.reset(e->NewByteArray(sRxDataBuffer.size())); |
| if (result.get() != NULL) { |
| e->SetByteArrayRegion(result.get(), 0, sRxDataBuffer.size(), |
| (const jbyte*)sRxDataBuffer.data()); |
| } else |
| LOG(ERROR) << StringPrintf("%s: Failed to allocate java byte array", |
| __func__); |
| } // else a nack is treated as a transceive failure to the upper layers |
| |
| sRxDataBuffer.clear(); |
| } |
| } while (0); |
| |
| sWaitingForTransceive = false; |
| if (targetLost) e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); |
| #if (NXP_EXTNS == TRUE && NFC_NXP_NON_STD_CARD == TRUE) |
| if (fNeedToSwitchBack) { |
| sSwitchBackTimer.set(1500, switchBackTimerProc); |
| } |
| #endif |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); |
| return result.release(); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doGetNdefType |
| ** |
| ** Description: Retrieve the type of tag. |
| ** e: JVM environment. |
| ** o: Java object. |
| ** libnfcType: Type of tag represented by JNI. |
| ** javaType: Not used. |
| ** |
| ** Returns: Type of tag represented by NFC Service. |
| ** |
| *******************************************************************************/ |
| static jint nativeNfcTag_doGetNdefType(JNIEnv*, jobject, jint libnfcType, |
| jint javaType) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: enter; libnfc type=%d; java type=%d", __func__, |
| libnfcType, javaType); |
| jint ndefType = NDEF_UNKNOWN_TYPE; |
| |
| // For NFA, libnfcType is mapped to the protocol value received |
| // in the NFA_ACTIVATED_EVT and NFA_DISC_RESULT_EVT event. |
| if (NFA_PROTOCOL_T1T == libnfcType) { |
| ndefType = NDEF_TYPE1_TAG; |
| } else if (NFA_PROTOCOL_T2T == libnfcType) { |
| ndefType = NDEF_TYPE2_TAG; |
| } else if (NFA_PROTOCOL_T3T == libnfcType) { |
| ndefType = NDEF_TYPE3_TAG; |
| } else if (NFA_PROTOCOL_ISO_DEP == libnfcType) { |
| ndefType = NDEF_TYPE4_TAG; |
| } else if (NFC_PROTOCOL_MIFARE == libnfcType) { |
| ndefType = NDEF_MIFARE_CLASSIC_TAG; |
| } else { |
| /* NFA_PROTOCOL_T5T and others */ |
| ndefType = NDEF_UNKNOWN_TYPE; |
| } |
| |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: exit; ndef type=%d", __func__, ndefType); |
| return ndefType; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doCheckNdefResult |
| ** |
| ** Description: Receive the result of checking whether the tag contains a |
| *NDEF |
| ** message. Called by the NFA_NDEF_DETECT_EVT. |
| ** status: Status of the operation. |
| ** maxSize: Maximum size of NDEF message. |
| ** currentSize: Current size of NDEF message. |
| ** flags: Indicate various states. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_doCheckNdefResult(tNFA_STATUS status, uint32_t maxSize, |
| uint32_t currentSize, uint8_t flags) { |
| // this function's flags parameter is defined using the following macros |
| // in nfc/include/rw_api.h; |
| //#define RW_NDEF_FL_READ_ONLY 0x01 /* Tag is read only */ |
| //#define RW_NDEF_FL_FORMATED 0x02 /* Tag formated for NDEF */ |
| //#define RW_NDEF_FL_SUPPORTED 0x04 /* NDEF supported by the tag */ |
| //#define RW_NDEF_FL_UNKNOWN 0x08 /* Unable to find if tag is ndef |
| // capable/formated/read only */ |
| //#define RW_NDEF_FL_FORMATABLE 0x10 /* Tag supports format operation */ |
| |
| if (!sCheckNdefWaitingForComplete) { |
| LOG(ERROR) << StringPrintf("%s: not waiting", __func__); |
| return; |
| } |
| |
| if (flags & RW_NDEF_FL_READ_ONLY) |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: flag read-only", __func__); |
| if (flags & RW_NDEF_FL_FORMATED) |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: flag formatted for ndef", __func__); |
| if (flags & RW_NDEF_FL_SUPPORTED) |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: flag ndef supported", __func__); |
| if (flags & RW_NDEF_FL_UNKNOWN) |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: flag all unknown", __func__); |
| if (flags & RW_NDEF_FL_FORMATABLE) |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: flag formattable", __func__); |
| |
| sCheckNdefWaitingForComplete = JNI_FALSE; |
| sCheckNdefStatus = status; |
| if (sCheckNdefStatus != NFA_STATUS_OK && |
| sCheckNdefStatus != NFA_STATUS_TIMEOUT) |
| sCheckNdefStatus = NFA_STATUS_FAILED; |
| sCheckNdefCapable = false; // assume tag is NOT ndef capable |
| if (sCheckNdefStatus == NFA_STATUS_OK) { |
| // NDEF content is on the tag |
| sCheckNdefMaxSize = maxSize; |
| sCheckNdefCurrentSize = currentSize; |
| sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY; |
| sCheckNdefCapable = true; |
| } else if (sCheckNdefStatus == NFA_STATUS_FAILED) { |
| // no NDEF content on the tag |
| sCheckNdefMaxSize = 0; |
| sCheckNdefCurrentSize = 0; |
| sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY; |
| if ((flags & RW_NDEF_FL_UNKNOWN) == 0) // if stack understands the tag |
| { |
| if (flags & RW_NDEF_FL_SUPPORTED) // if tag is ndef capable |
| sCheckNdefCapable = true; |
| } |
| } else if (sCheckNdefStatus == NFA_STATUS_TIMEOUT) { |
| LOG(ERROR) << StringPrintf("%s: timeout", __func__); |
| |
| sCheckNdefMaxSize = 0; |
| sCheckNdefCurrentSize = 0; |
| sCheckNdefCardReadOnly = false; |
| } else { |
| LOG(ERROR) << StringPrintf("%s: unknown status=0x%X", __func__, status); |
| sCheckNdefMaxSize = 0; |
| sCheckNdefCurrentSize = 0; |
| sCheckNdefCardReadOnly = false; |
| } |
| sem_post(&sCheckNdefSem); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doCheckNdef |
| ** |
| ** Description: Does the tag contain a NDEF message? |
| ** e: JVM environment. |
| ** o: Java object. |
| ** ndefInfo: NDEF info. |
| ** |
| ** Returns: Status code; 0 is success. |
| ** |
| *******************************************************************************/ |
| static jint nativeNfcTag_doCheckNdef(JNIEnv* e, jobject o, jintArray ndefInfo) { |
| tNFA_STATUS status = NFA_STATUS_FAILED; |
| jint* ndef = NULL; |
| int handle = sCurrentConnectedHandle; |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: enter; handle=%x", __func__, handle); |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__); |
| sIsCheckingNDef = true; |
| #if (NXP_EXTNS == TRUE) |
| if (sCurrentConnectedTargetProtocol == NFA_PROTOCOL_T3BT) { |
| ndef = e->GetIntArrayElements(ndefInfo, 0); |
| ndef[0] = 0; |
| ndef[1] = NDEF_MODE_READ_ONLY; |
| e->ReleaseIntArrayElements(ndefInfo, ndef, 0); |
| sIsCheckingNDef = false; |
| return NFA_STATUS_FAILED; |
| } |
| #endif |
| |
| // special case for Kovio |
| if (sCurrentConnectedTargetProtocol == TARGET_TYPE_KOVIO_BARCODE) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: Kovio tag, no NDEF", __func__); |
| ndef = e->GetIntArrayElements(ndefInfo, 0); |
| ndef[0] = 0; |
| ndef[1] = NDEF_MODE_READ_ONLY; |
| e->ReleaseIntArrayElements(ndefInfo, ndef, 0); |
| sIsCheckingNDef = false; |
| return NFA_STATUS_FAILED; |
| } |
| if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) { |
| nativeNfcTag_doReconnect(e, o); |
| } |
| |
| doReconnectFlag = 0; |
| |
| /* Create the write semaphore */ |
| if (sem_init(&sCheckNdefSem, 0, 0) == -1) { |
| LOG(ERROR) << StringPrintf( |
| "%s: Check NDEF semaphore creation failed (errno=0x%08x)", __func__, |
| errno); |
| sIsCheckingNDef = false; |
| return JNI_FALSE; |
| } |
| |
| if (NfcTag::getInstance().getActivationState() != NfcTag::Active) { |
| LOG(ERROR) << StringPrintf("%s: tag already deactivated", __func__); |
| goto TheEnd; |
| } |
| |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: try NFA_RwDetectNDef", __func__); |
| sCheckNdefWaitingForComplete = JNI_TRUE; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: NfcTag::getInstance ().mTechLibNfcTypes[%d]=%d", __func__, handle, |
| NfcTag::getInstance().mTechLibNfcTypes[handle]); |
| |
| if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && |
| legacy_mfc_reader) { |
| status = EXTNS_MfcCheckNDef(); |
| } else { |
| status = NFA_RwDetectNDef(); |
| } |
| |
| if (status != NFA_STATUS_OK) { |
| LOG(ERROR) << StringPrintf("%s: NFA_RwDetectNDef failed, status = 0x%X", |
| __func__, status); |
| goto TheEnd; |
| } |
| |
| /* Wait for check NDEF completion status */ |
| if (sem_wait(&sCheckNdefSem)) { |
| LOG(ERROR) << StringPrintf( |
| "%s: Failed to wait for check NDEF semaphore (errno=0x%08x)", __func__, |
| errno); |
| goto TheEnd; |
| } |
| |
| if (sCheckNdefStatus == NFA_STATUS_OK) { |
| // stack found a NDEF message on the tag |
| ndef = e->GetIntArrayElements(ndefInfo, 0); |
| if (NfcTag::getInstance().getProtocol() == NFA_PROTOCOL_T1T) |
| ndef[0] = NfcTag::getInstance().getT1tMaxMessageSize(); |
| else |
| ndef[0] = sCheckNdefMaxSize; |
| if (sCheckNdefCardReadOnly) |
| ndef[1] = NDEF_MODE_READ_ONLY; |
| else |
| ndef[1] = NDEF_MODE_READ_WRITE; |
| e->ReleaseIntArrayElements(ndefInfo, ndef, 0); |
| status = NFA_STATUS_OK; |
| } else if (sCheckNdefStatus == NFA_STATUS_FAILED) { |
| // stack did not find a NDEF message on the tag; |
| ndef = e->GetIntArrayElements(ndefInfo, 0); |
| if (NfcTag::getInstance().getProtocol() == NFA_PROTOCOL_T1T) |
| ndef[0] = NfcTag::getInstance().getT1tMaxMessageSize(); |
| else |
| ndef[0] = sCheckNdefMaxSize; |
| if (sCheckNdefCardReadOnly) |
| ndef[1] = NDEF_MODE_READ_ONLY; |
| else |
| ndef[1] = NDEF_MODE_READ_WRITE; |
| e->ReleaseIntArrayElements(ndefInfo, ndef, 0); |
| status = NFA_STATUS_FAILED; |
| if (setNdefDetectionTimeoutIfTagAbsent(e, o, |
| NFA_PROTOCOL_T3T | NFA_PROTOCOL_T5T)) |
| status = STATUS_CODE_TARGET_LOST; |
| } else { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: unknown status 0x%X", __func__, sCheckNdefStatus); |
| status = sCheckNdefStatus; |
| } |
| |
| /* Reconnect Mifare Classic Tag for furture use */ |
| if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) { |
| nativeNfcTag_doReconnect(e, o); |
| } |
| |
| TheEnd: |
| /* Destroy semaphore */ |
| if (sem_destroy(&sCheckNdefSem)) { |
| LOG(ERROR) << StringPrintf( |
| "%s: Failed to destroy check NDEF semaphore (errno=0x%08x)", __func__, |
| errno); |
| } |
| sCheckNdefWaitingForComplete = JNI_FALSE; |
| sIsCheckingNDef = false; |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: exit; status=0x%X", __func__, status); |
| return status; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_resetPresenceCheck |
| ** |
| ** Description: Reset variables related to presence-check. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_resetPresenceCheck() { |
| sIsTagPresent = true; |
| NfcTag::getInstance().mCashbeeDetected = false; |
| NfcTag::getInstance().mEzLinkTypeTag = false; |
| MfcResetPresenceCheckStatus(); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doPresenceCheckResult |
| ** |
| ** Description: Receive the result of presence-check. |
| ** status: Result of presence-check. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_doPresenceCheckResult(tNFA_STATUS status) { |
| SyncEventGuard guard(sPresenceCheckEvent); |
| sIsTagPresent = status == NFA_STATUS_OK; |
| sPresenceCheckEvent.notifyOne(); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doPresenceCheck |
| ** |
| ** Description: Check if the tag is in the RF field. |
| ** e: JVM environment. |
| ** o: Java object. |
| ** |
| ** Returns: True if tag is in RF field. |
| ** |
| *******************************************************************************/ |
| static jboolean nativeNfcTag_doPresenceCheck(JNIEnv*, jobject) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); |
| tNFA_STATUS status = NFA_STATUS_OK; |
| jboolean isPresent = JNI_FALSE; |
| uint8_t* uid; |
| uint32_t uid_len; |
| bool result; |
| NfcTag::getInstance().getTypeATagUID(&uid, &uid_len); |
| int handle = sCurrentConnectedHandle; |
| |
| if (NfcTag::getInstance().mNfcDisableinProgress) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s, Nfc disable in progress", __func__); |
| return JNI_FALSE; |
| } |
| |
| if (sIsCheckingNDef == true) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: Ndef is being checked", __func__); |
| return JNI_TRUE; |
| } |
| if (fNeedToSwitchBack) { |
| sSwitchBackTimer.kill(); |
| } |
| if (nfcManager_isNfcActive() == false) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: NFC is no longer active.", __func__); |
| return JNI_FALSE; |
| } |
| |
| if (!sRfInterfaceMutex.tryLock()) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: tag is being reSelected assume it is present", __func__); |
| return JNI_TRUE; |
| } |
| |
| sRfInterfaceMutex.unlock(); |
| |
| if (NfcTag::getInstance().isActivated() == false) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: tag already deactivated", __func__); |
| return JNI_FALSE; |
| } |
| |
| /*Presence check for Kovio - RF Deactive command with type Discovery*/ |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: handle=%d", __func__, handle); |
| if (sCurrentConnectedTargetProtocol == TARGET_TYPE_KOVIO_BARCODE) { |
| SyncEventGuard guard(sPresenceCheckEvent); |
| status = |
| NFA_RwPresenceCheck(NfcTag::getInstance().getPresenceCheckAlgorithm()); |
| if (status == NFA_STATUS_OK) { |
| sPresenceCheckEvent.wait(); |
| isPresent = sIsTagPresent ? JNI_TRUE : JNI_FALSE; |
| } |
| if (isPresent == JNI_FALSE) |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: tag absent", __func__); |
| return isPresent; |
| #if 0 |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: Kovio, force deactivate handling", __func__); |
| tNFA_DEACTIVATED deactivated = {NFA_DEACTIVATE_TYPE_IDLE}; |
| { |
| SyncEventGuard g (gDeactivatedEvent); |
| gActivated = false; //guard this variable from multi-threaded access |
| gDeactivatedEvent.notifyOne (); |
| } |
| |
| NfcTag::getInstance().setDeactivationState (deactivated); |
| nativeNfcTag_resetPresenceCheck(); |
| NfcTag::getInstance().connectionEventHandler (NFA_DEACTIVATED_EVT, NULL); |
| nativeNfcTag_abortWaits(); |
| NfcTag::getInstance().abort (); |
| |
| return JNI_FALSE; |
| #endif |
| } |
| |
| /* |
| * This fix is made because NFA_RwPresenceCheck cmd is not woking for ISO-DEP |
| * in CEFH mode |
| * Hence used the Properitary presence check cmd |
| * */ |
| |
| if (NfcTag::getInstance().mTechLibNfcTypes[handle] == NFA_PROTOCOL_ISO_DEP && |
| NFA_GetNCIVersion() != NCI_VERSION_2_0) { |
| if (sIsReconnecting == true) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: Reconnecting Tag", __func__); |
| return JNI_TRUE; |
| } |
| if (!pTransactionController->transactionAttempt( |
| TRANSACTION_REQUESTOR(TAG_PRESENCE_CHECK), |
| TRANSACTION_ATTEMPT_FOR_SECONDS(5))) { |
| LOG(ERROR) << StringPrintf( |
| "%s: Transaction in progress. Can not perform presence check", |
| __func__); |
| return JNI_FALSE; |
| } |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: presence check for TypeB / TypeA random uid", __func__); |
| sPresenceCheckTimer.set(500, presenceCheckTimerProc); |
| |
| tNFC_STATUS stat = NFA_RegVSCback( |
| true, nfaVSCNtfCallback); // Register CallBack for VS NTF |
| if (NFA_STATUS_OK != stat) { |
| LOG(ERROR) << StringPrintf("%s: Kill presence check timer", __func__); |
| sPresenceCheckTimer.kill(); |
| goto TheEnd; |
| } |
| { |
| SyncEventGuard guard(sNfaVSCResponseEvent); |
| stat = NFA_SendVsCommand(0x11, 0x00, NULL, nfaVSCCallback); |
| if (NFA_STATUS_OK == stat) { |
| /*Considering the FWI=14 for slowest tag, wait time is kept 5000*/ |
| result = sNfaVSCResponseEvent.wait( |
| 5000); // wait for NFA VS command to finish |
| if (result == FALSE) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: Timedout while waiting for presence check rsp", __func__); |
| pTransactionController->transactionEnd( |
| TRANSACTION_REQUESTOR(TAG_PRESENCE_CHECK)); |
| return JNI_FALSE; |
| } |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: presence check for TypeB - GOT NFA VS RSP", __func__); |
| } else { |
| LOG(ERROR) << StringPrintf( |
| "%s: Kill presence check timer, command failed", __func__); |
| sPresenceCheckTimer.kill(); |
| } |
| } |
| pTransactionController->transactionEnd( |
| TRANSACTION_REQUESTOR(TAG_PRESENCE_CHECK)); |
| |
| if (true == sVSCRsp) { |
| { |
| SyncEventGuard guard(sNfaVSCNotificationEvent); |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: presence check for TypeB - wait for NFA VS NTF to come", |
| __func__); |
| result = |
| sNfaVSCNotificationEvent.wait(5000); // wait for NFA VS NTF to come |
| sPresenceCheckTimer.kill(); |
| if (result == FALSE) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: Timedout while waiting for presence check Ntf", __func__); |
| return JNI_FALSE; |
| } |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: presence check for TypeB - GOT NFA VS NTF", __func__); |
| } |
| |
| if (false == sIsTagInField) { |
| isPresent = JNI_FALSE; |
| } else { |
| isPresent = JNI_TRUE; |
| } |
| } |
| NFA_RegVSCback(false, nfaVSCNtfCallback); // DeRegister CallBack for VS NTF |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: presence check for TypeB - return", __func__); |
| goto TheEnd; |
| } |
| |
| #if (NXP_EXTNS == TRUE) |
| if (NfcTag::getInstance().mTechLibNfcTypes[handle] == NFA_PROTOCOL_T3BT) { |
| uint8_t* pbuf = NULL; |
| uint8_t bufLen = 0x00; |
| bool waitOk = false; |
| int timeout = |
| NfcTag::getInstance().getTransceiveTimeout(sCurrentConnectedTargetType); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: enter; timeout = %d", __func__, timeout); |
| |
| SyncEventGuard g(sTransceiveEvent); |
| sTransceiveRfTimeout = false; |
| sWaitingForTransceive = true; |
| // sTransceiveDataLen = 0; |
| bufLen = (uint8_t)sizeof(Presence_check_TypeB); |
| pbuf = Presence_check_TypeB; |
| // memcpy(pbuf, Attrib_cmd_TypeB, bufLen); |
| status = NFA_SendRawFrame(pbuf, bufLen, |
| NFA_DM_DEFAULT_PRESENCE_CHECK_START_DELAY); |
| if (status != NFA_STATUS_OK) { |
| LOG(ERROR) << StringPrintf("%s: fail send; error=%d", __func__, status); |
| } else |
| waitOk = sTransceiveEvent.wait(timeout); |
| |
| if (waitOk == false || sTransceiveRfTimeout) // if timeout occurred |
| { |
| return JNI_FALSE; |
| ; |
| } else { |
| return JNI_TRUE; |
| } |
| } |
| #endif |
| |
| if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && |
| legacy_mfc_reader) { |
| status = EXTNS_MfcPresenceCheck(); |
| if (status == NFCSTATUS_SUCCESS) { |
| return (NFCSTATUS_SUCCESS == EXTNS_GetPresenceCheckStatus()) ? JNI_TRUE |
| : JNI_FALSE; |
| } |
| } |
| |
| { |
| SyncEventGuard guard(sPresenceCheckEvent); |
| status = |
| NFA_RwPresenceCheck(NfcTag::getInstance().getPresenceCheckAlgorithm()); |
| if (status == NFA_STATUS_OK) { |
| sPresenceCheckEvent.wait(); |
| isPresent = sIsTagPresent ? JNI_TRUE : JNI_FALSE; |
| } |
| } |
| |
| TheEnd: |
| |
| if (isPresent == JNI_FALSE) |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: tag absent", __func__); |
| return isPresent; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doIsNdefFormatable |
| ** |
| ** Description: Can tag be formatted to store NDEF message? |
| ** e: JVM environment. |
| ** o: Java object. |
| ** libNfcType: Type of tag. |
| ** uidBytes: Tag's unique ID. |
| ** pollBytes: Data from activation. |
| ** actBytes: Data from activation. |
| ** |
| ** Returns: True if formattable. |
| ** |
| *******************************************************************************/ |
| static jboolean nativeNfcTag_doIsNdefFormatable(JNIEnv* e, jobject o, |
| jint /*libNfcType*/, jbyteArray, |
| jbyteArray, jbyteArray) { |
| jboolean isFormattable = JNI_FALSE; |
| |
| tNFC_PROTOCOL protocol = NfcTag::getInstance().getProtocol(); |
| if (NFA_PROTOCOL_T1T == protocol || NFA_PROTOCOL_T5T == protocol || |
| NFC_PROTOCOL_MIFARE == protocol) { |
| isFormattable = JNI_TRUE; |
| } else if (NFA_PROTOCOL_T3T == protocol) { |
| isFormattable = NfcTag::getInstance().isFelicaLite() ? JNI_TRUE : JNI_FALSE; |
| } else if (NFA_PROTOCOL_T2T == protocol) { |
| isFormattable = (NfcTag::getInstance().isMifareUltralight() | |
| NfcTag::getInstance().isInfineonMyDMove() | |
| NfcTag::getInstance().isKovioType2Tag()) |
| ? JNI_TRUE |
| : JNI_FALSE; |
| } else if (NFA_PROTOCOL_ISO_DEP == protocol) { |
| /** |
| * Determines whether this is a formatable IsoDep tag - currectly only NXP |
| * DESFire |
| * is supported. |
| */ |
| uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00}; |
| |
| if (NfcTag::getInstance().isMifareDESFire()) { |
| /* Identifies as DESfire, use get version cmd to be sure */ |
| jbyteArray versionCmd = e->NewByteArray(5); |
| e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd); |
| jbyteArray respBytes = |
| nativeNfcTag_doTransceive(e, o, versionCmd, JNI_TRUE, NULL); |
| if (respBytes != NULL) { |
| // Check whether the response matches a typical DESfire |
| // response. |
| // libNFC even does more advanced checking than we do |
| // here, and will only format DESfire's with a certain |
| // major/minor sw version and NXP as a manufacturer. |
| // We don't want to do such checking here, to avoid |
| // having to change code in multiple places. |
| // A succesful (wrapped) DESFire getVersion command returns |
| // 9 bytes, with byte 7 0x91 and byte 8 having status |
| // code 0xAF (these values are fixed and well-known). |
| int respLength = e->GetArrayLength(respBytes); |
| uint8_t* resp = (uint8_t*)e->GetByteArrayElements(respBytes, NULL); |
| if (respLength == 9 && resp[7] == 0x91 && resp[8] == 0xAF) { |
| isFormattable = JNI_TRUE; |
| } |
| e->ReleaseByteArrayElements(respBytes, (jbyte*)resp, JNI_ABORT); |
| } |
| } |
| } |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: is formattable=%u", __func__, isFormattable); |
| return isFormattable; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doIsIsoDepNdefFormatable |
| ** |
| ** Description: Is ISO-DEP tag formattable? |
| ** e: JVM environment. |
| ** o: Java object. |
| ** pollBytes: Data from activation. |
| ** actBytes: Data from activation. |
| ** |
| ** Returns: True if formattable. |
| ** |
| *******************************************************************************/ |
| static jboolean nativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv* e, jobject o, |
| jbyteArray pollBytes, |
| jbyteArray actBytes) { |
| uint8_t uidFake[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); |
| jbyteArray uidArray = e->NewByteArray(8); |
| e->SetByteArrayRegion(uidArray, 0, 8, (jbyte*)uidFake); |
| return nativeNfcTag_doIsNdefFormatable(e, o, 0, uidArray, pollBytes, |
| actBytes); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_makeMifareNdefFormat |
| ** |
| ** Description: Format a mifare classic tag so it can store NDEF message. |
| ** e: JVM environment. |
| ** o: Java object. |
| ** key: Key to acces tag. |
| ** keySize: size of Key. |
| ** |
| ** Returns: True if ok. |
| ** |
| *******************************************************************************/ |
| static jboolean nativeNfcTag_makeMifareNdefFormat(JNIEnv* e, jobject o, |
| uint8_t* key, |
| uint32_t keySize) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__); |
| tNFA_STATUS status = NFA_STATUS_OK; |
| |
| status = nativeNfcTag_doReconnect(e, o); |
| if (status != NFA_STATUS_OK) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: reconnect error, status=%u", __func__, status); |
| return JNI_FALSE; |
| } |
| |
| sem_init(&sFormatSem, 0, 0); |
| sFormatOk = false; |
| |
| status = EXTNS_MfcFormatTag(key, keySize); |
| |
| if (status == NFA_STATUS_OK) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: wait for completion", __func__); |
| sem_wait(&sFormatSem); |
| status = sFormatOk ? NFA_STATUS_OK : NFA_STATUS_FAILED; |
| } else { |
| LOG(ERROR) << StringPrintf("%s: error status=%u", __func__, status); |
| } |
| |
| sem_destroy(&sFormatSem); |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); |
| return (status == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doNdefFormat |
| ** |
| ** Description: Format a tag so it can store NDEF message. |
| ** e: JVM environment. |
| ** o: Java object. |
| ** key: Not used. |
| ** |
| ** Returns: True if ok. |
| ** |
| *******************************************************************************/ |
| static jboolean nativeNfcTag_doNdefFormat(JNIEnv* e, jobject o, jbyteArray) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__); |
| tNFA_STATUS status = NFA_STATUS_OK; |
| |
| // Do not try to format if tag is already deactivated. |
| if (NfcTag::getInstance().isActivated() == false) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: tag already deactivated(no need to format)", __func__); |
| return JNI_FALSE; |
| } |
| |
| if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && |
| legacy_mfc_reader) { |
| static uint8_t mfc_key1[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; |
| static uint8_t mfc_key2[6] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7}; |
| jboolean result; |
| |
| result = |
| nativeNfcTag_makeMifareNdefFormat(e, o, mfc_key1, sizeof(mfc_key1)); |
| if (result == JNI_FALSE) { |
| result = |
| nativeNfcTag_makeMifareNdefFormat(e, o, mfc_key2, sizeof(mfc_key2)); |
| } |
| if (result == JNI_FALSE) { |
| LOG(ERROR) << StringPrintf("%s: error status=%u", __func__, |
| NFA_STATUS_FAILED); |
| EXTNS_SetConnectFlag(false); |
| } |
| return result; |
| } |
| |
| sem_init(&sFormatSem, 0, 0); |
| sFormatOk = false; |
| status = NFA_RwFormatTag(); |
| if (status == NFA_STATUS_OK) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: wait for completion", __func__); |
| sem_wait(&sFormatSem); |
| status = sFormatOk ? NFA_STATUS_OK : NFA_STATUS_FAILED; |
| } else { |
| LOG(ERROR) << StringPrintf("%s: error status=%u", __func__, status); |
| } |
| sem_destroy(&sFormatSem); |
| |
| if (sCurrentConnectedTargetProtocol == NFA_PROTOCOL_ISO_DEP) { |
| int retCode = NFCSTATUS_SUCCESS; |
| retCode = nativeNfcTag_doReconnect(e, o); |
| } |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); |
| return (status == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doMakeReadonlyResult |
| ** |
| ** Description: Receive the result of making a tag read-only. Called by the |
| ** NFA_SET_TAG_RO_EVT. |
| ** status: Status of the operation. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_doMakeReadonlyResult(tNFA_STATUS status) { |
| if (sMakeReadonlyWaitingForComplete != JNI_FALSE) { |
| sMakeReadonlyWaitingForComplete = JNI_FALSE; |
| sMakeReadonlyStatus = status; |
| |
| sem_post(&sMakeReadonlySem); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_makeMifareReadonly |
| ** |
| ** Description: Make the mifare classic tag read-only. |
| ** e: JVM environment. |
| ** o: Java object. |
| ** key: Key to access the tag. |
| ** keySize: size of Key. |
| ** |
| ** Returns: True if ok. |
| ** |
| *******************************************************************************/ |
| static jboolean nativeNfcTag_makeMifareReadonly(JNIEnv* e, jobject o, |
| uint8_t* key, int32_t keySize) { |
| jboolean result = JNI_FALSE; |
| tNFA_STATUS status = NFA_STATUS_OK; |
| |
| sMakeReadonlyStatus = NFA_STATUS_FAILED; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); |
| |
| /* Create the make_readonly semaphore */ |
| if (sem_init(&sMakeReadonlySem, 0, 0) == -1) { |
| LOG(ERROR) << StringPrintf( |
| "%s: Make readonly semaphore creation failed (errno=0x%08x)", __func__, |
| errno); |
| return JNI_FALSE; |
| } |
| |
| sMakeReadonlyWaitingForComplete = JNI_TRUE; |
| |
| status = nativeNfcTag_doReconnect(e, o); |
| if (status != NFA_STATUS_OK) { |
| goto TheEnd; |
| } |
| |
| status = EXTNS_MfcSetReadOnly(key, keySize); |
| if (status != NFA_STATUS_OK) { |
| goto TheEnd; |
| } |
| sem_wait(&sMakeReadonlySem); |
| |
| if (sMakeReadonlyStatus == NFA_STATUS_OK) { |
| result = JNI_TRUE; |
| } |
| |
| TheEnd: |
| /* Destroy semaphore */ |
| if (sem_destroy(&sMakeReadonlySem)) { |
| LOG(ERROR) << StringPrintf( |
| "%s: Failed to destroy read_only semaphore (errno=0x%08x)", __func__, |
| errno); |
| } |
| sMakeReadonlyWaitingForComplete = JNI_FALSE; |
| return result; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_doMakeReadonly |
| ** |
| ** Description: Make the tag read-only. |
| ** e: JVM environment. |
| ** o: Java object. |
| ** key: Key to access the tag. |
| ** |
| ** Returns: True if ok. |
| ** |
| *******************************************************************************/ |
| static jboolean nativeNfcTag_doMakeReadonly(JNIEnv* e, jobject o, jbyteArray) { |
| jboolean result = JNI_FALSE; |
| tNFA_STATUS status = NFA_STATUS_OK; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); |
| |
| if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && |
| legacy_mfc_reader) { |
| static uint8_t mfc_key1[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; |
| static uint8_t mfc_key2[6] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7}; |
| result = nativeNfcTag_makeMifareReadonly(e, o, mfc_key1, sizeof(mfc_key1)); |
| if (result == JNI_FALSE) { |
| result = |
| nativeNfcTag_makeMifareReadonly(e, o, mfc_key2, sizeof(mfc_key2)); |
| } |
| return result; |
| } |
| |
| /* Create the make_readonly semaphore */ |
| if (sem_init(&sMakeReadonlySem, 0, 0) == -1) { |
| LOG(ERROR) << StringPrintf( |
| "%s: Make readonly semaphore creation failed (errno=0x%08x)", __func__, |
| errno); |
| return JNI_FALSE; |
| } |
| |
| sMakeReadonlyWaitingForComplete = JNI_TRUE; |
| |
| // Hard-lock the tag (cannot be reverted) |
| status = NFA_RwSetTagReadOnly(true); |
| if (status == NFA_STATUS_REJECTED) { |
| status = NFA_RwSetTagReadOnly(false); // try soft lock |
| if (status != NFA_STATUS_OK) { |
| LOG(ERROR) << StringPrintf("%s: fail soft lock, status=%d", __func__, |
| status); |
| goto TheEnd; |
| } |
| } else if (status != NFA_STATUS_OK) { |
| LOG(ERROR) << StringPrintf("%s: fail hard lock, status=%d", __func__, |
| status); |
| goto TheEnd; |
| } |
| |
| /*Wait for check NDEF completion status*/ |
| if (sem_wait(&sMakeReadonlySem)) { |
| LOG(ERROR) << StringPrintf( |
| "%s: Failed to wait for make_readonly semaphore (errno=0x%08x)", |
| __func__, errno); |
| goto TheEnd; |
| } |
| |
| if (sMakeReadonlyStatus == NFA_STATUS_OK) { |
| result = JNI_TRUE; |
| } |
| |
| TheEnd: |
| /* Destroy semaphore */ |
| if (sem_destroy(&sMakeReadonlySem)) { |
| LOG(ERROR) << StringPrintf( |
| "%s: Failed to destroy read_only semaphore (errno=0x%08x)", __func__, |
| errno); |
| } |
| sMakeReadonlyWaitingForComplete = JNI_FALSE; |
| return result; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_registerNdefTypeHandler |
| ** |
| ** Description: Register a callback to receive NDEF message from the tag |
| ** from the NFA_NDEF_DATA_EVT. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| // register a callback to receive NDEF message from the tag |
| // from the NFA_NDEF_DATA_EVT; |
| void nativeNfcTag_registerNdefTypeHandler() { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); |
| sNdefTypeHandlerHandle = NFA_HANDLE_INVALID; |
| NFA_RegisterNDefTypeHandler(true, NFA_TNF_DEFAULT, (uint8_t*)"", 0, |
| ndefHandlerCallback); |
| if (legacy_mfc_reader) { |
| EXTNS_MfcRegisterNDefTypeHandler(ndefHandlerCallback); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_deregisterNdefTypeHandler |
| ** |
| ** Description: No longer need to receive NDEF message from the tag. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_deregisterNdefTypeHandler() { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); |
| NFA_DeregisterNDefTypeHandler(sNdefTypeHandlerHandle); |
| sNdefTypeHandlerHandle = NFA_HANDLE_INVALID; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: presenceCheckTimerProc |
| ** |
| ** Description: Callback function for presence check timer. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| static void presenceCheckTimerProc(union sigval) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); |
| sIsTagInField = false; |
| sIsReconnecting = false; |
| { |
| SyncEventGuard guard(sNfaVSCResponseEvent); |
| sNfaVSCResponseEvent.notifyOne(); |
| } |
| { |
| SyncEventGuard guard(sNfaVSCNotificationEvent); |
| sNfaVSCNotificationEvent.notifyOne(); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: sReconnectTimerProc |
| ** |
| ** Description: Callback function for reconnect timer. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| static void sReconnectTimerProc(union sigval) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); |
| { |
| SyncEventGuard guard(sNfaVSCResponseEvent); |
| sNfaVSCResponseEvent.notifyOne(); |
| } |
| { |
| SyncEventGuard guard(sNfaVSCNotificationEvent); |
| sNfaVSCNotificationEvent.notifyOne(); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_acquireRfInterfaceMutexLock |
| ** |
| ** Description: acquire lock |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_acquireRfInterfaceMutexLock() { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: try to acquire lock", __func__); |
| sRfInterfaceMutex.lock(); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: sRfInterfaceMutex lock", __func__); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: nativeNfcTag_releaseRfInterfaceMutexLock |
| ** |
| ** Description: release the lock |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void nativeNfcTag_releaseRfInterfaceMutexLock() { |
| sRfInterfaceMutex.unlock(); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: sRfInterfaceMutex unlock", __func__); |
| } |
| |
| /***************************************************************************** |
| ** |
| ** JNI functions for Android 4.0.3 |
| ** |
| *****************************************************************************/ |
| static JNINativeMethod gMethods[] = { |
| {"doConnect", "(I)I", (void*)nativeNfcTag_doConnect}, |
| {"doDisconnect", "()Z", (void*)nativeNfcTag_doDisconnect}, |
| {"doReconnect", "()I", (void*)nativeNfcTag_doReconnect}, |
| {"doHandleReconnect", "(I)I", (void*)nativeNfcTag_doHandleReconnect}, |
| {"doTransceive", "([BZ[I)[B", (void*)nativeNfcTag_doTransceive}, |
| {"doGetNdefType", "(II)I", (void*)nativeNfcTag_doGetNdefType}, |
| {"doCheckNdef", "([I)I", (void*)nativeNfcTag_doCheckNdef}, |
| {"doRead", "()[B", (void*)nativeNfcTag_doRead}, |
| {"doWrite", "([B)Z", (void*)nativeNfcTag_doWrite}, |
| {"doPresenceCheck", "()Z", (void*)nativeNfcTag_doPresenceCheck}, |
| {"doIsIsoDepNdefFormatable", "([B[B)Z", |
| (void*)nativeNfcTag_doIsIsoDepNdefFormatable}, |
| {"doNdefFormat", "([B)Z", (void*)nativeNfcTag_doNdefFormat}, |
| {"doMakeReadonly", "([B)Z", (void*)nativeNfcTag_doMakeReadonly}, |
| }; |
| |
| /******************************************************************************* |
| ** |
| ** Function: register_com_android_nfc_NativeNfcTag |
| ** |
| ** Description: Regisgter JNI functions with Java Virtual Machine. |
| ** e: Environment of JVM. |
| ** |
| ** Returns: Status of registration. |
| ** |
| *******************************************************************************/ |
| int register_com_android_nfc_NativeNfcTag(JNIEnv* e) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); |
| return jniRegisterNativeMethods(e, gNativeNfcTagClassName, gMethods, |
| NELEM(gMethods)); |
| } |
| |
| } /* namespace android */ |