blob: ed6e05a51e451b6639222afb3a50d4596da40db7 [file] [log] [blame]
/******************************************************************************
*
* Copyright (c) 2016, The Linux Foundation. All rights reserved.
* Not a Contribution.
*
* Copyright (C) 2015 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.
*
******************************************************************************/
/*
* Communicate with secure elements that are attached to the NFC
* controller.
*/
#include <semaphore.h>
#include <errno.h>
#include <ScopedLocalRef.h>
#include "OverrideLog.h"
#include "SecureElement.h"
#include "config.h"
#include "PowerSwitch.h"
#include "JavaClassConstants.h"
#include "nfc_api.h"
#include "phNxpConfig.h"
#include "PeerToPeer.h"
#if(NXP_EXTNS == TRUE)
#include "RoutingManager.h"
#if((NFC_NXP_ESE == TRUE)&&(NXP_EXTNS == TRUE))
#include <signal.h>
#include <sys/types.h>
#endif
#endif
/*****************************************************************************
**
** public variables
**
*****************************************************************************/
static int gSEId = -1; // secure element ID to use in connectEE(), -1 means not set
static int gGatePipe = -1; // gate id or static pipe id to use in connectEE(), -1 means not set
static bool gUseStaticPipe = false; // if true, use gGatePipe as static pipe id. if false, use as gate id
extern bool gTypeB_listen;
bool gReaderNotificationflag = false;
bool hold_the_transceive = false;
int dual_mode_current_state=0;
nfc_jni_native_data* mthreadnative;
extern Rdr_req_ntf_info_t swp_rdr_req_ntf_info ;
namespace android
{
extern void startRfDiscovery (bool isStart);
extern void setUiccIdleTimeout (bool enable);
extern bool isDiscoveryStarted();
extern int getScreenState();
#if((NFC_NXP_ESE == TRUE) && (NFC_NXP_CHIP_TYPE == PN548C2))
extern bool isp2pActivated();
#endif
extern SyncEvent sNfaSetConfigEvent;
extern tNFA_STATUS EmvCo_dosetPoll(jboolean enable);
extern tNFA_STATUS ResetEseSession();
extern void config_swp_reader_mode(bool mode);
extern void set_transcation_stat(bool result);
}
#if((NFC_NXP_ESE == TRUE)&&(NXP_EXTNS == TRUE))
/* hold the transceive flag should be set when the prio session is actrive/about to active*/
/* Event used to inform the prio session end and transceive resume*/
SyncEvent sSPIPrioSessionEndEvent;
static UINT32 nfccStandbytimeout; // timeout for secelem standby mode detection
static void NFCC_StandbyModeTimerCallBack (union sigval);
int active_ese_reset_control = 0;
#endif
SyncEvent mDualModeEvent;
static void setSPIState(bool mState);
//////////////////////////////////////////////
//////////////////////////////////////////////
#if(NXP_EXTNS == TRUE)
#define NFC_NUM_INTERFACE_MAP 3
#define NFC_SWP_RD_NUM_INTERFACE_MAP 1
static const tNCI_DISCOVER_MAPS nfc_interface_mapping_default[NFC_NUM_INTERFACE_MAP] =
{
/* Protocols that use Frame Interface do not need to be included in the interface mapping */
{
NCI_PROTOCOL_ISO_DEP,
NCI_INTERFACE_MODE_POLL_N_LISTEN,
NCI_INTERFACE_ISO_DEP
}
,
{
NCI_PROTOCOL_NFC_DEP,
NCI_INTERFACE_MODE_POLL_N_LISTEN,
NCI_INTERFACE_NFC_DEP
}
,
{
NCI_PROTOCOL_MIFARE,
NCI_INTERFACE_MODE_POLL,
NCI_INTERFACE_MIFARE
}
};
static const tNCI_DISCOVER_MAPS nfc_interface_mapping_uicc[NFC_SWP_RD_NUM_INTERFACE_MAP] =
{
/* Protocols that use Frame Interface do not need to be included in the interface mapping */
{
NCI_PROTOCOL_ISO_DEP,
NCI_INTERFACE_MODE_POLL,
NCI_INTERFACE_UICC_DIRECT
}
};
static const tNCI_DISCOVER_MAPS nfc_interface_mapping_ese[NFC_SWP_RD_NUM_INTERFACE_MAP] =
{
/* Protocols that use Frame Interface do not need to be included in the interface mapping */
{
NCI_PROTOCOL_ISO_DEP,
NCI_INTERFACE_MODE_POLL,
NCI_INTERFACE_ESE_DIRECT
}
};
/*******************************************************************************
**
** Function: startStopSwpReaderProc
**
** Description: handle timeout
**
** Returns: None
**
*******************************************************************************/
static void startStopSwpReaderProc (union sigval)
{
ALOGD ("%s: Timeout!!!", __FUNCTION__);
JNIEnv* e = NULL;
int disc_ntf_timeout = 10;
ScopedAttach attach(RoutingManager::getInstance().mNativeData->vm, &e);
if (e == NULL)
{
ALOGE ("%s: jni env is null", __FUNCTION__);
return;
}
GetNumValue ( NAME_NFA_DM_DISC_NTF_TIMEOUT, &disc_ntf_timeout, sizeof ( disc_ntf_timeout ) );
e->CallVoidMethod (RoutingManager::getInstance().mNativeData->manager, android::gCachedNfcManagerNotifyETSIReaderModeSwpTimeout,disc_ntf_timeout);
}
void SecureElement::discovery_map_cb (tNFC_DISCOVER_EVT event, tNFC_DISCOVER *p_data)
{
(void)event;
(void)p_data;
SyncEventGuard guard (sSecElem.mDiscMapEvent);
// ALOGD ("discovery_map_cb; status=%u", eventData->ee_register);
sSecElem.mDiscMapEvent.notifyOne();
}
#endif
SecureElement SecureElement::sSecElem;
const char* SecureElement::APP_NAME = "nfc_jni";
const UINT16 ACTIVE_SE_USE_ANY = 0xFFFF;
/*******************************************************************************
**
** Function: SecureElement
**
** Description: Initialize member variables.
**
** Returns: None
**
*******************************************************************************/
SecureElement::SecureElement ()
: mActiveEeHandle (NFA_HANDLE_INVALID),
mDestinationGate (4), //loopback gate
mNfaHciHandle (NFA_HANDLE_INVALID),
mNativeData (NULL),
mIsInit (false),
mActualNumEe (0),
mNumEePresent(0),
mbNewEE (true), // by default we start w/thinking there are new EE
mNewPipeId (0),
mNewSourceGate (0),
mActiveSeOverride(ACTIVE_SE_USE_ANY),
mCommandStatus (NFA_STATUS_OK),
mIsPiping (false),
mCurrentRouteSelection (NoRoute),
mActualResponseSize(0),
mUseOberthurWarmReset (false),
mActivatedInListenMode (false),
mOberthurWarmResetCommand (3),
mGetAtrRspwait (false),
mAtrInfolen (0),
mRfFieldIsOn(false),
mTransceiveWaitOk(false),
mAllowWiredMode(false),
mRecvdTransEvt(false),
mWiredModeRfFiledEnable(0)
{
memset (&mEeInfo, 0, sizeof(mEeInfo));
memset (&mUiccInfo, 0, sizeof(mUiccInfo));
memset (&mHciCfg, 0, sizeof(mHciCfg));
memset (mResponseData, 0, sizeof(mResponseData));
memset (mAidForEmptySelect, 0, sizeof(mAidForEmptySelect));
memset (&mLastRfFieldToggle, 0, sizeof(mLastRfFieldToggle));
memset (mAtrInfo, 0, sizeof( mAtrInfo));
memset (&mNfceeData_t, 0, sizeof(mNfceeData_t));
}
/*******************************************************************************
**
** Function: ~SecureElement
**
** Description: Release all resources.
**
** Returns: None
**
*******************************************************************************/
SecureElement::~SecureElement ()
{
}
/*******************************************************************************
**
** Function: getInstance
**
** Description: Get the SecureElement singleton object.
**
** Returns: SecureElement object.
**
*******************************************************************************/
SecureElement& SecureElement::getInstance()
{
return sSecElem;
}
/*******************************************************************************
**
** Function: setActiveSeOverride
**
** Description: Specify which secure element to turn on.
** activeSeOverride: ID of secure element
**
** Returns: None
**
*******************************************************************************/
void SecureElement::setActiveSeOverride(UINT8 activeSeOverride)
{
ALOGD ("SecureElement::setActiveSeOverride, seid=0x%X", activeSeOverride);
mActiveSeOverride = activeSeOverride;
}
/*******************************************************************************
**
** 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;
unsigned long num = 0;
ALOGD ("%s: enter", fn);
if (GetNumValue("NFA_HCI_DEFAULT_DEST_GATE", &num, sizeof(num)))
mDestinationGate = num;
ALOGD ("%s: Default destination gate: 0x%X", fn, mDestinationGate);
// active SE, if not set active all SEs, use the first one.
if (GetNumValue("ACTIVE_SE", &num, sizeof(num)))
{
mActiveSeOverride = num;
ALOGD ("%s: Active SE override: 0x%X", fn, mActiveSeOverride);
}
#if (NFC_NXP_ESE == TRUE && NFC_NXP_CHIP_TYPE == PN548C2)
if (GetNxpNumValue (NAME_NXP_WIRED_MODE_RF_FIELD_ENABLE, (void*)&num, sizeof(num)))
{
ALOGD ("%s: NAME_NXP_WIRED_MODE_RF_FIELD_ENABLE =%d",fn, num);
mWiredModeRfFiledEnable = num;
}
#endif
#if((NFC_NXP_ESE == TRUE)&&(NXP_EXTNS == TRUE))
if (GetNxpNumValue(NAME_NXP_NFCC_STANDBY_TIMEOUT, &nfccStandbytimeout, sizeof(nfccStandbytimeout)) == false)
{
nfccStandbytimeout = 20000;
}
ALOGD ("%s: NFCC standby mode timeout =0x%x", fn, nfccStandbytimeout);
if(nfccStandbytimeout > 0 && nfccStandbytimeout < 5000 )
{
nfccStandbytimeout = 5000;
}
else if (nfccStandbytimeout > 20000)
{
nfccStandbytimeout = 20000;
}
dual_mode_current_state = SPI_DWPCL_NOT_ACTIVE;
hold_the_transceive = false;
active_ese_reset_control = 0;
#endif
/*
* Since NXP doesn't support OBERTHUR RESET COMMAND, Hence commented
if (GetNumValue("OBERTHUR_WARM_RESET_COMMAND", &num, sizeof(num)))
{
mUseOberthurWarmReset = true;
mOberthurWarmResetCommand = (UINT8) num;
}*/
mActiveEeHandle = NFA_HANDLE_INVALID;
mNfaHciHandle = NFA_HANDLE_INVALID;
mNativeData = native;
mthreadnative = native;
mActualNumEe = MAX_NUM_EE;
mbNewEE = true;
mNewPipeId = 0;
mNewSourceGate = 0;
mRfFieldIsOn = false;
mActivatedInListenMode = false;
mCurrentRouteSelection = NoRoute;
memset (mEeInfo, 0, sizeof(mEeInfo));
memset (&mUiccInfo, 0, sizeof(mUiccInfo));
memset (&mHciCfg, 0, sizeof(mHciCfg));
mUsedAids.clear ();
memset(mAidForEmptySelect, 0, sizeof(mAidForEmptySelect));
// if no SE is to be used, get out.
if (mActiveSeOverride == 0)
{
ALOGD ("%s: No SE; No need to initialize SecureElement", fn);
return (false);
}
// 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++)
{
#ifdef GEMALTO_SE_SUPPORT
if ( (mEeInfo[xx].num_interface > 0) && (mEeInfo[xx].ee_handle != EE_HANDLE_0xF4 ) )
#else
if ((mEeInfo[xx].num_interface > 0) && (mEeInfo[xx].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) )
#endif
{
ALOGD ("%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)
{
ALOGE ("%s: fail hci register; error=0x%X", fn, nfaStat);
return (false);
}
mHciRegisterEvent.wait();
break;
}
}
GetStrValue(NAME_AID_FOR_EMPTY_SELECT, (char*)&mAidForEmptySelect[0], sizeof(mAidForEmptySelect));
mIsInit = true;
ALOGD ("%s: exit", fn);
return (true);
}
/*******************************************************************************
**
** Function: finalize
**
** Description: Release all resources.
**
** Returns: None
**
*******************************************************************************/
void SecureElement::finalize ()
{
static const char fn [] = "SecureElement::finalize";
ALOGD ("%s: enter", fn);
/* if (mNfaHciHandle != NFA_HANDLE_INVALID)
NFA_HciDeregister (const_cast<char*>(APP_NAME));*/
#if((NFC_NXP_ESE == TRUE)&&(NXP_EXTNS == TRUE))
NfccStandByOperation(STANDBY_TIMER_STOP);
#endif
mNfaHciHandle = NFA_HANDLE_INVALID;
mNativeData = NULL;
mIsInit = false;
mActualNumEe = 0;
mNumEePresent = 0;
mNewPipeId = 0;
mNewSourceGate = 0;
mIsPiping = false;
memset (mEeInfo, 0, sizeof(mEeInfo));
memset (&mUiccInfo, 0, sizeof(mUiccInfo));
ALOGD ("%s: exit", fn);
}
/*******************************************************************************
**
** 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";
ALOGD ("%s: enter; mbNewEE=%d, mActualNumEe=%d", fn, mbNewEE, mActualNumEe);
tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
/*Reading latest eEinfo incase it is updated*/
#if(NXP_EXTNS == TRUE)
mbNewEE = true;
mNumEePresent = 0;
#endif
// If mbNewEE is true then there is new EE info.
if (mbNewEE)
{
#if(NXP_EXTNS == TRUE)
memset (&mNfceeData_t, 0, sizeof (mNfceeData_t));
#endif
mActualNumEe = MAX_NUM_EE;
if ((nfaStat = NFA_EeGetInfo (&mActualNumEe, mEeInfo)) != NFA_STATUS_OK)
{
ALOGE ("%s: fail get info; error=0x%X", fn, nfaStat);
mActualNumEe = 0;
}
else
{
mbNewEE = false;
ALOGD ("%s: num EEs discovered: %u", fn, mActualNumEe);
if (mActualNumEe != 0)
{
for (UINT8 xx = 0; xx < mActualNumEe; xx++)
{
if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) )
mNumEePresent++;
ALOGD ("%s: EE[%u] Handle: 0x%04x Status: %s Num I/f: %u: (0x%02x, 0x%02x) Num TLVs: %u, Tech : (LA:0x%02x, LB:0x%02x, "
"LF:0x%02x, LBP:0x%02x)", fn, xx, mEeInfo[xx].ee_handle, eeStatusToString(mEeInfo[xx].ee_status),
mEeInfo[xx].num_interface, mEeInfo[xx].ee_interface[0], mEeInfo[xx].ee_interface[1], mEeInfo[xx].num_tlvs,
mEeInfo[xx].la_protocol, mEeInfo[xx].lb_protocol, mEeInfo[xx].lf_protocol, mEeInfo[xx].lbp_protocol);
#if(NXP_EXTNS == TRUE)
mNfceeData_t.mNfceeHandle[xx] = mEeInfo[xx].ee_handle;
mNfceeData_t.mNfceeStatus[xx] = mEeInfo[xx].ee_status;
#endif
for (size_t yy = 0; yy < mEeInfo[xx].num_tlvs; yy++)
{
ALOGD ("%s: EE[%u] TLV[%u] Tag: 0x%02x Len: %u Values[]: 0x%02x 0x%02x 0x%02x ...",
fn, xx, yy, mEeInfo[xx].ee_tlv[yy].tag, mEeInfo[xx].ee_tlv[yy].len, mEeInfo[xx].ee_tlv[yy].info[0],
mEeInfo[xx].ee_tlv[yy].info[1], mEeInfo[xx].ee_tlv[yy].info[2]);
}
}
}
}
}
ALOGD ("%s: exit; mActualNumEe=%d, mNumEePresent=%d", fn, mActualNumEe,mNumEePresent);
#if(NXP_EXTNS == TRUE)
mNfceeData_t.mNfceePresent = mNumEePresent;
#endif
return (mActualNumEe != 0);
}
/*******************************************************************************
**
** Function TimeDiff
**
** Description Computes time difference in milliseconds.
**
** Returns Time difference in milliseconds
**
*******************************************************************************/
static UINT32 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) {
ALOGE("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: setEseListenTechMask
**
** Description: Can be used to force ESE to only listen the specific
** Technologies.
** NFA_TECHNOLOGY_MASK_A 0x01
** NFA_TECHNOLOGY_MASK_B 0x02
**
** Returns: True if listening is configured.
**
*******************************************************************************/
bool SecureElement::setEseListenTechMask(UINT8 tech_mask ) {
static const char fn [] = "SecureElement::setEseListenTechMask";
tNFA_STATUS nfaStat;
ALOGD ("%s: enter", fn);
if (!mIsInit)
{
ALOGE ("%s: not init", fn);
return (NULL);
}
{
SyncEventGuard guard (SecureElement::getInstance().mEseListenEvent);
nfaStat = NFA_CeConfigureEseListenTech (0x4C0, (0x00));
if(nfaStat == NFA_STATUS_OK)
{
SecureElement::getInstance().mEseListenEvent.wait ();
return true;
}
else
ALOGE ("fail to stop ESE listen");
}
{
SyncEventGuard guard (SecureElement::getInstance().mEseListenEvent);
nfaStat = NFA_CeConfigureEseListenTech (0x4C0, (tech_mask));
if(nfaStat == NFA_STATUS_OK)
{
SecureElement::getInstance().mEseListenEvent.wait ();
return true;
}
else
ALOGE ("fail to start ESE listen");
}
return false;
}
/*******************************************************************************
**
** Function: isActivatedInListenMode
**
** Description: Can be used to determine if the SE is activated in listen mode
**
** Returns: True if the SE is activated in listen mode
**
*******************************************************************************/
bool SecureElement::isActivatedInListenMode() {
return mActivatedInListenMode;
}
/*******************************************************************************
**
** Function: getListOfEeHandles
**
** Description: Get the list of handles of all execution environments.
** e: Java Virtual Machine.
**
** Returns: List of handles of all execution environments.
**
*******************************************************************************/
jintArray SecureElement::getListOfEeHandles (JNIEnv* e)
{
static const char fn [] = "SecureElement::getListOfEeHandles";
ALOGD ("%s: enter", fn);
if (mNumEePresent == 0)
return NULL;
if (!mIsInit)
{
ALOGE ("%s: not init", fn);
return (NULL);
}
// Get Fresh EE info.
if (! getEeInfo())
return (NULL);
jintArray list = e->NewIntArray (mNumEePresent); //allocate array
jint jj = 0;
int cnt = 0;
for (int ii = 0; ii < mActualNumEe && cnt < mNumEePresent; ii++)
{
ALOGD ("%s: %u = 0x%X", fn, ii, mEeInfo[ii].ee_handle);
if ((mEeInfo[ii].num_interface == 0) || (mEeInfo[ii].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) )
{
continue;
}
jj = mEeInfo[ii].ee_handle & ~NFA_HANDLE_GROUP_EE;
ALOGD ("%s: Handle %u = 0x%X", fn, ii, jj);
jj = getGenericEseId(jj);
ALOGD ("%s: Generic id %u = 0x%X", fn, ii, jj);
e->SetIntArrayRegion (list, cnt++, 1, &jj);
}
ALOGD("%s: exit", fn);
return list;
}
/*******************************************************************************
**
** 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 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;
ALOGD ("%s: ENTER", __FUNCTION__);
if (! getEeInfo())
return (NULL);
num_of_nfcee_present = mNfceeData_t.mNfceePresent;
ALOGD("num_of_nfcee_present = %d",num_of_nfcee_present);
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);
ALOGD("eSE Active");
}
if(nfcee_handle[i] == EE_HANDLE_0xF4 && nfcee_status[i] == NFC_NFCEE_STATUS_ACTIVE)
{
seId = getGenericEseId(EE_HANDLE_0xF4 & ~NFA_HANDLE_GROUP_EE);
ALOGD("UICC Active");
}
ALOGD ("%s: Generic id %u = 0x%X", __FUNCTION__, i, seId);
e->SetIntArrayRegion (list, cnt++, 1, &seId);
}
ALOGD("%s: exit", __FUNCTION__);
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;
ALOGD ("%s: enter; seID=0x%X", fn, seID);
tNFA_HANDLE handle = getEseHandleFromGenericId(seID);
ALOGD ("%s: handle=0x%X", fn, handle);
if (!mIsInit)
{
ALOGE ("%s: not init", fn);
return false;
}
//if (mActiveEeHandle != NFA_HANDLE_INVALID)
//{
// ALOGD ("%s: already active", fn);
// return true;
//}
// Get Fresh EE info if needed.
if (! getEeInfo())
{
ALOGE ("%s: no EE info", fn);
return false;
}
UINT16 overrideEeHandle = 0;
// If the Active SE is overridden
if (mActiveSeOverride && (mActiveSeOverride != ACTIVE_SE_USE_ANY))
overrideEeHandle = NFA_HANDLE_GROUP_EE | mActiveSeOverride;
else //NXP
overrideEeHandle = handle;
ALOGD ("%s: override ee h=0x%X", fn, overrideEeHandle );
#if (NFC_NXP_ESE != TRUE || NFC_NXP_CHIP_TYPE == PN547C2)
if (mRfFieldIsOn) {
ALOGE("%s: RF field indication still on, resetting", fn);
mRfFieldIsOn = false;
}
#endif
//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) || (eeItem.ee_handle == EE_HANDLE_0xF4))
{
if (overrideEeHandle && (overrideEeHandle != eeItem.ee_handle) )
continue; // do not enable all SEs; only the override one
if (eeItem.ee_status != NFC_NFCEE_STATUS_INACTIVE)
{
ALOGD ("%s: h=0x%X already activated", fn, eeItem.ee_handle);
numActivatedEe++;
continue;
}
{
ALOGD ("%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++;
}
else
ALOGE ("%s: NFA_EeModeSet failed; error=0x%X", fn, nfaStat);
}
}
} //for
mActiveEeHandle = getDefaultEeHandle();
if (mActiveEeHandle == NFA_HANDLE_INVALID)
ALOGE ("%s: ee handle not found", fn);
ALOGD ("%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;
ALOGD ("%s: enter; seID=0x%X, mActiveEeHandle=0x%X", fn, seID, mActiveEeHandle);
tNFA_HANDLE handle = getEseHandleFromGenericId(seID);
ALOGD ("%s: handle=0x%X", fn, handle);
if (!mIsInit)
{
ALOGE ("%s: not init", fn);
goto TheEnd;
}
//if the controller is routing to sec elems or piping,
//then the secure element cannot be deactivated
if ((mCurrentRouteSelection == SecElemRoute) || mIsPiping)
{
ALOGE ("%s: still busy", fn);
goto TheEnd;
}
// if (mActiveEeHandle == NFA_HANDLE_INVALID)
// {
// ALOGE ("%s: invalid EE handle", fn);
// goto TheEnd;
// }
if (seID == NFA_HANDLE_INVALID)
{
ALOGE ("%s: invalid EE handle", fn);
goto TheEnd;
}
mActiveEeHandle = NFA_HANDLE_INVALID;
//NXP
//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)))
{
if (eeItem.ee_status == NFC_NFCEE_STATUS_INACTIVE)
{
ALOGD ("%s: h=0x%X already deactivated", fn, eeItem.ee_handle);
break;
}
{
ALOGD ("%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)
{
ALOGD ("%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)
{
ALOGE ("%s: NFA_EeModeSet success; status=0x%X", fn, nfaStat);
retval = true;
}
}
else
ALOGE ("%s: NFA_EeModeSet failed; error=0x%X", fn, nfaStat);
}
}
} //for
TheEnd:
ALOGD ("%s: exit; ok=%u", fn, retval);
return retval;
}
/*******************************************************************************
**
** 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* aidBuffer, UINT8 aidBufferLen, const UINT8* dataBuffer, UINT32 dataBufferLen,UINT32 evtSrc)
{
static const char fn [] = "SecureElement::notifyTransactionListenersOfAid";
ALOGD ("%s: enter; aid len=%u data len=%d", fn, aidBufferLen, dataBufferLen);
if (aidBufferLen == 0) {
return;
}
JNIEnv* e = NULL;
ScopedAttach attach(mNativeData->vm, &e);
if (e == NULL)
{
ALOGE ("%s: jni env is null", fn);
return;
}
const UINT16 tlvMaxLen = aidBufferLen + 10;
UINT8* tlv = new UINT8 [tlvMaxLen];
if (tlv == NULL)
{
ALOGE ("%s: fail allocate tlv", fn);
return;
}
memcpy (tlv, aidBuffer, aidBufferLen);
UINT16 tlvActualLen = aidBufferLen;
ScopedLocalRef<jobject> tlvJavaArray(e, e->NewByteArray(tlvActualLen));
if (tlvJavaArray.get() == NULL)
{
ALOGE ("%s: fail allocate array", fn);
goto TheEnd;
}
e->SetByteArrayRegion ((jbyteArray)tlvJavaArray.get(), 0, tlvActualLen, (jbyte *)tlv);
if (e->ExceptionCheck())
{
e->ExceptionClear();
ALOGE ("%s: fail fill array", fn);
goto TheEnd;
}
if(dataBufferLen > 0)
{
const UINT32 dataTlvMaxLen = dataBufferLen + 10;
UINT8* datatlv = new UINT8 [dataTlvMaxLen];
if (datatlv == NULL)
{
ALOGE ("%s: fail allocate tlv", fn);
return;
}
memcpy (datatlv, dataBuffer, dataBufferLen);
UINT16 dataTlvActualLen = dataBufferLen;
ScopedLocalRef<jobject> dataTlvJavaArray(e, e->NewByteArray(dataTlvActualLen));
if (dataTlvJavaArray.get() == NULL)
{
ALOGE ("%s: fail allocate array", fn);
goto Clean;
}
e->SetByteArrayRegion ((jbyteArray)dataTlvJavaArray.get(), 0, dataTlvActualLen, (jbyte *)datatlv);
if (e->ExceptionCheck())
{
e->ExceptionClear();
ALOGE ("%s: fail fill array", fn);
goto Clean;
}
e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyTransactionListeners, tlvJavaArray.get(), dataTlvJavaArray.get(), evtSrc);
if (e->ExceptionCheck())
{
e->ExceptionClear();
ALOGE ("%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();
ALOGE ("%s: fail notify", fn);
goto TheEnd;
}
}
TheEnd:
delete [] tlv;
ALOGD ("%s: exit", fn);
}
/*******************************************************************************
**
** Function: notifyConnectivityListeners
**
** Description: Notify the NFC service about a connectivity event from secure element.
** evtSrc: source of event UICC/eSE.
**
** Returns: None
**
*******************************************************************************/
void SecureElement::notifyConnectivityListeners (UINT8 evtSrc)
{
static const char fn [] = "SecureElement::notifyConnectivityListeners";
ALOGD ("%s: enter; evtSrc =%u", fn, evtSrc);
JNIEnv* e = NULL;
ScopedAttach attach(mNativeData->vm, &e);
if (e == NULL)
{
ALOGE ("%s: jni env is null", fn);
return;
}
e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyConnectivityListeners,evtSrc);
if (e->ExceptionCheck())
{
e->ExceptionClear();
ALOGE ("%s: fail notify", fn);
goto TheEnd;
}
TheEnd:
ALOGD ("%s: exit", fn);
}
/*******************************************************************************
**
** Function: notifyEmvcoMultiCardDetectedListeners
**
** Description: Notify the NFC service about a multiple card presented to
** Emvco reader.
**
** Returns: None
**
*******************************************************************************/
void SecureElement::notifyEmvcoMultiCardDetectedListeners ()
{
static const char fn [] = "SecureElement::notifyEmvcoMultiCardDetectedListeners";
ALOGD ("%s: enter; evtSrc =%u", fn);
JNIEnv* e = NULL;
ScopedAttach attach(mNativeData->vm, &e);
if (e == NULL)
{
ALOGE ("%s: jni env is null", fn);
return;
}
e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyEmvcoMultiCardDetectedListeners);
if (e->ExceptionCheck())
{
e->ExceptionClear();
ALOGE ("%s: fail notify", fn);
goto TheEnd;
}
TheEnd:
ALOGD ("%s: exit", fn);
}
/*******************************************************************************
**
** Function: connectEE
**
** Description: Connect to the execution environment.
**
** Returns: True if ok.
**
*******************************************************************************/
bool SecureElement::connectEE ()
{
static const char fn [] = "SecureElement::connectEE";
tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
bool retVal = false;
UINT8 destHost = 0;
unsigned long num = 0;
char pipeConfName[40];
tNFA_HANDLE eeHandle = mActiveEeHandle;
ALOGD ("%s: enter, mActiveEeHandle: 0x%04x, SEID: 0x%x, pipe_gate_num=%d, use pipe=%d",
fn, mActiveEeHandle, gSEId, gGatePipe, gUseStaticPipe);
if (!mIsInit)
{
ALOGE ("%s: not init", fn);
return (false);
}
if (gSEId != -1)
{
eeHandle = gSEId | NFA_HANDLE_GROUP_EE;
ALOGD ("%s: Using SEID: 0x%x", fn, eeHandle );
}
if (eeHandle == NFA_HANDLE_INVALID)
{
ALOGE ("%s: invalid handle 0x%X", fn, eeHandle);
return (false);
}
tNFA_EE_INFO *pEE = findEeByHandle (eeHandle);
if (pEE == NULL)
{
ALOGE ("%s: Handle 0x%04x NOT FOUND !!", fn, eeHandle);
return (false);
}
#if(NFC_NXP_ESE == TRUE && NFC_NXP_CHIP_TYPE != PN547C2)
//Do Nothing
#else
android::startRfDiscovery(false);
#endif
// Disable UICC idle timeout while the DH is connected
//android::setUiccIdleTimeout (false);
mNewSourceGate = 0;
if (gGatePipe == -1)
{
// pipe/gate num was not specifed by app, get from config file
mNewPipeId = 0;
// Construct the PIPE name based on the EE handle (e.g. NFA_HCI_STATIC_PIPE_ID_F3 for UICC0).
snprintf (pipeConfName, sizeof(pipeConfName), "NFA_HCI_STATIC_PIPE_ID_%02X", eeHandle & NFA_HANDLE_MASK);
if (GetNumValue(pipeConfName, &num, sizeof(num)) && (num != 0))
{
mNewPipeId = num;
ALOGD ("%s: Using static pipe id: 0x%X", __FUNCTION__, mNewPipeId);
}
else
{
ALOGD ("%s: Did not find value '%s' defined in the .conf", __FUNCTION__, pipeConfName);
}
}
else
{
if (gUseStaticPipe)
{
mNewPipeId = gGatePipe;
}
else
{
mNewPipeId = 0;
mDestinationGate= gGatePipe;
}
}
// If the .conf file had a static pipe to use, just use it.
if (mNewPipeId != 0)
{
#if(NXP_EXTNS == TRUE)
UINT8 host = (mNewPipeId == STATIC_PIPE_0x70) ? 0xC0 : 0x03;
#else
UINT8 host = (mNewPipeId == STATIC_PIPE_0x70) ? 0x02 : 0x03;
#endif
UINT8 gate = (mNewPipeId == STATIC_PIPE_0x70) ? 0xF0 : 0xF1;
nfaStat = NFA_HciAddStaticPipe(mNfaHciHandle, host, gate, mNewPipeId);
if (nfaStat != NFA_STATUS_OK)
{
ALOGE ("%s: fail create static pipe; error=0x%X", fn, nfaStat);
retVal = false;
goto TheEnd;
}
}
else
{
if ( (pEE->num_tlvs >= 1) && (pEE->ee_tlv[0].tag == NFA_EE_TAG_HCI_HOST_ID) )
destHost = pEE->ee_tlv[0].info[0];
else
#if(NXP_EXTNS == TRUE)
destHost = 0xC0;
#else
destHost = 2;
#endif
// Get a list of existing gates and pipes
{
ALOGD ("%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)
{
for (UINT8 xx = 0; xx < mHciCfg.num_pipes; xx++)
{
if ( (mHciCfg.pipe[xx].dest_host == destHost)
&& (mHciCfg.pipe[xx].dest_gate == mDestinationGate) )
{
mNewSourceGate = mHciCfg.pipe[xx].local_gate;
mNewPipeId = mHciCfg.pipe[xx].pipe_id;
ALOGD ("%s: found configured gate: 0x%02x pipe: 0x%02x", fn, mNewSourceGate, mNewPipeId);
break;
}
}
}
}
}
if (mNewSourceGate == 0)
{
ALOGD ("%s: allocate gate", fn);
//allocate a source gate and store in mNewSourceGate
SyncEventGuard guard (mAllocateGateEvent);
if ((nfaStat = NFA_HciAllocGate (mNfaHciHandle, mDestinationGate)) != NFA_STATUS_OK)
{
ALOGE ("%s: fail allocate source gate; error=0x%X", fn, nfaStat);
goto TheEnd;
}
mAllocateGateEvent.wait ();
if (mCommandStatus != NFA_STATUS_OK)
goto TheEnd;
}
if (mNewPipeId == 0)
{
ALOGD ("%s: create pipe", fn);
SyncEventGuard guard (mCreatePipeEvent);
nfaStat = NFA_HciCreatePipe (mNfaHciHandle, mNewSourceGate, destHost, mDestinationGate);
if (nfaStat != NFA_STATUS_OK)
{
ALOGE ("%s: fail create pipe; error=0x%X", fn, nfaStat);
goto TheEnd;
}
mCreatePipeEvent.wait ();
if (mCommandStatus != NFA_STATUS_OK)
goto TheEnd;
}
{
ALOGD ("%s: open pipe", fn);
SyncEventGuard guard (mPipeOpenedEvent);
nfaStat = NFA_HciOpenPipe (mNfaHciHandle, mNewPipeId);
if (nfaStat != NFA_STATUS_OK)
{
ALOGE ("%s: fail open pipe; error=0x%X", fn, nfaStat);
goto TheEnd;
}
mPipeOpenedEvent.wait ();
if (mCommandStatus != NFA_STATUS_OK)
goto TheEnd;
}
}
retVal = true;
TheEnd:
mIsPiping = retVal;
if (!retVal)
{
// if open failed we need to de-allocate the gate
disconnectEE(0);
}
ALOGD ("%s: exit; ok=%u", fn, retVal);
return retVal;
}
/*******************************************************************************
**
** Function: disconnectEE
**
** Description: Disconnect from the execution environment.
** seID: ID of secure element.
**
** Returns: True if ok.
**
*******************************************************************************/
bool SecureElement::disconnectEE (jint seID)
{
static const char fn [] = "SecureElement::disconnectEE";
tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
tNFA_HANDLE eeHandle = seID;
ALOGD("%s: seID=0x%X; handle=0x%04x", fn, seID, eeHandle);
if (mUseOberthurWarmReset)
{
//send warm-reset command to Oberthur secure element which deselects the applet;
//this is an Oberthur-specific command;
ALOGD("%s: try warm-reset on pipe id 0x%X; cmd=0x%X", fn, mNewPipeId, mOberthurWarmResetCommand);
SyncEventGuard guard (mRegistryEvent);
nfaStat = NFA_HciSetRegistry (mNfaHciHandle, mNewPipeId,
1, 1, &mOberthurWarmResetCommand);
if (nfaStat == NFA_STATUS_OK)
{
mRegistryEvent.wait ();
ALOGD("%s: completed warm-reset on pipe 0x%X", fn, mNewPipeId);
}
}
if (mNewSourceGate)
{
SyncEventGuard guard (mDeallocateGateEvent);
if ((nfaStat = NFA_HciDeallocGate (mNfaHciHandle, mNewSourceGate)) == NFA_STATUS_OK)
mDeallocateGateEvent.wait ();
else
ALOGE ("%s: fail dealloc gate; error=0x%X", fn, nfaStat);
}
mIsPiping = false;
/*clear the SPI transaction flag*/
if(dual_mode_current_state & SPI_ON)
dual_mode_current_state ^= SPI_ON;
hold_the_transceive = false;
// Re-enable UICC low-power mode
// Re-enable RF discovery
// Note that it only effactuates the current configuration,
// so if polling/listening were configured OFF (forex because
// the screen was off), they will stay OFF with this call.
/*Blocked as part done in connectEE, to allow wired mode during reader mode.*/
#if(NFC_NXP_ESE == TRUE && NFC_NXP_CHIP_TYPE != PN547C2)
// Do Nothing
#else
android::setUiccIdleTimeout (true);
android::startRfDiscovery(true);
#endif
return true;
}
/*******************************************************************************
**
** 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* xmitBuffer, INT32 xmitBufferSize, UINT8* recvBuffer,
INT32 recvBufferMaxSize, INT32& recvBufferActualSize, INT32 timeoutMillisec)
{
static const char fn [] = "SecureElement::transceive";
tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
bool isSuccess = false;
mTransceiveWaitOk = false;
UINT8 newSelectCmd[NCI_MAX_AID_LEN + 10];
#if(NXP_EXTNS == TRUE)
bool recovery;
#endif
ALOGD ("%s: enter; xmitBufferSize=%ld; recvBufferMaxSize=%ld; timeout=%ld", fn, xmitBufferSize, recvBufferMaxSize, timeoutMillisec);
// 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 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;
ALOGD ("%s: Empty AID SELECT cmd detected, substituting AID from config file, new length=%d", fn, idx);
}
#if((NFC_NXP_ESE == TRUE)&&(NXP_EXTNS == TRUE))
NfccStandByOperation(STANDBY_TIMER_STOP);
#endif
{
SyncEventGuard guard (mTransceiveEvent);
mActualResponseSize = 0;
memset (mResponseData, 0, sizeof(mResponseData));
#if((NFC_NXP_ESE == TRUE)&&(NXP_EXTNS == TRUE))
if(hold_the_transceive == true){
ALOGD("%s: holding the transceive\n", fn);
sSPIPrioSessionEndEvent.wait(timeoutMillisec);
if (mTransceiveWaitOk == false) //timeout occurs
{
ALOGE ("%s: holding the transceive for SPI Prio....wait response timeout\n", fn);
goto TheEnd;
}
}
#endif
if ((mNewPipeId == STATIC_PIPE_0x70) || (mNewPipeId == STATIC_PIPE_0x71))
#if(NXP_EXTNS == TRUE)
{
if((RoutingManager::getInstance().is_ee_recovery_ongoing()))
{
ALOGE ("%s: is_ee_recovery_ongoing ", fn);
SyncEventGuard guard (mEEdatapacketEvent);
mEEdatapacketEvent.wait();
}
else
{
ALOGE ("%s: Not in Recovery State", fn);
}
#if (NFC_NXP_ESE == TRUE && NFC_NXP_CHIP_TYPE != PN547C2)
if(!isWiredModeAllowedInRfState())
{
ALOGD("%s, Dont allow wired mode in this RF state", fn);
goto TheEnd;
}
#endif
#if((NFC_NXP_TRIPLE_MODE_PROTECTION==TRUE)&&((NFC_NXP_ESE_VER == JCOP_VER_3_2)||(NFC_NXP_ESE_VER == JCOP_VER_3_3)))
if((dual_mode_current_state == SPI_DWPCL_BOTH_ACTIVE))
{
ALOGD("%s, Dont allow wired mode...Dual Mode..", fn);
SyncEventGuard guard (mDualModeEvent);
mDualModeEvent.wait();
}
#endif
#if(NFC_NXP_ESE == TRUE)
active_ese_reset_control |= TRANS_WIRED_ONGOING;
#endif
#endif
nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, EVT_SEND_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData, timeoutMillisec);
#if(NXP_EXTNS == TRUE)
}
#endif
else
#if(NXP_EXTNS == TRUE)
{
#if(NFC_NXP_ESE == TRUE)
active_ese_reset_control |= TRANS_WIRED_ONGOING;
#endif
#endif
nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, NFA_HCI_EVT_POST_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData, timeoutMillisec);
#if(NXP_EXTNS == TRUE)
}
#endif
if (nfaStat == NFA_STATUS_OK)
{
// waitOk = mTransceiveEvent.wait (timeoutMillisec);
mTransceiveEvent.wait ();
#if((NFC_NXP_ESE == TRUE)&&(NXP_EXTNS == TRUE))
if(active_ese_reset_control & TRANS_WIRED_ONGOING)
{
active_ese_reset_control ^= TRANS_WIRED_ONGOING;
/*If only reset event is pending*/
if((active_ese_reset_control&RESET_BLOCKED))
{
SyncEventGuard guard (mResetOngoingEvent);
mResetOngoingEvent.wait();
}
if(!(active_ese_reset_control&TRANS_CL_ONGOING) &&
(active_ese_reset_control&RESET_BLOCKED))
{
active_ese_reset_control ^= RESET_BLOCKED;
}
}
#endif
if (mTransceiveWaitOk == false) //timeout occurs
{
ALOGE ("%s: wait response timeout", fn);
goto TheEnd;
}
}
else
{
ALOGE ("%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:
#if((NFC_NXP_ESE == TRUE)&&(NXP_EXTNS == TRUE))
if((active_ese_reset_control&TRANS_WIRED_ONGOING))
active_ese_reset_control ^= TRANS_WIRED_ONGOING;
#endif
ALOGD ("%s: exit; isSuccess: %d; recvBufferActualSize: %ld", fn, isSuccess, recvBufferActualSize);
return (isSuccess);
}
/*******************************************************************************
**
** Function: setCLState
**
** Description: Update current DWP CL state based on CL activation status
**
** Returns: None .
**
*******************************************************************************/
void SecureElement::setCLState(bool mState)
{
ALOGD ("%s: Entry setCLState \n", __FUNCTION__);
/*Check if the state is already dual mode*/
bool inDualModeAlready = (dual_mode_current_state == SPI_DWPCL_BOTH_ACTIVE);
if(mState)
{
dual_mode_current_state |= CL_ACTIVE;
#if((NFC_NXP_ESE == TRUE)&&(NXP_EXTNS == TRUE))
active_ese_reset_control |= TRANS_CL_ONGOING;
#endif
}
else
{
if(dual_mode_current_state & CL_ACTIVE)
{
dual_mode_current_state ^= CL_ACTIVE;
#if((NFC_NXP_ESE == TRUE)&&(NXP_EXTNS == TRUE))
if((active_ese_reset_control&TRANS_CL_ONGOING))
{
active_ese_reset_control ^= TRANS_CL_ONGOING;
/*If there is no pending wired rapdu or CL session*/
if(((active_ese_reset_control&RESET_BLOCKED))&&
(!(active_ese_reset_control &(TRANS_WIRED_ONGOING))))
{
/*unblock pending reset event*/
SyncEventGuard guard (sSecElem.mResetEvent);
sSecElem.mResetEvent.notifyOne();
active_ese_reset_control ^= RESET_BLOCKED;
}
}
#endif
if(inDualModeAlready)
{
SyncEventGuard guard (mDualModeEvent);
mDualModeEvent.notifyOne();
}
}
}
ALOGD ("%s: Exit setCLState = %d\n", __FUNCTION__, dual_mode_current_state);
}
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;
ALOGD ("%s: NFA_EE_MODE_SET_EVT; pEE->ee_status: %s (0x%04x)", fn, SecureElement::eeStatusToString(pEE->ee_status), pEE->ee_status);
}
else
ALOGE ("%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();
}
#if((NFC_NXP_ESE == TRUE)&&(NXP_EXTNS == TRUE))
static void NFCC_StandbyModeTimerCallBack (union sigval)
{
ALOGD ("%s timer timedout , sending standby mode cmd", __FUNCTION__);
SecureElement::getInstance().NfccStandByOperation(STANDBY_TIMER_TIMEOUT);
}
#endif
/*******************************************************************************
**
** 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";
ALOGD ("%s: enter; listen mode active=%u", fn, isActivated);
JNIEnv* e = NULL;
if (mNativeData == NULL)
{
ALOGE ("%s: mNativeData is null", fn);
return;
}
ScopedAttach attach(mNativeData->vm, &e);
if (e == NULL)
{
ALOGE ("%s: jni env is null", fn);
return;
}
mActivatedInListenMode = isActivated;
#if (NFC_NXP_ESE == TRUE && NFC_NXP_CHIP_TYPE != PN547C2)
if(!isActivated)
{
mRecvdTransEvt = false;
mAllowWiredMode = false;
SyncEventGuard guard (mAllowWiredModeEvent);
mAllowWiredModeEvent.notifyOne();
setCLState(false);
}
else
{
mAllowWiredMode = true;
}
#endif
if (mNativeData != NULL) {
if (isActivated) {
e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeListenActivated);
}
else {
e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeListenDeactivated);
}
}
if (e->ExceptionCheck())
{
e->ExceptionClear();
ALOGE ("%s: fail notify", fn);
}
ALOGD ("%s: exit", fn);
}
/*******************************************************************************
**
** 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";
ALOGD ("%s: enter; is active=%u", fn, isActive);
JNIEnv* e = NULL;
ScopedAttach attach(mNativeData->vm, &e);
if (e == NULL)
{
ALOGE ("%s: jni env is null", fn);
return;
}
mMutex.lock();
int ret = clock_gettime (CLOCK_MONOTONIC, &mLastRfFieldToggle);
if (ret == -1) {
ALOGE("%s: clock_gettime failed", fn);
// There is no good choice here...
}
if (isActive) {
mRfFieldIsOn = true;
e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeFieldActivated);
}
else {
mRfFieldIsOn = false;
#if (NFC_NXP_ESE == TRUE && NFC_NXP_CHIP_TYPE != PN547C2)
mRecvdTransEvt = false;
mAllowWiredMode = false;
SyncEventGuard guard (mAllowWiredModeEvent);
mAllowWiredModeEvent.notifyOne();
#endif
setCLState(false);
e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeFieldDeactivated);
}
mMutex.unlock();
if (e->ExceptionCheck())
{
e->ExceptionClear();
ALOGE ("%s: fail notify", fn);
}
ALOGD ("%s: exit", fn);
}
#if(NFC_NXP_ESE == TRUE && NFC_NXP_CHIP_TYPE == PN548C2)
/*Reader over SWP*/
void SecureElement::notifyEEReaderEvent (int evt, int data)
{
static const char fn [] = "SecureElement::notifyEEReaderEvent";
ALOGD ("%s: enter; event=%x", fn, evt);
mMutex.lock();
int ret = clock_gettime (CLOCK_MONOTONIC, &mLastRfFieldToggle);
if (ret == -1) {
ALOGE("%s: clock_gettime failed", fn);
// There is no good choice here...
}
switch (evt) {
case NFA_RD_SWP_READER_REQUESTED:
ALOGD ("%s: NFA_RD_SWP_READER_REQUESTED for tech %x", fn, data);
{
jboolean istypeA = false;
jboolean istypeB = false;
if(data & NFA_TECHNOLOGY_MASK_A)
istypeA = true;
if(data & NFA_TECHNOLOGY_MASK_B)
istypeB = true;
/*
* Start the protection time.This is to give user a specific time window to wait for the TAG,
* and prevents MW from infinite waiting to switch back to normal NFC-Fouram polling mode.
* */
unsigned long timeout = 0;
GetNxpNumValue(NAME_NXP_SWP_RD_START_TIMEOUT, (void *)&timeout, sizeof(timeout));
ALOGD ("SWP_RD_START_TIMEOUT : %d", timeout);
if (timeout > 0)
sSwpReaderTimer.set(1000*timeout,startStopSwpReaderProc);
}
break;
case NFA_RD_SWP_READER_START:
ALOGD ("%s: NFA_RD_SWP_READER_START", fn);
{
JNIEnv* e = NULL;
ScopedAttach attach(mNativeData->vm, &e);
if (e == NULL)
{
ALOGE ("%s: jni env is null", fn);
break;
}
sSwpReaderTimer.kill();
/*
* Start the protection time.This is to give user a specific time window to wait for the
* SWP Reader to finish with card, and prevents MW from infinite waiting to switch back to
* normal NFC-Forum polling mode.
*
* configuring timeout.
* */
unsigned long timeout = 0;
GetNxpNumValue(NAME_NXP_SWP_RD_TAG_OP_TIMEOUT, (void *)&timeout, sizeof(timeout));
ALOGD ("SWP_RD_TAG_OP_TIMEOUT : %d", timeout);
if (timeout > 0)
sSwpReaderTimer.set(2000*timeout,startStopSwpReaderProc);
e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySWPReaderActivated);
}
break;
case NFA_RD_SWP_READER_STOP:
ALOGD ("%s: NFA_RD_SWP_READER_STOP", fn);
break;
//TODO: Check this later. Need to update libnfc-nci for this symbol.
// case NFA_RD_SWP_READER_START_FAIL:
// ALOGD ("%s: NFA_RD_SWP_READER_STOP", fn);
// //sStopSwpReaderTimer.kill();
// e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySWPReaderRequestedFail);
// break;
default:
ALOGD ("%s: UNKNOWN EVENT ??", fn);
break;
}
mMutex.unlock();
ALOGD ("%s: exit", fn);
}
#endif
/*******************************************************************************
**
** Function: resetRfFieldStatus
**
** Description: Resets the field status.
** isActive: Whether any secure element is activated.
**
** Returns: None
**
*******************************************************************************/
void SecureElement::resetRfFieldStatus ()
{
static const char fn [] = "SecureElement::resetRfFieldStatus`";
ALOGD ("%s: enter;", fn);
mMutex.lock();
mRfFieldIsOn = false;
int ret = clock_gettime (CLOCK_MONOTONIC, &mLastRfFieldToggle);
if (ret == -1) {
ALOGE("%s: clock_gettime failed", fn);
// There is no good choice here...
}
mMutex.unlock();
ALOGD ("%s: exit", fn);
}
/*******************************************************************************
**
** Function: storeUiccInfo
**
** Description: Store a copy of the execution environment information from the stack.
** info: execution environment information.
**
** Returns: None
**
*******************************************************************************/
void SecureElement::storeUiccInfo (tNFA_EE_DISCOVER_REQ& info)
{
static const char fn [] = "SecureElement::storeUiccInfo";
ALOGD ("%s: Status: %u Num EE: %u", fn, info.status, info.num_ee);
SyncEventGuard guard (mUiccInfoEvent);
memcpy (&mUiccInfo, &info, sizeof(mUiccInfo));
for (UINT8 xx = 0; xx < info.num_ee; xx++)
{
//for each technology (A, B, F, B'), print the bit field that shows
//what protocol(s) is support by that technology
ALOGD ("%s EE[%u] Handle: 0x%04x techA: 0x%02x techB: 0x%02x techF: 0x%02x techBprime: 0x%02x",
fn, xx, info.ee_disc_info[xx].ee_handle,
info.ee_disc_info[xx].la_protocol,
info.ee_disc_info[xx].lb_protocol,
info.ee_disc_info[xx].lf_protocol,
info.ee_disc_info[xx].lbp_protocol);
}
mUiccInfoEvent.notifyOne ();
}
/*******************************************************************************
**
** Function getSeVerInfo
**
** Description Gets version information and id for a secure element. The
** seIndex parmeter is the zero based index of the secure
** element to get verion info for. The version infommation
** is returned as a string int the verInfo parameter.
**
** Returns ture on success, false on failure
**
*******************************************************************************/
bool SecureElement::getSeVerInfo(int seIndex, char * verInfo, int verInfoSz, UINT8 * seid)
{
ALOGD("%s: enter, seIndex=%d", __FUNCTION__, seIndex);
if (seIndex > (mActualNumEe-1))
{
ALOGE("%s: invalid se index: %d, only %d SEs in system", __FUNCTION__, seIndex, mActualNumEe);
return false;
}
*seid = mEeInfo[seIndex].ee_handle;
if ((mEeInfo[seIndex].num_interface == 0) || (mEeInfo[seIndex].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) )
{
return false;
}
strncpy(verInfo, "Version info not available", verInfoSz-1);
verInfo[verInfoSz-1] = '\0';
UINT8 pipe = (mEeInfo[seIndex].ee_handle == EE_HANDLE_0xF3) ? 0x70 : 0x71;
UINT8 host = (pipe == STATIC_PIPE_0x70) ? 0x02 : 0x03;
UINT8 gate = (pipe == STATIC_PIPE_0x70) ? 0xF0 : 0xF1;
tNFA_STATUS nfaStat = NFA_HciAddStaticPipe(mNfaHciHandle, host, gate, pipe);
if (nfaStat != NFA_STATUS_OK)
{
ALOGE ("%s: NFA_HciAddStaticPipe() failed, pipe = 0x%x, error=0x%X", __FUNCTION__, pipe, nfaStat);
return true;
}
SyncEventGuard guard (mVerInfoEvent);
if (NFA_STATUS_OK == (nfaStat = NFA_HciGetRegistry (mNfaHciHandle, pipe, 0x02)))
{
if (false == mVerInfoEvent.wait(200))
{
ALOGE ("%s: wait response timeout", __FUNCTION__);
}
else
{
snprintf(verInfo, verInfoSz-1, "Oberthur OS S/N: 0x%02x%02x%02x", mVerInfo[0], mVerInfo[1], mVerInfo[2]);
verInfo[verInfoSz-1] = '\0';
}
}
else
{
ALOGE ("%s: NFA_HciGetRegistry () failed: 0x%X", __FUNCTION__, nfaStat);
}
return true;
}
/*******************************************************************************
**
** Function getActualNumEe
**
** Description Returns number of secure elements we know about.
**
** Returns Number of secure elements we know about.
**
*******************************************************************************/
UINT8 SecureElement::getActualNumEe()
{
return mActualNumEe;
}
/*******************************************************************************
**
** Function: nfaHciCallback
**
** Description: Receive Host Controller Interface-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";
ALOGD ("%s: event=0x%X", fn, event);
int evtSrc = 0xFF;
switch (event)
{
case NFA_HCI_REGISTER_EVT:
{
ALOGD ("%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:
{
ALOGD ("%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;
ALOGD ("%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:
{
ALOGD ("%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:
{
ALOGD ("%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)
{
ALOGE("Pipe=0x%x is created and updated for se transcieve", eventData->created.pipe);
sSecElem.mNewPipeId = eventData->created.pipe;
}
sSecElem.mCreatePipeEvent.notifyOne();
}
break;
case NFA_HCI_OPEN_PIPE_EVT:
{
ALOGD ("%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:
ALOGD ("%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;
ALOGD ("%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_GET_REG_RSP_EVT :
ALOGD ("%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 == STATIC_PIPE_0x70) || (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:
ALOGD ("%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
{
ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; source UICC",fn);
evtSrc = SecureElement::getInstance().getGenericEseId(EE_HANDLE_0xF4 & ~NFA_HANDLE_GROUP_EE); //UICC
}
else if(eventData->rcvd_evt.pipe == 0x16) //ESE
{
ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; source ESE",fn);
evtSrc = SecureElement::getInstance().getGenericEseId(EE_HANDLE_0xF3 & ~NFA_HANDLE_GROUP_EE); //ESE
}
ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; ################################### ", fn);
if(eventData->rcvd_evt.evt_code == NFA_HCI_EVT_WTX)
{
ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT: NFA_HCI_EVT_WTX ", fn);
}
else if ((eventData->rcvd_evt.pipe == STATIC_PIPE_0x70) || (eventData->rcvd_evt.pipe == STATIC_PIPE_0x71))
{
ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; data from static pipe", fn);
SyncEventGuard guard (sSecElem.mTransceiveEvent);
sSecElem.mActualResponseSize = (eventData->rcvd_evt.evt_len > MAX_RESPONSE_SIZE) ? MAX_RESPONSE_SIZE : eventData->rcvd_evt.evt_len;
#if(NXP_EXTNS == TRUE)
#if(NFC_NXP_ESE == TRUE)
if(eventData->rcvd_evt.evt_len > 0)
{
sSecElem.mTransceiveWaitOk = true;
SecureElement::getInstance().NfccStandByOperation(STANDBY_TIMER_START);
}
/*If there is pending reset event to process*/
if((active_ese_reset_control&RESET_BLOCKED)&&
(!(active_ese_reset_control &(TRANS_CL_ONGOING))))
{
SyncEventGuard guard (sSecElem.mResetEvent);
sSecElem.mResetEvent.notifyOne();
}
#else
if(eventData->rcvd_evt.evt_len > 0)
{
sSecElem.mTransceiveWaitOk = true;
}
#endif
#endif
sSecElem.mTransceiveEvent.notifyOne ();
}
else if (eventData->rcvd_evt.evt_code == NFA_HCI_EVT_POST_DATA)
{
ALOGD ("%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)
{
ALOGD ("%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* data = NULL;
INT32 datalen = 0;
UINT8 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 *)eventData->rcvd_evt.p_evt_buf, 2+aidlen+1, eventData->rcvd_evt.evt_len);
}
if(datalen != -1)
{
/* 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];
sSecElem.notifyTransactionListenersOfAid (&eventData->rcvd_evt.p_evt_buf[2],aidlen,data,datalen,evtSrc);
}
else
{
ALOGE("Event data TLV length encoding Unsupported!");
}
}
}
else if (eventData->rcvd_evt.evt_code == NFA_HCI_EVT_CONNECTIVITY)
{
ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_CONNECTIVITY", fn);
// int pipe = (eventData->rcvd_evt.pipe); /*commented to eliminate unused variable warning*/
sSecElem.notifyConnectivityListeners (evtSrc);
}
else
{
ALOGD ("%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);
ALOGD ("%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;
ALOGD ("%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:
ALOGE ("%s: unknown event code=0x%X ????", fn, event);
break;
}
}
/*******************************************************************************
**
** 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 xx = 0; xx < mActualNumEe; xx++)
{
if (mEeInfo[xx].ee_handle == eeHandle)
return (&mEeInfo[xx]);
}
return (NULL);
}
/*******************************************************************************
**
** 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;
tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
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: getDefaultEeHandle
**
** Description: Get the handle to the execution environment.
**
** Returns: Handle to the execution environment.
**
*******************************************************************************/
tNFA_HANDLE SecureElement::getDefaultEeHandle ()
{
static const char fn [] = "SecureElement::activate";
ALOGE ("%s: - Enter", fn);
ALOGE ("%s: - mActualNumEe = %x mActiveSeOverride = 0x%02X", fn,mActualNumEe, mActiveSeOverride);
UINT16 overrideEeHandle = NFA_HANDLE_GROUP_EE | mActiveSeOverride;
// Find the first EE that is not the HCI Access i/f.
for (UINT8 xx = 0; xx < mActualNumEe; xx++)
{
if ( (mActiveSeOverride != ACTIVE_SE_USE_ANY) && (overrideEeHandle != mEeInfo[xx].ee_handle))
continue; //skip all the EE's that are ignored
ALOGE ("%s: - mEeInfo[xx].ee_handle = 0x%02x, mEeInfo[xx].ee_status = 0x%02x", fn,mEeInfo[xx].ee_handle, mEeInfo[xx].ee_status);
if ((mEeInfo[xx].num_interface != 0)
#ifndef GEMALTO_SE_SUPPORT
&&
(mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS)
#else
&&
(mEeInfo[xx].ee_handle == EE_HANDLE_0xF3 || mEeInfo[xx].ee_handle == EE_HANDLE_0xF4)
#endif
&&
(mEeInfo[xx].ee_status != NFC_NFCEE_STATUS_INACTIVE))
return (mEeInfo[xx].ee_handle);
}
return NFA_HANDLE_INVALID;
}
/*******************************************************************************
**
** Function: findUiccByHandle
**
** Description: Find information about an execution environment.
** eeHandle: Handle of the execution environment.
**
** Returns: Information about the execution environment.
**
*******************************************************************************/
tNFA_EE_DISCOVER_INFO *SecureElement::findUiccByHandle (tNFA_HANDLE eeHandle)
{
for (UINT8 index = 0; index < mUiccInfo.num_ee; index++)
{
if (mUiccInfo.ee_disc_info[index].ee_handle == eeHandle)
{
return (&mUiccInfo.ee_disc_info[index]);
}
}
ALOGE ("SecureElement::findUiccByHandle: ee h=0x%4x not found", eeHandle);
return NULL;
}
/*******************************************************************************
**
** Function: eeStatusToString
**
** Description: Convert status code to status text.
** status: Status code
**
** Returns: None
**
*******************************************************************************/
const char* SecureElement::eeStatusToString (UINT8 status)
{
switch (status)
{
case NFC_NFCEE_STATUS_ACTIVE:
return("Connected/Active");
case NFC_NFCEE_STATUS_INACTIVE:
return("Connected/Inactive");
case NFC_NFCEE_STATUS_REMOVED:
return("Removed");
}
return("?? Unknown ??");
}
/*******************************************************************************
**
** Function: connectionEventHandler
**
** Description: Receive card-emulation related events from stack.
** event: Event code.
** eventData: Event data.
**
** Returns: None
**
*******************************************************************************/
void SecureElement::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* /*eventData*/)
{
switch (event)
{
case NFA_CE_UICC_LISTEN_CONFIGURED_EVT:
{
SyncEventGuard guard (mUiccListenEvent);
mUiccListenEvent.notifyOne ();
}
break;
case NFA_CE_ESE_LISTEN_CONFIGURED_EVT:
{
SyncEventGuard guard (mEseListenEvent);
mEseListenEvent.notifyOne ();
}
break;
}
}
/*******************************************************************************
**
** Function: getAtr
**
** Description: GetAtr response from the connected eSE
**
** Returns: Returns True if success
**
*******************************************************************************/
bool SecureElement::getAtr(jint seID, UINT8* recvBuffer, INT32 *recvBufferSize)
{
static const char fn[] = "SecureElement::getAtr";
tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
UINT8 reg_index = 0x01;
ALOGD("%s: enter ;seID=0x%X", fn, seID);
#if (NFC_NXP_ESE == TRUE && NFC_NXP_CHIP_TYPE != PN547C2)
if(!isWiredModeAllowedInRfState())
{
ALOGD("Denying /atr in SE listen mode active");
return false;
}
#endif
{
SyncEventGuard guard (mGetRegisterEvent);
nfaStat = NFA_HciGetRegistry (mNfaHciHandle, mNewPipeId, reg_index);
if(nfaStat == NFA_STATUS_OK)
{
mGetAtrRspwait = true;
mGetRegisterEvent.wait();
ALOGE("%s: Received ATR response on pipe 0x%x ", fn, mNewPipeId);
}
}
*recvBufferSize = mAtrInfolen;
memcpy(recvBuffer, mAtrInfo, mAtrInfolen);
if(mAtrStatus == NFA_HCI_ANY_E_NOK)
reconfigureEseHciInit();
return (nfaStat == NFA_STATUS_OK)?true:false;
}
/*******************************************************************************
**
** Function: routeToSecureElement
**
** Description: Adjust controller's listen-mode routing table so transactions
** are routed to the secure elements.
**
** Returns: True if ok.
**
*******************************************************************************/
bool SecureElement::routeToSecureElement ()
{
static const char fn [] = "SecureElement::routeToSecureElement";
ALOGD ("%s: enter", fn);
tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
// tNFA_TECHNOLOGY_MASK tech_mask = NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B; /*commented to eliminate unused variable warning*/
bool retval = false;
if (! mIsInit)
{
ALOGE ("%s: not init", fn);
return false;
}
if (mCurrentRouteSelection == SecElemRoute)
{
ALOGE ("%s: already sec elem route", fn);
return true;
}
if (mActiveEeHandle == NFA_HANDLE_INVALID)
{
ALOGE ("%s: invalid EE handle", fn);
return false;
}
/* tNFA_EE_INFO* eeinfo = findEeByHandle(mActiveEeHandle);
if(eeinfo!=NULL){
if(eeinfo->la_protocol == 0x00 && eeinfo->lb_protocol != 0x00 )
{
gTypeB_listen = true;
}
}*/
ALOGD ("%s: exit; ok=%u", fn, retval);
return retval;
}
/*******************************************************************************
**
** Function: isBusy
**
** Description: Whether controller is routing listen-mode events to
** secure elements or a pipe is connected.
**
** Returns: True if either case is true.
**
*******************************************************************************/
bool SecureElement::isBusy ()
{
bool retval = mIsPiping ;
ALOGD ("SecureElement::isBusy: %u", retval);
return retval;
}
jint SecureElement::getGenericEseId(tNFA_HANDLE handle)
{
jint ret = 0xFF;
//Map the actual handle to generic id
if(handle == (EE_HANDLE_0xF3 & ~NFA_HANDLE_GROUP_EE) ) //ESE - 0xC0
{
ret = ESE_ID;
}
else if(handle == (EE_HANDLE_0xF4 & ~NFA_HANDLE_GROUP_EE) ) //UICC - 0x02
{
ret = UICC_ID;
}
return ret;
}
tNFA_HANDLE SecureElement::getEseHandleFromGenericId(jint eseId)
{
UINT16 handle = NFA_HANDLE_INVALID;
//Map the generic id to actual handle
if(eseId == ESE_ID) //ESE
{
handle = EE_HANDLE_0xF3; //0x4C0;
}
else if(eseId == UICC_ID) //UICC
{
handle = EE_HANDLE_0xF4; //0x402;
}
else if(eseId == DH_ID) //Host
{
handle = NFA_EE_HANDLE_DH; //0x400;
}
else if(eseId == EE_HANDLE_0xF3 || eseId == EE_HANDLE_0xF4)
{
handle = eseId;
}
return handle;
}
bool SecureElement::SecEle_Modeset(UINT8 type)
{
tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
bool retval = true;
ALOGD ("set EE mode = 0x%X", type);
if ((nfaStat = SecElem_EeModeSet (0x4C0, type)) == NFA_STATUS_OK)
{
#if 0
if (eeItem.ee_status == NFC_NFCEE_STATUS_INACTIVE)
{
ALOGE ("NFA_EeModeSet enable or disable success; status=0x%X", nfaStat);
retval = true;
}
#endif
}
else
{
retval = false;
ALOGE ("NFA_EeModeSet failed; error=0x%X",nfaStat);
}
return retval;
}
/*******************************************************************************
**
** Function: getEeHandleList
**
** Description: Get default Secure Element handle.
** isHCEEnabled: whether host routing is enabled or not.
**
** Returns: Returns Secure Element handle.
**
*******************************************************************************/
void SecureElement::getEeHandleList(tNFA_HANDLE *list, UINT8* count)
{
tNFA_HANDLE handle;
int i;
static const char fn [] = "SecureElement::getEeHandleList";
*count = 0;
for ( i = 0; i < mActualNumEe; i++)
{
ALOGD ("%s: %u = 0x%X", fn, i, mEeInfo[i].ee_handle);
if ((mEeInfo[i].ee_handle == 0x401) || (mEeInfo[i].num_interface == 0) || (mEeInfo[i].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) ||
(mEeInfo[i].ee_status == NFC_NFCEE_STATUS_INACTIVE))
{
continue;
}
handle = mEeInfo[i].ee_handle & ~NFA_HANDLE_GROUP_EE;
list[*count] = handle;
*count = *count + 1 ;
ALOGD ("%s: Handle %u = 0x%X", fn, i, handle);
}
}
bool SecureElement::sendEvent(UINT8 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;
}
#if((NFC_NXP_ESE == TRUE)&&(NXP_EXTNS == TRUE))
/*******************************************************************************
**
** Function NfccStandByTimerOperation
**
** Description start/stops the standby timer
**
** Returns void
**
*******************************************************************************/
void SecureElement::NfccStandByOperation(nfcc_standby_operation_t value)
{
static IntervalTimer mNFCCStandbyModeTimer; // timer to enable standby mode for NFCC
ALOGD("In SecureElement::NfccStandByOperation value = %d", value);
switch(value)
{
case STANDBY_TIMER_START:
if(nfccStandbytimeout > 0)
{
mNFCCStandbyModeTimer.set(nfccStandbytimeout , NFCC_StandbyModeTimerCallBack );
}
break;
case STANDBY_TIMER_STOP:
{
if(nfccStandbytimeout > 0)
mNFCCStandbyModeTimer.kill();
}
break;
case STANDBY_TIMER_TIMEOUT:
{
bool stat = false;
//Send the EVT_END_OF_APDU_TRANSFER after the transceive timer timed out
stat = SecureElement::getInstance().sendEvent(SecureElement::EVT_END_OF_APDU_TRANSFER);
if(stat)
{
ALOGD ("%s sending standby mode command successful", __FUNCTION__);
}
}
break;
case STANDBY_GPIO_HIGH:
{
jint ret_val = -1;
NFCSTATUS status = NFCSTATUS_FAILED;
/* Set the ESE VDD gpio to high to make sure P61 is powered, even if NFCC
* is in standby
*/
ret_val = NFC_EnableWired ((void *)&status);
if (ret_val < 0)
{
ALOGD("NFC_EnableWired failed");
}
else
{
if (status != NFCSTATUS_SUCCESS)
{
ALOGD("SE is being used by SPI");
}
}
}
break;
case STANDBY_GPIO_LOW:
{
jint ret_val = -1;
NFCSTATUS status = NFCSTATUS_FAILED;
/* Set the ESE VDD gpio to low to make sure P61 is reset. */
ret_val = NFC_DisableWired ((void *)&status);
if (ret_val < 0)
{
ALOGD("NFC_DisableWired failed");
}
else
{
if (status != NFCSTATUS_SUCCESS)
{
ALOGD("SE is not being released by Pn54x driver");
}
}
}
break;
default:
ALOGE("Wrong param");
break;
}
}
#endif
/*******************************************************************************
**
** Function: reconfigureEseHciInit
**
** Description: Reinitialize the HCI network for SecureElement
**
** Returns: Returns Status SUCCESS or FAILED.
**
*******************************************************************************/
tNFA_STATUS SecureElement::reconfigureEseHciInit()
{
static const char fn[] = "reconfigureEseHciInit";
tNFA_STATUS status = NFA_STATUS_FAILED;
if (isActivatedInListenMode()) {
ALOGD("Denying HCI re-initialization due to SE listen mode active");
return status;
}
if (isRfFieldOn()) {
ALOGD("Denying HCI re-initialization due to SE in active RF field");
return status;
}
if(android::isDiscoveryStarted() == true)
{
android::startRfDiscovery(false);
}
status = android::ResetEseSession();
if(status == NFA_STATUS_OK)
{
SecEle_Modeset(0x00);
usleep(100 * 1000);
SecEle_Modeset(0x01);
usleep(300 * 1000);
}
android::startRfDiscovery(true);
return status;
}
#if (NFC_NXP_ESE == TRUE && NFC_NXP_CHIP_TYPE != PN547C2)
bool SecureElement::isWiredModeAllowedInRfState()
{
static const char fn[] = "isWiredModeAllowedInRfState";
bool status = false;
ALOGD("%s; enter", fn);
//mRecvdTransEvt = false; //reset to false before 2.5sec wait
SyncEventGuard guard (mAllowWiredModeEvent);
if(android::isp2pActivated())
{
status = true;
}
else if(isActivatedInListenMode())
{
ALOGD("%s; mAllowWiredMode=%d ",fn, mAllowWiredMode);
if(mAllowWiredMode)
status = true;
else
status = mAllowWiredModeEvent.wait(2500);
}
else if(isRfFieldOn() && (mWiredModeRfFiledEnable != 0x00))
{
status = mAllowWiredModeEvent.wait(2500);
}
else
{
status = true;
}
if(status == false)
{
ALOGD("%s; Timeout occurs: Check for RF_OFF, Link loss and mRecvdTransEvt=%d",fn, mRecvdTransEvt);
if(!isActivatedInListenMode() || !isRfFieldOn() || !mRecvdTransEvt)
status = true;
}
return status;
}
#endif
#if(NFC_NXP_ESE == TRUE && NFC_NXP_CHIP_TYPE == PN548C2)
/*******************************************************************************
**
** Function: etsiInitConfig
**
** Description: Chnage the ETSI state before start configuration
**
** Returns: None
**
*******************************************************************************/
void SecureElement::etsiInitConfig()
{
ALOGD ("%s: Enter", __FUNCTION__);
swp_rdr_req_ntf_info.mMutex.lock();
if((swp_rdr_req_ntf_info.swp_rd_state == STATE_SE_RDR_MODE_START_CONFIG) &&
((swp_rdr_req_ntf_info.swp_rd_req_info.tech_mask & NFA_TECHNOLOGY_MASK_A) ||
(swp_rdr_req_ntf_info.swp_rd_req_info.tech_mask & NFA_TECHNOLOGY_MASK_B)))
{
if((swp_rdr_req_ntf_info.swp_rd_req_info.tech_mask & NFA_TECHNOLOGY_MASK_A))
{
swp_rdr_req_ntf_info.swp_rd_req_current_info.tech_mask |= NFA_TECHNOLOGY_MASK_A;
}
if((swp_rdr_req_ntf_info.swp_rd_req_info.tech_mask & NFA_TECHNOLOGY_MASK_B))
{
swp_rdr_req_ntf_info.swp_rd_req_current_info.tech_mask |= NFA_TECHNOLOGY_MASK_B;
}
swp_rdr_req_ntf_info.swp_rd_req_current_info.src = swp_rdr_req_ntf_info.swp_rd_req_info.src;
swp_rdr_req_ntf_info.swp_rd_state = STATE_SE_RDR_MODE_START_IN_PROGRESS;
ALOGD ("%s: new ETSI state : STATE_SE_RDR_MODE_START_IN_PROGRESS", __FUNCTION__);
}
else if((swp_rdr_req_ntf_info.swp_rd_state == STATE_SE_RDR_MODE_STOP_CONFIG) &&
(swp_rdr_req_ntf_info.swp_rd_req_current_info.src == swp_rdr_req_ntf_info.swp_rd_req_info.src))
{
android::set_transcation_stat(false);
swp_rdr_req_ntf_info.swp_rd_state = STATE_SE_RDR_MODE_STOP_IN_PROGRESS;
ALOGD ("%s: new ETSI state : STATE_SE_RDR_MODE_STOP_IN_PROGRESS", __FUNCTION__);
}
swp_rdr_req_ntf_info.mMutex.unlock();
}
/*******************************************************************************
**
** Function: etsiReaderConfig
**
** Description: Configuring to Emvco Profile
**
** Returns: Status
**
*******************************************************************************/
tNFC_STATUS SecureElement::etsiReaderConfig(int eeHandle)
{
tNFC_STATUS status;
ALOGD ("%s: Enter", __FUNCTION__);
ALOGD ("%s: eeHandle : 0x%4x", __FUNCTION__,eeHandle);
/* Setting up the emvco poll profile*/
status = android::EmvCo_dosetPoll(true);
if (status != NFA_STATUS_OK)
{
ALOGE ("%s: fail enable polling; error=0x%X", __FUNCTION__, status);
}
ALOGD ("%s: NFA_RD_SWP_READER_REQUESTED EE_HANDLE_0xF4 %x", __FUNCTION__, EE_HANDLE_0xF4);
ALOGD ("%s: NFA_RD_SWP_READER_REQUESTED EE_HANDLE_0xF3 %x", __FUNCTION__, EE_HANDLE_0xF3);
if(eeHandle == EE_HANDLE_0xF4) //UICC
{
SyncEventGuard guard (mDiscMapEvent);
ALOGD ("%s: mapping intf for UICC", __FUNCTION__);
status = NFC_DiscoveryMap (NFC_SWP_RD_NUM_INTERFACE_MAP,(tNCI_DISCOVER_MAPS *)nfc_interface_mapping_uicc
,SecureElement::discovery_map_cb);
if (status != NFA_STATUS_OK)
{
ALOGE ("%s: fail intf mapping for UICC; error=0x%X", __FUNCTION__, status);
return status;
}
mDiscMapEvent.wait ();
}
else if(eeHandle == EE_HANDLE_0xF3) //ESE
{
SyncEventGuard guard (mDiscMapEvent);
ALOGD ("%s: mapping intf for ESE", __FUNCTION__);
status = NFC_DiscoveryMap (NFC_SWP_RD_NUM_INTERFACE_MAP,(tNCI_DISCOVER_MAPS *)nfc_interface_mapping_ese
,SecureElement::discovery_map_cb);
if (status != NFA_STATUS_OK)
{
ALOGE ("%s: fail intf mapping for ESE; error=0x%X", __FUNCTION__, status);
return status;
}
mDiscMapEvent.wait ();
}
else
{
ALOGD ("%s: UNKNOWN SOURCE!!! ", __FUNCTION__);
return NFA_STATUS_FAILED;
}
return NFA_STATUS_OK;
}
/*******************************************************************************
**
** Function: etsiResetReaderConfig
**
** Description: Configuring from Emvco profile to Nfc forum profile
**
** Returns: Status
**
*******************************************************************************/
tNFC_STATUS SecureElement::etsiResetReaderConfig()
{
tNFC_STATUS status;
ALOGD ("%s: Enter", __FUNCTION__);
status = android::EmvCo_dosetPoll(false);
if (status != NFA_STATUS_OK)
{
ALOGE ("%s: fail enable polling; error=0x%X", __FUNCTION__, status);
}
{
SyncEventGuard guard (mDiscMapEvent);
ALOGD ("%s: mapping intf for DH", __FUNCTION__);
status = NFC_DiscoveryMap (NFC_NUM_INTERFACE_MAP,(tNCI_DISCOVER_MAPS *) nfc_interface_mapping_default
,SecureElement::discovery_map_cb);
if (status != NFA_STATUS_OK)
{
ALOGE ("%s: fail intf mapping for ESE; error=0x%X", __FUNCTION__, status);
return status;
}
mDiscMapEvent.wait ();
return NFA_STATUS_OK;
}
}
#endif
int SecureElement::decodeBerTlvLength(UINT8* data,int index, int data_length )
{
int decoded_length = -1;
int length = 0;
int temp = data[index] & 0xff;
int temp_len = 0;
ALOGD("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) {
ALOGE("Invalid TLV length encoding!");
goto TheEnd;
}
if (data_length < length + index) {
ALOGE("Not enough data provided!");
goto TheEnd;
}
} else {
ALOGE("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 {
ALOGE("Index out of range! [0..[%d" , data_length);
goto TheEnd;
}
index += 2;
if (length < 0x100) {
ALOGE("Invalid TLV length encoding!");
goto TheEnd;
}
if (data_length < length + index) {
ALOGE("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 {
ALOGE("Index out of range! [0..[%d", data_length);
goto TheEnd;
}
index += 3;
if (length < 0x10000) {
ALOGE("Invalid TLV length encoding!");
goto TheEnd;
}
if (data_length < length + index) {
ALOGE("Not enough data provided!");
goto TheEnd;
}
decoded_length = length;
} else {
ALOGE("Unsupported TLV length encoding!");
}
TheEnd:
ALOGD("decoded_length = %d", decoded_length);
return decoded_length;
}
#if((NFC_NXP_ESE == TRUE)&&(NXP_EXTNS == TRUE))
void spi_prio_signal_handler (int signum, siginfo_t *info, void *unused)
{
ALOGD ("%s: Inside the Signal Handler %d\n", __FUNCTION__, SIG_NFC);
if (signum == SIG_NFC)
{
ALOGD ("%s: Signal is SIG_NFC\n", __FUNCTION__);
if(info->si_int & P61_STATE_SPI_PRIO)
{
ALOGD ("%s: SPI PRIO request Signal....=%d\n", __FUNCTION__);
hold_the_transceive = true;
setSPIState(true);
}
else if(info->si_int & P61_STATE_SPI_PRIO_END)
{
ALOGD ("%s: SPI PRIO End Signal\n", __FUNCTION__);
hold_the_transceive = false;
SyncEventGuard guard (sSPIPrioSessionEndEvent);
sSPIPrioSessionEndEvent.notifyOne ();
}
else if(info->si_int & P61_STATE_SPI)
{
ALOGD ("%s: SPI OPEN request Signal....=%d\n", __FUNCTION__);
setSPIState(true);
}
else if(info->si_int & P61_STATE_SPI_END)
{
ALOGD ("%s: SPI End Signal\n", __FUNCTION__);
hold_the_transceive = false;
setSPIState(false);
}
}
}
#endif
#if((NFC_NXP_ESE == TRUE)&&(NXP_EXTNS == TRUE))
/*******************************************************************************
**
** Function: setCPTimeout
**
** Description: sets the CP timeout for SE -P61 if its present.
**
**
** Returns: void.
**
*******************************************************************************/
void SecureElement::setCPTimeout()
{
tNFA_HANDLE handle;
tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
UINT8 received_getatr[32];
UINT8 selectISD[]= {0x00,0xa4,0x04,0x00,0x08,0xA0,0x00,0x00,0x01,0x51,0x00,0x00,0x00,0x00};
UINT8 received_selectISD[64];
UINT8 setCPTimeoutcmdbuff[]= {0x80,0xDC,0x00,0x00,0x08,0xEF,0x06,0xA0,0x04,0x84,0x02,0x00,0x00};
UINT8 CPTimeoutvalue[2]= {0x00,0x00};
UINT8 received_setCPTimeout[32];
int i;
bool found =false;
long retlen = 0;
INT32 timeout =12000;
INT32 sSendlength;
INT32 recvBufferActualSize = 0;
static const char fn [] = "SecureElement::setCPTimeout";
for ( i = 0; i < mActualNumEe; i++)
{
if (mEeInfo[i].ee_handle == 0x4C0)
{
nfaStat = NFA_STATUS_OK;
handle = mEeInfo[i].ee_handle & ~NFA_HANDLE_GROUP_EE;
ALOGD ("%s: %u = 0x%X", fn, i, mEeInfo[i].ee_handle);
break;
}
}
if(nfaStat == NFA_STATUS_OK)
{
if (GetNxpByteArrayValue(NAME_NXP_CP_TIMEOUT,(char *) CPTimeoutvalue,
sizeof(CPTimeoutvalue), &retlen))
{
ALOGD ("%s: READ NAME_CP_TIMEOUT Value", __FUNCTION__);
memcpy((setCPTimeoutcmdbuff+(sizeof(setCPTimeoutcmdbuff)-2)),CPTimeoutvalue,2);
found = true;
}
else
{
ALOGD ("%s:CP_TIMEOUT Value not found!!!", __FUNCTION__);
}
if(found)
{
bool stat = false;
stat = SecEle_Modeset(0x01);
if(stat == true)
{
stat = connectEE();
if(stat == true)
{
stat = getAtr(ESE_ID,received_getatr,&recvBufferActualSize);
if(stat == true)
{
/*select card manager*/
stat = transceive(selectISD,(INT32)sizeof(selectISD),received_selectISD,
(int)sizeof(received_selectISD), recvBufferActualSize, timeout);
if(stat == true)
{
/*set timeout value in CP registry*/
transceive(setCPTimeoutcmdbuff,(INT32)sizeof(setCPTimeoutcmdbuff),
received_setCPTimeout, (int)sizeof(received_setCPTimeout), recvBufferActualSize, timeout);
}
}
}
}
sendEvent(SecureElement::EVT_END_OF_APDU_TRANSFER);
disconnectEE(ESE_ID);
}
}
}
#endif
#if(NXP_EXTNS == TRUE)
/*******************************************************************************
**
** Function: setSPIState
**
** Description: Update current SPI state based on Signals
**
** Returns: None .
**
*******************************************************************************/
static void setSPIState(bool mState)
{
ALOGD ("%s: Enter setSPIState \n", __FUNCTION__);
/*Check if the state is already dual mode*/
bool inDualModeAlready = (dual_mode_current_state == SPI_DWPCL_BOTH_ACTIVE);
if(mState)
{
dual_mode_current_state |= SPI_ON;
}
else
{
if(dual_mode_current_state & SPI_ON)
{
dual_mode_current_state ^= SPI_ON;
if(inDualModeAlready)
{
SyncEventGuard guard (mDualModeEvent);
mDualModeEvent.notifyOne();
}
}
}
ALOGD ("%s: Exit setSPIState = %d\n", __FUNCTION__, dual_mode_current_state);
}
/*******************************************************************************
**
** 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;
ALOGD("%s:Enter mode = %d", __FUNCTION__, mode);
#if((NFC_NXP_ESE == TRUE))
if((mode == NFA_EE_MD_DEACTIVATE)&&(active_ese_reset_control&(TRANS_WIRED_ONGOING|TRANS_CL_ONGOING)))
{
active_ese_reset_control |= RESET_BLOCKED;
SyncEventGuard guard (sSecElem.mResetEvent);
sSecElem.mResetEvent.wait();
}
#endif
SyncEventGuard guard (sSecElem.mEeSetModeEvent);
stat = NFA_EeModeSet(handle, mode);
if(stat == NFA_STATUS_OK)
{
sSecElem.mEeSetModeEvent.wait ();
}
#if((NFC_NXP_ESE == TRUE))
if((active_ese_reset_control&RESET_BLOCKED))
{
SyncEventGuard guard (sSecElem.mResetOngoingEvent);
sSecElem.mResetOngoingEvent.notifyOne();
}
#endif
return stat;
}
#endif