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