diff serial/collect_atr.c @ 38:1d96f3b4f155

serial: started with fcsim-serial-atr
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 20 Mar 2021 19:19:46 +0000
parents
children
line wrap: on
line diff
--- /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');
+}