view sw/sniff-dec/dispatch.c @ 58:95ed46b5f8f1 default tip

doc/Sniffing-hw-setup: mv-sniffer is here
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 04 Oct 2023 05:55:09 +0000
parents b0524d1dc6ef
children
line wrap: on
line source

/*
 * Dispatching received FPGA words based on the current state.
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#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 begins\n",
			linebuf, lineno);
		state = STATE_ATR_TS;
		atr_begin();
	} else {
		printf(PREFIX "RST low, card session ends\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;
	case STATE_CMD_HDR:
		if (check_parity())
			return;
		extract_rx_byte();
		cmd_hdr_byte_in();
		return;
	case STATE_CMD_PROC:
		if (check_parity())
			return;
		extract_rx_byte();
		cmd_proc_byte_in();
		return;
	case STATE_CMD_DATA:
		if (check_parity())
			return;
		extract_rx_byte();
		cmd_data_byte_in();
		return;
	case STATE_CMD_SW:
		if (check_parity())
			return;
		extract_rx_byte();
		cmd_sw2_byte_in();
		return;
	default:
		fprintf(stderr, "BUG in top state machine: invalid state\n");
		abort();
	}
}