diff --git a/firmware/src_simtrace/card_emu.c b/firmware/src_simtrace/card_emu.c index 97b3d94e..ec9fdb8c 100644 --- a/firmware/src_simtrace/card_emu.c +++ b/firmware/src_simtrace/card_emu.c @@ -165,6 +165,45 @@ static void flush_rx_buffer(struct card_handle *ch) * be transmitted now */ } +/* convert a non-contiguous PTS request/responsei into a contiguous + * buffer, returning the number of bytes used in the buffer */ +static int serialize_pts(uint8_t *out, const uint8_t *in) +{ + int i = 0; + + out[i++] = in[_PTSS]; + out[i++] = in[_PTS0]; + if (in[_PTS0] & (1 << 4)) + out[i++] = in[_PTS1]; + if (in[_PTS0] & (1 << 5)) + out[i++] = in[_PTS2]; + if (in[_PTS0] & (1 << 6)) + out[i++] = in[_PTS3]; + out[i++] = in[_PCK]; + + return i; +} + +static void flush_pts(struct card_handle *ch) +{ + struct req_ctx *rctx; + struct cardemu_usb_msg_pts_info *ptsi; + + rctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY); + if (!rctx) + return; + + ptsi = (struct cardemu_usb_msg_pts_info *) rctx->data; + ptsi->hdr.msg_type = CEMU_USB_MSGT_DO_PTS; + ptsi->hdr.data_len = serialize_pts(ptsi->req, ch->pts.req); + serialize_pts(ptsi->resp, ch->pts.resp); + + req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING); + + /* FIXME: call into USB code to see if this buffer can + * be transmitted now */ +} + static void update_fidi(struct card_handle *ch) { int rc; @@ -310,6 +349,7 @@ process_byte_pts(struct card_handle *ch, uint8_t byte) case PTS_S_WAIT_REQ_PCK: ch->pts.req[_PCK] = byte; /* FIXME: check PCK */ + /* FIXME: check if proposal matches capabilities in ATR */ memcpy(ch->pts.resp, ch->pts.req, sizeof(ch->pts.resp)); break; default: @@ -320,6 +360,12 @@ process_byte_pts(struct card_handle *ch, uint8_t byte) /* calculate the next state and set it */ set_pts_state(ch, next_pts_state(ch)); + if (ch->pts.state == PTS_S_WAIT_RESP_PTSS) { + flush_pts(ch); + /* activate UART TX to transmit PTS response */ + card_emu_uart_enable(ch->uart_chan, ENABLE_TX); + } + return ISO_S_IN_PTS; } diff --git a/firmware/test/card_emu_tests.c b/firmware/test/card_emu_tests.c index 235f5115..e071dfa0 100644 --- a/firmware/test/card_emu_tests.c +++ b/firmware/test/card_emu_tests.c @@ -180,6 +180,25 @@ static void get_and_verify_rctx(int state, const uint8_t *data, unsigned int len req_ctx_set_state(rctx, RCTX_S_FREE); } +static void get_and_verify_rctx_pps(const uint8_t *data, unsigned int len) +{ + struct req_ctx *rctx; + struct cardemu_usb_msg_pts_info *ptsi; + + rctx = req_ctx_find_get(0, RCTX_S_USB_TX_PENDING, RCTX_S_USB_TX_BUSY); + assert(rctx); + dump_rctx(rctx); + + ptsi = (struct cardemu_usb_msg_pts_info *) rctx->data; + /* FIXME: verify */ + assert(ptsi->hdr.msg_type == CEMU_USB_MSGT_DO_PTS); + assert(!memcmp(ptsi->req, data, len)); + assert(!memcmp(ptsi->resp, data, len)); + + /* free the req_ctx, indicating it has fully arrived on the host */ + req_ctx_set_state(rctx, RCTX_S_FREE); +} + /* emulate a TPDU header being sent by the reader/phone */ static void rdr_send_tpdu_hdr(struct card_handle *ch, const uint8_t *tpdu_hdr) { @@ -304,6 +323,27 @@ test_tpdu_card2reader(struct card_handle *ch, const uint8_t *hdr, const uint8_t card_emu_io_statechg(ch, CARD_IO_CLK, 1); } +const uint8_t pps[] = { + /* PPSS identifies the PPS request or response and is set to + * 'FF'. */ + 0xFF, // PPSS + /* In PPS0, each bit 5, 6 or 7 set to 1 indicates the presence + * of an optional byte PPS 1 , PPS 2 , PPS 3 , + * respectively. Bits 4 to 1 encode a type T to propose a + * transmission protocol. Bit 8 is reserved for future + * use and shall be set to 0. */ + 0b00010000, // PPS0: PPS1 present + 0x00, // PPS1 proposed Fi/Di value + 0xFF ^ 0b00010000// PCK +}; + +static void +test_ppss(struct card_handle *ch) +{ + reader_send_bytes(ch, pps, sizeof(pps)); + get_and_verify_rctx_pps(pps, sizeof(pps)); + card_tx_verify_chars(ch, pps, sizeof(pps)); +} /* READ RECORD (offset 0, 10 bytes) */ const uint8_t tpdu_hdr_read_rec[] = { 0xA0, 0xB2, 0x00, 0x00, 0x0A }; @@ -327,6 +367,8 @@ int main(int argc, char **argv) io_start_card(ch); card_tx_verify_chars(ch, NULL, 0); + test_ppss(ch); + for (i = 0; i < 2; i++) { test_tpdu_reader2card(ch, tpdu_hdr_write_rec, tpdu_body_write_rec, sizeof(tpdu_body_write_rec));