aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/test/card_emu_tests.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2015-11-09 00:50:54 +0100
committerHarald Welte <laforge@gnumonks.org>2015-11-09 00:50:54 +0100
commit9d3e38242cfd3aa9a6f665851ad0bf43d3f57e75 (patch)
treef053a734ccb0db944f9fb003732649b055905c5b /firmware/test/card_emu_tests.c
parentf64f68871ef4bc81236bdbc326098cb3f323f99a (diff)
initial commit of more code towards card emulation
I couldn't help but to spend my sunday on working towards card emulation, including * various state machines in the target about ISO7816 states * tc_etu timer import from simtrace1 * req_ctx import from simtrace1 (needs renaming and simplifiation) * USB protocol description as cardemu_prot.h * some host-based testing code to test the state machines The code seems to work fine throughout card reset, sending ATR and receiving the TPDU header of the first APDU, up to the point where it marks the TPDU header as to-be-transmitted over th bulk-in endpoint. Sending the ATR must be done inside the firmware for timing requirements. From that point onwards, the host needs to respond at the very least with a procedure byte, and some indication whether or not the card emulator should continue to transmit data (card->reader), or receive data (reader->card). The code is intentionally not hooked up yet with the USB logic nor with the UART. I want host-based testing completed before doing that.
Diffstat (limited to 'firmware/test/card_emu_tests.c')
-rw-r--r--firmware/test/card_emu_tests.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/firmware/test/card_emu_tests.c b/firmware/test/card_emu_tests.c
new file mode 100644
index 0000000..82f22e2
--- /dev/null
+++ b/firmware/test/card_emu_tests.c
@@ -0,0 +1,160 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "card_emu.h"
+#include "cardemu_prot.h"
+#include "tc_etu.h"
+#include "req_ctx.h"
+
+/* stub functions required by card_emu.c */
+
+int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
+{
+ printf("uart_update_fidi(uart_chan=%u, fidi=%u)\n", uart_chan, fidi);
+ return 0;
+}
+
+int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
+{
+ printf("TX: 0x%02x\n", byte);
+ return 1;
+}
+
+void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
+{
+ printf("uart_enable(uart_chan=%u, rxtx=0x%02x)\n", uart_chan, rxtx);
+}
+
+void tc_etu_set_wtime(uint8_t tc_chan, uint16_t wtime)
+{
+ printf("tc_etu_set_wtime(tc_chan=%u, wtime=%u)\n", tc_chan, wtime);
+}
+
+void tc_etu_set_etu(uint8_t tc_chan, uint16_t etu)
+{
+ printf("tc_etu_set_etu(tc_chan=%u, etu=%u)\n", tc_chan, etu);
+}
+
+void tc_etu_init(uint8_t chan_nr, void *handle)
+{
+}
+
+
+
+
+#if 0
+/* process a single byte received from the reader */
+void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte);
+
+/* return a single byte to be transmitted to the reader */
+int card_emu_get_tx_byte(struct card_handle *ch, uint8_t *byte);
+
+/* hardware driver informs us that a card I/O signal has changed */
+void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active);
+
+/* User sets a new ATR to be returned during next card reset */
+int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len);
+#endif
+
+
+static int verify_atr(struct card_handle *ch)
+{
+ uint8_t atr[4];
+ uint8_t byte;
+ unsigned int i;
+
+ printf("receiving + verifying ATR:");
+ for (i = 0; i < sizeof(atr); i++) {
+ assert(card_emu_get_tx_byte(ch, &atr[i]) == 1);
+ printf(" %02x", atr[i]);
+ }
+ printf("\n");
+ assert(card_emu_get_tx_byte(ch, &byte) == 0);
+
+ return 1;
+}
+
+static void io_start_card(struct card_handle *ch)
+{
+ uint8_t byte;
+
+ /* bring the card up from the dead */
+ card_emu_io_statechg(ch, CARD_IO_VCC, 1);
+ assert(card_emu_get_tx_byte(ch, &byte) == 0);
+ card_emu_io_statechg(ch, CARD_IO_CLK, 1);
+ assert(card_emu_get_tx_byte(ch, &byte) == 0);
+ card_emu_io_statechg(ch, CARD_IO_RST, 1);
+ assert(card_emu_get_tx_byte(ch, &byte) == 0);
+
+ /* release from reset and verify th ATR */
+ card_emu_io_statechg(ch, CARD_IO_RST, 0);
+ verify_atr(ch);
+}
+
+static void send_bytes(struct card_handle *ch, const uint8_t *bytes, unsigned int len)
+{
+ unsigned int i;
+ for (i = 0; i < len; i++)
+ card_emu_process_rx_byte(ch, bytes[i]);
+}
+
+static void dump_rctx(struct req_ctx *rctx)
+{
+ struct cardemu_usb_msg_hdr *mh =
+ (struct cardemu_usb_msg_hdr *) rctx->data;
+ struct cardemu_usb_msg_rx_data *rxd;
+ int i;
+
+ printf("req_ctx(%p): state=%u, size=%u, tot_len=%u, idx=%u, data=%p\n",
+ rctx, rctx->state, rctx->size, rctx->tot_len, rctx->idx, rctx->data);
+ printf(" msg_type=%u, seq_nr=%u, data_len=%u\n",
+ mh->msg_type, mh->seq_nr, mh->data_len);
+
+ switch (mh->msg_type) {
+ case CEMU_USB_MSGT_DO_RX_DATA:
+ rxd = (struct cardemu_usb_msg_rx_data *)mh;
+ printf(" flags=%x, data=", rxd->flags);
+ for (i = 0; i < mh->data_len; i++)
+ printf(" %02x", rxd->data[i]);
+ printf("\n");
+ break;
+ }
+}
+
+static void send_tpdu_hdr(struct card_handle *ch, const uint8_t *tpdu_hdr)
+{
+ struct req_ctx *rctx;
+
+ /* we don't want a receive context to become available during
+ * the first four bytes */
+ send_bytes(ch, tpdu_hdr, 4);
+ assert(!req_ctx_find_get(1, RCTX_S_USB_TX_PENDING, RCTX_S_USB_TX_BUSY));
+
+ send_bytes(ch, tpdu_hdr+4, 1);
+ /* but then after the final byte of the TPDU header, we want a
+ * receive context to be available for USB transmission */
+ rctx = req_ctx_find_get(1, RCTX_S_USB_TX_PENDING, RCTX_S_USB_TX_BUSY);
+ assert(rctx);
+ dump_rctx(rctx);
+}
+
+const uint8_t tpdu_hdr_sel_mf[] = { 0xA0, 0xA4, 0x00, 0x00, 0x02 };
+
+int main(int argc, char **argv)
+{
+ struct card_handle *ch;
+
+ req_ctx_init();
+
+ ch = card_emu_init(0, 23, 42);
+ assert(ch);
+
+ io_start_card(ch);
+
+ send_tpdu_hdr(ch, tpdu_hdr_sel_mf);
+
+ exit(0);
+}