FreeCalypso > hg > fc-sim-tools
view serial/exchange.c @ 58:871281cb0555
doc/Low-level-commands: apdu-checksw documented
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Tue, 23 Mar 2021 00:21:02 +0000 |
parents | be27d1c85861 |
children |
line wrap: on
line source
/* * This module implements the main function of our back end: * exchanging APDUs with the SIM. */ #include <sys/types.h> #include <stdio.h> static collect_one_byte() { u_char buf; int rc; rc = collect_bytes_from_sim(&buf, 1); if (rc < 0) return rc; else return buf; } static void finish_sw(sw1, data, datalen) unsigned sw1, datalen; u_char *data; { unsigned sw2, n; int rc; rc = collect_one_byte(); if (rc < 0) { printf("back end error at SW2 Rx step\n"); 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; u_char *data; { int rc; unsigned null_count, bytes_sent, ack, ack1; ack = ins & 0xFE; ack1 = ~ins & 0xFE; bytes_sent = 0; null_count = 0; for (;;) { rc = collect_one_byte(); if (rc < 0) { printf("back end error at procedure byte step\n"); 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_bytes_to_sim(data + bytes_sent, datalen - bytes_sent); if (rc < 0) { printf("back end error at data output step\n"); return; } bytes_sent = datalen; continue; } if ((rc & 0xFE) == ack1) { if (bytes_sent >= datalen) goto bad_xfer_req; rc = send_bytes_to_sim(data + bytes_sent, 1); if (rc < 0) { printf("back end error at data output step\n"); return; } bytes_sent++; continue; } printf("ERROR: non-understood procedure byte %02X\n", rc); return; } } static void exchange_data_in(ins, datalen) unsigned ins, datalen; { int rc; unsigned null_count, bytes_rcvd, ack, ack1; u_char data[256]; if (!datalen) datalen = 256; ack = ins & 0xFE; ack1 = ~ins & 0xFE; bytes_rcvd = 0; null_count = 0; for (;;) { rc = collect_one_byte(); if (rc < 0) { printf("back end error at procedure byte step\n"); 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, data, bytes_rcvd); return; } if ((rc & 0xFE) == ack) { if (bytes_rcvd >= datalen) { bad_xfer_req: printf( "ERROR: SIM requests more xfer after we received all expected data\n"); return; } rc = collect_bytes_from_sim(data + bytes_rcvd, datalen - bytes_rcvd); if (rc < 0) { printf("back end error at data input step\n"); return; } bytes_rcvd = datalen; continue; } if ((rc & 0xFE) == ack1) { if (bytes_rcvd >= datalen) goto bad_xfer_req; rc = collect_one_byte(); if (rc < 0) { printf("back end error at data input step\n"); return; } data[bytes_rcvd++] = rc; continue; } printf("ERROR: non-understood procedure byte %02X\n", rc); return; } } void apdu_exchange(cmd_apdu, cmd_apdu_len) u_char *cmd_apdu; unsigned cmd_apdu_len; { int rc; rc = send_bytes_to_sim(cmd_apdu, 5); if (rc < 0) { printf("back end error at the command sending step\n"); return; } if (cmd_apdu_len > 5) exchange_data_out(cmd_apdu[1], cmd_apdu + 5, cmd_apdu_len - 5); else exchange_data_in(cmd_apdu[1], cmd_apdu[4]); }