FreeCalypso > hg > fc-sim-tools
diff serial/exchange.c @ 43:be27d1c85861
serial: main function implemented
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 20 Mar 2021 21:49:59 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/serial/exchange.c Sat Mar 20 21:49:59 2021 +0000 @@ -0,0 +1,183 @@ +/* + * 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]); +}