view serial/collect_atr.c @ 99:97ba63d9361a

scripts/fcsim1-sst: turn off STK & OTA services In the initial unprogrammed state of the cards from Grcard, SST has services 25 through 29 set to allocated and activated. However, these cards appear to not actually support OTA, ENVELOPE commands do nothing (just return SW 9000), and they were never observed issuing any proactive SIM commands, even after a feature-generous TERMINAL PROFILE. Therefore, let's list these STK & OTA services as allocated, but not activated in our FCSIM1 SST.
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 05 May 2021 04:26:07 +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');
}