对比新文件 |
| | |
| | | #include <errno.h> |
| | | #include <string.h> |
| | | #include <stdlib.h> |
| | | |
| | | #include "T1.h" |
| | | #include "phdriver.h" |
| | | #include "se_api.h" |
| | | #include "mk_misc.h" |
| | | #include "mk_trace.h" |
| | | |
| | | static uint8_t gp_data_tx[270]; |
| | | static uint8_t gp_data_tx_bck[270]; |
| | | uint8_t gp_data_rx[270]; |
| | | static T1_params g_T1_params; |
| | | static uint8_t g_all_data_buf[1024]; |
| | | |
| | | atr_info g_atr = { |
| | | .len = 0x13, |
| | | .vendor_ID = {0x00}, |
| | | .dll_IC = 0x01, |
| | | .bgt = {0x00, 0x01}, |
| | | .bwt = {0x03, 0xE8}, |
| | | .max_freq = {0x4E, 0x20}, |
| | | .checksum = 0x00, |
| | | .default_IFSC = 0xFE, |
| | | .num_channels = 0x01, |
| | | .max_IFSC = {0x00, 0xFF}, |
| | | .capbilities = {0x00, 0x14}, // Extended frame length feature doesn't support |
| | | }; |
| | | |
| | | uint32_t g_recv_total_len = 0; |
| | | |
| | | static uint8_t t1_calculate_LRC(uint8_t *p_data, uint16_t offset, uint16_t len); |
| | | static uint16_t t1_calculate_CRC(uint8_t *p_data, uint16_t offset, uint16_t len); |
| | | static void t1_set_epilogue(uint8_t *p_data, uint16_t offset, uint16_t len); |
| | | |
| | | static ESESTATUS t1_read(uint16_t *p_data_len); |
| | | |
| | | static uint8_t set_info_len(uint8_t *p_data, uint16_t info_len); |
| | | static uint16_t get_info_len(uint8_t *p_data); |
| | | static ESESTATUS decode_ATR(uint8_t *p_data, bool is_CIP); |
| | | static void free_tx_part_mem(void); |
| | | static void reset_for_resync_rsp(void); |
| | | |
| | | static ESESTATUS do_T1_recovery_at_decode_Iframe(void); |
| | | static ESESTATUS do_T1_recovery_at_decode_Sframe(void); |
| | | static ESESTATUS do_T1_recovery_at_decode_Rframe(void); |
| | | static ESESTATUS t1_recv_data_store_in_list(uint8_t *p_data, uint16_t data_len, uint16_t total_len); |
| | | static void t1_recv_data_list_destroy(void); |
| | | static void reset_ATR(void); |
| | | |
| | | /****************************************************************************** |
| | | * @Function Transmit_receive_process |
| | | * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. |
| | | ******************************************************************************/ |
| | | ESESTATUS Transmit_receive_process(void) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | g_ese_ctx.is_read_done = false; |
| | | |
| | | g_recv_total_len = 0; |
| | | while (STATE_IDEL != g_ese_ctx.next_T1_state) |
| | | { |
| | | switch (g_ese_ctx.p_T1_params->tx_frame_type) |
| | | { |
| | | case IFRAME: |
| | | { |
| | | status = t1_send_Iframe(); |
| | | break; |
| | | } |
| | | |
| | | case RFRAME: |
| | | { |
| | | status = t1_send_Rframe(); |
| | | break; |
| | | } |
| | | |
| | | case SFRAME: |
| | | { |
| | | status = t1_send_Sframe(); |
| | | break; |
| | | } |
| | | case FRAME_TYPE_INVALID_MAX: |
| | | case FRAME_TYPE_INVALID_MIN: |
| | | { |
| | | status = ESESTATUS_INVALID_PARAMETER; |
| | | LOG_INFO(TRACE_MODULE_SE, "%s : invalid T1 frame type: %d\r\n", __FUNCTION__, g_ese_ctx.p_T1_params->tx_frame_type); |
| | | } |
| | | } |
| | | |
| | | if (ESESTATUS_SUCCESS == status) |
| | | { |
| | | #ifdef DBG_LEVEL_STACK |
| | | gDumpStackFlag = false; |
| | | #endif |
| | | g_ese_ctx.p_T1_params->blk_retry_cnt = 0; |
| | | status = response_process(); |
| | | // Do not need handle the status value |
| | | } |
| | | else |
| | | { |
| | | if (((ESESTATUS_PH_IO != status) && (ESESTATUS_MEM_EXCEPTION != status)) || (g_ese_ctx.p_T1_params->blk_retry_cnt >= g_ese_ctx.max_blk_retry_cnt)) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s: send frame failed, frameType = %d, status = %d, retryCnt = %d\r\n", __FUNCTION__, |
| | | g_ese_ctx.p_T1_params->tx_frame_type, status, g_ese_ctx.max_blk_retry_cnt); |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | break; |
| | | } |
| | | else |
| | | { |
| | | // resend |
| | | g_ese_ctx.p_T1_params->blk_retry_cnt++; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function response_process |
| | | * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. |
| | | ******************************************************************************/ |
| | | ESESTATUS response_process(void) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | uint16_t data_len = 0; |
| | | |
| | | // LOG_INFO(TRACE_MODULE_SE, "%s: enter\r\n", __FUNCTION__); |
| | | status = t1_read(&data_len); |
| | | |
| | | if (ESESTATUS_SUCCESS == status) |
| | | { |
| | | status = t1_chk_epilogue(gp_data_rx, 0, data_len); |
| | | if (status == ESESTATUS_SUCCESS) |
| | | { |
| | | status = t1_decode_frame(data_len); |
| | | |
| | | if (ESESTATUS_SUCCESS == status) |
| | | { |
| | | } |
| | | } |
| | | else |
| | | { |
| | | do_T1_recovery_at_undecode(); |
| | | } |
| | | } |
| | | else if (ESESTATUS_FATAL_ERROR == status) |
| | | { |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | } |
| | | else |
| | | { |
| | | do_T1_recovery_at_undecode(); |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_send_Sframe |
| | | * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. |
| | | ******************************************************************************/ |
| | | #if defined(__GNUC__) |
| | | #pragma GCC diagnostic push |
| | | #pragma GCC diagnostic ignored "-Wswitch-enum" |
| | | #endif |
| | | ESESTATUS t1_send_Sframe(void) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | int ret = -1; |
| | | uint8_t frame_len = 0; |
| | | |
| | | if (SFRAME_TYPE_INVALID == g_ese_ctx.p_T1_params->tx_sub_Sframe_type) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s : invalid S-block frame type: %d\r\n", __FUNCTION__, g_ese_ctx.p_T1_params->tx_sub_Sframe_type); |
| | | return ESESTATUS_INVALID_PARAMETER; |
| | | } |
| | | else |
| | | { |
| | | frame_len = get_header_len(true); |
| | | } |
| | | |
| | | // memset(gp_data_tx, 0, sizeof(gp_data_tx)); |
| | | switch (g_ese_ctx.p_T1_params->tx_sub_Sframe_type) |
| | | { |
| | | case RESYNC_REQ: |
| | | { |
| | | gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | RESYNC_REQ); |
| | | break; |
| | | } |
| | | |
| | | case IFS_REQ: |
| | | { |
| | | uint8_t len_offset = 0, info_len = 0x02; |
| | | frame_len += info_len; |
| | | gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | IFS_REQ); |
| | | len_offset = set_info_len(gp_data_tx, info_len); |
| | | gp_data_tx[len_offset + 1] = (uint8_t)(g_ese_ctx.max_IFSD >> 8); |
| | | gp_data_tx[len_offset + 2] = (uint8_t)(g_ese_ctx.max_IFSD & 0xFF); |
| | | break; |
| | | } |
| | | |
| | | case IFS_RSP: |
| | | { |
| | | uint8_t len_offset = 0, info_len = 0; |
| | | info_len = (uint8_t)get_info_len(gp_data_rx); |
| | | frame_len += info_len; |
| | | gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | IFS_REQ); |
| | | len_offset = set_info_len(gp_data_tx, info_len); |
| | | memcpy(&gp_data_tx[len_offset + 1], &gp_data_rx[len_offset + 1], info_len); |
| | | break; |
| | | } |
| | | |
| | | case ABORT_REQ: |
| | | { |
| | | gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | ABORT_REQ); |
| | | break; |
| | | } |
| | | case WTX_RSP: |
| | | { |
| | | uint8_t len_offset = 0, info_len = 1; |
| | | frame_len += info_len; |
| | | gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | WTX_RSP); |
| | | len_offset = set_info_len(gp_data_tx, info_len); |
| | | gp_data_tx[len_offset + 1] = g_ese_ctx.p_T1_params->wtx_info; |
| | | break; |
| | | } |
| | | |
| | | case CIP_REQ: |
| | | { |
| | | /* Note:T1 CIP_REQ for ATR, the frame's INFO length should be 1 byte, |
| | | */ |
| | | gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | CIP_REQ); |
| | | break; |
| | | } |
| | | |
| | | case PROP_END_APDU_REQ: |
| | | { |
| | | gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | PROP_END_APDU_REQ); |
| | | break; |
| | | } |
| | | |
| | | case HARD_RESET_REQ: |
| | | { |
| | | break; |
| | | } |
| | | |
| | | case ATR_REQ: |
| | | { |
| | | gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | ATR_REQ); |
| | | break; |
| | | } |
| | | |
| | | default: |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s : invalid S-block frame type: %X\r\n", __FUNCTION__, g_ese_ctx.p_T1_params->tx_sub_Sframe_type); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | gp_data_tx[T1_NAD_OFFSET] = NAD_D2C; |
| | | // caculate LRC or CRC and set it to pFramebuff |
| | | t1_set_epilogue(gp_data_tx, 0, frame_len); |
| | | |
| | | ret = phdriver_write(gp_data_tx, frame_len); |
| | | if (-1 == ret) |
| | | { |
| | | status = ESESTATUS_PH_IO; |
| | | LOG_INFO(TRACE_MODULE_SE, "write fail: %s, errno = %d, ret = %d\r\n", __FUNCTION__, errno, ret); |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | #if defined(__GNUC__) |
| | | #pragma GCC diagnostic pop |
| | | #endif |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_send_Iframe |
| | | * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. |
| | | ******************************************************************************/ |
| | | ESESTATUS t1_send_Iframe(void) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | int ret = -1; |
| | | uint16_t frame_len = 0; |
| | | uint8_t *p_frame_buf = NULL; |
| | | uint16_t len_offset = 0; |
| | | uint16_t send_len = 0; |
| | | uint16_t tx_data_offset = 0; |
| | | |
| | | if (g_ese_ctx.p_T1_params->recovery_cnt > g_ese_ctx.max_recovery_cnt) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s fatal error, recovery_cnt = %d\r\n", __FUNCTION__, g_ese_ctx.p_T1_params->recovery_cnt); |
| | | status = ESESTATUS_FATAL_ERROR; |
| | | goto cleanup; |
| | | } |
| | | else if ((g_ese_ctx.p_T1_params->p_data_tx_part != NULL)) |
| | | { |
| | | // LOG_INFO(TRACE_MODULE_SE, "%s retry_send_part, tx_len_part = %u\r\n", __FUNCTION__, g_ese_ctx.p_T1_params->tx_len_part); |
| | | p_frame_buf = g_ese_ctx.p_T1_params->p_data_tx_part; |
| | | frame_len = g_ese_ctx.p_T1_params->tx_len_part; |
| | | goto retry_send_part; |
| | | } |
| | | |
| | | tx_data_offset = g_ese_ctx.p_T1_params->tx_data_offset; |
| | | |
| | | frame_len = (g_ese_ctx.is_T1_ext_hdr_len ? T1_EXT_HEADER_LEN : T1_HEADER_LEN) + ((LRC == g_atr.checksum) ? T1_LRC_LEN : T1_CRC_LEN); |
| | | |
| | | if ((g_ese_ctx.p_T1_params->tx_len - tx_data_offset) > g_ese_ctx.max_IFSC) |
| | | { |
| | | g_ese_ctx.p_T1_params->is_device_chaining = true; |
| | | send_len = g_ese_ctx.max_IFSC; |
| | | tx_data_offset += g_ese_ctx.max_IFSC; |
| | | } |
| | | else |
| | | { |
| | | g_ese_ctx.p_T1_params->is_device_chaining = false; |
| | | send_len = g_ese_ctx.p_T1_params->tx_len - tx_data_offset; |
| | | tx_data_offset += send_len; |
| | | } |
| | | |
| | | frame_len += send_len; |
| | | // memset(gp_data_tx, 0, sizeof(gp_data_tx)); |
| | | p_frame_buf = gp_data_tx; |
| | | |
| | | p_frame_buf[T1_NAD_OFFSET] = NAD_D2C; |
| | | len_offset = set_info_len(p_frame_buf, send_len); |
| | | memcpy((p_frame_buf + len_offset + 1), (g_ese_ctx.p_T1_params->p_data_tx + g_ese_ctx.p_T1_params->tx_data_offset), send_len); |
| | | g_ese_ctx.p_T1_params->tx_data_offset = tx_data_offset; |
| | | |
| | | // memset(gp_data_tx_bck, 0, sizeof(gp_data_tx_bck)); |
| | | memcpy(gp_data_tx_bck, p_frame_buf, frame_len); |
| | | g_ese_ctx.p_T1_params->p_data_tx_part = gp_data_tx_bck; |
| | | g_ese_ctx.p_T1_params->tx_len_part = frame_len; |
| | | |
| | | retry_send_part: |
| | | p_frame_buf[T1_PCB_OFFSET] = 0x00; |
| | | if (g_ese_ctx.p_T1_params->is_device_chaining) |
| | | { |
| | | p_frame_buf[T1_PCB_OFFSET] |= T1_CHAINING_MASK; |
| | | } |
| | | p_frame_buf[T1_PCB_OFFSET] |= (g_ese_ctx.seq_num_device << 6); |
| | | |
| | | t1_set_epilogue(p_frame_buf, 0, frame_len); |
| | | |
| | | ret = phdriver_write(p_frame_buf, frame_len); |
| | | if (-1 == ret) |
| | | { |
| | | status = ESESTATUS_PH_IO; |
| | | LOG_INFO(TRACE_MODULE_SE, "write fail: %s, errno = %d, ret = %d\r\n", __FUNCTION__, errno, ret); |
| | | } |
| | | |
| | | cleanup: |
| | | |
| | | if (S_ABORT_RSP == g_ese_ctx.next_T1_state) |
| | | { |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | free_tx_part_mem(); |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_send_Rframe |
| | | * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. |
| | | ******************************************************************************/ |
| | | ESESTATUS t1_send_Rframe(void) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | int ret = -1; |
| | | uint8_t frame_len = 0; |
| | | uint8_t *p_frame_buff = gp_data_tx; |
| | | |
| | | if (RNACK_INVALID_ERROR == g_ese_ctx.p_T1_params->tx_sub_Rframe_type) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s : invalid R-block frame type: %d\r\n", __FUNCTION__, g_ese_ctx.p_T1_params->tx_sub_Sframe_type); |
| | | return ESESTATUS_INVALID_PARAMETER; |
| | | } |
| | | else |
| | | { |
| | | frame_len = get_header_len(true); |
| | | } |
| | | |
| | | // memset(gp_data_tx, 0, sizeof(gp_data_tx)); |
| | | // pFramebuff = gp_data_tx; |
| | | |
| | | if (RNACK_PARITY_ERROR == g_ese_ctx.p_T1_params->tx_sub_Rframe_type) |
| | | { |
| | | p_frame_buff[1] = 0x81; |
| | | } |
| | | else if (RNACK_OTHER_ERROR == g_ese_ctx.p_T1_params->tx_sub_Rframe_type) |
| | | { |
| | | p_frame_buff[1] = 0x82; |
| | | } |
| | | else |
| | | { // if (RACK == g_ese_ctx.p_T1_params->subRFrameType) { |
| | | p_frame_buff[1] = 0x80; |
| | | } |
| | | |
| | | p_frame_buff[1] |= (g_ese_ctx.seq_num_card << 4); |
| | | |
| | | p_frame_buff[T1_NAD_OFFSET] = NAD_D2C; |
| | | // caculate LRC or CRC and set it to pFramebuff |
| | | t1_set_epilogue(p_frame_buff, 0, frame_len); |
| | | |
| | | ret = phdriver_write(p_frame_buff, frame_len); |
| | | if (-1 == ret) |
| | | { |
| | | status = ESESTATUS_PH_IO; |
| | | |
| | | LOG_INFO(TRACE_MODULE_SE, "write fail: %s, errno = %d, ret = %d\r\n", __FUNCTION__, errno, ret); |
| | | } |
| | | else |
| | | { |
| | | // LOG_INFO(TRACE_MODULE_SE, "\nTx", 2, pFramebuff, frameLen); |
| | | // LOG_INFO(TRACE_MODULE_SE, "\n"); |
| | | } |
| | | |
| | | if (NULL == p_frame_buff) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s failed, frame buffer malloc memory failed\r\n", __FUNCTION__); |
| | | status = ESESTATUS_MEM_EXCEPTION; |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_calculate_LRC |
| | | * @Param p_data - data to compute the LRC over. |
| | | * offset - calculate start offset. |
| | | * len - data length, not include the epilogue byte. |
| | | * @Returns On success return the LRC of the data. |
| | | ******************************************************************************/ |
| | | static uint8_t t1_calculate_LRC(uint8_t *p_data, uint16_t offset, uint16_t len) |
| | | { |
| | | uint8_t LRC = 0; |
| | | uint16_t i = 0; |
| | | for (i = offset; i < len; i++) |
| | | { |
| | | LRC = LRC ^ p_data[i]; |
| | | } |
| | | return LRC; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_calculate_CRC |
| | | * @Param p_data - data to compute the CRC over. |
| | | * offset - calculate start offset. |
| | | * len - data length, not include the epilogue bytes.. |
| | | * @Returns On success return the CRC of the data. |
| | | ******************************************************************************/ |
| | | static uint16_t t1_calculate_CRC(uint8_t *p_data, uint16_t offset, uint16_t len) |
| | | { |
| | | uint16_t crc; |
| | | |
| | | crc = (uint16_t)CRC_PRESET; |
| | | |
| | | int i, j; |
| | | for (i = offset; i < len; i++) |
| | | { |
| | | crc = crc ^ ((unsigned short)p_data[i]); |
| | | for (j = 0; j < 8; j++) |
| | | { |
| | | if ((crc & 0x0001) == 0x0001) |
| | | { |
| | | crc = (crc >> 1) ^ CRC_POLYNOMIAL; |
| | | } |
| | | else |
| | | { |
| | | crc = crc >> 1; |
| | | } |
| | | } |
| | | } |
| | | crc = ~crc; |
| | | |
| | | return crc; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_set_epilogue |
| | | * @Param p_data - data to compute the LRC or CRC over. |
| | | * offset - calculate start offset. |
| | | * len - data length, include the epilogue byte(s). |
| | | ******************************************************************************/ |
| | | static void t1_set_epilogue(uint8_t *p_data, uint16_t offset, uint16_t len) |
| | | { |
| | | if ((LRC == g_atr.checksum) || |
| | | (CIP_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type) |
| | | /*|| (ATR_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)*/ |
| | | || (CIP_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type) |
| | | /*|| (ATR_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)*/) |
| | | { |
| | | // LRC |
| | | p_data[len - 1] = t1_calculate_LRC(p_data, offset, len - 1); |
| | | } |
| | | else |
| | | { |
| | | const uint16_t CRC = t1_calculate_CRC(p_data, offset, len - 2); |
| | | |
| | | p_data[len - 2] = (uint8_t)(CRC >> 8); |
| | | p_data[len - 1] = (uint8_t)CRC; |
| | | } |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_chk_epilogue |
| | | * @Param p_data - data to compute the LRC or CRC over. |
| | | * offset - calculate start offset. |
| | | * len - data length, include the epilogue byte(s). |
| | | * @Returns ESESTATUS_SUCCESS if caculate result is equal to response's epilogue, |
| | | * else ESESTATUS_PARITY_ERROR. |
| | | ******************************************************************************/ |
| | | ESESTATUS t1_chk_epilogue(uint8_t *p_data, uint16_t offset, uint16_t len) |
| | | { |
| | | ESESTATUS status = ESESTATUS_PARITY_ERROR; |
| | | |
| | | /* Note:T1 CIP_REQ for ATR, the frame's INFO length should be 1 byte, |
| | | * do not support 2 bytes length. |
| | | * And epiLogue field should use LRC (1 byte). |
| | | */ |
| | | if ((LRC == g_atr.checksum) || |
| | | (CIP_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type) |
| | | /*|| (ATR_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)*/ |
| | | || (CIP_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type) |
| | | /*|| (ATR_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)*/) |
| | | { |
| | | // LRC |
| | | const uint8_t LRC = t1_calculate_LRC(p_data, offset, len - 1); |
| | | if (LRC == p_data[len - 1]) |
| | | { |
| | | status = ESESTATUS_SUCCESS; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | uint16_t rspCRC = (uint16_t)(((uint16_t)p_data[len - 2]) << 8); |
| | | rspCRC |= p_data[len - 1]; |
| | | const uint16_t CRC = t1_calculate_CRC(p_data, offset, len - 2); |
| | | if (CRC == rspCRC) |
| | | { |
| | | status = ESESTATUS_SUCCESS; |
| | | } |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_read |
| | | * @Param p_data_len - point to data length. |
| | | * @Returns On success return ESESTATUS_SUCCESS, else ESESTATUS_xxx. |
| | | ******************************************************************************/ |
| | | static ESESTATUS t1_read(uint16_t *p_data_len) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | int ret = -1; |
| | | const uint32_t sof_max_cnt = g_ese_ctx.max_read_retry_cnt; |
| | | uint32_t sof_cnt = 0; |
| | | uint16_t total_cnt = 0, num_Bytes_to_read = 0, read_index = 0; |
| | | |
| | | #ifdef USE_SPI_SPLIT_READ |
| | | const uint8_t hdrLen = get_header_len(false) + 1; |
| | | #else |
| | | const uint8_t hdrLen = g_ese_ctx.max_IFSD; |
| | | #endif |
| | | |
| | | #ifdef DBG_LEVEL_STACK |
| | | if (gDumpStackFlag) |
| | | { |
| | | dumpCallstack(); |
| | | } |
| | | gDumpStackFlag = true; |
| | | #endif |
| | | |
| | | // memset(gp_data_rx, 0x00, sizeof(gp_data_rx)); |
| | | do |
| | | { |
| | | sys_timer_delay_ms(1); // 10 |
| | | |
| | | ret = phdriver_read(gp_data_rx, 1); |
| | | |
| | | if ((ret < 0) || (NAD_C2DT != gp_data_rx[0])) |
| | | { |
| | | sof_cnt++; |
| | | continue; |
| | | } |
| | | else |
| | | { |
| | | phdriver_read(gp_data_rx + 1, (hdrLen - 1)); |
| | | |
| | | if (g_ese_ctx.is_T1_ext_hdr_len) |
| | | { |
| | | num_Bytes_to_read = (uint16_t)(((uint16_t)gp_data_rx[T1_FRAME_LEN_OFFSET]) << 8); |
| | | num_Bytes_to_read |= gp_data_rx[T1_FRAME_LEN_OFFSET2]; |
| | | |
| | | if (CRC == g_atr.checksum) |
| | | { |
| | | num_Bytes_to_read += 1; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | num_Bytes_to_read = gp_data_rx[T1_FRAME_LEN_OFFSET]; |
| | | } |
| | | read_index = hdrLen; |
| | | total_cnt += hdrLen; |
| | | // LOG_INFO(TRACE_MODULE_SE, "_spi_read() [HDR] read data right!! \r\n"); |
| | | break; |
| | | } |
| | | } while (sof_cnt < sof_max_cnt); |
| | | |
| | | /*SOF Read timeout happened, go for frame retransmission*/ |
| | | if (sof_cnt == sof_max_cnt) |
| | | { |
| | | if (ret >= 0) |
| | | { |
| | | ret = -1; |
| | | status = ESESTATUS_PH_IOR_INVALID_DATA; |
| | | } |
| | | else |
| | | { |
| | | status = ESESTATUS_PH_IO; |
| | | } |
| | | // LOG_INFO(TRACE_MODULE_SE, "_spi_read() [HDR] execption, ret = %d, sofCnt = %X\r\n", ret, sofCnt); |
| | | } |
| | | |
| | | #ifdef USE_SPI_SPLIT_READ |
| | | if (ret < 0) |
| | | { |
| | | if ((-1 == ret) && (4 == errno)) |
| | | { |
| | | // Interrupted system call, is NFC_DLD_FLUSH |
| | | status = ESESTATUS_FATAL_ERROR; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (0 != num_Bytes_to_read) |
| | | { |
| | | ret = phdriver_read(&gp_data_rx[read_index], num_Bytes_to_read); |
| | | if (ret < 0) |
| | | { |
| | | status = ESESTATUS_PH_IO; |
| | | LOG_INFO(TRACE_MODULE_SE, "%s _spi_read() [payload] execption, ret = %x, errno = %d\r\n", __FUNCTION__, ret, errno); |
| | | } |
| | | else |
| | | { |
| | | // LOG_INFO(TRACE_MODULE_SE, " _spi_read() [payload] right!!!!!!!!!!!!!!\r\n"); |
| | | total_cnt += num_Bytes_to_read; |
| | | } |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | if (ESESTATUS_SUCCESS != status) |
| | | { |
| | | *p_data_len = 0; |
| | | // LOG_INFO(TRACE_MODULE_SE, "RxFail\r\n"); |
| | | // LOG_INFO(TRACE_MODULE_SE, "read fail: %s, errno = %d, ret = %d\r\n", __FUNCTION__, errno, ret); |
| | | } |
| | | else |
| | | { |
| | | *p_data_len = total_cnt; |
| | | |
| | | // LOG_INFO(TRACE_MODULE_SE, "Rx\r\n"); |
| | | } |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_decode_frame |
| | | * @Param data_len - data length. |
| | | * @Returns On success return ESESTATUS_SUCCESS, else ESESTATUS_xxx. |
| | | ******************************************************************************/ |
| | | ESESTATUS t1_decode_frame(uint16_t data_len) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | uint8_t pcb = gp_data_rx[T1_PCB_OFFSET]; |
| | | T1_pcb_bits *p_pcb_bits; |
| | | |
| | | if (g_ese_ctx.p_T1_params) |
| | | { |
| | | p_pcb_bits = &g_ese_ctx.p_T1_params->last_rx_pcb_bits; |
| | | } |
| | | else |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "p_T1_params is NULL\r\n"); |
| | | return ESESTATUS_INVALID_PCB; |
| | | } |
| | | |
| | | // memset(p_pcb_bits, 0x00, sizeof(T1_pcb_bits)); |
| | | memcpy(p_pcb_bits, &pcb, sizeof(uint8_t)); |
| | | uint16_t infoLen = get_info_len(gp_data_rx); |
| | | uint8_t dataOffset = get_header_len(false); |
| | | |
| | | if (0x00 == p_pcb_bits->msb) |
| | | { |
| | | // I-FRAME decoded |
| | | g_ese_ctx.p_T1_params->last_rx_frame_type = IFRAME; |
| | | g_ese_ctx.p_T1_params->last_rx_sub_Sframe_type = SFRAME_TYPE_INVALID; |
| | | g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type = RNACK_INVALID_ERROR; |
| | | |
| | | g_ese_ctx.p_T1_params->wtx_cnt = 0; |
| | | |
| | | if (g_ese_ctx.is_seq_num_dr && (p_pcb_bits->bit7 != g_ese_ctx.seq_num_card)) |
| | | { |
| | | g_ese_ctx.seq_num_card ^= 0x01; |
| | | } |
| | | g_ese_ctx.is_seq_num_dr = false; |
| | | |
| | | if (p_pcb_bits->bit7 == g_ese_ctx.seq_num_card) |
| | | { |
| | | g_ese_ctx.p_T1_params->recovery_cnt = 0; |
| | | g_ese_ctx.p_T1_params->resync_CIP_req_cnt = 0; |
| | | g_ese_ctx.is_resync_recovery_flag = false; |
| | | |
| | | if (p_pcb_bits->bit6) |
| | | { |
| | | g_ese_ctx.p_T1_params->is_card_chaining = true; |
| | | g_ese_ctx.seq_num_card = (g_ese_ctx.seq_num_card ^ 0x01); |
| | | |
| | | status = t1_recv_data_store_in_list(&gp_data_rx[dataOffset], infoLen, data_len); |
| | | |
| | | if (ESESTATUS_SUCCESS != status) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s, t1_recv_data_store_in_list failed, terminate transmission, status = %d\r\n", __FUNCTION__, status); |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | free_tx_part_mem(); |
| | | } |
| | | else |
| | | { |
| | | // Card response chaining and successfully, then request the next segments data. |
| | | g_ese_ctx.next_T1_state = R_ACK; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = RFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RACK; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | g_ese_ctx.p_T1_params->is_card_chaining = false; |
| | | status = t1_recv_data_store_in_list(&gp_data_rx[dataOffset], infoLen, data_len); |
| | | if (ESESTATUS_SUCCESS != status) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s, t1_recv_data_store_in_list failed, terminate transmission, status = %d\r\n", __FUNCTION__, status); |
| | | } |
| | | else |
| | | { |
| | | // Not chaining, and response success. |
| | | } |
| | | |
| | | g_ese_ctx.seq_num_device = (g_ese_ctx.seq_num_device ^ 0x01); |
| | | g_ese_ctx.seq_num_card = (g_ese_ctx.seq_num_card ^ 0x01); |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | free_tx_part_mem(); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s, received invalid seqNum = %02X, seq_num_card = %02X\r\n", __FUNCTION__, p_pcb_bits->bit7, g_ese_ctx.seq_num_card); |
| | | status = do_T1_recovery_at_decode_Iframe(); |
| | | } |
| | | } |
| | | else if ((0x01 == p_pcb_bits->msb) && (0x00 == p_pcb_bits->bit7)) |
| | | { |
| | | // R-FRAME decoded |
| | | g_ese_ctx.p_T1_params->last_rx_frame_type = RFRAME; |
| | | g_ese_ctx.p_T1_params->last_rx_sub_Sframe_type = SFRAME_TYPE_INVALID; |
| | | |
| | | if ((0x00 == p_pcb_bits->lsb) && (0x00 == p_pcb_bits->bit2)) |
| | | { |
| | | g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type = RACK; |
| | | if ((NULL != g_ese_ctx.p_T1_params->p_data_tx) && g_ese_ctx.p_T1_params->is_device_chaining) |
| | | { |
| | | if (g_ese_ctx.seq_num_device != p_pcb_bits->bit5) |
| | | { |
| | | // Device chaining, valid card request the next segments of device data to send. |
| | | // seq_num_device should changed, but the seq_num_card unchanged until received card I-block. |
| | | g_ese_ctx.seq_num_device = p_pcb_bits->bit5; |
| | | g_ese_ctx.next_T1_state = I_BLK; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = IFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RNACK_INVALID_ERROR; |
| | | free_tx_part_mem(); |
| | | } |
| | | else |
| | | { |
| | | status = do_T1_recovery_at_decode_Rframe(); |
| | | } |
| | | } |
| | | else if (NULL != g_ese_ctx.p_T1_params->p_data_tx) |
| | | { |
| | | status = ESESTATUS_INVALID_PARAMETER; |
| | | LOG_INFO(TRACE_MODULE_SE, "%s: Device initiates unchaining I-block cannot receive RACK, terminate transmit.\r\n", __FUNCTION__); |
| | | // terminate transmit |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | } |
| | | else |
| | | { |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | g_ese_ctx.p_T1_params->last_rx_sub_Sframe_type = SFRAME_TYPE_INVALID; |
| | | if ((0x01 == p_pcb_bits->lsb) && (0x00 == p_pcb_bits->bit2)) |
| | | { |
| | | g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type = RNACK_PARITY_ERROR; |
| | | status = ESESTATUS_PARITY_ERROR; |
| | | } |
| | | else if ((0x00 == p_pcb_bits->lsb) && (0x01 == p_pcb_bits->bit2)) |
| | | { |
| | | // Other error |
| | | g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type = RNACK_OTHER_ERROR; |
| | | status = ESESTATUS_UNKNOWN_ERROR; |
| | | } |
| | | else |
| | | { |
| | | g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type = RNACK_INVALID_ERROR; |
| | | status = ESESTATUS_UNKNOWN_ERROR; |
| | | } |
| | | |
| | | // LOG_INFO(TRACE_MODULE_SE, "%s: PCB = 0x%02X, recovery_cnt = %d, max_recovery_cnt = %d\r\n", __FUNCTION__, pcb, |
| | | // g_ese_ctx.p_T1_params->recovery_cnt, |
| | | // g_ese_ctx.max_recovery_cnt); |
| | | do_T1_recovery_at_decode_Rframe(); |
| | | } |
| | | } |
| | | else if ((0x01 == p_pcb_bits->msb) && (0x01 == p_pcb_bits->bit7)) |
| | | { |
| | | g_ese_ctx.p_T1_params->last_rx_frame_type = SFRAME; |
| | | g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type = RNACK_INVALID_ERROR; |
| | | |
| | | LOG_INFO(TRACE_MODULE_SE, "%s S-Frame Received\r\n", __FUNCTION__); |
| | | uint8_t subFrameType = pcb & T1_S_BLOCK_SUB_TYPE_MASK; |
| | | if (RESYNC_RSP != subFrameType) |
| | | { |
| | | g_ese_ctx.is_resync_recovery_flag = false; |
| | | } |
| | | |
| | | switch (subFrameType) |
| | | { |
| | | case RESYNC_RSP: |
| | | { |
| | | g_ese_ctx.p_T1_params->last_rx_sub_Sframe_type = RESYNC_RSP; |
| | | status = do_T1_recovery_at_decode_Sframe(); |
| | | break; |
| | | } |
| | | |
| | | case IFS_REQ: |
| | | { |
| | | uint16_t IFSC = 0; |
| | | if (2 == infoLen) |
| | | { |
| | | IFSC = (uint16_t)(((uint16_t)gp_data_rx[dataOffset]) << 8); |
| | | IFSC |= gp_data_rx[dataOffset + 1]; |
| | | LOG_INFO(TRACE_MODULE_SE, "%s IFS_RSP Received, IFSD = %04X\r\n", __FUNCTION__, IFSC); |
| | | } |
| | | else if (1 == infoLen) |
| | | { |
| | | IFSC = (uint16_t)gp_data_rx[dataOffset]; |
| | | LOG_INFO(TRACE_MODULE_SE, "%s IFS_RSP Received, IFSD = %02X\r\n", __FUNCTION__, IFSC); |
| | | } |
| | | else |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s Invalid IFS_RSP Received\r\n", __FUNCTION__); |
| | | } |
| | | g_ese_ctx.max_IFSC = IFSC; |
| | | g_ese_ctx.next_T1_state = S_IFS_RSP; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = SFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = IFS_RSP; |
| | | break; |
| | | } |
| | | |
| | | case IFS_RSP: |
| | | { |
| | | g_ese_ctx.p_T1_params->last_rx_sub_Sframe_type = IFS_RSP; |
| | | uint16_t IFSD = 0; |
| | | uint8_t offset = get_header_len(false); |
| | | if (2 == infoLen) |
| | | { |
| | | IFSD = (uint16_t)(((uint16_t)gp_data_rx[offset]) << 8); |
| | | IFSD |= gp_data_rx[offset + 1]; |
| | | LOG_INFO(TRACE_MODULE_SE, "%s IFS_RSP Received, IFSD = %04X\r\n", __FUNCTION__, IFSD); |
| | | } |
| | | else if (1 == infoLen) |
| | | { |
| | | IFSD = (uint16_t)gp_data_rx[offset]; |
| | | LOG_INFO(TRACE_MODULE_SE, "%s IFS_RSP Received, IFSD = %02X\r\n", __FUNCTION__, IFSD); |
| | | } |
| | | else |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s Invalid IFS_RSP Received\r\n", __FUNCTION__); |
| | | } |
| | | if (g_ese_ctx.max_IFSD != IFSD) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s : invalid IFS receive paylod, receivedIFSD = %X, sentIFSD = %X\r\n", __FUNCTION__, IFSD, g_ese_ctx.max_IFSD); |
| | | } |
| | | status = do_T1_recovery_at_decode_Sframe(); |
| | | break; |
| | | } |
| | | |
| | | case ABORT_REQ: |
| | | case ABORT_RSP: |
| | | { |
| | | // Rule 9: only chaining cmd or rsp will send (receive) ABORT_REQ |
| | | if (g_ese_ctx.p_T1_params->is_card_chaining || g_ese_ctx.p_T1_params->is_device_chaining) |
| | | { |
| | | t1_recv_data_list_destroy(); |
| | | } |
| | | |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | break; |
| | | } |
| | | |
| | | case WTX_REQ: |
| | | { |
| | | if (g_ese_ctx.p_T1_params->wtx_cnt <= g_ese_ctx.max_wtx_cnt) |
| | | { |
| | | g_ese_ctx.p_T1_params->wtx_cnt++; |
| | | |
| | | g_ese_ctx.p_T1_params->wtx_info = gp_data_rx[get_header_len(false)]; |
| | | g_ese_ctx.next_T1_state = S_WTX_RSP; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = SFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = WTX_RSP; |
| | | } |
| | | else |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s : failed, WTX_REQ counter larger than maxWtxCnt\r\n", __FUNCTION__); |
| | | status = ESESTATUS_FAILED; |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | } |
| | | break; |
| | | } |
| | | |
| | | case CIP_RSP: |
| | | { |
| | | status = decode_ATR(gp_data_rx, true); |
| | | reset_for_resync_rsp(); |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | break; |
| | | } |
| | | |
| | | case PROP_END_APDU_RSP: |
| | | { |
| | | status = ESESTATUS_SUCCESS; |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | break; |
| | | } |
| | | |
| | | case HARD_RESET_RSP: |
| | | { |
| | | status = ESESTATUS_SUCCESS; |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | break; |
| | | } |
| | | |
| | | case ATR_RSP: |
| | | { |
| | | status = decode_ATR(gp_data_rx, false); |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | break; |
| | | } |
| | | |
| | | default: |
| | | { |
| | | status = ESESTATUS_SUCCESS; |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | LOG_INFO(TRACE_MODULE_SE, "%s : invalid S-block frame type: %X\r\n", __FUNCTION__, subFrameType); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // LOG_ERROR(TRACE_MODULE_SE, "[RX]Nothing\r\n"); |
| | | LOG_INFO(TRACE_MODULE_SE, "%s Wrong-Frame Received, PCB = %X\r\n", __FUNCTION__, pcb); |
| | | status = ESESTATUS_INVALID_PCB; |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /** Contains the Prologue and (or not) Epilogue field length **/ |
| | | uint8_t get_header_len(bool contains_epilogue) |
| | | { |
| | | uint8_t len = 0; |
| | | bool is_T1_ext_hdr_len = g_ese_ctx.is_T1_ext_hdr_len; |
| | | uint8_t checksum = g_atr.checksum; |
| | | if ((SFRAME == g_ese_ctx.p_T1_params->tx_frame_type) && ((CIP_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type) |
| | | /*|| (ATR_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)*/)) |
| | | { |
| | | is_T1_ext_hdr_len = false; |
| | | checksum = 0; |
| | | } |
| | | |
| | | len = (is_T1_ext_hdr_len ? T1_EXT_HEADER_LEN : T1_HEADER_LEN); |
| | | if (contains_epilogue) |
| | | { |
| | | len += ((checksum == 0) ? T1_LRC_LEN : T1_CRC_LEN); |
| | | } |
| | | |
| | | return len; |
| | | } |
| | | |
| | | static uint8_t set_info_len(uint8_t *p_data, uint16_t info_len) |
| | | { |
| | | uint8_t len_offset = 0; |
| | | bool is_T1_ext_hdr_len = g_ese_ctx.is_T1_ext_hdr_len; |
| | | if ((SFRAME == g_ese_ctx.p_T1_params->tx_frame_type) && ((CIP_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type) |
| | | /*|| (ATR_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)*/)) |
| | | { |
| | | is_T1_ext_hdr_len = false; |
| | | } |
| | | |
| | | if (is_T1_ext_hdr_len) |
| | | { |
| | | p_data[T1_FRAME_LEN_OFFSET] = (uint8_t)(info_len >> 8); |
| | | p_data[T1_FRAME_LEN_OFFSET2] = (uint8_t)(info_len & 0xFF); |
| | | len_offset = T1_FRAME_LEN_OFFSET2; |
| | | } |
| | | else |
| | | { |
| | | p_data[T1_FRAME_LEN_OFFSET] = (uint8_t)(info_len & 0xFF); |
| | | len_offset = T1_FRAME_LEN_OFFSET; |
| | | } |
| | | return len_offset; |
| | | } |
| | | |
| | | static uint16_t get_info_len(uint8_t *p_data) |
| | | { |
| | | uint16_t info_len = 0; |
| | | bool is_T1_ext_hdr_len = g_ese_ctx.is_T1_ext_hdr_len; |
| | | if ((SFRAME == g_ese_ctx.p_T1_params->tx_frame_type) && ((CIP_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type) |
| | | /*|| (ATR_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)*/)) |
| | | { |
| | | is_T1_ext_hdr_len = false; |
| | | } |
| | | |
| | | if (is_T1_ext_hdr_len) |
| | | { |
| | | info_len = (uint16_t)(((uint16_t)p_data[T1_FRAME_LEN_OFFSET]) << 8); |
| | | info_len |= p_data[T1_FRAME_LEN_OFFSET2]; |
| | | } |
| | | else |
| | | { |
| | | info_len = p_data[T1_FRAME_LEN_OFFSET]; |
| | | } |
| | | return info_len; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function decode_ATR |
| | | * @Param p_data - received data and its must be PCB = 0xE4 or 0xE7. |
| | | * is_CIP - true if received data's PCB = 0xE4. |
| | | * @Return ESESTATUS_SUCCESS if decode ATR success, else ESESTATUS_INVALID_T1_LEN. |
| | | ******************************************************************************/ |
| | | static ESESTATUS decode_ATR(uint8_t *p_data, bool is_CIP) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | uint16_t info_len = get_info_len(p_data); |
| | | uint8_t *p_start = &p_data[T1_FRAME_LEN_OFFSET]; |
| | | if (!is_CIP && g_ese_ctx.is_T1_ext_hdr_len) |
| | | { |
| | | // Currently, ATR length is 0x13, exttended frame length high byte should be 0x00 |
| | | p_start++; |
| | | } |
| | | |
| | | if (sizeof(atr_info) == (info_len + 1)) |
| | | { |
| | | memcpy(&g_atr.len, p_start, sizeof(atr_info)); |
| | | } |
| | | else if (0 == p_data[T1_FRAME_LEN_OFFSET]) |
| | | { |
| | | // Do nothing, keep befor ATR value. |
| | | reset_ATR(); |
| | | } |
| | | else |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s : invalid ATR response AtrInfoLen = %02X\r\n", __FUNCTION__, (uint8_t)sizeof(atr_info)); |
| | | |
| | | status = ESESTATUS_INVALID_T1_LEN; |
| | | } |
| | | |
| | | if (ESESTATUS_SUCCESS == status) |
| | | { |
| | | g_ese_ctx.max_IFSC = (uint16_t)(((uint16_t)g_atr.max_IFSC[0]) << 8); |
| | | g_ese_ctx.max_IFSC |= g_atr.max_IFSC[1]; |
| | | g_ese_ctx.is_T1_ext_hdr_len = (g_atr.capbilities[1] & 0x08) != 0; |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function init_Iframe_from_cmd_apdu |
| | | * @Param p_cmd_apdu - 7816-4 APDU that shall be sent. |
| | | * cmd_len - Length of the apduCmd to be sent. |
| | | * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. |
| | | ******************************************************************************/ |
| | | ESESTATUS init_Iframe_from_cmd_apdu(uint8_t *p_cmd_apdu, uint16_t cmd_len) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | |
| | | g_ese_ctx.p_T1_params = &g_T1_params; |
| | | g_ese_ctx.p_T1_params->is_device_chaining = (cmd_len > g_ese_ctx.max_IFSC ? true : false); |
| | | g_ese_ctx.next_T1_state = I_BLK; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = IFRAME; |
| | | g_ese_ctx.p_T1_params->p_data_tx = p_cmd_apdu; |
| | | g_ese_ctx.p_T1_params->tx_len = cmd_len; |
| | | |
| | | g_ese_ctx.p_T1_params->tx_data_offset = 0; |
| | | g_ese_ctx.p_T1_params->tx_len_part = 0; |
| | | g_ese_ctx.p_T1_params->p_data_tx_part = NULL; |
| | | |
| | | g_ese_ctx.p_T1_params->resync_CIP_req_cnt = 0; |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function deinit_Iframe_from_cmd_apdu |
| | | * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. |
| | | ******************************************************************************/ |
| | | void deinit_Iframe_from_cmd_apdu(void) |
| | | { |
| | | if (NULL != g_ese_ctx.p_T1_params) |
| | | { |
| | | g_ese_ctx.p_T1_params->p_data_tx = NULL; |
| | | |
| | | if (NULL != g_ese_ctx.p_T1_params->p_data_tx_part) |
| | | { |
| | | g_ese_ctx.p_T1_params->p_data_tx_part = NULL; |
| | | } |
| | | |
| | | g_ese_ctx.p_T1_params = NULL; |
| | | } |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function free_tx_part_mem |
| | | ******************************************************************************/ |
| | | static void free_tx_part_mem(void) |
| | | { |
| | | if (NULL != g_ese_ctx.p_T1_params) |
| | | { |
| | | if (NULL != g_ese_ctx.p_T1_params->p_data_tx_part) |
| | | { |
| | | g_ese_ctx.p_T1_params->p_data_tx_part = NULL; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function reset_for_resync_rsp |
| | | ******************************************************************************/ |
| | | static void reset_for_resync_rsp(void) |
| | | { |
| | | g_ese_ctx.seq_num_card = 0; |
| | | g_ese_ctx.seq_num_device = 0; |
| | | g_ese_ctx.p_T1_params->recovery_cnt = 0; |
| | | g_ese_ctx.p_T1_params->resync_CIP_req_cnt = 0; |
| | | g_ese_ctx.p_T1_params->wtx_cnt = 0; |
| | | g_ese_ctx.p_T1_params->tx_data_offset = 0; |
| | | if (g_ese_ctx.p_T1_params->is_card_chaining) |
| | | { |
| | | t1_recv_data_list_destroy(); |
| | | } |
| | | g_ese_ctx.p_T1_params->is_device_chaining = false; |
| | | g_ese_ctx.p_T1_params->is_card_chaining = false; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function do_T1_recovery_at_undecode |
| | | * @Returns On success return ESESTATUS_SUCCESS, else ESESTATUS_FATAL_ERROR. |
| | | ******************************************************************************/ |
| | | ESESTATUS do_T1_recovery_at_undecode(void) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | if (g_ese_ctx.p_T1_params->recovery_cnt < g_ese_ctx.max_recovery_cnt) |
| | | { |
| | | g_ese_ctx.p_T1_params->recovery_cnt++; |
| | | |
| | | if ((SFRAME != g_ese_ctx.p_T1_params->tx_frame_type) || (WTX_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)) |
| | | { |
| | | g_ese_ctx.next_T1_state = R_PARITY_ERR; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = RFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RNACK_PARITY_ERROR; |
| | | // Should use the N(S), that is g_ese_ctx.seq_num_device |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (((SFRAME != g_ese_ctx.p_T1_params->tx_frame_type) || (WTX_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)) && !g_ese_ctx.is_resync_recovery_flag) |
| | | { |
| | | g_ese_ctx.is_resync_recovery_flag = true; |
| | | |
| | | // Do case 4 |
| | | g_ese_ctx.next_T1_state = S_RESYNC_REQ; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = SFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = RESYNC_REQ; |
| | | } |
| | | else if (g_ese_ctx.is_resync_recovery_flag) |
| | | { |
| | | if (g_ese_ctx.p_T1_params->resync_CIP_req_cnt < g_ese_ctx.max_recovery_cnt) |
| | | { |
| | | g_ese_ctx.p_T1_params->resync_CIP_req_cnt++; |
| | | |
| | | // Do case 5 |
| | | g_ese_ctx.next_T1_state = S_CIP_REQ; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = SFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = CIP_REQ; |
| | | } |
| | | else |
| | | { |
| | | status = ESESTATUS_FATAL_ERROR; |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // Chip hard reset if warm reset failed. |
| | | if ((SFRAME == g_ese_ctx.p_T1_params->tx_frame_type) && (CIP_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s: warm reset failed, TODO need chip hard reset to recover\r\n", __FUNCTION__); |
| | | // need to chip hard reset |
| | | status = ESESTATUS_FATAL_ERROR; |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | } |
| | | else |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s: S(... REQ) failed, warm reset to recover lastTxFrameType = %d, lastTxSFrameType = %d\r\n", __FUNCTION__, |
| | | g_ese_ctx.p_T1_params->tx_frame_type, g_ese_ctx.p_T1_params->tx_sub_Sframe_type); |
| | | |
| | | g_ese_ctx.next_T1_state = S_CIP_REQ; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = SFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = CIP_REQ; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function do_T1_recovery_at_decode_Iframe |
| | | * @Returns On success return ESESTATUS_SUCCESS, else ESESTATUS_FATAL_ERROR. |
| | | ******************************************************************************/ |
| | | static ESESTATUS do_T1_recovery_at_decode_Iframe(void) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | T1_frame_types last_rx_frame_type = g_ese_ctx.p_T1_params->last_rx_frame_type; |
| | | T1_pcb_bits *p_pcb_bits = &g_ese_ctx.p_T1_params->last_rx_pcb_bits; |
| | | |
| | | if (IFRAME == last_rx_frame_type) |
| | | { |
| | | if (g_ese_ctx.p_T1_params->recovery_cnt < g_ese_ctx.max_recovery_cnt) |
| | | { |
| | | g_ese_ctx.p_T1_params->recovery_cnt++; |
| | | if (p_pcb_bits->bit7 != g_ese_ctx.seq_num_card) |
| | | { |
| | | g_ese_ctx.next_T1_state = R_OTHER_ERR; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = RFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RNACK_OTHER_ERROR; |
| | | } |
| | | else |
| | | { |
| | | // Cannot be occured this case |
| | | LOG_INFO(TRACE_MODULE_SE, |
| | | "%s: an I-block received, seqNum exception, terminate transmission. lastTxSeqNum = %d, lastRxExpectedNum = %d, lastRxSeqNum = %d\r\n", |
| | | __FUNCTION__, g_ese_ctx.seq_num_device, g_ese_ctx.seq_num_card, p_pcb_bits->bit7); |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | g_ese_ctx.is_resync_recovery_flag = false; |
| | | status = ESESTATUS_INVALID_PARAMETER; |
| | | free_tx_part_mem(); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // Should transmit RESYNC_REQ to recover. |
| | | LOG_INFO(TRACE_MODULE_SE, "%s: lastRecvFrameType = %d, recovery_cnt = %d, max_recovery_cnt = %d RESYNC_REQ should be sent to recover\r\n", |
| | | __FUNCTION__, last_rx_frame_type, g_ese_ctx.p_T1_params->recovery_cnt, g_ese_ctx.max_recovery_cnt); |
| | | // RESYNC_REQ only send once, recovery_cnt should not be reset to zero. |
| | | g_ese_ctx.is_resync_recovery_flag = true; |
| | | |
| | | g_ese_ctx.next_T1_state = S_RESYNC_REQ; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = SFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = RESYNC_REQ; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | status = ESESTATUS_INVALID_PARAMETER; |
| | | LOG_INFO(TRACE_MODULE_SE, |
| | | "%s: should be called when received an invalid IFrame, but non-IFrame received, lastRecvFrameType = %d, recovery_cnt = %d, max_recovery_cnt = " |
| | | "%d\r\n", |
| | | __FUNCTION__, last_rx_frame_type, g_ese_ctx.p_T1_params->recovery_cnt, g_ese_ctx.max_recovery_cnt); |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | free_tx_part_mem(); |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function do_T1_recovery_at_decode_Sframe |
| | | * @Returns On success return ESESTATUS_SUCCESS, else ESESTATUS_FATAL_ERROR. |
| | | ******************************************************************************/ |
| | | static ESESTATUS do_T1_recovery_at_decode_Sframe(void) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | T1_frame_types last_rx_frame_type = g_ese_ctx.p_T1_params->last_rx_frame_type; |
| | | Sframe_types last_rx_sub_Sframe_type = g_ese_ctx.p_T1_params->last_rx_sub_Sframe_type; |
| | | |
| | | if ((SFRAME == last_rx_frame_type) && (NULL != g_ese_ctx.p_T1_params->p_data_tx)) |
| | | { |
| | | // recovery_cnt will be ignored for RESYNC_RSP and IFS_RSP |
| | | if (RESYNC_RSP == last_rx_sub_Sframe_type) |
| | | { |
| | | reset_for_resync_rsp(); |
| | | g_ese_ctx.next_T1_state = I_BLK; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = IFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = SFRAME_TYPE_INVALID; |
| | | g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RNACK_INVALID_ERROR; |
| | | } |
| | | else if (IFS_RSP == last_rx_sub_Sframe_type) |
| | | { |
| | | if (g_ese_ctx.p_T1_params->is_card_chaining) |
| | | { |
| | | g_ese_ctx.next_T1_state = R_ACK; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = RFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = SFRAME_TYPE_INVALID; |
| | | g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RACK; |
| | | } |
| | | else if (g_ese_ctx.p_T1_params->is_device_chaining) |
| | | { |
| | | g_ese_ctx.next_T1_state = I_BLK; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = IFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = SFRAME_TYPE_INVALID; |
| | | g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RNACK_INVALID_ERROR; |
| | | } |
| | | else |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s: device initiates block I-block is unchaining, terminate transmit when received IFS_RSP\r\n", __FUNCTION__); |
| | | // terminate transmit |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s: device initiates block is an I-block, lastTxFrameType = %d, but device received R-block, cannot be occurred.\r\n", |
| | | __FUNCTION__, last_rx_sub_Sframe_type); |
| | | // terminate transmit |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | status = ESESTATUS_INVALID_PARAMETER; |
| | | LOG_INFO(TRACE_MODULE_SE, |
| | | "%s: should be called when received an SFrame, but non-SFrame received, lastRecvFrameType = %d, recovery_cnt = %d, max_recovery_cnt = %d\r\n", |
| | | __FUNCTION__, last_rx_frame_type, g_ese_ctx.p_T1_params->recovery_cnt, g_ese_ctx.max_recovery_cnt); |
| | | |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | } |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function do_T1_recovery_at_decode_Rframe |
| | | * @Returns On success return ESESTATUS_SUCCESS, else ESESTATUS_FATAL_ERROR. |
| | | ******************************************************************************/ |
| | | static ESESTATUS do_T1_recovery_at_decode_Rframe(void) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | T1_frame_types last_rx_frame_type = g_ese_ctx.p_T1_params->last_rx_frame_type; |
| | | Rframe_types last_rx_sub_Rframe_type = g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type; |
| | | |
| | | if (RFRAME == last_rx_frame_type) |
| | | { |
| | | if (g_ese_ctx.p_T1_params->recovery_cnt < g_ese_ctx.max_recovery_cnt) |
| | | { |
| | | g_ese_ctx.p_T1_params->recovery_cnt++; |
| | | |
| | | if ((NULL != g_ese_ctx.p_T1_params->p_data_tx)) |
| | | { |
| | | // device initiates block is an I-block |
| | | if (IFRAME == g_ese_ctx.p_T1_params->tx_frame_type) |
| | | { |
| | | if (RACK == last_rx_sub_Rframe_type) |
| | | { |
| | | g_ese_ctx.next_T1_state = R_OTHER_ERR; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = RFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RNACK_OTHER_ERROR; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = SFRAME_TYPE_INVALID; |
| | | LOG_INFO(TRACE_MODULE_SE, "%s: RACK for RNACK_OTHER_ERROR\r\n", __FUNCTION__); |
| | | } |
| | | else if (RNACK_PARITY_ERROR == last_rx_sub_Rframe_type) |
| | | { |
| | | g_ese_ctx.next_T1_state = I_BLK; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = IFRAME; |
| | | // LOG_INFO(TRACE_MODULE_SE, "%s: RNACK_PARITY_ERROR, resend IFRAME\r\n", __FUNCTION__); |
| | | } |
| | | else if (RNACK_OTHER_ERROR == last_rx_sub_Rframe_type) |
| | | { |
| | | g_ese_ctx.seq_num_device ^= 0x01; |
| | | g_ese_ctx.is_seq_num_dr = true; |
| | | g_ese_ctx.next_T1_state = I_BLK; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = IFRAME; |
| | | // LOG_INFO(TRACE_MODULE_SE, "%s: RNACK_OTHER_ERROR, resend IFRAME\r\n", __FUNCTION__); |
| | | } |
| | | else |
| | | { |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | g_ese_ctx.is_resync_recovery_flag = false; |
| | | LOG_INFO( |
| | | TRACE_MODULE_SE, |
| | | "%s: lastSendIFrame, lastRecvRFrame recovery failed, unkonwn lastRFrameType = %d, recovery_cnt = %d, max_recovery_cnt = %d\r\n", |
| | | __FUNCTION__, g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type, g_ese_ctx.p_T1_params->recovery_cnt, g_ese_ctx.max_recovery_cnt); |
| | | } |
| | | } |
| | | else if (SFRAME == g_ese_ctx.p_T1_params->tx_frame_type) |
| | | { |
| | | if ((WTX_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type) || (IFS_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type) || |
| | | (ABORT_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, |
| | | "%s: device initiates block is an I-block, lastTxSubSFrameType = %d, but device received R-block, cannot be occurred.\r\n", |
| | | __FUNCTION__, g_ese_ctx.p_T1_params->tx_sub_Sframe_type); |
| | | // terminate transmit |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | g_ese_ctx.is_resync_recovery_flag = false; |
| | | } |
| | | else |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s: device initiates block is I-block, lastTxSubSFrameType = %d, recovery_cnt = %d\r\n", __FUNCTION__, |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type, g_ese_ctx.p_T1_params->recovery_cnt); |
| | | } |
| | | } |
| | | else if (RFRAME == g_ese_ctx.p_T1_params->tx_frame_type) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s: device initiates block is I-block, lastTxSubRFrameType = %d, recovery_cnt = %d\r\n", __FUNCTION__, |
| | | g_ese_ctx.p_T1_params->tx_sub_Rframe_type, g_ese_ctx.p_T1_params->recovery_cnt); |
| | | } |
| | | else |
| | | { |
| | | // unknown R-block type, terminate transmit |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | g_ese_ctx.is_resync_recovery_flag = false; |
| | | LOG_INFO(TRACE_MODULE_SE, "%s: lastSend unknown frame type, recovery_cnt = %d\r\n", __FUNCTION__, g_ese_ctx.p_T1_params->recovery_cnt); |
| | | } |
| | | } |
| | | else if (SFRAME == g_ese_ctx.p_T1_params->tx_frame_type) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s: device initiates block is S-block, lastTxSubSFrameType = %d, recovery_cnt = %d\r\n", __FUNCTION__, |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type, g_ese_ctx.p_T1_params->recovery_cnt); |
| | | } |
| | | else |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s: device initiates block cannot be an R-block, lastTxFrameType = %d\r\n", __FUNCTION__, |
| | | g_ese_ctx.p_T1_params->tx_frame_type); |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | g_ese_ctx.is_resync_recovery_flag = false; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (!g_ese_ctx.is_resync_recovery_flag && (NULL != g_ese_ctx.p_T1_params->p_data_tx)) |
| | | { |
| | | g_ese_ctx.is_resync_recovery_flag = true; |
| | | g_ese_ctx.next_T1_state = S_RESYNC_REQ; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = SFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = RESYNC_REQ; |
| | | } |
| | | else if (g_ese_ctx.is_resync_recovery_flag && (NULL != g_ese_ctx.p_T1_params->p_data_tx)) |
| | | { |
| | | free_tx_part_mem(); |
| | | g_ese_ctx.is_resync_recovery_flag = false; |
| | | g_ese_ctx.next_T1_state = S_CIP_REQ; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = SFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = CIP_REQ; |
| | | } |
| | | else |
| | | { |
| | | status = ESESTATUS_INVALID_PARAMETER; |
| | | LOG_INFO(TRACE_MODULE_SE, |
| | | "%s: should be called when received an RFrame, but non-RFrame received, lastRecvFrameType = %d, recovery_cnt = %d, max_recovery_cnt = " |
| | | "%d\r\n", |
| | | __FUNCTION__, last_rx_frame_type, g_ese_ctx.p_T1_params->recovery_cnt, g_ese_ctx.max_recovery_cnt); |
| | | // terminate transmit |
| | | g_ese_ctx.next_T1_state = STATE_IDEL; |
| | | } |
| | | } |
| | | } |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_recv_data_store_in_list |
| | | * @Param p_data - 7816-4 APDU response that shall be stored. |
| | | * data_len - Length of the APDU response. |
| | | * total_len - T=1 total length, contains prologue and epilogue. |
| | | * @Returns On Success ESESTATUS_SUCCESS else ESESTATUS error. |
| | | ******************************************************************************/ |
| | | static ESESTATUS t1_recv_data_store_in_list(uint8_t *p_data, uint16_t data_len, uint16_t total_len) |
| | | { |
| | | if ((0 == data_len) || (data_len != (total_len - get_header_len(true)))) |
| | | { |
| | | // Other error, do nothing |
| | | return ESESTATUS_INVALID_T1_LEN; |
| | | } |
| | | |
| | | // if (g_recv_total_len == 0) |
| | | // { |
| | | // memset(g_all_data_buf, 0, sizeof(g_all_data_buf)); |
| | | // } |
| | | memcpy(g_all_data_buf + g_recv_total_len, p_data, data_len); |
| | | g_recv_total_len += data_len; |
| | | return ESESTATUS_SUCCESS; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_recv_data_list_destroy |
| | | ******************************************************************************/ |
| | | static void t1_recv_data_list_destroy(void) |
| | | { |
| | | g_recv_total_len = 0; |
| | | } |
| | | |
| | | static void reset_ATR(void) |
| | | { |
| | | atr_info atr = { |
| | | .len = 0x13, |
| | | .vendor_ID = {0x00}, |
| | | .dll_IC = 0x01, |
| | | .bgt = {0x00, 0x01}, |
| | | .bwt = {0x03, 0xE8}, |
| | | .max_freq = {0x4E, 0x20}, |
| | | .checksum = 0x00, |
| | | .default_IFSC = 0xFE, |
| | | .num_channels = 0x01, |
| | | .max_IFSC = {0x00, 0xFF}, |
| | | .capbilities = {0x00, 0x14}, // Extended frame length feature doesn't support |
| | | }; |
| | | |
| | | g_atr = atr; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_transmit_receive_apdu |
| | | * @Param p_cmd_apdu - 7816-4 APDU that shall be sent. |
| | | * cmd_len - Length of the apduCmd to be sent. |
| | | * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. |
| | | ******************************************************************************/ |
| | | ESESTATUS t1_transmit_receive_apdu(uint8_t *p_cmd_apdu, uint16_t cmd_len) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | // LOG_INFO(TRACE_MODULE_SE, "%s: Enter\r\n", __FUNCTION__); |
| | | status = init_Iframe_from_cmd_apdu(p_cmd_apdu, cmd_len); |
| | | if (ESESTATUS_SUCCESS != status) |
| | | { |
| | | goto cleanup; |
| | | } |
| | | |
| | | status = Transmit_receive_process(); |
| | | |
| | | if (ESESTATUS_SUCCESS != status) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_SE, "%s: t1_transmit_receive_apdu failed, status = %d\r\n", __FUNCTION__, status); |
| | | } |
| | | |
| | | cleanup: |
| | | deinit_Iframe_from_cmd_apdu(); |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_CIP_req |
| | | * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. |
| | | ******************************************************************************/ |
| | | ESESTATUS t1_CIP_req(void) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | // LOG_INFO(TRACE_MODULE_SE, "t1CIPReq() enter\r\n"); |
| | | |
| | | g_ese_ctx.p_T1_params = &g_T1_params; |
| | | g_ese_ctx.p_T1_params->is_device_chaining = false; |
| | | g_ese_ctx.next_T1_state = S_CIP_REQ; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = SFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = CIP_REQ; |
| | | |
| | | status = Transmit_receive_process(); |
| | | g_ese_ctx.p_T1_params = NULL; |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_ATR_req |
| | | * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. |
| | | ******************************************************************************/ |
| | | ESESTATUS t1_ATR_req(void) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | |
| | | g_ese_ctx.p_T1_params = &g_T1_params; |
| | | g_ese_ctx.p_T1_params->is_device_chaining = false; |
| | | g_ese_ctx.next_T1_state = S_ATR_REQ; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = SFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = ATR_REQ; |
| | | |
| | | status = Transmit_receive_process(); |
| | | g_ese_ctx.p_T1_params = NULL; |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_IFSD_req |
| | | * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. |
| | | ******************************************************************************/ |
| | | ESESTATUS t1_IFSD_req(void) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | |
| | | g_ese_ctx.p_T1_params = &g_T1_params; |
| | | g_ese_ctx.p_T1_params->is_device_chaining = false; |
| | | g_ese_ctx.next_T1_state = S_IFS_REQ; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = SFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = IFS_REQ; |
| | | |
| | | status = Transmit_receive_process(); |
| | | g_ese_ctx.p_T1_params = NULL; |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * @Function t1_prop_end_apdu_req |
| | | * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. |
| | | ******************************************************************************/ |
| | | ESESTATUS t1_prop_end_apdu_req(void) |
| | | { |
| | | ESESTATUS status = ESESTATUS_SUCCESS; |
| | | |
| | | g_ese_ctx.p_T1_params = &g_T1_params; |
| | | g_ese_ctx.p_T1_params->is_device_chaining = false; |
| | | g_ese_ctx.next_T1_state = S_PROP_END_APDU_REQ; |
| | | g_ese_ctx.p_T1_params->tx_frame_type = SFRAME; |
| | | g_ese_ctx.p_T1_params->tx_sub_Sframe_type = PROP_END_APDU_REQ; |
| | | |
| | | status = Transmit_receive_process(); |
| | | g_ese_ctx.p_T1_params = NULL; |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /****************************************************************************** |
| | | * Function t1_receive_data_and_get |
| | | * @Param pp_Data - a pointer address to the received data. |
| | | * data_len - a pointer to the length of the received data. |
| | | * Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. |
| | | ******************************************************************************/ |
| | | ESESTATUS t1_receive_data_and_get(uint8_t **pp_Data, uint16_t *data_len) |
| | | { |
| | | *data_len = (uint16_t)g_recv_total_len; |
| | | *pp_Data = g_all_data_buf; |
| | | return ESESTATUS_SUCCESS; |
| | | } |