FreeCalypso > hg > freecalypso-tools
diff target-utils/simagent/exchange.c @ 783:c136a1a2474b
simagent: initial implementation of APDU exchange
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 13 Mar 2021 22:06:08 +0000 |
parents | |
children | 839bf41e7be0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/simagent/exchange.c Sat Mar 13 22:06:08 2021 +0000 @@ -0,0 +1,118 @@ +/* + * This module implements our main function: exchange of command + * and response APDUs. + */ + +#include "types.h" + +extern int sim_if_state; + +static void +finish_sw(sw1, data, datalen) + unsigned sw1, datalen; + u8 *data; +{ + unsigned sw2, n; + int rc; + + rc = rx_sim_byte_hl(); + if (rc < 0) + 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; + u8 *data; +{ + int rc; + unsigned null_count, bytes_sent, ack, ack1; + + ack = ins & 0xFE; + ack1 = ~ins & 0xFE; + bytes_sent = 0; + null_count = 0; + for (;;) { + rc = rx_sim_byte_hl(); + if (rc < 0) + 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_to_sim(data + bytes_sent, + datalen - bytes_sent); + if (rc < 0) + return; + bytes_sent = datalen; + continue; + } + if ((rc & 0xFE) == ack1) { + if (bytes_sent >= datalen) + goto bad_xfer_req; + rc = send_to_sim(data + bytes_sent, 1); + if (rc < 0) + return; + bytes_sent++; + continue; + } + printf("ERROR: non-understood procedure byte %02X\n", rc); + return; + } +} + +static void +exchange_data_in(ins, datalen) + unsigned ins, datalen; +{ + printf("ERROR: data in mode not implemented yet\n"); +} + +void +cmd_exchange(argstr) + char *argstr; +{ + u8 cmd[260]; + int rc; + + if (sim_if_state != 2) { + printf("ERROR: SIM interface is not up\n"); + return; + } + rc = decode_hex_string_arg(argstr, cmd, 260); + if (rc < 0) + return; + if (rc < 5) { + printf("ERROR: command APDU is shorter than 5 bytes\n"); + return; + } + rc = flush_rx_fifo(); + if (rc < 0) + return; + rc = send_to_sim(cmd, 5); + if (rc < 0) + return; + if (rc > 5) + exchange_data_out(cmd[1], cmd + 5, rc - 5); + else + exchange_data_in(cmd[1], cmd[4]); +}