/******************************************************************************
*
* Copyright 2018 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.
*
******************************************************************************/
#define LOG_TAG "NxpEseHal"
#include <log/log.h>
#include <phNxpEseProto7816_3.h>
extern bool ese_debug_enabled;
/******************************************************************************
\section Introduction Introduction
* This module provide the 7816-3 protocol level implementation for ESE
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_ResetProtoParams(void);
static ESESTATUS phNxpEseProto7816_SendRawFrame(uint32_t data_len,
uint8_t* p_data);
static ESESTATUS phNxpEseProto7816_GetRawFrame(uint32_t* data_len,
uint8_t** pp_data);
static uint8_t phNxpEseProto7816_ComputeLRC(unsigned char* p_buff,
uint32_t offset, uint32_t length);
static ESESTATUS phNxpEseProto7816_CheckLRC(uint32_t data_len, uint8_t* p_data);
static ESESTATUS phNxpEseProto7816_SendSFrame(sFrameInfo_t sFrameData);
static ESESTATUS phNxpEseProto7816_SendIframe(iFrameInfo_t iFrameData);
static ESESTATUS phNxpEseProto7816_sendRframe(rFrameTypes_t rFrameType);
static ESESTATUS phNxpEseProto7816_SetFirstIframeContxt(void);
static ESESTATUS phNxpEseProto7816_SetNextIframeContxt(void);
static ESESTATUS phNxpEseProro7816_SaveIframeData(uint8_t* p_data,
uint32_t data_len);
static ESESTATUS phNxpEseProto7816_ResetRecovery(void);
static ESESTATUS phNxpEseProto7816_RecoverySteps(void);
static ESESTATUS phNxpEseProto7816_DecodeFrame(uint8_t* p_data,
uint32_t data_len);
static ESESTATUS phNxpEseProto7816_ProcessResponse(void);
static ESESTATUS TransceiveProcess(void);
static ESESTATUS phNxpEseProto7816_RSync(void);
static ESESTATUS phNxpEseProto7816_ResetProtoParams(void);
/******************************************************************************
* Function phNxpEseProto7816_SendRawFrame
*
* Description This internal function is called send the data to ESE
*
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_SendRawFrame(uint32_t data_len,
uint8_t* p_data) {
ESESTATUS status = ESESTATUS_FAILED;
ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__);
status = phNxpEse_WriteFrame(data_len, p_data);
if (ESESTATUS_SUCCESS != status) {
ALOGE("%s Error phNxpEse_WriteFrame\n", __FUNCTION__);
} else {
ALOGD_IF(ese_debug_enabled, "%s phNxpEse_WriteFrame Success \n",
__FUNCTION__);
}
ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__);
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_GetRawFrame
*
* Description This internal function is called read the data from the ESE
*
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_GetRawFrame(uint32_t* data_len,
uint8_t** pp_data) {
ESESTATUS status = ESESTATUS_FAILED;
status = phNxpEse_read(data_len, pp_data);
if (ESESTATUS_SUCCESS != status) {
ALOGE("%s phNxpEse_read failed , status : 0x%x", __FUNCTION__, status);
}
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_ComputeLRC
*
* Description This internal function is called compute the LRC
*
* Returns On success return true or else false.
*
******************************************************************************/
static uint8_t phNxpEseProto7816_ComputeLRC(unsigned char* p_buff,
uint32_t offset, uint32_t length) {
uint32_t LRC = 0, i = 0;
ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__);
for (i = offset; i < length; i++) {
LRC = LRC ^ p_buff[i];
}
ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__);
return (uint8_t)LRC;
}
/******************************************************************************
* Function phNxpEseProto7816_CheckLRC
*
* Description This internal function is called compute and compare the
* received LRC of the received data
*
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_CheckLRC(uint32_t data_len,
uint8_t* p_data) {
ESESTATUS status = ESESTATUS_SUCCESS;
uint8_t calc_crc = 0;
uint8_t recv_crc = 0;
ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__);
recv_crc = p_data[data_len - 1];
/* calculate the CRC after excluding CRC */
calc_crc = phNxpEseProto7816_ComputeLRC(p_data, 1, (data_len - 1));
ALOGD_IF(ese_debug_enabled, "Received LRC:0x%x Calculated LRC:0x%x", recv_crc,
calc_crc);
if (recv_crc != calc_crc) {
status = ESESTATUS_FAILED;
ALOGE("%s LRC failed", __FUNCTION__);
}
ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__);
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_SendSFrame
*
* Description This internal function is called to send S-frame with all
* updated 7816-3 headers
*
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_SendSFrame(sFrameInfo_t sFrameData) {
ESESTATUS status = ESESTATUS_FAILED;
uint32_t frame_len = 0;
uint8_t* p_framebuff = NULL;
uint8_t pcb_byte = 0;
ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__);
sFrameInfo_t sframeData = sFrameData;
/* This update is helpful in-case a R-NACK is transmitted from the MW */
phNxpEseProto7816_3_Var.lastSentNonErrorframeType = SFRAME;
switch (sframeData.sFrameType) {
case RESYNCH_REQ:
frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN);
p_framebuff = (uint8_t*)phNxpEse_memalloc(frame_len * sizeof(uint8_t));
if (NULL == p_framebuff) {
return ESESTATUS_FAILED;
}
p_framebuff[2] = 0;
p_framebuff[3] = 0x00;
pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */
pcb_byte |= PH_PROTO_7816_S_RESYNCH;
break;
case INTF_RESET_REQ:
frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN);
p_framebuff = (uint8_t*)phNxpEse_memalloc(frame_len * sizeof(uint8_t));
if (NULL == p_framebuff) {
return ESESTATUS_FAILED;
}
p_framebuff[2] = 0;
p_framebuff[3] = 0x00;
pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */
pcb_byte |= PH_PROTO_7816_S_RESET;
break;
case PROP_END_APDU_REQ:
frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN);
p_framebuff = (uint8_t*)phNxpEse_memalloc(frame_len * sizeof(uint8_t));
if (NULL == p_framebuff) {
return ESESTATUS_FAILED;
}
p_framebuff[2] = 0;
p_framebuff[3] = 0x00;
pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */
pcb_byte |= PH_PROTO_7816_S_END_OF_APDU;
break;
case WTX_RSP:
frame_len = (PH_PROTO_7816_HEADER_LEN + 1 + PH_PROTO_7816_CRC_LEN);
p_framebuff = (uint8_t*)phNxpEse_memalloc(frame_len * sizeof(uint8_t));
if (NULL == p_framebuff) {
return ESESTATUS_FAILED;
}
p_framebuff[2] = 0x01;
p_framebuff[3] = 0x01;
pcb_byte |= PH_PROTO_7816_S_BLOCK_RSP;
pcb_byte |= PH_PROTO_7816_S_WTX;
break;
default:
ALOGE("Invalid S-block");
break;
}
if (NULL != p_framebuff) {
/* frame the packet */
p_framebuff[0] = 0x00; /* NAD Byte */
p_framebuff[1] = pcb_byte; /* PCB */
p_framebuff[frame_len - 1] =
phNxpEseProto7816_ComputeLRC(p_framebuff, 0, (frame_len - 1));
ALOGD_IF(ese_debug_enabled, "S-Frame PCB: %x\n", p_framebuff[1]);
status = phNxpEseProto7816_SendRawFrame(frame_len, p_framebuff);
phNxpEse_free(p_framebuff);
} else {
ALOGE("Invalid S-block or malloc for s-block failed");
}
ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__);
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_sendRframe
*
* Description This internal function is called to send R-frame with all
* updated 7816-3 headers
*
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_sendRframe(rFrameTypes_t rFrameType) {
ESESTATUS status = ESESTATUS_FAILED;
uint8_t recv_ack[4] = {0x00, 0x80, 0x00, 0x00};
if (RNACK == rFrameType) /* R-NACK */
{
recv_ack[1] = 0x82;
} else /* R-ACK*/
{
/* This update is helpful in-case a R-NACK is transmitted from the MW */
phNxpEseProto7816_3_Var.lastSentNonErrorframeType = RFRAME;
}
recv_ack[1] |=
((phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.seqNo ^ 1)
<< 4);
ALOGD_IF(ese_debug_enabled, "%s recv_ack[1]:0x%x", __FUNCTION__, recv_ack[1]);
recv_ack[3] =
phNxpEseProto7816_ComputeLRC(recv_ack, 0x00, (sizeof(recv_ack) - 1));
status = phNxpEseProto7816_SendRawFrame(sizeof(recv_ack), recv_ack);
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_SendIframe
*
* Description This internal function is called to send I-frame with all
* updated 7816-3 headers
*
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_SendIframe(iFrameInfo_t iFrameData) {
ESESTATUS status = ESESTATUS_FAILED;
uint32_t frame_len = 0;
uint8_t* p_framebuff = NULL;
uint8_t pcb_byte = 0;
ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__);
if (0 == iFrameData.sendDataLen) {
ALOGE("I frame Len is 0, INVALID");
return ESESTATUS_FAILED;
}
/* This update is helpful in-case a R-NACK is transmitted from the MW */
phNxpEseProto7816_3_Var.lastSentNonErrorframeType = IFRAME;
frame_len = (iFrameData.sendDataLen + PH_PROTO_7816_HEADER_LEN +
PH_PROTO_7816_CRC_LEN);
p_framebuff = (uint8_t*)phNxpEse_memalloc(frame_len * sizeof(uint8_t));
if (NULL == p_framebuff) {
ALOGE("Heap allocation failed");
return ESESTATUS_FAILED;
}
/* frame the packet */
p_framebuff[0] = 0x00; /* NAD Byte */
if (iFrameData.isChained) {
/* make B6 (M) bit high */
pcb_byte |= PH_PROTO_7816_CHAINING;
}
/* Update the send seq no */
pcb_byte |=
(phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.seqNo << 6);
/* store the pcb byte */
p_framebuff[1] = pcb_byte;
/* store I frame length */
p_framebuff[2] = iFrameData.sendDataLen;
/* store I frame */
phNxpEse_memcpy(&(p_framebuff[3]), iFrameData.p_data + iFrameData.dataOffset,
iFrameData.sendDataLen);
p_framebuff[frame_len - 1] =
phNxpEseProto7816_ComputeLRC(p_framebuff, 0, (frame_len - 1));
status = phNxpEseProto7816_SendRawFrame(frame_len, p_framebuff);
phNxpEse_free(p_framebuff);
ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__);
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_SetNextIframeContxt
*
* Description This internal function is called to set the context for next
*I-frame.
* Not applicable for the first I-frame of the transceive
*
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_SetFirstIframeContxt(void) {
ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__);
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.dataOffset = 0;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = IFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.seqNo =
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.seqNo ^ 1;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_IFRAME;
if (phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.totalDataLen >
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLen) {
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.isChained = true;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.sendDataLen =
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLen;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.totalDataLen =
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.totalDataLen -
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLen;
} else {
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.sendDataLen =
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.totalDataLen;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.isChained = false;
}
ALOGD_IF(ese_debug_enabled, "I-Frame Data Len: %d Seq. no:%d",
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.sendDataLen,
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.seqNo);
ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__);
return ESESTATUS_SUCCESS;
}
/******************************************************************************
* Function phNxpEseProto7816_SetNextIframeContxt
*
* Description This internal function is called to set the context for next
*I-frame.
* Not applicable for the first I-frame of the transceive
*
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_SetNextIframeContxt(void) {
ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__);
/* Expecting to reach here only after first of chained I-frame is sent and
* before the last chained is sent */
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = IFRAME;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_IFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.seqNo =
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.seqNo ^ 1;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.dataOffset =
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.dataOffset +
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.maxDataLen;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.p_data =
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.p_data;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLen =
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.maxDataLen;
// if chained
if (phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.totalDataLen >
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.maxDataLen) {
ALOGD_IF(ese_debug_enabled, "Process Chained Frame");
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.isChained = true;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.sendDataLen =
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.maxDataLen;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.totalDataLen =
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.totalDataLen -
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.maxDataLen;
} else {
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.isChained = false;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.sendDataLen =
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.totalDataLen;
}
ALOGD_IF(ese_debug_enabled, "I-Frame Data Len: %d",
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.sendDataLen);
ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__);
return ESESTATUS_SUCCESS;
}
/******************************************************************************
* Function phNxpEseProto7816_ResetRecovery
*
* Description This internal function is called to do reset the recovery
*pareameters
*
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProro7816_SaveIframeData(uint8_t* p_data,
uint32_t data_len) {
ESESTATUS status = ESESTATUS_FAILED;
ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__);
ALOGD_IF(ese_debug_enabled, "Data[0]=0x%x len=%d Data[%d]=0x%x", p_data[0],
data_len, data_len - 1, p_data[data_len - 1]);
if (ESESTATUS_SUCCESS != phNxpEse_StoreDatainList(data_len, p_data)) {
ALOGE("%s - Error storing chained data in list", __FUNCTION__);
} else {
status = ESESTATUS_SUCCESS;
}
ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__);
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_ResetRecovery
*
* Description This internal function is called to do reset the recovery
*pareameters
*
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_ResetRecovery(void) {
phNxpEseProto7816_3_Var.recoveryCounter = 0;
return ESESTATUS_SUCCESS;
}
/******************************************************************************
* Function phNxpEseProto7816_RecoverySteps
*
* Description This internal function is called when 7816-3 stack failed to
*recover
* after PH_PROTO_7816_FRAME_RETRY_COUNT, and the interface has
*to be
* recovered
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_RecoverySteps(void) {
if (phNxpEseProto7816_3_Var.recoveryCounter <=
PH_PROTO_7816_FRAME_RETRY_COUNT) {
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType =
INTF_RESET_REQ;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType =
INTF_RESET_REQ;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
SEND_S_INTF_RST;
} else { /* If recovery fails */
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE;
}
return ESESTATUS_SUCCESS;
}
/******************************************************************************
* Function phNxpEseProto7816_DecodeSecureTimer
*
* Description This internal function is to decode the secure timer.
* value from the payload
* Returns void
*
******************************************************************************/
static void phNxpEseProto7816_DecodeSecureTimer(uint8_t* frameOffset,
unsigned int* secureTimer,
uint8_t* p_data) {
uint8_t byteCounter = 0;
uint8_t dataLength = p_data[++(*frameOffset)]; /* To get the L of TLV */
if (dataLength > 0) {
/* V of TLV: Retrieve each byte(4 byte) and push it to get the secure timer
* value (unsigned long) */
for (byteCounter = 1; byteCounter <= dataLength; byteCounter++) {
(*frameOffset)++;
*secureTimer = (*secureTimer) << 8;
*secureTimer |= p_data[(*frameOffset)];
}
} else {
(*frameOffset)++; /* Goto the end of current marker if length is zero */
}
return;
}
/******************************************************************************
* Function phNxpEseProto7816_DecodeSFrameData
*
* Description This internal function is to decode S-frame payload.
* Returns void
*
******************************************************************************/
static void phNxpEseProto7816_DecodeSFrameData(uint8_t* p_data) {
uint8_t maxSframeLen = 0, dataType = 0, frameOffset = 0;
frameOffset = PH_PROPTO_7816_FRAME_LENGTH_OFFSET;
maxSframeLen =
p_data[frameOffset] +
frameOffset; /* to be in sync with offset which starts from index 0 */
while (maxSframeLen > frameOffset) {
frameOffset += 1; /* To get the Type (TLV) */
dataType = p_data[frameOffset];
ALOGD_IF(ese_debug_enabled, "%s frameoffset=%d value=0x%x\n", __FUNCTION__,
frameOffset, p_data[frameOffset]);
switch (dataType) /* Type (TLV) */
{
case PH_PROPTO_7816_SFRAME_TIMER1:
phNxpEseProto7816_DecodeSecureTimer(
&frameOffset,
&phNxpEseProto7816_3_Var.secureTimerParams.secureTimer1, p_data);
break;
case PH_PROPTO_7816_SFRAME_TIMER2:
phNxpEseProto7816_DecodeSecureTimer(
&frameOffset,
&phNxpEseProto7816_3_Var.secureTimerParams.secureTimer2, p_data);
break;
case PH_PROPTO_7816_SFRAME_TIMER3:
phNxpEseProto7816_DecodeSecureTimer(
&frameOffset,
&phNxpEseProto7816_3_Var.secureTimerParams.secureTimer3, p_data);
break;
default:
frameOffset +=
p_data[frameOffset + 1]; /* Goto the end of current marker */
break;
}
}
ALOGD_IF(ese_debug_enabled, "secure timer t1 = 0x%x t2 = 0x%x t3 = 0x%x",
phNxpEseProto7816_3_Var.secureTimerParams.secureTimer1,
phNxpEseProto7816_3_Var.secureTimerParams.secureTimer2,
phNxpEseProto7816_3_Var.secureTimerParams.secureTimer3);
return;
}
/******************************************************************************
* Function phNxpEseProto7816_DecodeFrame
*
* Description This internal function is used to
* 1. Identify the received frame
* 2. If the received frame is I-frame with expected sequence
number, store it or else send R-NACK
3. If the received frame is R-frame,
3.1 R-ACK with expected seq. number: Send the next
chained I-frame
3.2 R-ACK with different sequence number: Sebd the R-Nack
3.3 R-NACK: Re-send the last frame
4. If the received frame is S-frame, send back the correct
S-frame response.
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_DecodeFrame(uint8_t* p_data,
uint32_t data_len) {
ESESTATUS status = ESESTATUS_SUCCESS;
uint8_t pcb;
phNxpEseProto7816_PCB_bits_t pcb_bits;
ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__);
ALOGD_IF(ese_debug_enabled, "Retry Counter = %d\n",
phNxpEseProto7816_3_Var.recoveryCounter);
pcb = p_data[PH_PROPTO_7816_PCB_OFFSET];
// memset(&phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.rcvPcbBits, 0x00,
// sizeof(struct PCB_BITS));
phNxpEse_memset(&pcb_bits, 0x00, sizeof(phNxpEseProto7816_PCB_bits_t));
phNxpEse_memcpy(&pcb_bits, &pcb, sizeof(uint8_t));
if (0x00 == pcb_bits.msb) /* I-FRAME decoded should come here */
{
ALOGD_IF(ese_debug_enabled, "%s I-Frame Received", __FUNCTION__);
phNxpEseProto7816_3_Var.wtx_counter = 0;
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = IFRAME;
if (phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.seqNo !=
pcb_bits.bit7) // != pcb_bits->bit7)
{
ALOGD_IF(ese_debug_enabled, "%s I-Frame lastRcvdIframeInfo.seqNo:0x%x",
__FUNCTION__, pcb_bits.bit7);
phNxpEseProto7816_ResetRecovery();
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.seqNo = 0x00;
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.seqNo |=
pcb_bits.bit7;
if (pcb_bits.bit6) {
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.isChained =
true;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.errCode =
NO_ERROR;
status = phNxpEseProro7816_SaveIframeData(&p_data[3], data_len - 4);
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
SEND_R_ACK;
} else {
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.isChained =
false;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
IDLE_STATE;
status = phNxpEseProro7816_SaveIframeData(&p_data[3], data_len - 4);
}
} else {
phNxpEse_Sleep(DELAY_ERROR_RECOVERY);
if (phNxpEseProto7816_3_Var.recoveryCounter <
PH_PROTO_7816_FRAME_RETRY_COUNT) {
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.errCode =
OTHER_ERROR;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
SEND_R_NACK;
phNxpEseProto7816_3_Var.recoveryCounter++;
} else {
phNxpEseProto7816_RecoverySteps();
phNxpEseProto7816_3_Var.recoveryCounter++;
}
}
} else if ((0x01 == pcb_bits.msb) &&
(0x00 == pcb_bits.bit7)) /* R-FRAME decoded should come here */
{
ALOGD_IF(ese_debug_enabled, "%s R-Frame Received", __FUNCTION__);
phNxpEseProto7816_3_Var.wtx_counter = 0;
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = RFRAME;
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.seqNo =
0; // = 0;
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.seqNo |=
pcb_bits.bit5;
if ((pcb_bits.lsb == 0x00) && (pcb_bits.bit2 == 0x00)) {
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.errCode =
NO_ERROR;
phNxpEseProto7816_ResetRecovery();
if (phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.seqNo !=
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.seqNo) {
status = phNxpEseProto7816_SetNextIframeContxt();
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
SEND_IFRAME;
} else {
// error handling.
}
} /* Error handling 1 : Parity error */
else if (((pcb_bits.lsb == 0x01) && (pcb_bits.bit2 == 0x00)) ||
/* Error handling 2: Other indicated error */
((pcb_bits.lsb == 0x00) && (pcb_bits.bit2 == 0x01))) {
phNxpEse_Sleep(DELAY_ERROR_RECOVERY);
if ((pcb_bits.lsb == 0x00) && (pcb_bits.bit2 == 0x01))
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.errCode =
OTHER_ERROR;
else
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.errCode =
PARITY_ERROR;
if (phNxpEseProto7816_3_Var.recoveryCounter <
PH_PROTO_7816_FRAME_RETRY_COUNT) {
if (phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType == IFRAME) {
phNxpEse_memcpy(&phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx,
&phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx,
sizeof(phNxpEseProto7816_NextTx_Info_t));
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
SEND_IFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = IFRAME;
} else if (phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType ==
RFRAME) {
/* Usecase to reach the below case:
I-frame sent first, followed by R-NACK and we receive a R-NACK with
last sent I-frame sequence number*/
if ((phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo
.seqNo ==
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.seqNo) &&
(phNxpEseProto7816_3_Var.lastSentNonErrorframeType == IFRAME)) {
phNxpEse_memcpy(&phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx,
&phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx,
sizeof(phNxpEseProto7816_NextTx_Info_t));
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
SEND_IFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = IFRAME;
}
/* Usecase to reach the below case:
R-frame sent first, followed by R-NACK and we receive a R-NACK with
next expected I-frame sequence number*/
else if ((phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo
.seqNo != phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx
.IframeInfo.seqNo) &&
(phNxpEseProto7816_3_Var.lastSentNonErrorframeType ==
RFRAME)) {
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.errCode =
NO_ERROR;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
SEND_R_ACK;
}
/* Usecase to reach the below case:
I-frame sent first, followed by R-NACK and we receive a R-NACK with
next expected I-frame sequence number + all the other unexpected
scenarios */
else {
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.errCode =
OTHER_ERROR;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
SEND_R_NACK;
}
} else if (phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType ==
SFRAME) {
/* Copy the last S frame sent */
phNxpEse_memcpy(&phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx,
&phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx,
sizeof(phNxpEseProto7816_NextTx_Info_t));
}
phNxpEseProto7816_3_Var.recoveryCounter++;
} else {
phNxpEseProto7816_RecoverySteps();
phNxpEseProto7816_3_Var.recoveryCounter++;
}
// resend previously send I frame
}
/* Error handling 3 */
else if ((pcb_bits.lsb == 0x01) && (pcb_bits.bit2 == 0x01)) {
phNxpEse_Sleep(DELAY_ERROR_RECOVERY);
if (phNxpEseProto7816_3_Var.recoveryCounter <
PH_PROTO_7816_FRAME_RETRY_COUNT) {
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.errCode =
SOF_MISSED_ERROR;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx =
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx;
phNxpEseProto7816_3_Var.recoveryCounter++;
} else {
phNxpEseProto7816_RecoverySteps();
phNxpEseProto7816_3_Var.recoveryCounter++;
}
} else /* Error handling 4 */
{
phNxpEse_Sleep(DELAY_ERROR_RECOVERY);
if (phNxpEseProto7816_3_Var.recoveryCounter <
PH_PROTO_7816_FRAME_RETRY_COUNT) {
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.errCode =
UNDEFINED_ERROR;
phNxpEseProto7816_3_Var.recoveryCounter++;
} else {
phNxpEseProto7816_RecoverySteps();
phNxpEseProto7816_3_Var.recoveryCounter++;
}
}
} else if ((0x01 == pcb_bits.msb) &&
(0x01 == pcb_bits.bit7)) /* S-FRAME decoded should come here */
{
ALOGD_IF(ese_debug_enabled, "%s S-Frame Received", __FUNCTION__);
int32_t frameType = (int32_t)(pcb & 0x3F); /*discard upper 2 bits */
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = SFRAME;
if (frameType != WTX_REQ) {
phNxpEseProto7816_3_Var.wtx_counter = 0;
}
switch (frameType) {
case RESYNCH_REQ:
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType =
RESYNCH_REQ;
break;
case RESYNCH_RSP:
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType =
RESYNCH_RSP;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
IDLE_STATE;
break;
case IFSC_REQ:
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType =
IFSC_REQ;
break;
case IFSC_RES:
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType =
IFSC_RES;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
IDLE_STATE;
break;
case ABORT_REQ:
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType =
ABORT_REQ;
break;
case ABORT_RES:
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType =
ABORT_RES;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
IDLE_STATE;
break;
case WTX_REQ:
phNxpEseProto7816_3_Var.wtx_counter++;
ALOGD_IF(ese_debug_enabled, "%s Wtx_counter value - %lu", __FUNCTION__,
phNxpEseProto7816_3_Var.wtx_counter);
ALOGD_IF(ese_debug_enabled, "%s Wtx_counter wtx_counter_limit - %lu",
__FUNCTION__, phNxpEseProto7816_3_Var.wtx_counter_limit);
/* Previous sent frame is some S-frame but not WTX response S-frame */
if (phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.SframeInfo.sFrameType !=
WTX_RSP &&
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType ==
SFRAME) { /* Goto recovery if it keep coming here for more than
recovery counter max. value */
if (phNxpEseProto7816_3_Var.recoveryCounter <
PH_PROTO_7816_FRAME_RETRY_COUNT) { /* Re-transmitting the previous
sent S-frame */
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx =
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx;
phNxpEseProto7816_3_Var.recoveryCounter++;
} else {
phNxpEseProto7816_RecoverySteps();
phNxpEseProto7816_3_Var.recoveryCounter++;
}
} else { /* Checking for WTX counter with max. allowed WTX count */
if (phNxpEseProto7816_3_Var.wtx_counter ==
phNxpEseProto7816_3_Var.wtx_counter_limit) {
phNxpEseProto7816_3_Var.wtx_counter = 0;
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo
.sFrameType = INTF_RESET_REQ;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType =
INTF_RESET_REQ;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
SEND_S_INTF_RST;
ALOGE("%s Interface Reset to eSE wtx count reached!!!",
__FUNCTION__);
} else {
phNxpEse_Sleep(DELAY_ERROR_RECOVERY);
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo
.sFrameType = WTX_REQ;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType =
WTX_RSP;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
SEND_S_WTX_RSP;
}
}
break;
case WTX_RSP:
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType =
WTX_RSP;
break;
case INTF_RESET_REQ:
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType =
INTF_RESET_REQ;
break;
case INTF_RESET_RSP:
phNxpEseProto7816_ResetProtoParams();
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType =
INTF_RESET_RSP;
if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0)
phNxpEseProto7816_DecodeSFrameData(p_data);
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
IDLE_STATE;
break;
case PROP_END_APDU_REQ:
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType =
PROP_END_APDU_REQ;
break;
case PROP_END_APDU_RSP:
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType =
PROP_END_APDU_RSP;
if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0)
phNxpEseProto7816_DecodeSFrameData(p_data);
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
IDLE_STATE;
break;
default:
ALOGE("%s Wrong S-Frame Received", __FUNCTION__);
break;
}
} else {
ALOGE("%s Wrong-Frame Received", __FUNCTION__);
}
ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__);
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_ProcessResponse
*
* Description This internal function is used to
* 1. Check the LRC
* 2. Initiate decoding of received frame of data.
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_ProcessResponse(void) {
uint32_t data_len = 0;
uint8_t* p_data = NULL;
ESESTATUS status = ESESTATUS_FAILED;
ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__);
status = phNxpEseProto7816_GetRawFrame(&data_len, &p_data);
ALOGD_IF(ese_debug_enabled, "%s p_data ----> %p len ----> 0x%x", __FUNCTION__,
p_data, data_len);
if (ESESTATUS_SUCCESS == status) {
/* Resetting the timeout counter */
phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO;
/* LRC check followed */
status = phNxpEseProto7816_CheckLRC(data_len, p_data);
if (status == ESESTATUS_SUCCESS) {
/* Resetting the RNACK retry counter */
phNxpEseProto7816_3_Var.rnack_retry_counter = PH_PROTO_7816_VALUE_ZERO;
phNxpEseProto7816_DecodeFrame(p_data, data_len);
} else {
ALOGE("%s LRC Check failed", __FUNCTION__);
if (phNxpEseProto7816_3_Var.rnack_retry_counter <
phNxpEseProto7816_3_Var.rnack_retry_limit) {
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = INVALID;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.errCode =
PARITY_ERROR;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.seqNo =
(!phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.seqNo)
<< 4;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
SEND_R_NACK;
phNxpEseProto7816_3_Var.rnack_retry_counter++;
} else {
phNxpEseProto7816_3_Var.rnack_retry_counter = PH_PROTO_7816_VALUE_ZERO;
/* Re-transmission failed completely, Going to exit */
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
IDLE_STATE;
phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO;
}
}
} else {
ALOGE("%s phNxpEseProto7816_GetRawFrame failed", __FUNCTION__);
if ((SFRAME == phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType) &&
((WTX_RSP ==
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.SframeInfo.sFrameType) ||
(RESYNCH_RSP ==
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.SframeInfo.sFrameType))) {
if (phNxpEseProto7816_3_Var.rnack_retry_counter <
phNxpEseProto7816_3_Var.rnack_retry_limit) {
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = INVALID;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.errCode =
OTHER_ERROR;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.seqNo =
(!phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.seqNo)
<< 4;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
SEND_R_NACK;
phNxpEseProto7816_3_Var.rnack_retry_counter++;
} else {
phNxpEseProto7816_3_Var.rnack_retry_counter = PH_PROTO_7816_VALUE_ZERO;
/* Re-transmission failed completely, Going to exit */
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
IDLE_STATE;
phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO;
}
} else {
phNxpEse_Sleep(DELAY_ERROR_RECOVERY);
/* re transmit the frame */
if (phNxpEseProto7816_3_Var.timeoutCounter <
PH_PROTO_7816_TIMEOUT_RETRY_COUNT) {
phNxpEseProto7816_3_Var.timeoutCounter++;
ALOGE("%s re-transmitting the previous frame", __FUNCTION__);
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx =
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx;
} else {
/* Re-transmission failed completely, Going to exit */
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
IDLE_STATE;
phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO;
ALOGE("%s calling phNxpEse_StoreDatainList", __FUNCTION__);
phNxpEse_StoreDatainList(data_len, p_data);
}
}
}
ALOGD_IF(ese_debug_enabled, "Exit %s Status 0x%x", __FUNCTION__, status);
return status;
}
/******************************************************************************
* Function TransceiveProcess
*
* Description This internal function is used to
* 1. Send the raw data received from application after
*computing LRC
* 2. Receive the the response data from ESE, decode, process
*and
* store the data.
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS TransceiveProcess(void) {
ESESTATUS status = ESESTATUS_FAILED;
sFrameInfo_t sFrameInfo;
ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__);
while (phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState !=
IDLE_STATE) {
ALOGD_IF(ese_debug_enabled, "%s nextTransceiveState %x", __FUNCTION__,
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState);
switch (phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState) {
case SEND_IFRAME:
status = phNxpEseProto7816_SendIframe(
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo);
break;
case SEND_R_ACK:
status = phNxpEseProto7816_sendRframe(RACK);
break;
case SEND_R_NACK:
status = phNxpEseProto7816_sendRframe(RNACK);
break;
case SEND_S_RSYNC:
sFrameInfo.sFrameType = RESYNCH_REQ;
status = phNxpEseProto7816_SendSFrame(sFrameInfo);
break;
case SEND_S_INTF_RST:
sFrameInfo.sFrameType = INTF_RESET_REQ;
status = phNxpEseProto7816_SendSFrame(sFrameInfo);
break;
case SEND_S_EOS:
sFrameInfo.sFrameType = PROP_END_APDU_REQ;
status = phNxpEseProto7816_SendSFrame(sFrameInfo);
break;
case SEND_S_WTX_RSP:
sFrameInfo.sFrameType = WTX_RSP;
status = phNxpEseProto7816_SendSFrame(sFrameInfo);
break;
default:
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
IDLE_STATE;
break;
}
if (ESESTATUS_SUCCESS == status) {
phNxpEse_memcpy(&phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx,
&phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx,
sizeof(phNxpEseProto7816_NextTx_Info_t));
status = phNxpEseProto7816_ProcessResponse();
} else {
ALOGD_IF(ese_debug_enabled,
"%s Transceive send failed, going to recovery!", __FUNCTION__);
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
IDLE_STATE;
}
};
ALOGD_IF(ese_debug_enabled, "Exit %s Status 0x%x", __FUNCTION__, status);
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_Transceive
*
* Description This function is used to
* 1. Send the raw data received from application after
*computing LRC
* 2. Receive the the response data from ESE, decode, process
*and
* store the data.
* 3. Get the final complete data and sent back to application
*
* Returns On success return true or else false.
*
******************************************************************************/
ESESTATUS phNxpEseProto7816_Transceive(phNxpEse_data* pCmd,
phNxpEse_data* pRsp) {
ESESTATUS status = ESESTATUS_FAILED;
ESESTATUS wStatus = ESESTATUS_FAILED;
phNxpEse_data pRes;
ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__);
if ((NULL == pCmd) || (NULL == pRsp) ||
(phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState !=
PH_NXP_ESE_PROTO_7816_IDLE))
return status;
phNxpEse_memset(&pRes, 0x00, sizeof(phNxpEse_data));
/* Updating the transceive information to the protocol stack */
phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState =
PH_NXP_ESE_PROTO_7816_TRANSCEIVE;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.p_data = pCmd->p_data;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.totalDataLen =
pCmd->len;
ALOGD_IF(ese_debug_enabled, "Transceive data ptr 0x%p len:%d", pCmd->p_data,
pCmd->len);
status = phNxpEseProto7816_SetFirstIframeContxt();
status = TransceiveProcess();
if (ESESTATUS_FAILED == status) {
/* ESE hard reset to be done */
ALOGE("Transceive failed, hard reset to proceed");
wStatus = phNxpEse_GetData(&pRes.len, &pRes.p_data);
if (ESESTATUS_SUCCESS == wStatus) {
ALOGE(
"%s Data successfully received at 7816, packaging to "
"send upper layers: DataLen = %d",
__FUNCTION__, pRes.len);
/* Copy the data to be read by the upper layer via transceive api */
pRsp->len = pRes.len;
pRsp->p_data = pRes.p_data;
}
} else {
// fetch the data info and report to upper layer.
wStatus = phNxpEse_GetData(&pRes.len, &pRes.p_data);
if (ESESTATUS_SUCCESS == wStatus) {
ALOGD_IF(ese_debug_enabled,
"%s Data successfully received at 7816, packaging to "
"send upper layers: DataLen = %d",
__FUNCTION__, pRes.len);
/* Copy the data to be read by the upper layer via transceive api */
pRsp->len = pRes.len;
pRsp->p_data = pRes.p_data;
} else
status = ESESTATUS_FAILED;
}
phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState =
PH_NXP_ESE_PROTO_7816_IDLE;
ALOGD_IF(ese_debug_enabled, "Exit %s Status 0x%x", __FUNCTION__, status);
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_RSync
*
* Description This function is used to send the RSync command
*
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_RSync(void) {
ESESTATUS status = ESESTATUS_FAILED;
phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState =
PH_NXP_ESE_PROTO_7816_TRANSCEIVE;
/* send the end of session s-frame */
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType =
RESYNCH_REQ;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_RSYNC;
status = TransceiveProcess();
phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState =
PH_NXP_ESE_PROTO_7816_IDLE;
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_ResetProtoParams
*
* Description This function is used to reset the 7816 protocol stack
*instance
*
* Returns On success return true or else false.
*
******************************************************************************/
static ESESTATUS phNxpEseProto7816_ResetProtoParams(void) {
unsigned long int tmpWTXCountlimit = PH_PROTO_7816_VALUE_ZERO;
unsigned long int tmpRNACKCountlimit = PH_PROTO_7816_VALUE_ZERO;
tmpWTXCountlimit = phNxpEseProto7816_3_Var.wtx_counter_limit;
tmpRNACKCountlimit = phNxpEseProto7816_3_Var.rnack_retry_limit;
phNxpEse_memset(&phNxpEseProto7816_3_Var, PH_PROTO_7816_VALUE_ZERO,
sizeof(phNxpEseProto7816_t));
phNxpEseProto7816_3_Var.wtx_counter_limit = tmpWTXCountlimit;
phNxpEseProto7816_3_Var.rnack_retry_limit = tmpRNACKCountlimit;
phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState =
PH_NXP_ESE_PROTO_7816_IDLE;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE;
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = INVALID;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = INVALID;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLen =
IFSC_SIZE_SEND;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.p_data = NULL;
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType = INVALID;
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.maxDataLen =
IFSC_SIZE_SEND;
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.p_data = NULL;
/* Initialized with sequence number of the last I-frame sent */
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.seqNo =
PH_PROTO_7816_VALUE_ONE;
/* Initialized with sequence number of the last I-frame received */
phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.seqNo =
PH_PROTO_7816_VALUE_ONE;
/* Initialized with sequence number of the last I-frame received */
phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.seqNo =
PH_PROTO_7816_VALUE_ONE;
phNxpEseProto7816_3_Var.recoveryCounter = PH_PROTO_7816_VALUE_ZERO;
phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO;
phNxpEseProto7816_3_Var.wtx_counter = PH_PROTO_7816_VALUE_ZERO;
/* This update is helpful in-case a R-NACK is transmitted from the MW */
phNxpEseProto7816_3_Var.lastSentNonErrorframeType = UNKNOWN;
phNxpEseProto7816_3_Var.rnack_retry_counter = PH_PROTO_7816_VALUE_ZERO;
return ESESTATUS_SUCCESS;
}
/******************************************************************************
* Function phNxpEseProto7816_Reset
*
* Description This function is used to reset the 7816 protocol stack
*instance
*
* Returns On success return true or else false.
*
******************************************************************************/
ESESTATUS phNxpEseProto7816_Reset(void) {
ESESTATUS status = ESESTATUS_FAILED;
/* Resetting host protocol instance */
phNxpEseProto7816_ResetProtoParams();
/* Resynchronising ESE protocol instance */
status = phNxpEseProto7816_RSync();
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_Open
*
* Description This function is used to open the 7816 protocol stack
*instance
*
* Returns On success return true or else false.
*
******************************************************************************/
ESESTATUS phNxpEseProto7816_Open(phNxpEseProto7816InitParam_t initParam) {
ESESTATUS status = ESESTATUS_FAILED;
status = phNxpEseProto7816_ResetProtoParams();
ALOGD_IF(ese_debug_enabled, "%s: First open completed, Congratulations",
__FUNCTION__);
/* Update WTX max. limit */
phNxpEseProto7816_3_Var.wtx_counter_limit = initParam.wtx_counter_limit;
phNxpEseProto7816_3_Var.rnack_retry_limit = initParam.rnack_retry_limit;
if (initParam.interfaceReset) /* Do interface reset */
{
status = phNxpEseProto7816_IntfReset(initParam.pSecureTimerParams);
if (ESESTATUS_SUCCESS == status) {
phNxpEse_memcpy(initParam.pSecureTimerParams,
&phNxpEseProto7816_3_Var.secureTimerParams,
sizeof(phNxpEseProto7816SecureTimer_t));
}
} else /* Do R-Sync */
{
status = phNxpEseProto7816_RSync();
}
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_Close
*
* Description This function is used to close the 7816 protocol stack
*instance
*
* Returns On success return true or else false.
*
******************************************************************************/
ESESTATUS phNxpEseProto7816_Close(
phNxpEseProto7816SecureTimer_t* pSecureTimerParams) {
ESESTATUS status = ESESTATUS_FAILED;
if (phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState !=
PH_NXP_ESE_PROTO_7816_IDLE)
return status;
phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState =
PH_NXP_ESE_PROTO_7816_DEINIT;
phNxpEseProto7816_3_Var.recoveryCounter = 0;
phNxpEseProto7816_3_Var.wtx_counter = 0;
/* send the end of session s-frame */
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType =
PROP_END_APDU_REQ;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_EOS;
status = TransceiveProcess();
if (ESESTATUS_FAILED == status) {
/* reset all the structures */
ALOGE("%s TransceiveProcess failed ", __FUNCTION__);
}
phNxpEse_memcpy(pSecureTimerParams,
&phNxpEseProto7816_3_Var.secureTimerParams,
sizeof(phNxpEseProto7816SecureTimer_t));
phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState =
PH_NXP_ESE_PROTO_7816_IDLE;
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_IntfReset
*
* Description This function is used to reset just the current interface
*
* Returns On success return true or else false.
*
******************************************************************************/
ESESTATUS phNxpEseProto7816_IntfReset(
phNxpEseProto7816SecureTimer_t* pSecureTimerParam) {
ESESTATUS status = ESESTATUS_FAILED;
ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__);
phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState =
PH_NXP_ESE_PROTO_7816_TRANSCEIVE;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME;
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType =
INTF_RESET_REQ;
phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState =
SEND_S_INTF_RST;
status = TransceiveProcess();
if (ESESTATUS_FAILED == status) {
/* reset all the structures */
ALOGE("%s TransceiveProcess failed ", __FUNCTION__);
}
phNxpEse_memcpy(pSecureTimerParam, &phNxpEseProto7816_3_Var.secureTimerParams,
sizeof(phNxpEseProto7816SecureTimer_t));
phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState =
PH_NXP_ESE_PROTO_7816_IDLE;
ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__);
return status;
}
/******************************************************************************
* Function phNxpEseProto7816_SetIfscSize
*
* Description This function is used to set the max T=1 data send size
*
* Returns Always return true (1).
*
******************************************************************************/
ESESTATUS phNxpEseProto7816_SetIfscSize(uint16_t IFSC_Size) {
phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLen = IFSC_Size;
return ESESTATUS_SUCCESS;
}
/** @} */