#include #include #include #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; }