| /****************************************************************************** |
| * |
| * 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. |
| * |
| * Copyright 2018 NXP |
| * |
| ******************************************************************************/ |
| |
| #include "SecureElement.h" |
| #include <nativehelper/ScopedLocalRef.h> |
| #include "JavaClassConstants.h" |
| #include "NfcJniUtil.h" |
| #include <android-base/stringprintf.h> |
| #include <base/logging.h> |
| #include <semaphore.h> |
| #include <errno.h> |
| #include "config.h" |
| #include "phNxpConfig.h" |
| #include "nfc_config.h" |
| #include "RoutingManager.h" |
| using android::base::StringPrintf; |
| |
| SecureElement SecureElement::sSecElem; |
| const char* SecureElement::APP_NAME = "nfc_jni"; |
| extern bool nfc_debug_enabled; |
| |
| #include "MposManager.h" |
| namespace android |
| { |
| extern void startRfDiscovery (bool isStart); |
| } |
| uint8_t SecureElement::mStaticPipeProp; |
| /******************************************************************************* |
| ** |
| ** Function: SecureElement |
| ** |
| ** Description: Initialize member variables. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| SecureElement::SecureElement() : |
| mNewPipeId (0), |
| mNativeData(NULL), |
| mbNewEE (true), |
| mIsInit (false), |
| mNewSourceGate (0), |
| mRfFieldIsOn(false), |
| mActivatedInListenMode (false) |
| { |
| memset (&mEeInfo, 0, nfcFL.nfccFL._NFA_EE_MAX_EE_SUPPORTED *sizeof(tNFA_EE_INFO)); |
| memset (mAidForEmptySelect, 0, sizeof(mAidForEmptySelect)); |
| memset (&mHciCfg, 0, sizeof(mHciCfg)); |
| memset (&mLastRfFieldToggle, 0, sizeof(mLastRfFieldToggle)); |
| } |
| /******************************************************************************* |
| ** |
| ** Function: getInstance |
| ** |
| ** Description: Get the SecureElement singleton object. |
| ** |
| ** Returns: SecureElement object. |
| ** |
| *******************************************************************************/ |
| SecureElement& SecureElement::getInstance() { return sSecElem; } |
| |
| /******************************************************************************* |
| ** |
| ** Function: initialize |
| ** |
| ** Description: Initialize all member variables. |
| ** native: Native data. |
| ** |
| ** Returns: True if ok. |
| ** |
| *******************************************************************************/ |
| bool SecureElement::initialize(nfc_jni_native_data* native) { |
| static const char fn [] = "SecureElement::initialize"; |
| tNFA_STATUS nfaStat; |
| |
| LOG(INFO) << StringPrintf("%s: enter", fn); |
| |
| |
| mActiveEeHandle = NFA_HANDLE_INVALID; |
| mNfaHciHandle = NFA_HANDLE_INVALID; |
| |
| mNativeData = native; |
| mthreadnative = native; |
| mActualNumEe = nfcFL.nfccFL._NFA_EE_MAX_EE_SUPPORTED; |
| mbNewEE = true; |
| mNewPipeId = 0; |
| mNewSourceGate = 0; |
| unsigned long val = 0; |
| memset (mEeInfo, 0, sizeof(mEeInfo)); |
| memset (&mHciCfg, 0, sizeof(mHciCfg)); |
| memset(mAidForEmptySelect, 0, sizeof(mAidForEmptySelect)); |
| if (GetNxpNumValue(NAME_NXP_DEFAULT_UICC2_SELECT, &muicc2_selected, sizeof(muicc2_selected)) == false) |
| { |
| muicc2_selected = UICC2_ID; |
| } |
| if (GetNxpNumValue(NAME_NXP_SMB_TRANSCEIVE_TIMEOUT, &val, sizeof(val)) == true) |
| { |
| SmbTransceiveTimeOutVal = val; |
| } |
| else |
| { |
| SmbTransceiveTimeOutVal = WIRED_MODE_TRANSCEIVE_TIMEOUT; |
| } |
| LOG(INFO) << StringPrintf("%s: SMB transceive timeout %d", fn, SmbTransceiveTimeOutVal); |
| initializeEeHandle(); |
| |
| // Get Fresh EE info. |
| if (! getEeInfo()) |
| return (false); |
| |
| // If the controller has an HCI Network, register for that |
| //for (size_t xx = 0; xx < mActualNumEe; xx++) |
| for (size_t xx = 0; xx < MAX_NUM_EE; xx++) |
| { |
| |
| if((mEeInfo[xx].ee_handle != EE_HANDLE_0xF4) |
| || ((((mEeInfo[xx].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) |
| && (mEeInfo[xx].ee_status == NFC_NFCEE_STATUS_ACTIVE)) || (NFA_GetNCIVersion() == NCI_VERSION_2_0)))) |
| { |
| LOG(INFO) << StringPrintf("%s: Found HCI network, try hci register", fn); |
| |
| SyncEventGuard guard (mHciRegisterEvent); |
| |
| nfaStat = NFA_HciRegister (const_cast<char*>(APP_NAME), nfaHciCallback, true); |
| if (nfaStat != NFA_STATUS_OK) |
| { |
| LOG(ERROR) << StringPrintf("%s: fail hci register; error=0x%X", fn, nfaStat); |
| return (false); |
| } |
| mHciRegisterEvent.wait(); |
| break; |
| } |
| } |
| |
| mIsInit = true; |
| LOG(INFO) << StringPrintf("%s: exit", fn); |
| return (true); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: getGenericEseId |
| ** |
| ** Description: Whether controller is routing listen-mode events to |
| ** secure elements or a pipe is connected. |
| ** |
| ** Returns: Return the generic SE id ex:- 00,01,02,04 |
| ** |
| *******************************************************************************/ |
| jint SecureElement::getGenericEseId(tNFA_HANDLE handle) { |
| jint ret = 0xFF; |
| static const char fn [] = "SecureElement::getGenericEseId"; |
| LOG(INFO) << StringPrintf("%s: enter; ESE-Handle = 0x%X", fn, handle); |
| |
| //Map the actual handle to generic id |
| if(handle == (EE_HANDLE_0xF3 & ~NFA_HANDLE_GROUP_EE) ) //ESE - 0xC0 |
| { |
| ret = ESE_ID; |
| } |
| else if(handle == (SecureElement::getInstance().EE_HANDLE_0xF4 & ~NFA_HANDLE_GROUP_EE) ) //UICC - 0x02 |
| { |
| ret = UICC_ID; |
| } |
| if(handle == (EE_HANDLE_0xF8 & ~NFA_HANDLE_GROUP_EE)) //UICC2 - 0x04 |
| { |
| ret = UICC2_ID; |
| } |
| else if (handle == (EE_HANDLE_0xF9 & ~NFA_HANDLE_GROUP_EE)) //UICC2 - 0x04 |
| { |
| ret = UICC3_ID; |
| } |
| LOG(INFO) << StringPrintf("%s: exit; ESE-Generic-ID = 0x%02X", fn, ret); |
| return ret; |
| } |
| /******************************************************************************* |
| ** |
| ** Function TimeDiff |
| ** |
| ** Description Computes time difference in milliseconds. |
| ** |
| ** Returns Time difference in milliseconds |
| ** |
| *******************************************************************************/ |
| static uint32_t TimeDiff(timespec start, timespec end) |
| { |
| end.tv_sec -= start.tv_sec; |
| end.tv_nsec -= start.tv_nsec; |
| |
| if (end.tv_nsec < 0) { |
| end.tv_nsec += 10e8; |
| end.tv_sec -=1; |
| } |
| |
| return (end.tv_sec * 1000) + (end.tv_nsec / 10e5); |
| } |
| /******************************************************************************* |
| ** |
| ** Function: isRfFieldOn |
| ** |
| ** Description: Can be used to determine if the SE is in an RF field |
| ** |
| ** Returns: True if the SE is activated in an RF field |
| ** |
| *******************************************************************************/ |
| bool SecureElement::isRfFieldOn() { |
| AutoMutex mutex(mMutex); |
| if (mRfFieldIsOn) { |
| return true; |
| } |
| struct timespec now; |
| int ret = clock_gettime(CLOCK_MONOTONIC, &now); |
| if (ret == -1) { |
| DLOG_IF(ERROR, nfc_debug_enabled) |
| << StringPrintf("isRfFieldOn(): clock_gettime failed"); |
| return false; |
| } |
| if (TimeDiff(mLastRfFieldToggle, now) < 50) { |
| // If it was less than 50ms ago that RF field |
| // was turned off, still return ON. |
| return true; |
| } else { |
| return false; |
| } |
| } |
| /******************************************************************************* |
| ** |
| ** Function: notifyListenModeState |
| ** |
| ** Description: Notify the NFC service about whether the SE was activated |
| ** in listen mode. |
| ** isActive: Whether the secure element is activated. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void SecureElement::notifyListenModeState (bool isActivated) { |
| static const char fn [] = "SecureElement::notifyListenMode"; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: enter; listen mode active=%u", fn, isActivated); |
| |
| JNIEnv* e = NULL; |
| if (mNativeData == NULL) |
| { |
| DLOG_IF(ERROR, nfc_debug_enabled) |
| << StringPrintf("%s: mNativeData is null", fn); |
| return; |
| } |
| |
| ScopedAttach attach(mNativeData->vm, &e); |
| if (e == NULL) |
| { |
| DLOG_IF(ERROR, nfc_debug_enabled) |
| << StringPrintf("%s: jni env is null", fn); |
| return; |
| } |
| |
| mActivatedInListenMode = isActivated; |
| |
| if (mNativeData != NULL) { |
| if (isActivated) { |
| e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeListenActivated); |
| } |
| else { |
| e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeListenDeactivated); |
| } |
| } |
| |
| if (e->ExceptionCheck()) |
| { |
| e->ExceptionClear(); |
| DLOG_IF(ERROR, nfc_debug_enabled) |
| << StringPrintf("%s: fail notify", fn); |
| } |
| |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: exit", fn); |
| } |
| /******************************************************************************* |
| ** |
| ** Function: notifyTransactionListenersOfAid |
| ** |
| ** Description: Notify the NFC service about a transaction event from |
| ** secure element. |
| ** aid: Buffer contains application ID. |
| ** aidLen: Length of application ID. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void SecureElement::notifyTransactionListenersOfAid(const uint8_t* aidBuffer, |
| uint8_t aidBufferLen, |
| const uint8_t* dataBuffer, |
| uint32_t dataBufferLen, |
| uint32_t evtSrc) { |
| { |
| static const char fn [] = "SecureElement::notifyTransactionListenersOfAid"; |
| |
| if (aidBufferLen == 0) { |
| return; |
| } |
| |
| JNIEnv* e = NULL; |
| ScopedAttach attach(mNativeData->vm, &e); |
| if (e == NULL) |
| { |
| LOG(ERROR) << StringPrintf("%s: jni env is null", fn); |
| return; |
| } |
| |
| const uint16_t tlvMaxLen = aidBufferLen + 10; |
| uint8_t* tlv = new uint8_t [tlvMaxLen]; |
| if (tlv == NULL) |
| { |
| LOG(ERROR) << StringPrintf("%s: fail allocate tlv", fn); |
| return; |
| } |
| |
| memcpy (tlv, aidBuffer, aidBufferLen); |
| uint16_t tlvActualLen = aidBufferLen; |
| |
| ScopedLocalRef<jobject> tlvJavaArray(e, e->NewByteArray(tlvActualLen)); |
| if (tlvJavaArray.get() == NULL) |
| { |
| LOG(ERROR) << StringPrintf("%s: fail allocate array", fn); |
| goto TheEnd; |
| } |
| |
| e->SetByteArrayRegion ((jbyteArray)tlvJavaArray.get(), 0, tlvActualLen, (jbyte *)tlv); |
| if (e->ExceptionCheck()) |
| { |
| e->ExceptionClear(); |
| LOG(ERROR) << StringPrintf("%s: fail fill array", fn); |
| goto TheEnd; |
| } |
| |
| if(dataBufferLen > 0) |
| { |
| const uint32_t dataTlvMaxLen = dataBufferLen + 10; |
| uint8_t* datatlv = new uint8_t [dataTlvMaxLen]; |
| if (datatlv == NULL) |
| { |
| LOG(ERROR) << StringPrintf("%s: fail allocate tlv", fn); |
| return; |
| } |
| |
| memcpy (datatlv, dataBuffer, dataBufferLen); |
| uint16_t dataTlvActualLen = dataBufferLen; |
| |
| ScopedLocalRef<jobject> dataTlvJavaArray(e, e->NewByteArray(dataTlvActualLen)); |
| if (dataTlvJavaArray.get() == NULL) |
| { |
| LOG(ERROR) << StringPrintf("%s: fail allocate array", fn); |
| goto Clean; |
| } |
| |
| e->SetByteArrayRegion ((jbyteArray)dataTlvJavaArray.get(), 0, dataTlvActualLen, (jbyte *)datatlv); |
| if (e->ExceptionCheck()) |
| { |
| e->ExceptionClear(); |
| LOG(ERROR) << StringPrintf("%s: fail fill array", fn); |
| goto Clean; |
| } |
| |
| e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyTransactionListeners, tlvJavaArray.get(), dataTlvJavaArray.get(), evtSrc); |
| if (e->ExceptionCheck()) |
| { |
| e->ExceptionClear(); |
| LOG(ERROR) << StringPrintf("%s: fail notify", fn); |
| goto Clean; |
| } |
| |
| Clean: |
| delete [] datatlv; |
| } |
| else |
| { |
| e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyTransactionListeners, tlvJavaArray.get(), NULL, evtSrc); |
| if (e->ExceptionCheck()) |
| { |
| e->ExceptionClear(); |
| LOG(ERROR) << StringPrintf("%s: fail notify", fn); |
| goto TheEnd; |
| } |
| } |
| TheEnd: |
| delete [] tlv; |
| LOG(INFO) << StringPrintf("%s: exit", fn); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: decodeBerTlvLength |
| ** |
| ** Description: Decodes BER TLV length from the data provided |
| ** data : array of data to be processed |
| ** index : offset from which to consider processing |
| ** data_length : length of data to be processed |
| ** |
| ** Returns: decoded_length |
| ** |
| *******************************************************************************/ |
| int SecureElement::decodeBerTlvLength(uint8_t* data, int index, |
| int data_length) { |
| int decoded_length = -1; |
| int length = 0; |
| int temp = data[index] & 0xff; |
| |
| LOG(INFO) << StringPrintf("decodeBerTlvLength index= %d data[index+0]=0x%x data[index+1]=0x%x len=%d",index, data[index], data[index+1], data_length); |
| |
| if (temp < 0x80) { |
| decoded_length = temp; |
| } else if (temp == 0x81) { |
| if( index < data_length ) { |
| length = data[index+1] & 0xff; |
| if (length < 0x80) { |
| LOG(ERROR) << StringPrintf("Invalid TLV length encoding!"); |
| goto TheEnd; |
| } |
| if (data_length < length + index) { |
| LOG(ERROR) << StringPrintf("Not enough data provided!"); |
| goto TheEnd; |
| } |
| } else { |
| LOG(ERROR) << StringPrintf("Index %d out of range! [0..[%d",index, data_length); |
| goto TheEnd; |
| } |
| decoded_length = length; |
| } else if (temp == 0x82) { |
| if( (index + 1)< data_length ) { |
| length = ((data[index] & 0xff) << 8) |
| | (data[index + 1] & 0xff); |
| } else { |
| LOG(ERROR) << StringPrintf("Index out of range! [0..[%d" , data_length); |
| goto TheEnd; |
| } |
| index += 2; |
| if (length < 0x100) { |
| LOG(ERROR) << StringPrintf("Invalid TLV length encoding!"); |
| goto TheEnd; |
| } |
| if (data_length < length + index) { |
| LOG(ERROR) << StringPrintf("Not enough data provided!"); |
| goto TheEnd; |
| } |
| decoded_length = length; |
| } else if (temp == 0x83) { |
| if( (index + 2)< data_length ) { |
| length = ((data[index] & 0xff) << 16) |
| | ((data[index + 1] & 0xff) << 8) |
| | (data[index + 2] & 0xff); |
| } else { |
| LOG(ERROR) << StringPrintf("Index out of range! [0..[%d", data_length); |
| goto TheEnd; |
| } |
| index += 3; |
| if (length < 0x10000) { |
| LOG(ERROR) << StringPrintf("Invalid TLV length encoding!"); |
| goto TheEnd; |
| } |
| if (data_length < length + index) { |
| LOG(ERROR) << StringPrintf("Not enough data provided!"); |
| goto TheEnd; |
| } |
| decoded_length = length; |
| } else { |
| LOG(ERROR) << StringPrintf("Unsupported TLV length encoding!"); |
| } |
| TheEnd: |
| LOG(INFO) << StringPrintf("decoded_length = %d", decoded_length); |
| |
| return decoded_length; |
| } |
| /******************************************************************************* |
| ** |
| ** Function: notifyRfFieldEvent |
| ** |
| ** Description: Notify the NFC service about RF field events from the stack. |
| ** isActive: Whether any secure element is activated. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void SecureElement::notifyRfFieldEvent (bool isActive) |
| { |
| static const char fn [] = "SecureElement::notifyRfFieldEvent"; |
| DLOG_IF(ERROR, nfc_debug_enabled) |
| << StringPrintf("%s: enter; is active=%u", fn, isActive); |
| |
| |
| mMutex.lock(); |
| int ret = clock_gettime (CLOCK_MONOTONIC, &mLastRfFieldToggle); |
| if (ret == -1) { |
| DLOG_IF(ERROR, nfc_debug_enabled) |
| << StringPrintf("%s: clock_gettime failed", fn); |
| // There is no good choice here... |
| } |
| if (isActive) |
| { |
| mRfFieldIsOn = true; |
| } |
| else |
| { |
| mRfFieldIsOn = false; |
| } |
| mMutex.unlock(); |
| DLOG_IF(ERROR, nfc_debug_enabled) |
| << StringPrintf("%s: exit", fn); |
| } |
| /******************************************************************************* |
| ** |
| ** Function: nfaHciCallback |
| ** |
| ** Description: Receive HCI-related events from stack. |
| ** event: Event code. |
| ** eventData: Event data. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void SecureElement::nfaHciCallback(tNFA_HCI_EVT event, |
| tNFA_HCI_EVT_DATA* eventData) { |
| static const char fn [] = "SecureElement::nfaHciCallback"; |
| LOG(INFO) << StringPrintf("%s: event=0x%X", fn, event); |
| int evtSrc = 0xFF; |
| |
| switch (event) |
| { |
| case NFA_HCI_REGISTER_EVT: |
| { |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_REGISTER_EVT; status=0x%X; handle=0x%X", fn, |
| eventData->hci_register.status, eventData->hci_register.hci_handle); |
| SyncEventGuard guard (sSecElem.mHciRegisterEvent); |
| sSecElem.mNfaHciHandle = eventData->hci_register.hci_handle; |
| sSecElem.mHciRegisterEvent.notifyOne(); |
| } |
| break; |
| |
| case NFA_HCI_ALLOCATE_GATE_EVT: |
| { |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_ALLOCATE_GATE_EVT; status=0x%X; gate=0x%X", fn, eventData->status, eventData->allocated.gate); |
| SyncEventGuard guard (sSecElem.mAllocateGateEvent); |
| sSecElem.mCommandStatus = eventData->status; |
| sSecElem.mNewSourceGate = (eventData->allocated.status == NFA_STATUS_OK) ? eventData->allocated.gate : 0; |
| sSecElem.mAllocateGateEvent.notifyOne(); |
| } |
| break; |
| |
| case NFA_HCI_DEALLOCATE_GATE_EVT: |
| { |
| tNFA_HCI_DEALLOCATE_GATE& deallocated = eventData->deallocated; |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_DEALLOCATE_GATE_EVT; status=0x%X; gate=0x%X", fn, deallocated.status, deallocated.gate); |
| SyncEventGuard guard (sSecElem.mDeallocateGateEvent); |
| sSecElem.mDeallocateGateEvent.notifyOne(); |
| } |
| break; |
| |
| case NFA_HCI_GET_GATE_PIPE_LIST_EVT: |
| { |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_GET_GATE_PIPE_LIST_EVT; status=0x%X; num_pipes: %u num_gates: %u", fn, |
| eventData->gates_pipes.status, eventData->gates_pipes.num_pipes, eventData->gates_pipes.num_gates); |
| SyncEventGuard guard (sSecElem.mPipeListEvent); |
| sSecElem.mCommandStatus = eventData->gates_pipes.status; |
| sSecElem.mHciCfg = eventData->gates_pipes; |
| sSecElem.mPipeListEvent.notifyOne(); |
| } |
| break; |
| |
| case NFA_HCI_CREATE_PIPE_EVT: |
| { |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_CREATE_PIPE_EVT; status=0x%X; pipe=0x%X; src gate=0x%X; dest host=0x%X; dest gate=0x%X", fn, |
| eventData->created.status, eventData->created.pipe, eventData->created.source_gate, eventData->created.dest_host, eventData->created.dest_gate); |
| SyncEventGuard guard (sSecElem.mCreatePipeEvent); |
| sSecElem.mCommandStatus = eventData->created.status; |
| if(eventData->created.dest_gate == 0xF0) |
| { |
| LOG(ERROR) << StringPrintf("Pipe=0x%x is created and updated for se transcieve", eventData->created.pipe); |
| sSecElem.mNewPipeId = eventData->created.pipe; |
| } |
| sSecElem.mCreatedPipe = eventData->created.pipe; |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_CREATE_PIPE_EVT; pipe=0x%X", fn, eventData->created.pipe); |
| sSecElem.mCreatePipeEvent.notifyOne(); |
| } |
| break; |
| case NFA_HCI_OPEN_PIPE_EVT: |
| { |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_OPEN_PIPE_EVT; status=0x%X; pipe=0x%X", fn, eventData->opened.status, eventData->opened.pipe); |
| SyncEventGuard guard (sSecElem.mPipeOpenedEvent); |
| sSecElem.mCommandStatus = eventData->opened.status; |
| sSecElem.mPipeOpenedEvent.notifyOne(); |
| } |
| break; |
| |
| case NFA_HCI_EVENT_SENT_EVT: |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_EVENT_SENT_EVT; status=0x%X", fn, eventData->evt_sent.status); |
| break; |
| |
| case NFA_HCI_RSP_RCVD_EVT: //response received from secure element |
| { |
| tNFA_HCI_RSP_RCVD& rsp_rcvd = eventData->rsp_rcvd; |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_RSP_RCVD_EVT; status: 0x%X; code: 0x%X; pipe: 0x%X; len: %u", fn, |
| rsp_rcvd.status, rsp_rcvd.rsp_code, rsp_rcvd.pipe, rsp_rcvd.rsp_len); |
| } |
| break; |
| case NFA_HCI_RSP_APDU_RCVD_EVT: |
| { |
| if(eventData->apdu_rcvd.apdu_len > 0) |
| { |
| sSecElem.mTransceiveWaitOk = true; |
| sSecElem.mActualResponseSize = (eventData->apdu_rcvd.apdu_len > MAX_RESPONSE_SIZE) ? MAX_RESPONSE_SIZE : eventData->apdu_rcvd.apdu_len; |
| } |
| sSecElem.mTransceiveEvent.notifyOne (); |
| break; |
| } |
| case NFA_HCI_APDU_ABORTED_EVT: |
| { |
| if(eventData->apdu_aborted.atr_len > 0) |
| { |
| sSecElem.mAbortEventWaitOk = true; |
| SyncEventGuard guard(sSecElem.mAbortEvent); |
| memcpy(sSecElem.mAtrInfo, eventData->apdu_aborted.p_atr, eventData->apdu_aborted.atr_len); |
| sSecElem.mAtrInfolen = eventData->apdu_aborted.atr_len; |
| sSecElem.mAtrStatus = eventData->rcvd_evt.status; |
| sSecElem.mAbortEvent.notifyOne(); |
| } |
| else |
| { |
| sSecElem.mAbortEventWaitOk = false; |
| SyncEventGuard guard(sSecElem.mAbortEvent); |
| sSecElem.mAbortEvent.notifyOne(); |
| } |
| break; |
| } |
| case NFA_HCI_GET_REG_RSP_EVT : |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_GET_REG_RSP_EVT; status: 0x%X; pipe: 0x%X, len: %d", fn, |
| eventData->registry.status, eventData->registry.pipe, eventData->registry.data_len); |
| if(sSecElem.mGetAtrRspwait == true) |
| { |
| /*GetAtr response*/ |
| sSecElem.mGetAtrRspwait = false; |
| SyncEventGuard guard (sSecElem.mGetRegisterEvent); |
| memcpy(sSecElem.mAtrInfo, eventData->registry.reg_data, eventData->registry.data_len); |
| sSecElem.mAtrInfolen = eventData->registry.data_len; |
| sSecElem.mAtrStatus = eventData->registry.status; |
| sSecElem.mGetRegisterEvent.notifyOne(); |
| } |
| else if (eventData->registry.data_len >= 19 && ((eventData->registry.pipe == mStaticPipeProp) || (eventData->registry.pipe == STATIC_PIPE_0x71))) |
| { |
| SyncEventGuard guard (sSecElem.mVerInfoEvent); |
| // Oberthur OS version is in bytes 16,17, and 18 |
| sSecElem.mVerInfo[0] = eventData->registry.reg_data[16]; |
| sSecElem.mVerInfo[1] = eventData->registry.reg_data[17]; |
| sSecElem.mVerInfo[2] = eventData->registry.reg_data[18]; |
| sSecElem.mVerInfoEvent.notifyOne (); |
| } |
| break; |
| |
| case NFA_HCI_EVENT_RCVD_EVT: |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_EVENT_RCVD_EVT; code: 0x%X; pipe: 0x%X; data len: %u", fn, |
| eventData->rcvd_evt.evt_code, eventData->rcvd_evt.pipe, eventData->rcvd_evt.evt_len); |
| if(eventData->rcvd_evt.pipe == 0x0A) //UICC |
| { |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_EVENT_RCVD_EVT; source UICC",fn); |
| evtSrc = SecureElement::getInstance().getGenericEseId(SecureElement::getInstance().EE_HANDLE_0xF4 & ~NFA_HANDLE_GROUP_EE); //UICC |
| } |
| else if(eventData->rcvd_evt.pipe == 0x16) //ESE |
| { |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_EVENT_RCVD_EVT; source ESE",fn); |
| evtSrc = SecureElement::getInstance().getGenericEseId(EE_HANDLE_0xF3 & ~NFA_HANDLE_GROUP_EE); //ESE |
| } |
| else if(eventData->rcvd_evt.pipe == CONNECTIVITY_PIPE_ID_UICC3) //UICC3 |
| { |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_EVENT_RCVD_EVT; source UICC3",fn); |
| evtSrc = SecureElement::getInstance().getGenericEseId(SecureElement::getInstance().EE_HANDLE_0xF9 & ~NFA_HANDLE_GROUP_EE); //UICC |
| } |
| else if (((eventData->rcvd_evt.evt_code == NFA_HCI_EVT_ATR)) |
| &&(eventData->rcvd_evt.pipe == mStaticPipeProp)) |
| { |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_EVENT_RCVD_EVT: NFA_HCI_ABORT; status:0x%X, pipe:0x%X, len:%d", fn,\ |
| eventData->rcvd_evt.status, eventData->rcvd_evt.pipe, eventData->rcvd_evt.evt_len); |
| if(eventData->rcvd_evt.evt_len > 0) |
| { |
| sSecElem.mAbortEventWaitOk = true; |
| SyncEventGuard guard(sSecElem.mAbortEvent); |
| memcpy(sSecElem.mAtrInfo, eventData->rcvd_evt.p_evt_buf, eventData->rcvd_evt.evt_len); |
| sSecElem.mAtrInfolen = eventData->rcvd_evt.evt_len; |
| sSecElem.mAtrStatus = eventData->rcvd_evt.status; |
| sSecElem.mAbortEvent.notifyOne(); |
| } |
| else |
| { |
| sSecElem.mAbortEventWaitOk = false; |
| SyncEventGuard guard(sSecElem.mAbortEvent); |
| sSecElem.mAbortEvent.notifyOne(); |
| } |
| } |
| else if (eventData->rcvd_evt.evt_code == NFA_HCI_EVT_POST_DATA) |
| { |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_POST_DATA", fn); |
| SyncEventGuard guard (sSecElem.mTransceiveEvent); |
| sSecElem.mActualResponseSize = (eventData->rcvd_evt.evt_len > MAX_RESPONSE_SIZE) ? MAX_RESPONSE_SIZE : eventData->rcvd_evt.evt_len; |
| sSecElem.mTransceiveEvent.notifyOne (); |
| } |
| else if (eventData->rcvd_evt.evt_code == NFA_HCI_EVT_TRANSACTION) |
| { |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_TRANSACTION", fn); |
| // If we got an AID, notify any listeners |
| if ((eventData->rcvd_evt.evt_len > 3) && (eventData->rcvd_evt.p_evt_buf[0] == 0x81) ) |
| { |
| int aidlen = eventData->rcvd_evt.p_evt_buf[1]; |
| uint8_t* data = NULL; |
| int32_t datalen = 0; |
| uint8_t dataStartPosition = 0; |
| if((eventData->rcvd_evt.evt_len > 2+aidlen) && (eventData->rcvd_evt.p_evt_buf[2+aidlen] == 0x82)) |
| { |
| //BERTLV decoding here, to support extended data length for params. |
| datalen = SecureElement::decodeBerTlvLength((uint8_t *)eventData->rcvd_evt.p_evt_buf, 2+aidlen+1, eventData->rcvd_evt.evt_len); |
| } |
| if(datalen >= 0) |
| { |
| /* Over 128 bytes data of transaction can not receive on PN547, Ref. BER-TLV length fields in ISO/IEC 7816 */ |
| if ( datalen < 0x80) |
| { |
| dataStartPosition = 2+aidlen+2; |
| } |
| else if ( datalen < 0x100) |
| { |
| dataStartPosition = 2+aidlen+3; |
| } |
| else if ( datalen < 0x10000) |
| { |
| dataStartPosition = 2+aidlen+4; |
| } |
| else if ( datalen < 0x1000000) |
| { |
| dataStartPosition = 2+aidlen+5; |
| } |
| data = &eventData->rcvd_evt.p_evt_buf[dataStartPosition]; |
| |
| if (nfcFL.nfcNxpEse && nfcFL.eseFL._ESE_ETSI_READER_ENABLE) |
| { |
| if(MposManager::getInstance().validateHCITransactionEventParams(data, datalen) == NFA_STATUS_OK) |
| sSecElem.notifyTransactionListenersOfAid(&eventData->rcvd_evt.p_evt_buf[2], |
| aidlen, data, datalen, evtSrc); |
| } |
| else |
| sSecElem.notifyTransactionListenersOfAid(&eventData->rcvd_evt.p_evt_buf[2], |
| aidlen, data, datalen, evtSrc); |
| } |
| else |
| { |
| LOG(ERROR) << StringPrintf("Event data TLV length encoding Unsupported!"); |
| } |
| } |
| } |
| else if (eventData->rcvd_evt.evt_code == NFA_HCI_EVT_CONNECTIVITY) |
| { |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_CONNECTIVITY", fn); |
| } |
| else |
| { |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_EVENT_RCVD_EVT; ################################### eventData->rcvd_evt.evt_code = 0x%x , NFA_HCI_EVT_CONNECTIVITY = 0x%x", fn, eventData->rcvd_evt.evt_code, NFA_HCI_EVT_CONNECTIVITY); |
| |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_EVENT_RCVD_EVT; ################################### ", fn); |
| |
| } |
| break; |
| |
| case NFA_HCI_SET_REG_RSP_EVT: //received response to write registry command |
| { |
| tNFA_HCI_REGISTRY& registry = eventData->registry; |
| LOG(INFO) << StringPrintf("%s: NFA_HCI_SET_REG_RSP_EVT; status=0x%X; pipe=0x%X", fn, registry.status, registry.pipe); |
| SyncEventGuard guard (sSecElem.mRegistryEvent); |
| sSecElem.mRegistryEvent.notifyOne (); |
| break; |
| } |
| default: |
| LOG(ERROR) << StringPrintf("%s: unknown event code=0x%X ????", fn, event); |
| break; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: transceive |
| ** |
| ** Description: Send data to the secure element; read it's response. |
| ** xmitBuffer: Data to transmit. |
| ** xmitBufferSize: Length of data. |
| ** recvBuffer: Buffer to receive response. |
| ** recvBufferMaxSize: Maximum size of buffer. |
| ** recvBufferActualSize: Actual length of response. |
| ** timeoutMillisec: timeout in millisecond. |
| ** |
| ** Returns: True if ok. |
| ** |
| *******************************************************************************/ |
| bool SecureElement::transceive (uint8_t* xmitBuffer, int32_t xmitBufferSize, uint8_t* recvBuffer, |
| int32_t recvBufferMaxSize, int32_t& recvBufferActualSize, int32_t timeoutMillisec) |
| { |
| |
| |
| static const char fn [] = "SecureElement::transceive"; |
| tNFA_STATUS nfaStat = NFA_STATUS_FAILED; |
| bool isSuccess = false; |
| mTransceiveWaitOk = false; |
| uint8_t newSelectCmd[NCI_MAX_AID_LEN + 10]; |
| isSuccess = false; |
| |
| |
| // Check if we need to replace an "empty" SELECT command. |
| // 1. Has there been a AID configured, and |
| // 2. Is that AID a valid length (i.e 16 bytes max), and |
| // 3. Is the APDU at least 4 bytes (for header), and |
| // 4. Is INS == 0xA4 (SELECT command), and |
| // 5. Is P1 == 0x04 (SELECT by AID), and |
| // 6. Is the APDU len 4 or 5 bytes. |
| // |
| // Note, the length of the configured AID is in the first |
| // byte, and AID starts from the 2nd byte. |
| if (mAidForEmptySelect[0] // 1 |
| && (mAidForEmptySelect[0] <= NCI_MAX_AID_LEN) // 2 |
| && (xmitBufferSize >= 4) // 3 |
| && (xmitBuffer[1] == 0xA4) // 4 |
| && (xmitBuffer[2] == 0x04) // 5 |
| && (xmitBufferSize <= 5)) // 6 |
| { |
| uint8_t idx = 0; |
| |
| // Copy APDU command header from the input buffer. |
| memcpy(&newSelectCmd[0], &xmitBuffer[0], 4); |
| idx = 4; |
| |
| // Set the Lc value to length of the new AID |
| newSelectCmd[idx++] = mAidForEmptySelect[0]; |
| |
| // Copy the AID |
| memcpy(&newSelectCmd[idx], &mAidForEmptySelect[1], mAidForEmptySelect[0]); |
| idx += mAidForEmptySelect[0]; |
| |
| // If there is an Le (5th byte of APDU), add it to the end. |
| if (xmitBufferSize == 5) |
| newSelectCmd[idx++] = xmitBuffer[4]; |
| |
| // Point to the new APDU |
| xmitBuffer = &newSelectCmd[0]; |
| xmitBufferSize = idx; |
| |
| LOG(INFO) << StringPrintf("%s: Empty AID SELECT cmd detected, substituting AID from config file, new length=%d", fn, idx); |
| } |
| |
| { |
| SyncEventGuard guard (mTransceiveEvent); |
| mActualResponseSize = 0; |
| memset (mResponseData, 0, sizeof(mResponseData)); |
| nfaStat = NFA_HciSendApdu (mNfaHciHandle, mActiveEeHandle, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData, timeoutMillisec); |
| |
| if (nfaStat == NFA_STATUS_OK) |
| { |
| mTransceiveEvent.wait (); |
| } |
| else |
| { |
| LOG(ERROR) << StringPrintf("%s: fail send data; error=0x%X", fn, nfaStat); |
| goto TheEnd; |
| } |
| } |
| if (mActualResponseSize > recvBufferMaxSize) |
| recvBufferActualSize = recvBufferMaxSize; |
| else |
| recvBufferActualSize = mActualResponseSize; |
| |
| memcpy (recvBuffer, mResponseData, recvBufferActualSize); |
| isSuccess = true; |
| TheEnd: |
| return (isSuccess); |
| } |
| /******************************************************************************* |
| ** |
| ** Function: getActiveSecureElementList |
| ** |
| ** Description: Get the list of Activated Secure elements. |
| ** e: Java Virtual Machine. |
| ** |
| ** Returns: List of Activated Secure elements. |
| ** |
| *******************************************************************************/ |
| jintArray SecureElement::getActiveSecureElementList (JNIEnv* e) |
| { |
| uint8_t num_of_nfcee_present = 0; |
| tNFA_HANDLE nfcee_handle[MAX_NFCEE]; |
| tNFA_EE_STATUS nfcee_status[MAX_NFCEE]; |
| jint seId = 0; |
| int cnt = 0; |
| int i; |
| |
| if (! getEeInfo()) |
| return (NULL); |
| |
| num_of_nfcee_present = mNfceeData_t.mNfceePresent; |
| |
| jintArray list = e->NewIntArray (num_of_nfcee_present); //allocate array |
| |
| for(i = 1; i<= num_of_nfcee_present ; i++) |
| { |
| nfcee_handle[i] = mNfceeData_t.mNfceeHandle[i]; |
| nfcee_status[i] = mNfceeData_t.mNfceeStatus[i]; |
| |
| if(nfcee_handle[i] == EE_HANDLE_0xF3 && nfcee_status[i] == NFC_NFCEE_STATUS_ACTIVE) |
| { |
| seId = getGenericEseId(EE_HANDLE_0xF3 & ~NFA_HANDLE_GROUP_EE); |
| } |
| |
| if(nfcee_handle[i] == EE_HANDLE_0xF4 && nfcee_status[i] == NFC_NFCEE_STATUS_ACTIVE) |
| { |
| seId = getGenericEseId(EE_HANDLE_0xF4 & ~NFA_HANDLE_GROUP_EE); |
| } |
| |
| if(nfcee_handle[i] == EE_HANDLE_0xF8 && nfcee_status[i] == NFC_NFCEE_STATUS_ACTIVE) |
| { |
| seId = getGenericEseId(EE_HANDLE_0xF8 & ~NFA_HANDLE_GROUP_EE); |
| } |
| |
| e->SetIntArrayRegion (list, cnt++, 1, &seId); |
| } |
| |
| return list; |
| } |
| /******************************************************************************* |
| ** |
| ** Function: activate |
| ** |
| ** Description: Turn on the secure element. |
| ** seID: ID of secure element; 0xF3 or 0xF4. |
| ** |
| ** Returns: True if ok. |
| ** |
| *******************************************************************************/ |
| bool SecureElement::activate (jint seID) |
| { |
| static const char fn [] = "SecureElement::activate"; |
| tNFA_STATUS nfaStat = NFA_STATUS_FAILED; |
| int numActivatedEe = 0; |
| |
| tNFA_HANDLE handle = getEseHandleFromGenericId(seID); |
| |
| LOG(INFO) << StringPrintf("%s: enter handle=0x%X, seID=0x%X", fn, handle,seID); |
| |
| // Get Fresh EE info if needed. |
| if (! getEeInfo()) |
| { |
| LOG(ERROR) << StringPrintf("%s: no EE info", fn); |
| return false; |
| } |
| if(SecureElement::getInstance().getGateAndPipeList() != SMX_PIPE_ID) |
| return false; |
| |
| //activate every discovered secure element |
| for (int index=0; index < mActualNumEe; index++) |
| { |
| tNFA_EE_INFO& eeItem = mEeInfo[index]; |
| |
| if (eeItem.ee_handle == EE_HANDLE_0xF3) |
| { |
| if (eeItem.ee_status != NFC_NFCEE_STATUS_INACTIVE) |
| { |
| LOG(INFO) << StringPrintf("%s: h=0x%X already activated", fn, eeItem.ee_handle); |
| numActivatedEe++; |
| continue; |
| } |
| |
| { |
| LOG(INFO) << StringPrintf("%s: set EE mode activate; h=0x%X", fn, eeItem.ee_handle); |
| if ((nfaStat = SecElem_EeModeSet (eeItem.ee_handle, NFA_EE_MD_ACTIVATE)) == NFA_STATUS_OK) |
| { |
| if (eeItem.ee_status == NFC_NFCEE_STATUS_ACTIVE) |
| numActivatedEe++; |
| if(eeItem.ee_handle == EE_HANDLE_0xF3) |
| { |
| SyncEventGuard guard (SecureElement::getInstance().mModeSetNtf); |
| if(SecureElement::getInstance().mModeSetNtf.wait(500) == false) |
| { |
| LOG(ERROR) << StringPrintf("%s: timeout waiting for setModeNtf", __func__); |
| } |
| } |
| } |
| else |
| LOG(ERROR) << StringPrintf("%s: NFA_EeModeSet failed; error=0x%X", fn, nfaStat); |
| } |
| } |
| } //for |
| |
| mActiveEeHandle = getActiveEeHandle(handle); |
| |
| if (mActiveEeHandle == NFA_HANDLE_INVALID) |
| LOG(ERROR) << StringPrintf("%s: ee handle not found", fn); |
| |
| LOG(INFO) << StringPrintf("%s: exit; active ee h=0x%X", fn, mActiveEeHandle); |
| return mActiveEeHandle != NFA_HANDLE_INVALID; |
| } |
| /******************************************************************************* |
| ** |
| ** Function: deactivate |
| ** |
| ** Description: Turn off the secure element. |
| ** seID: ID of secure element; 0xF3 or 0xF4. |
| ** |
| ** Returns: True if ok. |
| ** |
| *******************************************************************************/ |
| bool SecureElement::deactivate (jint seID) |
| { |
| static const char fn [] = "SecureElement::deactivate"; |
| tNFA_STATUS nfaStat = NFA_STATUS_FAILED; |
| bool retval = false; |
| |
| LOG(INFO) << StringPrintf("%s: enter; seID=0x%X, mActiveEeHandle=0x%X", fn, seID, mActiveEeHandle); |
| |
| tNFA_HANDLE handle = getEseHandleFromGenericId(seID); |
| |
| LOG(INFO) << StringPrintf("%s: handle=0x%X", fn, handle); |
| |
| if (!mIsInit) |
| { |
| LOG(ERROR) << StringPrintf("%s: not init", fn); |
| goto TheEnd; |
| } |
| |
| |
| if (seID == NFA_HANDLE_INVALID) |
| { |
| LOG(ERROR) << StringPrintf("%s: invalid EE handle", fn); |
| goto TheEnd; |
| } |
| |
| mActiveEeHandle = NFA_HANDLE_INVALID; |
| |
| //deactivate secure element |
| for (int index=0; index < mActualNumEe; index++) |
| { |
| tNFA_EE_INFO& eeItem = mEeInfo[index]; |
| |
| if (eeItem.ee_handle == handle && |
| ((eeItem.ee_handle == EE_HANDLE_0xF3) || (eeItem.ee_handle == EE_HANDLE_0xF4) || |
| (eeItem.ee_handle == EE_HANDLE_0xF8)|| |
| (eeItem.ee_handle == EE_HANDLE_0xF9))) { |
| if (eeItem.ee_status == NFC_NFCEE_STATUS_INACTIVE) |
| { |
| LOG(INFO) << StringPrintf("%s: h=0x%X already deactivated", fn, eeItem.ee_handle); |
| break; |
| } |
| |
| { |
| LOG(INFO) << StringPrintf("%s: set EE mode activate; h=0x%X", fn, eeItem.ee_handle); |
| if ((nfaStat = SecElem_EeModeSet (eeItem.ee_handle, NFA_EE_MD_DEACTIVATE)) == NFA_STATUS_OK) |
| { |
| LOG(INFO) << StringPrintf("%s: eeItem.ee_status =0x%X NFC_NFCEE_STATUS_INACTIVE = %x", fn, eeItem.ee_status, NFC_NFCEE_STATUS_INACTIVE); |
| if (eeItem.ee_status == NFC_NFCEE_STATUS_INACTIVE) |
| { |
| LOG(ERROR) << StringPrintf("%s: NFA_EeModeSet success; status=0x%X", fn, nfaStat); |
| retval = true; |
| } |
| } |
| else |
| LOG(ERROR) << StringPrintf("%s: NFA_EeModeSet failed; error=0x%X", fn, nfaStat); |
| } |
| } |
| } //for |
| |
| TheEnd: |
| LOG(INFO) << StringPrintf("%s: exit; ok=%u", fn, retval); |
| return retval; |
| } |
| /******************************************************************************* |
| ** |
| ** Function: SecElem_EeModeSet |
| ** |
| ** Description: Perform SE mode set ON/OFF based on mode type |
| ** |
| ** Returns: NFA_STATUS_OK/NFA_STATUS_FAILED. |
| ** |
| *******************************************************************************/ |
| tNFA_STATUS SecureElement::SecElem_EeModeSet(uint16_t handle, uint8_t mode) |
| { |
| tNFA_STATUS stat = NFA_STATUS_FAILED; |
| LOG(INFO) << StringPrintf("%s:Enter mode = %d", __func__, mode); |
| |
| SyncEventGuard guard (sSecElem.mEeSetModeEvent); |
| stat = NFA_EeModeSet(handle, mode); |
| if(stat == NFA_STATUS_OK) |
| { |
| sSecElem.mEeSetModeEvent.wait (); |
| } |
| |
| return stat; |
| } |
| /******************************************************************************* |
| ** |
| ** Function: getSETechnology |
| ** |
| ** Description: return the technologies suported by se. |
| ** eeHandle: Handle to execution environment. |
| ** |
| ** Returns: Information about an execution environment. |
| ** |
| *******************************************************************************/ |
| jint SecureElement::getSETechnology(tNFA_HANDLE eeHandle) |
| { |
| int tech_mask = 0x00; |
| //static const char fn [] = "SecureElement::getSETechnology"; |
| // Get Fresh EE info. |
| if (! getEeInfo()) |
| { |
| //ALOGE("%s: No updated eeInfo available", fn); |
| } |
| |
| tNFA_EE_INFO* eeinfo = findEeByHandle(eeHandle); |
| |
| if(eeinfo!=NULL){ |
| if(eeinfo->la_protocol != 0x00) |
| { |
| tech_mask |= 0x01; |
| } |
| |
| if(eeinfo->lb_protocol != 0x00) |
| { |
| tech_mask |= 0x02; |
| } |
| |
| if(eeinfo->lf_protocol != 0x00) |
| { |
| tech_mask |= 0x04; |
| } |
| } |
| |
| return tech_mask; |
| } |
| /******************************************************************************* |
| ** |
| ** Function: notifyModeSet |
| ** |
| ** Description: Perform SE mode set ON/OFF based on mode type |
| ** |
| ** Returns: NFA_STATUS_OK/NFA_STATUS_FAILED. |
| ** |
| *******************************************************************************/ |
| void SecureElement::notifyModeSet (tNFA_HANDLE eeHandle, bool success, tNFA_EE_STATUS eeStatus) |
| { |
| static const char* fn = "SecureElement::notifyModeSet"; |
| if (success) |
| { |
| tNFA_EE_INFO *pEE = sSecElem.findEeByHandle (eeHandle); |
| if (pEE) |
| { |
| pEE->ee_status = eeStatus; |
| LOG(INFO) << StringPrintf("%s: NFA_EE_MODE_SET_EVT; (0x%04x)", fn, pEE->ee_status); |
| } |
| else |
| LOG(INFO) << StringPrintf("%s: NFA_EE_MODE_SET_EVT; EE: 0x%04x not found. mActiveEeHandle: 0x%04x", fn, eeHandle, sSecElem.mActiveEeHandle); |
| } |
| SyncEventGuard guard (sSecElem.mEeSetModeEvent); |
| sSecElem.mEeSetModeEvent.notifyOne(); |
| } |
| /******************************************************************************* |
| ** |
| ** Function: getAtr |
| ** |
| ** Description: GetAtr response from the connected eSE |
| ** |
| ** Returns: Returns True if success |
| ** |
| *******************************************************************************/ |
| bool SecureElement::getAtr(jint seID, uint8_t* recvBuffer, int32_t *recvBufferSize) |
| { |
| static const char fn[] = "SecureElement::getAtr"; |
| tNFA_STATUS nfaStat = NFA_STATUS_FAILED; |
| int timeoutMillisec = 10000; |
| |
| LOG(INFO) << StringPrintf("%s: enter; seID=0x%X", fn, seID); |
| if(nfcFL.nfcNxpEse) { |
| /*ETSI 12 Gate Info ATR */ |
| mAbortEventWaitOk = false; |
| uint8_t mAtrInfo1[EVT_ABORT_MAX_RSP_LEN]={0}; |
| uint8_t atr_len = EVT_ABORT_MAX_RSP_LEN; |
| SyncEventGuard guard (mAbortEvent); |
| nfaStat = NFA_HciSendEvent(mNfaHciHandle, mNewPipeId, EVT_ABORT, 0, NULL, atr_len, mAtrInfo1, timeoutMillisec); |
| { |
| mAbortEvent.wait(); |
| } |
| if(mAbortEventWaitOk == false) |
| { |
| LOG(INFO) << StringPrintf("%s (EVT_ABORT)Wait reposne timeout", fn); |
| nfaStat = NFA_STATUS_FAILED; |
| } |
| else |
| { |
| *recvBufferSize = mAtrInfolen; |
| memcpy(recvBuffer, mAtrInfo, mAtrInfolen); |
| } |
| } |
| |
| return (nfaStat == NFA_STATUS_OK)?true:false; |
| } |
| /******************************************************************************* |
| ** |
| ** Function: SecEle_Modeset |
| ** |
| ** Description: reSet NFCEE. |
| ** |
| ** Returns: True if ok. |
| ** |
| *******************************************************************************/ |
| bool SecureElement::SecEle_Modeset(uint8_t type) |
| { |
| tNFA_STATUS nfaStat = NFA_STATUS_FAILED; |
| bool retval = true; |
| |
| LOG(INFO) << StringPrintf("set EE mode = 0x%X", type); |
| nfaStat = SecElem_EeModeSet (EE_HANDLE_0xF3, type); |
| if ( nfaStat == NFA_STATUS_OK) |
| { |
| LOG(INFO) << StringPrintf("SecEle_Modeset: Success"); |
| } |
| else |
| { |
| retval = false; |
| } |
| return retval; |
| } |
| /******************************************************************************* |
| ** |
| ** Function: initializeEeHandle |
| ** |
| ** Description: Set NFCEE handle. |
| ** |
| ** Returns: True if ok. |
| ** |
| *******************************************************************************/ |
| bool SecureElement::initializeEeHandle () |
| { |
| if(NFA_GetNCIVersion() == NCI_VERSION_2_0) |
| EE_HANDLE_0xF4 = 0x480; |
| else |
| EE_HANDLE_0xF4 = 0x402; |
| return true; |
| } |
| /******************************************************************************* |
| ** |
| ** Function: getEeInfo |
| ** |
| ** Description: Get latest information about execution environments from stack. |
| ** |
| ** Returns: True if at least 1 EE is available. |
| ** |
| *******************************************************************************/ |
| bool SecureElement::getEeInfo() |
| { |
| static const char fn [] = "SecureElement::getEeInfo"; |
| LOG(INFO) << StringPrintf("%s: enter; mbNewEE=%d, mActualNumEe=%d", fn, mbNewEE, mActualNumEe); |
| tNFA_STATUS nfaStat = NFA_STATUS_FAILED; |
| |
| /*Reading latest eEinfo incase it is updated*/ |
| mbNewEE = true; |
| mNumEePresent = 0; |
| |
| if (mbNewEE) |
| { |
| |
| memset (&mNfceeData_t, 0, sizeof (mNfceeData_t)); |
| |
| mActualNumEe = nfcFL.nfccFL._NFA_EE_MAX_EE_SUPPORTED; |
| if ((nfaStat = NFA_EeGetInfo(&mActualNumEe, mEeInfo)) != NFA_STATUS_OK) |
| { |
| LOG(ERROR) << StringPrintf("%s: fail get info; error=0x%X", fn, nfaStat); |
| mActualNumEe = 0; |
| } |
| else |
| { |
| mbNewEE = false; |
| |
| LOG(ERROR) << StringPrintf("%s: num EEs discovered: %u", fn, mActualNumEe); |
| if (mActualNumEe != 0) |
| { |
| for (uint8_t xx = 0; xx < mActualNumEe; xx++) |
| { |
| if (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) |
| mNumEePresent++; |
| |
| mNfceeData_t.mNfceeHandle[xx] = mEeInfo[xx].ee_handle; |
| mNfceeData_t.mNfceeStatus[xx] = mEeInfo[xx].ee_status; |
| } |
| } |
| } |
| } |
| LOG(INFO) << StringPrintf("%s: exit; mActualNumEe=%d, mNumEePresent=%d", fn, mActualNumEe,mNumEePresent); |
| |
| mNfceeData_t.mNfceePresent = mNumEePresent; |
| |
| return (mActualNumEe != 0); |
| } |
| /******************************************************************************* |
| ** |
| ** Function: findEeByHandle |
| ** |
| ** Description: Find information about an execution environment. |
| ** eeHandle: Handle to execution environment. |
| ** |
| ** Returns: Information about an execution environment. |
| ** |
| *******************************************************************************/ |
| tNFA_EE_INFO *SecureElement::findEeByHandle (tNFA_HANDLE eeHandle) |
| { |
| for (uint8_t xx = 0; xx < mActualNumEe; xx++) |
| { |
| if (mEeInfo[xx].ee_handle == eeHandle) |
| return (&mEeInfo[xx]); |
| } |
| return (NULL); |
| } |
| /******************************************************************************* |
| ** |
| ** Function: getEseHandleFromGenericId |
| ** |
| ** Description: Whether controller is routing listen-mode events to |
| ** secure elements or a pipe is connected. |
| ** |
| ** Returns: Returns Secure element Handle ex:- 402, 4C0, 481 |
| ** |
| *******************************************************************************/ |
| tNFA_HANDLE SecureElement::getEseHandleFromGenericId(jint eseId) |
| { |
| uint16_t handle = NFA_HANDLE_INVALID; |
| static const char fn [] = "SecureElement::getEseHandleFromGenericId"; |
| LOG(INFO) << StringPrintf("%s: enter; ESE-ID = 0x%02X", fn, eseId); |
| |
| //Map the generic id to actual handle |
| if(eseId == ESE_ID || eseId == EE_APP_HANLDE_ESE) //ESE |
| { |
| handle = EE_HANDLE_0xF3; //0x4C0; |
| } |
| else if(eseId == UICC_ID || eseId == EE_APP_HANLDE_UICC) //UICC |
| { |
| handle = SecureElement::getInstance().EE_HANDLE_0xF4; //0x402; |
| } |
| else if(eseId == UICC2_ID || eseId == EE_APP_HANLDE_UICC2) //UICC |
| { |
| handle = RoutingManager::getInstance().getUicc2selected(); //0x402; |
| } |
| else if(eseId == UICC3_ID || eseId == EE_APP_HANLDE_UICC3) //UICC |
| { |
| handle = SecureElement::getInstance().EE_HANDLE_0xF9; //0x482; |
| } |
| else if(eseId == DH_ID) //Host |
| { |
| handle = SecureElement::getInstance().EE_HANDLE_0xF0; //0x400; |
| } |
| else if(eseId == EE_HANDLE_0xF3 || eseId == EE_HANDLE_0xF4 || eseId == EE_HANDLE_0xF9) |
| { |
| handle = eseId; |
| } |
| LOG(INFO) << StringPrintf("%s: enter; ESE-Handle = 0x%03X", fn, handle); |
| return handle; |
| } |
| /******************************************************************************* |
| ** |
| ** Function: getActiveEeHandle |
| ** |
| ** Description: Get the handle to the execution environment. |
| ** |
| ** Returns: Handle to the execution environment. |
| ** |
| *******************************************************************************/ |
| tNFA_HANDLE SecureElement::getActiveEeHandle (tNFA_HANDLE handle) |
| { |
| static const char fn [] = "SecureElement::getActiveEeHandle"; |
| LOG(INFO) << StringPrintf("%s: - Enter", fn); |
| |
| for (uint8_t xx = 0; xx < mActualNumEe; xx++) |
| { |
| if (mEeInfo[xx].ee_handle == EE_HANDLE_0xF3) |
| { |
| return (mEeInfo[xx].ee_handle); |
| } |
| |
| } |
| return NFA_HANDLE_INVALID; |
| } |
| /******************************************************************************* |
| ** |
| ** Function setNfccPwrConfig |
| ** |
| ** Description sends the link cntrl command to eSE with the value passed |
| ** |
| ** Returns status |
| ** |
| *******************************************************************************/ |
| tNFA_STATUS SecureElement::setNfccPwrConfig(uint8_t value) |
| { |
| static const char fn [] = "SecureElement::setNfccPwrConfig()"; |
| tNFA_STATUS nfaStat = NFA_STATUS_FAILED; |
| static uint8_t cur_value = 0xFF; |
| LOG(INFO) << StringPrintf("%s: Enter: config= 0x%X", fn, value); |
| cur_value = value; |
| SyncEventGuard guard (mPwrLinkCtrlEvent); |
| nfaStat = NFA_SendPowerLinkCommand((uint8_t)EE_HANDLE_0xF3, value); |
| if(nfaStat == NFA_STATUS_OK) |
| mPwrLinkCtrlEvent.wait(NFC_CMD_TIMEOUT); |
| LOG(INFO) << StringPrintf("%s: Exit: Status= 0x%X", fn, mPwrCmdstatus); |
| return mPwrCmdstatus; |
| } |
| bool SecureElement::sendEvent(uint8_t event) |
| { |
| tNFA_STATUS nfaStat = NFA_STATUS_FAILED; |
| bool retval = true; |
| nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, event, 0x00, NULL, 0x00,NULL, 0); |
| |
| if(nfaStat != NFA_STATUS_OK) |
| retval = false; |
| |
| return retval; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: getEeHandleList |
| ** |
| ** Description: Get default Secure Element handle. |
| ** isHCEEnabled: whether host routing is enabled or not. |
| ** |
| ** Returns: Returns Secure Element list and count. |
| ** |
| *******************************************************************************/ |
| void SecureElement::getEeHandleList(tNFA_HANDLE *list, uint8_t* count) |
| { |
| tNFA_HANDLE handle; |
| int i; |
| static const char fn [] = "SecureElement::getEeHandleList"; |
| *count = 0; |
| for ( i = 0; i < mActualNumEe; i++) |
| { |
| LOG(INFO) << StringPrintf("%s: %d = 0x%X", fn, i, mEeInfo[i].ee_handle); |
| if ((mEeInfo[i].ee_handle == 0x401) || (mEeInfo[i].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) || |
| (mEeInfo[i].ee_status == NFC_NFCEE_STATUS_INACTIVE)) |
| { |
| LOG(INFO) << StringPrintf("%s: %u = 0x%X", fn, i, mEeInfo[i].ee_handle); |
| continue; |
| } |
| |
| handle = mEeInfo[i].ee_handle & ~NFA_HANDLE_GROUP_EE; |
| list[*count] = handle; |
| *count = *count + 1 ; |
| LOG(INFO) << StringPrintf("%s: Handle %d = 0x%X", fn, i, handle); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: getGateAndPipeList |
| ** |
| ** Description: Get the gate and pipe list. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| uint8_t SecureElement::getGateAndPipeList() |
| { |
| tNFA_STATUS nfaStat = NFA_STATUS_FAILED; |
| static const char fn [] = "SecureElement::getActiveEeHandle"; |
| //uint8_t destHost = (EE_HANDLE_0xF3 & ~NFA_HANDLE_GROUP_EE); |
| |
| // Get a list of existing gates and pipes |
| LOG(INFO) << StringPrintf("%s: get gate, pipe list", fn); |
| SyncEventGuard guard (mPipeListEvent); |
| nfaStat = NFA_HciGetGateAndPipeList (mNfaHciHandle); |
| if (nfaStat == NFA_STATUS_OK) |
| { |
| mPipeListEvent.wait(); |
| if (mHciCfg.status == NFA_STATUS_OK) |
| { |
| mNewPipeId = 0x19; |
| /*WA: Not updated the pipe id from libnfc-nci |
| for (uint8_t xx = 0; xx < mHciCfg.num_pipes; xx++) |
| { |
| if ( (mHciCfg.pipe[xx].dest_host == destHost)) |
| { |
| mNewSourceGate = mHciCfg.pipe[xx].local_gate; |
| mNewPipeId = mHciCfg.pipe[xx].pipe_id; |
| |
| LOG(INFO) << StringPrintf("%s: found configured gate: 0x%02x pipe: 0x%02x", fn, mNewSourceGate, mNewPipeId); |
| break; |
| } |
| } |
| */ |
| } |
| } |
| return mNewPipeId; |
| } |
| /******************************************************************************* |
| ** |
| ** Function getLastRfFiledToggleTime |
| ** |
| ** Description Provides the last RF filed toggile timer |
| ** |
| ** Returns timespec |
| ** |
| *******************************************************************************/ |
| struct timespec SecureElement::getLastRfFiledToggleTime(void) |
| { |
| return mLastRfFieldToggle; |
| } |
| /******************************************************************************* |
| ** |
| ** Function: finalize |
| ** |
| ** Description: Release all resources. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void SecureElement::finalize() { |
| mIsInit = false; |
| mNativeData = NULL; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: releasePendingTransceive |
| ** |
| ** Description: release any pending transceive wait. |
| ** |
| ** Returns: None. |
| ** |
| *******************************************************************************/ |
| void SecureElement::releasePendingTransceive() |
| { |
| static const char fn [] = "SecureElement::releasePendingTransceive"; |
| LOG(INFO) << StringPrintf("%s: Entered", fn); |
| if(mIsWiredModeOpen) |
| { |
| SyncEventGuard guard (mTransceiveEvent); |
| mTransceiveEvent.notifyOne(); |
| } |
| LOG(INFO) << StringPrintf("%s: Exit", fn); |
| } |