view serial/collect_atr.c @ 93:6041c601304d

fcsim1-mkprov: revert OTA key addition It appears that GrcardSIM2 cards (which is what we got for FCSIM1) do not support OTA after all, contrary to what we were previously led to believe by some tech support emails from Grcard - apparently those support emails and OTA descriptions referred to some other card model(s).
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 21 Apr 2021 05:38:39 +0000
parents 1d96f3b4f155
children
line wrap: on
line source

/*
 * 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');
}