#include #include #include #include "phdriver.h" #include "se_api.h" #include "mk_misc.h" #include "mk_trace.h" /****************************************************************************** * @Function t1_read_no_wait * @Param p_data_len - point to data length. * @Returns On success return ESESTATUS_SUCCESS, else ESESTATUS_xxx. ******************************************************************************/ static ESESTATUS t1_read_no_wait(uint16_t *p_data_len) { ESESTATUS status = ESESTATUS_SUCCESS; int ret = -1; 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)); // sys_timer_delay_ms(1); // 10 ret = phdriver_read(gp_data_rx, 1); if ((ret < 0) || (NAD_C2DT != gp_data_rx[0])) { return ESESTATUS_NO_DATA_TO_RECEIVE; } else { ret = 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]; // CRC has 2 bytes, so the second read len is INF len + 1 if (CRC == g_atr.checksum) { num_bytes_to_read += 1; } } else { // LRC has 1 bytes, so the second read len is INF len num_bytes_to_read = gp_data_rx[T1_FRAME_LEN_OFFSET]; } read_index = hdrLen; total_cnt += hdrLen; } #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 { status = ESESTATUS_FAILED; } } 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; } else { total_cnt += num_bytes_to_read; } } } #endif if (ESESTATUS_SUCCESS != status) { *p_data_len = 0; } else { *p_data_len = total_cnt; } return status; } /****************************************************************************** * @Function response_no_wait_process * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. ******************************************************************************/ static ESESTATUS response_no_wait_process(void) { ESESTATUS status = ESESTATUS_SUCCESS; uint16_t data_len = 0; status = t1_read_no_wait(&data_len); if (status == ESESTATUS_NO_DATA_TO_RECEIVE) { return ESESTATUS_NO_DATA_TO_RECEIVE; } 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 { status = do_T1_recovery_at_undecode(); } } else if (ESESTATUS_FATAL_ERROR == status) { g_ese_ctx.next_T1_state = STATE_IDEL; } else { status = do_T1_recovery_at_undecode(); } return status; } /****************************************************************************** * @Function transmit_only_process * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. ******************************************************************************/ static ESESTATUS transmit_only_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(); // just send 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) { if ((g_ese_ctx.p_T1_params->is_device_chaining == true) && (g_ese_ctx.next_T1_state != STATE_IDEL)) { #ifdef DBG_LEVEL_STACK gDumpStackFlag = false; #endif g_ese_ctx.p_T1_params->blk_retry_cnt = 0; status = response_process(); // status = response_no_wait_process(); } else { break; } } 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 receive_only_process * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. ******************************************************************************/ static ESESTATUS receive_only_process(void) { ESESTATUS status = ESESTATUS_SUCCESS; #ifdef DBG_LEVEL_STACK gDumpStackFlag = false; #endif g_ese_ctx.p_T1_params->blk_retry_cnt = 0; status = response_no_wait_process(); while ((status != ESESTATUS_NO_DATA_TO_RECEIVE) && (g_ese_ctx.next_T1_state != STATE_IDEL)) { if (g_ese_ctx.p_T1_params->last_rx_frame_type == IFRAME) { if ((g_ese_ctx.p_T1_params->is_card_chaining == true) && (g_ese_ctx.next_T1_state == R_ACK)) { status = Transmit_receive_process(); // status = transmit_only_process(); } break; } else // if (g_ese_ctx.p_T1_params->last_rx_frame_type == RFRAME) { transmit_only_process(); status = response_no_wait_process(); } } return status; } /****************************************************************************** * @Function t1_transmit_only_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_only_apdu(uint8_t *p_cmd_apdu, uint16_t cmd_len) { ESESTATUS status = ESESTATUS_SUCCESS; status = init_Iframe_from_cmd_apdu(p_cmd_apdu, cmd_len); if (ESESTATUS_SUCCESS != status) { goto cleanup; } status = transmit_only_process(); if (ESESTATUS_SUCCESS != status) { LOG_INFO(TRACE_MODULE_SE, "%s: failed, status = %d\r\n", __FUNCTION__, status); } else { // if success,after receiving the resp,execu deinit_Iframe_from_cmd_apdu return status; } cleanup: deinit_Iframe_from_cmd_apdu(); return status; } /****************************************************************************** * @Function t1_receive_only_apdu * @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error. ******************************************************************************/ ESESTATUS t1_receive_only_apdu(void) { ESESTATUS status = ESESTATUS_SUCCESS; status = receive_only_process(); // response_no_wait_process(); if (ESESTATUS_NO_DATA_TO_RECEIVE == status) { return ESESTATUS_NO_DATA_TO_RECEIVE; } if (ESESTATUS_SUCCESS != status) { LOG_INFO(TRACE_MODULE_SE, "%s: failed, status = %d\r\n", __FUNCTION__, status); } deinit_Iframe_from_cmd_apdu(); return status; }