changeset 38:1d96f3b4f155

serial: started with fcsim-serial-atr
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 20 Mar 2021 19:19:46 +0000
parents 4e5586c7f275
children 61a8ac93764f
files .hgignore serial/Makefile serial/atrmain.c serial/collect_atr.c serial/invtable.c serial/serport.c
diffstat 6 files changed, 295 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Wed Mar 17 06:44:12 2021 +0000
+++ b/.hgignore	Sat Mar 20 19:19:46 2021 +0000
@@ -9,6 +9,8 @@
 ^pcsc/fc-pcsc-backend$
 ^pcsc/fc-pcsc-list$
 
+^serial/fcsim-serial-atr$
+
 ^simtool/fc-simtool$
 
 ^uicc/fc-uicc-tool$
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serial/Makefile	Sat Mar 20 19:19:46 2021 +0000
@@ -0,0 +1,21 @@
+CC=	gcc
+CFLAGS=	-O2
+PROGS=	fcsim-serial-atr
+
+INSTALL_PREFIX=	/opt/freecalypso
+
+INSTBIN=${INSTALL_PREFIX}/bin
+
+ATR_OBJS=	atrmain.o collect_atr.o invtable.o serport.o
+
+all:	${PROGS}
+
+fcsim-serial-atr:	${ATR_OBJS}
+	${CC} ${CFLAGS} -o $@ ${ATR_OBJS}
+
+install:
+	mkdir -p ${INSTBIN}
+	install -c ${PROGS} ${INSTBIN}
+
+clean:
+	rm -f ${PROGS} *.o
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serial/atrmain.c	Sat Mar 20 19:19:46 2021 +0000
@@ -0,0 +1,26 @@
+/*
+ * This module implements the main() function for fcsim-serial-atr utility.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+main(argc, argv)
+	char **argv;
+{
+	int rc;
+
+	if (argc != 3) {
+		fprintf(stderr, "usage: %s ttyport baud\n", argv[0]);
+		exit(1);
+	}
+	open_serial_port(argv[1]);
+	set_serial_params(atoi(argv[2]));
+	set_serial_nonblock(0);
+	serial_card_reset();
+	rc = collect_atr();
+	if (rc < 0)
+		exit(1);
+	print_atr("ATR:");
+	exit(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serial/collect_atr.c	Sat Mar 20 19:19:46 2021 +0000
@@ -0,0 +1,162 @@
+/*
+ * This module contains the code for collecting ATR bytes from the SIM,
+ * as well as subsequent byte Rx.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+extern int target_fd;
+
+#define	MAX_ATR_BYTES	33
+
+extern unsigned char inverse_coding_table[256];
+
+u_char atr_buf[MAX_ATR_BYTES];
+unsigned atr_length;
+int inverse_coding;
+
+void
+invert_bytes(buf, nbytes)
+	u_char *buf;
+	unsigned nbytes;
+{
+	unsigned n;
+
+	for (n = 0; n < nbytes; n++)
+		buf[n] = inverse_coding_table[buf[n]];
+}
+
+collect_bytes_from_sim(buf, expect_len)
+	u_char *buf;
+	unsigned expect_len;
+{
+	fd_set fds;
+	struct timeval tv;
+	unsigned rcvd;
+	int cc;
+
+	for (rcvd = 0; rcvd < expect_len; ) {
+		FD_ZERO(&fds);
+		FD_SET(target_fd, &fds);
+		tv.tv_sec = 2;
+		tv.tv_usec = 0;
+		cc = select(target_fd+1, &fds, NULL, NULL, &tv);
+		if (cc < 0) {
+			if (errno == EINTR)
+				continue;
+			perror("select");
+			return(-1);
+		}
+		if (cc < 1) {
+			fprintf(stderr,
+			"error: timeout waiting for byte(s) from SIM\n");
+			return(-1);
+		}
+		cc = read(target_fd, buf + rcvd, expect_len - rcvd);
+		if (cc <= 0) {
+			perror("read after successful select");
+			return(-1);
+		}
+		rcvd += cc;
+	}
+	if (inverse_coding)
+		invert_bytes(buf, rcvd);
+	return(0);
+}
+
+check_atr_tck()
+{
+	unsigned b, p;
+
+	b = 0;
+	for (p = 1; p < atr_length; p++)
+		b ^= atr_buf[p];
+	if (b) {
+		fprintf(stderr, "error: ATR checksum is bad\n");
+		return(-1);
+	}
+	return(0);
+}
+
+collect_atr()
+{
+	int rc;
+	unsigned count, y, nhist, have_tck;
+
+	rc = collect_bytes_from_sim(atr_buf, 2);
+	if (rc < 0)
+		return(rc);
+	if (atr_buf[0] == 0x3B) {
+		/* direct convention */
+	} else if (atr_buf[0] == 0x03) {
+		/* inverse convention */
+		inverse_coding = 1;
+		atr_buf[0] = 0x3F;
+		atr_buf[1] = inverse_coding_table[atr_buf[1]];
+	} else {
+		fprintf(stderr,
+		"error: received TS=0x%02X, matches neither convention\n",
+			atr_buf[0]);
+		return(-1);
+	}
+	atr_length = 2;
+	nhist = atr_buf[1] & 0x0F;
+	y = atr_buf[1] & 0xF0;
+	have_tck = 0;
+	while (y) {
+		count = 0;
+		if (y & 0x10)
+			count++;
+		if (y & 0x20)
+			count++;
+		if (y & 0x40)
+			count++;
+		if (y & 0x80)
+			count++;
+		if (atr_length + count > MAX_ATR_BYTES) {
+atr_too_long:		fprintf(stderr, "error: ATR exceeds 33 byte limit\n");
+			return(-1);
+		}
+		rc = collect_bytes_from_sim(atr_buf + atr_length, count);
+		if (rc < 0)
+			return(rc);
+		atr_length += count;
+		if (y & 0x80) {
+			y = atr_buf[atr_length-1] & 0xF0;
+			if (atr_buf[atr_length-1] & 0x0F)
+				have_tck = 1;
+		} else
+			y = 0;
+	}
+	count = nhist + have_tck;
+	if (count) {
+		if (atr_length + count > MAX_ATR_BYTES)
+			goto atr_too_long;
+		rc = collect_bytes_from_sim(atr_buf + atr_length, count);
+		if (rc < 0)
+			return(rc);
+		atr_length += count;
+	}
+	if (have_tck)
+		return check_atr_tck();
+	else
+		return 0;
+}
+
+void
+print_atr(head)
+	char *head;
+{
+	unsigned n;
+
+	fputs(head, stdout);
+	for (n = 0; n < atr_length; n++) {
+		printf(" %02X", atr_buf[n]);
+	}
+	putchar('\n');
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serial/invtable.c	Sat Mar 20 19:19:46 2021 +0000
@@ -0,0 +1,27 @@
+/*
+ * We must support SIM cards using either direct or inverse coding
+ * convention.  When inverse coding convention is in use, we have to
+ * translate every sent and received byte ourselves.  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
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serial/serport.c	Sat Mar 20 19:19:46 2021 +0000
@@ -0,0 +1,57 @@
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <asm/ioctls.h>
+#include <asm/termbits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int target_fd;
+
+open_serial_port(ttyport)
+	char *ttyport;
+{
+	target_fd = open(ttyport, O_RDWR|O_NONBLOCK);
+	if (target_fd < 0) {
+		perror(ttyport);
+		exit(1);
+	}
+	ioctl(target_fd, TIOCEXCL);
+	return 0;
+}
+
+set_serial_params(br)
+{
+	struct termios2 target_termios;
+
+	target_termios.c_iflag = IGNBRK;
+	target_termios.c_oflag = 0;
+	target_termios.c_cflag = BOTHER|CLOCAL|HUPCL|CREAD|CS8|CSTOPB|PARENB;
+	target_termios.c_lflag = 0;
+	target_termios.c_cc[VMIN] = 1;
+	target_termios.c_cc[VTIME] = 0;
+	target_termios.c_ispeed = br;
+	target_termios.c_ospeed = br;
+	if (ioctl(target_fd, TCSETSF2, &target_termios) < 0) {
+		perror("TCSETSF2");
+		exit(1);
+	}
+	return 0;
+}
+
+set_serial_nonblock(state)
+	int state;
+{
+	ioctl(target_fd, FIONBIO, &state);
+}
+
+serial_card_reset()
+{
+	int mctl_arg = TIOCM_DTR | TIOCM_RTS;
+
+	ioctl(target_fd, TIOCMBIS, &mctl_arg);
+	usleep(20000);
+	ioctl(target_fd, TCFLSH, TCIFLUSH);
+	ioctl(target_fd, TIOCMBIC, &mctl_arg);
+}