C++程序  |  1318行  |  56.2 KB

/******************************************************************************
 *
 *  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;
}
/** @} */