blob: f87e80cc7e12218e810c4ee34be3a09558e76707 [file] [log] [blame]
/******************************************************************************
*
* Copyright 2018-2020 NXP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include "eSEClient.h"
#include <IChannel.h>
#include <JcDnld.h>
#include <LsClient.h>
#include <dirent.h>
#include <ese_config.h>
#include <log/log.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <vendor/nxp/nxpnfc/2.0/INxpNfc.h>
#include "NfcAdaptation.h"
#include "NxpEse.h"
#include "hal_nxpese.h"
#include "phNxpEse_Apdu_Api.h"
#include "phNxpEse_Spm.h"
using android::sp;
using android::hardware::hidl_vec;
using android::hardware::Void;
using vendor::nxp::nxpese::V1_0::implementation::NxpEse;
using vendor::nxp::nxpnfc::V2_0::INxpNfc;
sp<INxpNfc> mHalNxpNfc = nullptr;
void seteSEClientState(uint8_t state);
IChannel_t Ch;
se_extns_entry se_intf;
void* eSEClientUpdate_ThreadHandler(void* data);
void* eSEClientUpdate_Thread(void* data);
void* eSEUpdate_SE_SeqHandler(void* data);
void eSEClientUpdate_Thread();
SESTATUS ESE_ChannelInit(IChannel* ch);
SESTATUS handleJcopOsDownload();
void* LSUpdate_Thread(void* data);
uint8_t performLSUpdate();
SESTATUS initializeEse(phNxpEse_initMode mode, SEDomainID Id);
ese_update_state_t ese_update = ESE_UPDATE_COMPLETED;
SESTATUS eSEUpdate_SeqHandler();
int16_t SE_Open() { return SESTATUS_SUCCESS; }
void SE_Reset() { phNxpEse_coldReset(); }
bool SE_Transmit(uint8_t* xmitBuffer, int32_t xmitBufferSize,
uint8_t* recvBuffer, int32_t recvBufferMaxSize,
int32_t& recvBufferActualSize, int32_t timeoutMillisec) {
phNxpEse_data cmdData;
phNxpEse_data rspData;
cmdData.len = xmitBufferSize;
cmdData.p_data = xmitBuffer;
recvBufferMaxSize++;
timeoutMillisec++;
if (phNxpEse_Transceive(&cmdData, &rspData) != ESESTATUS_SUCCESS) {
ALOGE("%s: Ese Transceive failed", __FUNCTION__);
}
recvBufferActualSize = rspData.len;
if (rspData.p_data != NULL && rspData.len) {
memcpy(&recvBuffer[0], rspData.p_data, rspData.len);
}
ALOGE("%s: size = 0x%x ", __FUNCTION__, recvBufferActualSize);
return true;
}
void SE_JcopDownLoadReset() { phNxpEse_resetJcopUpdate(); }
bool SE_Close(int16_t mHandle) {
if (mHandle != 0)
return true;
else
return false;
}
uint8_t SE_getInterfaceInfo() { return INTF_SE; }
/***************************************************************************
**
** Function: checkEseClientUpdate
**
** Description: Check the initial condition
and interafce for eSE Client update for LS and JCOP download
**
** Returns: SUCCESS of ok
**
*******************************************************************************/
void checkEseClientUpdate() {
ALOGD("%s enter: ", __func__);
checkeSEClientRequired(ESE_INTF_SPI);
se_intf.isJcopUpdateRequired = getJcopUpdateRequired();
se_intf.isLSUpdateRequired = getLsUpdateRequired();
se_intf.sJcopUpdateIntferface = getJcopUpdateIntf();
se_intf.sLsUpdateIntferface = getLsUpdateIntf();
if ((se_intf.isJcopUpdateRequired && se_intf.sJcopUpdateIntferface) ||
(se_intf.isLSUpdateRequired && se_intf.sLsUpdateIntferface))
seteSEClientState(ESE_UPDATE_STARTED);
}
/***************************************************************************
**
** Function: perform_eSEClientUpdate
**
** Description: Perform LS and JCOP download during hal service init
**
** Returns: SUCCESS / SESTATUS_FAILED
**
*******************************************************************************/
SESTATUS perform_eSEClientUpdate() {
ALOGD("%s enter: ", __func__);
eSEClientUpdate_Thread();
return SESTATUS_SUCCESS;
}
SESTATUS ESE_ChannelInit(IChannel* ch) {
ch->open = SE_Open;
ch->close = SE_Close;
ch->transceive = SE_Transmit;
ch->transceiveRaw = SE_Transmit;
ch->doeSE_Reset = SE_Reset;
ch->doeSE_JcopDownLoadReset = SE_JcopDownLoadReset;
ch->getInterfaceInfo = SE_getInterfaceInfo;
return SESTATUS_SUCCESS;
}
/*******************************************************************************
**
** Function: eSEClientUpdate_Thread
**
** Description: Perform eSE update
**
** Returns: SUCCESS of ok
**
*******************************************************************************/
void eSEClientUpdate_Thread() {
SESTATUS status = SESTATUS_FAILED;
pthread_t thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (pthread_create(&thread, &attr, &eSEClientUpdate_ThreadHandler, NULL) !=
0) {
ALOGD("Thread creation failed");
status = SESTATUS_FAILED;
} else {
status = SESTATUS_SUCCESS;
ALOGD("Thread creation success");
}
pthread_attr_destroy(&attr);
}
/*******************************************************************************
**
** Function: eSEClientUpdate_Thread
**
** Description: Perform eSE update
**
** Returns: SUCCESS of ok
**
*******************************************************************************/
void eSEClientUpdate_SE_Thread() {
SESTATUS status = SESTATUS_FAILED;
pthread_t thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (pthread_create(&thread, &attr, &eSEUpdate_SE_SeqHandler, NULL) != 0) {
ALOGD("Thread creation failed");
status = SESTATUS_FAILED;
} else {
status = SESTATUS_SUCCESS;
ALOGD("Thread creation success");
}
pthread_attr_destroy(&attr);
}
/*******************************************************************************
**
** Function: eSEClientUpdate_ThreadHandler
**
** Description: Perform JCOP Download
**
** Returns: SUCCESS of ok
**
*******************************************************************************/
void* eSEUpdate_SE_SeqHandler(void* data) {
(void)data;
ALOGD("%s Enter\n", __func__);
eSEUpdate_SeqHandler();
ALOGD("%s Exit eSEUpdate_SE_SeqHandler\n", __func__);
return NULL;
}
/*******************************************************************************
**
** Function: eSEClientUpdate_ThreadHandler
**
** Description: Perform JCOP Download
**
** Returns: SUCCESS of ok
**
*******************************************************************************/
void* eSEClientUpdate_ThreadHandler(void* data) {
(void)data;
int cnt = 0;
ALOGD("%s Enter\n", __func__);
while (((mHalNxpNfc == nullptr) && (cnt < 3))) {
mHalNxpNfc = INxpNfc::tryGetService();
if (mHalNxpNfc == nullptr) ALOGD(": Failed to retrieve the NXP NFC HAL!");
if (mHalNxpNfc != nullptr) {
ALOGD("INxpNfc::getService() returned %p (%s)", mHalNxpNfc.get(),
(mHalNxpNfc->isRemote() ? "remote" : "local"));
}
usleep(100 * 1000);
cnt++;
}
if (mHalNxpNfc != nullptr) {
if (!se_intf.isJcopUpdateRequired && mHalNxpNfc->isJcopUpdateRequired()) {
se_intf.isJcopUpdateRequired = true;
ALOGD(" se_intf.isJcopUpdateRequired = %d", se_intf.isJcopUpdateRequired);
}
if (!se_intf.isLSUpdateRequired && mHalNxpNfc->isLsUpdateRequired()) {
se_intf.isLSUpdateRequired = true;
ALOGD("se_intf.isLSUpdateRequired = %d", se_intf.isLSUpdateRequired);
}
}
if (se_intf.isJcopUpdateRequired) {
if (se_intf.sJcopUpdateIntferface == ESE_INTF_NFC) {
seteSEClientState(ESE_JCOP_UPDATE_REQUIRED);
return NULL;
} else if (se_intf.sJcopUpdateIntferface == ESE_INTF_SPI) {
seteSEClientState(ESE_JCOP_UPDATE_REQUIRED);
}
}
if ((ESE_JCOP_UPDATE_REQUIRED != ese_update) &&
(se_intf.isLSUpdateRequired)) {
if (se_intf.sLsUpdateIntferface == ESE_INTF_NFC) {
seteSEClientState(ESE_LS_UPDATE_REQUIRED);
return NULL;
} else if (se_intf.sLsUpdateIntferface == ESE_INTF_SPI) {
seteSEClientState(ESE_LS_UPDATE_REQUIRED);
}
}
if ((ese_update == ESE_JCOP_UPDATE_REQUIRED) ||
(ese_update == ESE_LS_UPDATE_REQUIRED))
eSEUpdate_SeqHandler();
ALOGD("%s Exit eSEClientUpdate_Thread\n", __func__);
return NULL;
}
/*******************************************************************************
**
** Function: handleJcopOsDownload
**
** Description: Perform JCOP update
**
** Returns: SUCCESS of ok
**
*******************************************************************************/
SESTATUS handleJcopOsDownload() {
SESTATUS status = SESTATUS_FAILED;
uint8_t retstat;
status = initializeEse(ESE_MODE_OSU, ESE);
if (status == SESTATUS_SUCCESS) {
retstat = JCDNLD_Init(&Ch);
if (retstat != STATUS_SUCCESS) {
ALOGE("%s: JCDND initialization failed", __FUNCTION__);
if (phNxpEse_ResetEndPoint_Cntxt(0) != ESESTATUS_SUCCESS) {
ALOGE("%s: Reset SE EndPoint failed", __FUNCTION__);
}
phNxpEse_close(ESESTATUS_SUCCESS);
return status;
} else {
retstat = JCDNLD_StartDownload();
if (retstat != SESTATUS_SUCCESS) {
ALOGE("%s: JCDNLD_StartDownload failed", __FUNCTION__);
}
}
JCDNLD_DeInit();
if (phNxpEse_ResetEndPoint_Cntxt(0) != ESESTATUS_SUCCESS) {
ALOGE("%s: Reset SE EndPoint failed", __FUNCTION__);
}
phNxpEse_close(ESESTATUS_SUCCESS);
}
status = SESTATUS_SUCCESS;
return status;
}
/*******************************************************************************
**
** Function: performLSUpdate
**
** Description: Perform LS update
**
** Returns: SUCCESS of ok
**
*******************************************************************************/
uint8_t performLSUpdate() {
const char* SEterminal = "eSEx";
bool ret = false;
char terminalID[5];
uint8_t status = SESTATUS_FAILED;
bool isSEPresent = false;
bool isVISOPresent = false;
ret = geteSETerminalId(terminalID);
ALOGI("performLSUpdate Terminal val = %s", terminalID);
if ((ret) && (strncmp(SEterminal, terminalID, 3) == 0)) {
isSEPresent = true;
}
ret = geteUICCTerminalId(terminalID);
if ((ret) && (strncmp(SEterminal, terminalID, 3) == 0)) {
isVISOPresent = true;
}
seteSEClientState(ESE_UPDATE_STARTED);
if (isSEPresent) {
ALOGE("%s:On eSE domain ", __FUNCTION__);
status = initializeEse(ESE_MODE_NORMAL, ESE);
ALOGE("%s:On eSE domain ", __FUNCTION__);
if (status == SESTATUS_SUCCESS) {
status = performLSDownload(&Ch);
if (phNxpEse_ResetEndPoint_Cntxt(ESE) != ESESTATUS_SUCCESS) {
ALOGE("%s: Reset SE EndPoint failed", __FUNCTION__);
}
}
phNxpEse_close(ESESTATUS_SUCCESS);
}
if (isVISOPresent) {
ALOGE("%s:On eUICC domain ", __FUNCTION__);
status = initializeEse(ESE_MODE_NORMAL, EUICC);
if (status == SESTATUS_SUCCESS) {
status = performLSDownload(&Ch);
if (phNxpEse_ResetEndPoint_Cntxt(EUICC) != ESESTATUS_SUCCESS) {
ALOGE("%s: Reset SE EndPoint failed", __FUNCTION__);
}
}
phNxpEse_close(ESESTATUS_SUCCESS);
}
return status;
}
/*******************************************************************************
**
** Function: initializeEse
**
** Description: Open & Initialize libese
**
** Returns: SUCCESS of ok
**
*******************************************************************************/
SESTATUS initializeEse(phNxpEse_initMode mode, SEDomainID Id) {
uint8_t retstat;
SESTATUS status = SESTATUS_FAILED;
phNxpEse_initParams initParams;
memset(&initParams, 0x00, sizeof(phNxpEse_initParams));
initParams.initMode = mode;
ALOGE("%s: Mode = %d", __FUNCTION__, mode);
retstat = phNxpEse_open(initParams);
if (retstat != ESESTATUS_SUCCESS) {
return status;
}
retstat = phNxpEse_SetEndPoint_Cntxt(Id);
if (retstat != ESESTATUS_SUCCESS) {
ALOGE("%s: Set SE EndPoint failed", __FUNCTION__);
}
retstat = phNxpEse_init(initParams);
if (retstat != ESESTATUS_SUCCESS) {
if (phNxpEse_ResetEndPoint_Cntxt(Id) != ESESTATUS_SUCCESS) {
ALOGE("%s: Reset SE EndPoint failed", __FUNCTION__);
}
phNxpEse_close(ESESTATUS_SUCCESS);
return status;
}
ESE_ChannelInit(&Ch);
status = SESTATUS_SUCCESS;
return status;
}
/*******************************************************************************
**
** Function: seteSEClientState
**
** Description: Function to set the eSEUpdate state
**
** Returns: SUCCESS of ok
**
*******************************************************************************/
void seteSEClientState(uint8_t state) {
ALOGE("%s: State = %d", __FUNCTION__, state);
ese_update = (ese_update_state_t)state;
}
/*******************************************************************************
**
** Function: sendeSEUpdateState
**
** Description: Notify NFC HAL LS / JCOP download state
**
** Returns: SUCCESS of ok
**
*******************************************************************************/
void sendeSEUpdateState(uint8_t state) {
ALOGE("%s: State = %d", __FUNCTION__, state);
phNxpEse_SPM_SetEseClientUpdateState(state);
}
/*******************************************************************************
**
** Function: eSEUpdate_SeqHandler
**
** Description: ESE client update handler
**
** Returns: SUCCESS of ok
**
*******************************************************************************/
SESTATUS eSEUpdate_SeqHandler() {
switch (ese_update) {
case ESE_UPDATE_STARTED:
break;
case ESE_JCOP_UPDATE_REQUIRED:
ALOGE("%s: ESE_JCOP_UPDATE_REQUIRED", __FUNCTION__);
if (se_intf.isJcopUpdateRequired) {
if (se_intf.sJcopUpdateIntferface == ESE_INTF_SPI) {
handleJcopOsDownload();
sendeSEUpdateState(ESE_JCOP_UPDATE_COMPLETED);
setJcopUpdateRequired(false);
} else if (se_intf.sJcopUpdateIntferface == ESE_INTF_NFC) {
return SESTATUS_SUCCESS;
}
}
[[fallthrough]];
case ESE_JCOP_UPDATE_COMPLETED:
ALOGE("%s: ESE_JCOP_UPDATE_COMPLETED", __FUNCTION__);
[[fallthrough]];
case ESE_LS_UPDATE_REQUIRED:
if (se_intf.isLSUpdateRequired) {
if (se_intf.sLsUpdateIntferface == ESE_INTF_SPI) {
performLSUpdate();
sendeSEUpdateState(ESE_LS_UPDATE_COMPLETED);
setLsUpdateRequired(false);
} else if (se_intf.sLsUpdateIntferface == ESE_INTF_NFC) {
seteSEClientState(ESE_LS_UPDATE_REQUIRED);
return SESTATUS_SUCCESS;
}
}
ALOGE("%s: ESE_LS_UPDATE_REQUIRED", __FUNCTION__);
[[fallthrough]];
case ESE_LS_UPDATE_COMPLETED:
ALOGE("%s: ESE_LS_UPDATE_COMPLETED", __FUNCTION__);
[[fallthrough]];
case ESE_UPDATE_COMPLETED:
seteSEClientState(ESE_UPDATE_COMPLETED);
sendeSEUpdateState(ESE_UPDATE_COMPLETED);
NxpEse::initSEService();
NxpEse::initVIrtualISOService();
ALOGE("%s: ESE_UPDATE_COMPLETED", __FUNCTION__);
break;
}
return SESTATUS_SUCCESS;
}