changeset 783:c136a1a2474b

simagent: initial implementation of APDU exchange
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 13 Mar 2021 22:06:08 +0000
parents badc5399d641
children 839bf41e7be0
files target-utils/simagent/Makefile target-utils/simagent/byterx.c target-utils/simagent/cmdtab.c target-utils/simagent/exchange.c
diffstat 4 files changed, 141 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/target-utils/simagent/Makefile	Sat Mar 13 21:39:34 2021 +0000
+++ b/target-utils/simagent/Makefile	Sat Mar 13 22:06:08 2021 +0000
@@ -7,8 +7,8 @@
 INSTDIR=/opt/freecalypso/target-bin
 
 PROG=	simagent
-OBJS=	crt0.o byterx.o cmdtab.o invtable.o main.o simup.o spenh.o stringarg.o \
-	tx.o
+OBJS=	crt0.o byterx.o cmdtab.o exchange.o invtable.o main.o simup.o spenh.o \
+	stringarg.o tx.o
 LIBS=	../libcommon/libcommon.a ../libprintf/libprintf.a ../libbase/libbase.a \
 	../libc/libc.a
 LIBGCC=	`${CC} -print-file-name=libgcc.a`
--- a/target-utils/simagent/byterx.c	Sat Mar 13 21:39:34 2021 +0000
+++ b/target-utils/simagent/byterx.c	Sat Mar 13 22:06:08 2021 +0000
@@ -1,6 +1,7 @@
 #include <stdlib.h>
 #include "types.h"
 #include "simregs.h"
+#include "timeout.h"
 
 rx_sim_byte(count)
 	unsigned count;
@@ -12,6 +13,24 @@
 	return(-1);
 }
 
+rx_sim_byte_hl()
+{
+	int rc;
+	unsigned parcnt;
+
+	for (parcnt = 0; parcnt < 3; parcnt++) {
+		rc = rx_sim_byte(SIM_WAIT_TIMEOUT);
+		if (rc < 0) {
+			printf("ERROR: timeout waiting for SIM response\n");
+			return(-1);
+		}
+		if (rc & 0x100)
+			return rc & 0xFF;
+	}
+	printf("ERROR: received bad parity 3 times in a row\n");
+	return(-1);
+}
+
 flush_rx_fifo()
 {
 	unsigned count;
--- a/target-utils/simagent/cmdtab.c	Sat Mar 13 21:39:34 2021 +0000
+++ b/target-utils/simagent/cmdtab.c	Sat Mar 13 22:06:08 2021 +0000
@@ -3,6 +3,7 @@
 extern void cmd_abbr();
 extern void cmd_abbw();
 extern void cmd_baud_switch();
+extern void cmd_exchange();
 extern void cmd_jump();
 extern void cmd_r8();
 extern void cmd_r16();
@@ -21,6 +22,7 @@
 extern void print_atr();
 
 const struct cmdtab cmdtab[] = {
+	{"X", cmd_exchange},
 	{"abbinit", abb_init},
 	{"abbpage2", abb_unlock_page2},
 	{"abbr", cmd_abbr},
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/target-utils/simagent/exchange.c	Sat Mar 13 22:06:08 2021 +0000
@@ -0,0 +1,118 @@
+/*
+ * This module implements our main function: exchange of command
+ * and response APDUs.
+ */
+
+#include "types.h"
+
+extern int sim_if_state;
+
+static void
+finish_sw(sw1, data, datalen)
+	unsigned sw1, datalen;
+	u8 *data;
+{
+	unsigned sw2, n;
+	int rc;
+
+	rc = rx_sim_byte_hl();
+	if (rc < 0)
+		return;
+	sw2 = rc;
+	for (n = 0; n < datalen; n++)
+		printf("%02X", data[n]);
+	printf("%02X%02X\n", sw1, sw2);
+}
+
+static void
+exchange_data_out(ins, data, datalen)
+	unsigned ins, datalen;
+	u8 *data;
+{
+	int rc;
+	unsigned null_count, bytes_sent, ack, ack1;
+
+	ack = ins & 0xFE;
+	ack1 = ~ins & 0xFE;
+	bytes_sent = 0;
+	null_count = 0;
+	for (;;) {
+		rc = rx_sim_byte_hl();
+		if (rc < 0)
+			return;
+		if (rc == 0x60) {
+			null_count++;
+			if (null_count >= 32) {
+				printf(
+		"ERROR: too many stalling NULL bytes received from SIM\n");
+				return;
+			}
+			continue;
+		}
+		if ((rc & 0xF0) == 0x60 || (rc & 0xF0) == 0x90) {
+			finish_sw(rc, 0, 0);
+			return;
+		}
+		if ((rc & 0xFE) == ack) {
+			if (bytes_sent >= datalen) {
+bad_xfer_req:			printf(
+		"ERROR: SIM requests more xfer after we sent everything\n");
+				return;
+			}
+			rc = send_to_sim(data + bytes_sent,
+					 datalen - bytes_sent);
+			if (rc < 0)
+				return;
+			bytes_sent = datalen;
+			continue;
+		}
+		if ((rc & 0xFE) == ack1) {
+			if (bytes_sent >= datalen)
+				goto bad_xfer_req;
+			rc = send_to_sim(data + bytes_sent, 1);
+			if (rc < 0)
+				return;
+			bytes_sent++;
+			continue;
+		}
+		printf("ERROR: non-understood procedure byte %02X\n", rc);
+		return;
+	}
+}
+
+static void
+exchange_data_in(ins, datalen)
+	unsigned ins, datalen;
+{
+	printf("ERROR: data in mode not implemented yet\n");
+}
+
+void
+cmd_exchange(argstr)
+	char *argstr;
+{
+	u8 cmd[260];
+	int rc;
+
+	if (sim_if_state != 2) {
+		printf("ERROR: SIM interface is not up\n");
+		return;
+	}
+	rc = decode_hex_string_arg(argstr, cmd, 260);
+	if (rc < 0)
+		return;
+	if (rc < 5) {
+		printf("ERROR: command APDU is shorter than 5 bytes\n");
+		return;
+	}
+	rc = flush_rx_fifo();
+	if (rc < 0)
+		return;
+	rc = send_to_sim(cmd, 5);
+	if (rc < 0)
+		return;
+	if (rc > 5)
+		exchange_data_out(cmd[1], cmd + 5, rc - 5);
+	else
+		exchange_data_in(cmd[1], cmd[4]);
+}