# HG changeset patch # User Mychaela Falconia # Date 1693471583 0 # Node ID 118a12e9483bc566e1c21385950fff78aa40c609 # Parent 510bef2b20005d72df7de4d37a4889f30580378c simtrace3-sniff-dec started diff -r 510bef2b2000 -r 118a12e9483b .hgignore --- a/.hgignore Wed Aug 30 05:39:53 2023 +0000 +++ b/.hgignore Thu Aug 31 08:46:23 2023 +0000 @@ -19,4 +19,5 @@ ^boards/sim-fpc-pasv/pcb/gerbers\. ^boards/sim-fpc-pasv/src/elements\.pcb$ +^sw/sniff-dec/simtrace3-sniff-dec$ ^sw/sniff-rx/simtrace3-sniff-rx$ diff -r 510bef2b2000 -r 118a12e9483b sw/sniff-dec/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sw/sniff-dec/Makefile Thu Aug 31 08:46:23 2023 +0000 @@ -0,0 +1,20 @@ +CC= gcc +CFLAGS= -O2 +PROG= simtrace3-sniff-dec +OBJS= atr.o command.o dispatch.o invtable.o main.o parity.o pps.o + +INSTALL_PREFIX= /opt/freecalypso + +INSTBIN=${INSTALL_PREFIX}/bin + +all: ${PROG} + +${PROG}: ${OBJS} ${LIBS} + ${CC} ${CFLAGS} -o $@ ${OBJS} ${LIBS} + +install: + mkdir -p ${INSTBIN} + install -c ${PROG} ${INSTBIN} + +clean: + rm -f *.o ${PROG} diff -r 510bef2b2000 -r 118a12e9483b sw/sniff-dec/atr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sw/sniff-dec/atr.c Thu Aug 31 08:46:23 2023 +0000 @@ -0,0 +1,175 @@ +/* + * Here we implement ATR decoding. + */ + +#include +#include +#include +#include +#include +#include "state.h" + +extern char linebuf[]; +extern int lineno; +extern unsigned rx_byte; +extern int state; + +#define MAX_ATR_BYTES 33 + +#define SUBST_TS 0 +#define SUBST_T0 1 +#define SUBST_TAn 2 +#define SUBST_TBn 3 +#define SUBST_TCn 4 +#define SUBST_TDn 5 +#define SUBST_HIST 6 +#define SUBST_TCK 7 + +static char atr_start_timestamp[18]; +static int atr_start_line; +static int substate; +static u_char atr_bytes[MAX_ATR_BYTES]; +static unsigned byte_count; +static u_char latch_y, latch_k, have_tck; + +void +atr_begin() +{ + strcpy(atr_start_timestamp, linebuf); + atr_start_line = lineno; + substate = SUBST_TS; + byte_count = 0; +} + +static int +advance_state() +{ + if (substate == SUBST_TAn) { + if (latch_y & 0x10) + return 0; + substate = SUBST_TBn; + } + if (substate == SUBST_TBn) { + if (latch_y & 0x20) + return 0; + substate = SUBST_TCn; + } + if (substate == SUBST_TCn) { + if (latch_y & 0x40) + return 0; + substate = SUBST_TDn; + } + if (substate == SUBST_TDn) { + if (latch_y & 0x80) + return 0; + substate = SUBST_HIST; + } + if (substate == SUBST_HIST) { + if (latch_k) + return 0; + substate = SUBST_TCK; + } + if (substate == SUBST_TCK) { + if (have_tck) + return 0; + return 1; + } + fprintf(stderr, "BUG in ATR decoder: bad state in advance_state()\n"); + abort(); +} + +static void +check_tck() +{ + unsigned n, xor; + + xor = 0; + for (n = 1; n < byte_count; n++) + xor ^= atr_bytes[n]; + printf(" TCK is %s\n", xor ? "bad!" : "correct"); +} + +static void +atr_finish() +{ + unsigned n; + + printf("%s line %d: ATR\n", atr_start_timestamp, atr_start_line); + for (n = 0; n < byte_count; n++) + printf(" %02X", atr_bytes[n]); + putchar('\n'); + if (have_tck) + check_tck(); + state = STATE_READY_FOR_CMD; +} + +void +atr_byte_in() +{ + atr_bytes[byte_count++] = rx_byte; + switch (substate) { + case SUBST_TS: + substate = SUBST_T0; + return; + case SUBST_T0: + latch_y = rx_byte & 0xF0; + latch_k = rx_byte & 0x0F; + have_tck = 0; + substate = SUBST_TAn; + if (advance_state()) { + atr_finish(); + return; + } + return; + case SUBST_TAn: + substate = SUBST_TBn; + if (advance_state()) { + atr_finish(); + return; + } + break; + case SUBST_TBn: + substate = SUBST_TCn; + if (advance_state()) { + atr_finish(); + return; + } + break; + case SUBST_TCn: + substate = SUBST_TDn; + if (advance_state()) { + atr_finish(); + return; + } + break; + case SUBST_TDn: + latch_y = rx_byte & 0xF0; + if (rx_byte & 0x0F) + have_tck = 1; + substate = SUBST_TAn; + if (advance_state()) { + atr_finish(); + return; + } + break; + case SUBST_HIST: + latch_k--; + if (advance_state()) { + atr_finish(); + return; + } + break; + case SUBST_TCK: + atr_finish(); + return; + default: + fprintf(stderr, + "BUG in ATR decoder: bad state in atr_byte_in()\n"); + abort(); + } + if (byte_count < MAX_ATR_BYTES) + return; + printf("%s line %d: ERROR: ATR is too long\n", atr_start_timestamp, + atr_start_line); + state = STATE_ERROR; +} diff -r 510bef2b2000 -r 118a12e9483b sw/sniff-dec/command.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sw/sniff-dec/command.c Thu Aug 31 08:46:23 2023 +0000 @@ -0,0 +1,23 @@ +/* + * Here we implement decoding of command APDU exchanges. + */ + +#include +#include +#include +#include +#include +#include "state.h" + +extern char linebuf[]; +extern int lineno; +extern unsigned rx_byte; +extern int state; + +void +start_cmd_header() +{ + printf("input line %d: command header, end of implementation so far\n", + lineno); + exit(0); +} diff -r 510bef2b2000 -r 118a12e9483b sw/sniff-dec/dispatch.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sw/sniff-dec/dispatch.c Thu Aug 31 08:46:23 2023 +0000 @@ -0,0 +1,150 @@ +/* + * Dispatching received FPGA words based on the current state. + */ + +#include +#include +#include +#include "state.h" + +extern char linebuf[]; +extern int lineno; +extern unsigned fpga_word; + +extern u_char parity_table[256]; +extern u_char inverse_coding_table[256]; + +int state; +int inverse_conv; +unsigned rx_byte; + +#define PREFIX "%s line %d: " + +static void +handle_rst_change() +{ + if (fpga_word & 0x4000) { + printf(PREFIX "RST high, card session begin\n", + linebuf, lineno); + state = STATE_ATR_TS; + atr_begin(); + } else { + printf(PREFIX "RST low, card session end\n", linebuf, lineno); + state = STATE_RSTLOW; + } +} + +static int +byte_prelim_checks() +{ + if (!(fpga_word & 0x4000)) { + printf(PREFIX "ERROR: char Rx with RST low\n", linebuf, lineno); + return 1; + } + if (fpga_word & 0x0200) { + printf(PREFIX "ERROR: start bit midpoint sampled high\n", + linebuf, lineno); + return 1; + } + if (fpga_word & 0x0400) { + printf(PREFIX "ISO 7816-3 section 7.3 error signal\n", + linebuf, lineno); + return 1; + } + return 0; +} + +static int +check_parity() +{ + unsigned expect_par; + + expect_par = (parity_table[fpga_word & 0xFF] ^ inverse_conv) << 8; + if ((fpga_word & 0x100) != expect_par) { + printf(PREFIX "ERROR: bad character parity\n", linebuf, lineno); + state = STATE_ERROR; + return 1; + } + return 0; +} + +static void +extract_rx_byte() +{ + if (inverse_conv) + rx_byte = inverse_coding_table[fpga_word & 0xFF]; + else + rx_byte = fpga_word & 0xFF; +} + +void +process_fpga_word() +{ + if (fpga_word & 0x8000) { + handle_rst_change(); + return; + } + if (state == STATE_ERROR) + return; + if (byte_prelim_checks()) { + state = STATE_ERROR; + return; + } + switch (state) { + case STATE_UNDEF: + printf(PREFIX "ERROR: char Rx without preceding RST high\n", + linebuf, lineno); + state = STATE_ERROR; + return; + case STATE_RSTLOW: + printf(PREFIX "ERROR: char Rx after RST low\n", + linebuf, lineno); + state = STATE_ERROR; + return; + case STATE_ATR_TS: + if ((fpga_word & 0x1FF) == 0x13B) { + printf(PREFIX "TS sets direct coding convention\n", + linebuf, lineno); + inverse_conv = 0; + rx_byte = 0x3B; + atr_byte_in(); + state = STATE_ATR_CONT; + } else if ((fpga_word & 0x1FF) == 0x103) { + printf(PREFIX "TS sets inverse coding convention\n", + linebuf, lineno); + inverse_conv = 1; + rx_byte = 0x3F; + atr_byte_in(); + state = STATE_ATR_CONT; + } else { + printf(PREFIX "ERROR: invalid char after RST high\n", + linebuf, lineno); + state = STATE_ERROR; + } + return; + case STATE_ATR_CONT: + if (check_parity()) + return; + extract_rx_byte(); + atr_byte_in(); + return; + case STATE_READY_FOR_CMD: + if (check_parity()) + return; + extract_rx_byte(); + if (rx_byte == 0xFF) + start_pps_msg(); + else + start_cmd_header(); + return; + case STATE_PPS_MSG: + if (check_parity()) + return; + extract_rx_byte(); + pps_byte_in(); + return; + default: + fprintf(stderr, "BUG in top state machine: invalid state\n"); + abort(); + } +} diff -r 510bef2b2000 -r 118a12e9483b sw/sniff-dec/invtable.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sw/sniff-dec/invtable.c Thu Aug 31 08:46:23 2023 +0000 @@ -0,0 +1,27 @@ +/* + * We would like to be able to decode trace sessions with SIM cards using + * either direct or inverse coding convention. When inverse coding convention + * is in use, we have to translate every logged byte in software. Here we + * define the table for the inverse coding convention. + */ + +unsigned char inverse_coding_table[256] = { + +0xFF,0x7F,0xBF,0x3F,0xDF,0x5F,0x9F,0x1F,0xEF,0x6F,0xAF,0x2F,0xCF,0x4F,0x8F,0x0F, +0xF7,0x77,0xB7,0x37,0xD7,0x57,0x97,0x17,0xE7,0x67,0xA7,0x27,0xC7,0x47,0x87,0x07, +0xFB,0x7B,0xBB,0x3B,0xDB,0x5B,0x9B,0x1B,0xEB,0x6B,0xAB,0x2B,0xCB,0x4B,0x8B,0x0B, +0xF3,0x73,0xB3,0x33,0xD3,0x53,0x93,0x13,0xE3,0x63,0xA3,0x23,0xC3,0x43,0x83,0x03, +0xFD,0x7D,0xBD,0x3D,0xDD,0x5D,0x9D,0x1D,0xED,0x6D,0xAD,0x2D,0xCD,0x4D,0x8D,0x0D, +0xF5,0x75,0xB5,0x35,0xD5,0x55,0x95,0x15,0xE5,0x65,0xA5,0x25,0xC5,0x45,0x85,0x05, +0xF9,0x79,0xB9,0x39,0xD9,0x59,0x99,0x19,0xE9,0x69,0xA9,0x29,0xC9,0x49,0x89,0x09, +0xF1,0x71,0xB1,0x31,0xD1,0x51,0x91,0x11,0xE1,0x61,0xA1,0x21,0xC1,0x41,0x81,0x01, +0xFE,0x7E,0xBE,0x3E,0xDE,0x5E,0x9E,0x1E,0xEE,0x6E,0xAE,0x2E,0xCE,0x4E,0x8E,0x0E, +0xF6,0x76,0xB6,0x36,0xD6,0x56,0x96,0x16,0xE6,0x66,0xA6,0x26,0xC6,0x46,0x86,0x06, +0xFA,0x7A,0xBA,0x3A,0xDA,0x5A,0x9A,0x1A,0xEA,0x6A,0xAA,0x2A,0xCA,0x4A,0x8A,0x0A, +0xF2,0x72,0xB2,0x32,0xD2,0x52,0x92,0x12,0xE2,0x62,0xA2,0x22,0xC2,0x42,0x82,0x02, +0xFC,0x7C,0xBC,0x3C,0xDC,0x5C,0x9C,0x1C,0xEC,0x6C,0xAC,0x2C,0xCC,0x4C,0x8C,0x0C, +0xF4,0x74,0xB4,0x34,0xD4,0x54,0x94,0x14,0xE4,0x64,0xA4,0x24,0xC4,0x44,0x84,0x04, +0xF8,0x78,0xB8,0x38,0xD8,0x58,0x98,0x18,0xE8,0x68,0xA8,0x28,0xC8,0x48,0x88,0x08, +0xF0,0x70,0xB0,0x30,0xD0,0x50,0x90,0x10,0xE0,0x60,0xA0,0x20,0xC0,0x40,0x80,0x00 + +}; diff -r 510bef2b2000 -r 118a12e9483b sw/sniff-dec/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sw/sniff-dec/main.c Thu Aug 31 08:46:23 2023 +0000 @@ -0,0 +1,69 @@ +/* + * simtrace3-sniff-dec main module: reading the log file. + */ + +#include +#include +#include +#include +#include + +char *log_filename; +char linebuf[128]; +int lineno; +unsigned fpga_word; + +static void +process_line() +{ + char *cp; + + cp = index(linebuf, '\n'); + if (!cp) { + fprintf(stderr, "%s line %d: too long or missing newline\n", + log_filename, lineno); + exit(1); + } + if (linebuf[0] != '[') + return; + cp = linebuf + 1; + while (isdigit(*cp) || *cp == ':' || *cp == '.') + cp++; + if (*cp++ != ']') { +invalid: fprintf(stderr, "%s line %d: failed to parse\n", + log_filename, lineno); + exit(1); + } + if (!isspace(*cp)) + goto invalid; + *cp++ = '\0'; + if (strlen(linebuf) > 17) + goto invalid; + while (isspace(*cp)) + cp++; + if (!isxdigit(cp[0]) || !isxdigit(cp[1]) || !isxdigit(cp[2]) || + !isxdigit(cp[3]) || !isspace(cp[4])) + goto invalid; + fpga_word = strtoul(cp, 0, 16); + process_fpga_word(); +} + +main(argc, argv) + char **argv; +{ + FILE *inf; + + if (argc != 2) { + fprintf(stderr, "usage: %s logfile\n", argv[0]); + exit(1); + } + log_filename = argv[1]; + inf = fopen(log_filename, "r"); + if (!inf) { + perror(log_filename); + exit(1); + } + for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) + process_line(); + exit(0); +} diff -r 510bef2b2000 -r 118a12e9483b sw/sniff-dec/parity.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sw/sniff-dec/parity.c Thu Aug 31 08:46:23 2023 +0000 @@ -0,0 +1,23 @@ +/* + * We need to check the parity of each received ISO 7816-3 character in + * software; this module provides the needed table. + */ + +unsigned char parity_table[256] = { + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 +}; diff -r 510bef2b2000 -r 118a12e9483b sw/sniff-dec/pps.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sw/sniff-dec/pps.c Thu Aug 31 08:46:23 2023 +0000 @@ -0,0 +1,116 @@ +/* + * Here we implement PPS request/response message decoding. + */ + +#include +#include +#include +#include +#include +#include "state.h" + +extern char linebuf[]; +extern int lineno; +extern unsigned rx_byte; +extern int state; + +#define SUBST_PPS0 0 +#define SUBST_PPS1 1 +#define SUBST_PPS2 2 +#define SUBST_PPS3 3 +#define SUBST_PCK 4 + +static char pps_start_timestamp[18]; +static int pps_start_line; +static int substate; +static u_char pps_bytes[6]; +static unsigned byte_count; + +void +start_pps_msg() +{ + strcpy(pps_start_timestamp, linebuf); + pps_start_line = lineno; + pps_bytes[0] = rx_byte; + byte_count = 1; + state = STATE_PPS_MSG; + substate = SUBST_PPS0; +} + +static void +advance_state() +{ + if (substate == SUBST_PPS1) { + if (pps_bytes[1] & 0x10) + return; + substate = SUBST_PPS2; + } + if (substate == SUBST_PPS2) { + if (pps_bytes[1] & 0x20) + return; + substate = SUBST_PPS3; + } + if (substate == SUBST_PPS3) { + if (pps_bytes[2] & 0x40) + return; + substate = SUBST_PCK; + } + if (substate == SUBST_PCK) + return; + fprintf(stderr, "BUG in PPS decoder: bad state in advance_state()\n"); + abort(); +} + +static void +check_pck() +{ + unsigned n, xor; + + xor = 0; + for (n = 0; n < byte_count; n++) + xor ^= pps_bytes[n]; + printf(" PCK is %s\n", xor ? "bad!" : "correct"); +} + +static void +pps_finish() +{ + unsigned n; + + printf("%s line %d: PPS", pps_start_timestamp, pps_start_line); + for (n = 0; n < byte_count; n++) + printf(" %02X", pps_bytes[n]); + putchar('\n'); + check_pck(); + state = STATE_READY_FOR_CMD; +} + +void +pps_byte_in() +{ + pps_bytes[byte_count++] = rx_byte; + switch (substate) { + case SUBST_PPS0: + substate = SUBST_PPS1; + advance_state(); + return; + case SUBST_PPS1: + substate = SUBST_PPS2; + advance_state(); + return; + case SUBST_PPS2: + substate = SUBST_PPS3; + advance_state(); + return; + case SUBST_PPS3: + substate = SUBST_PCK; + return; + case SUBST_PCK: + pps_finish(); + return; + default: + fprintf(stderr, + "BUG in PPS decoder: bad state in pps_byte_in()\n"); + abort(); + } +} diff -r 510bef2b2000 -r 118a12e9483b sw/sniff-dec/state.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sw/sniff-dec/state.h Thu Aug 31 08:46:23 2023 +0000 @@ -0,0 +1,13 @@ +/* + * This header file defines our little state machine for SIMtrace session + * log analysis. + */ + +#define STATE_UNDEF 0 +#define STATE_ERROR 1 +#define STATE_RSTLOW 2 +#define STATE_ATR_TS 3 +#define STATE_ATR_CONT 4 +#define STATE_READY_FOR_CMD 5 +#define STATE_PPS_MSG 6 +#define STATE_CMD_HDR 7