FreeCalypso > hg > freecalypso-tools
view target-utils/simagent/exchange.c @ 898:203c025e71ab
CHANGES: fc-host-tools-r17 released
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 03 Apr 2022 19:09:21 +0000 |
parents | 56506e9165bc |
children |
line wrap: on
line source
/* * 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; { int rc; unsigned null_count, bytes_rcvd, ack, ack1; u8 data[256]; if (!datalen) datalen = 256; ack = ins & 0xFE; ack1 = ~ins & 0xFE; bytes_rcvd = 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, 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; } while (bytes_rcvd < datalen) { rc = rx_sim_byte_hl(); if (rc < 0) return; data[bytes_rcvd++] = rc; } continue; } if ((rc & 0xFE) == ack1) { if (bytes_rcvd >= datalen) goto bad_xfer_req; rc = rx_sim_byte_hl(); if (rc < 0) return; data[bytes_rcvd++] = rc; continue; } printf("ERROR: non-understood procedure byte %02X\n", rc); return; } } void cmd_exchange(argstr) char *argstr; { u8 cmd[260]; unsigned count; 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; count = rc; if (count < 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 (count > 5) exchange_data_out(cmd[1], cmd + 5, count - 5); else exchange_data_in(cmd[1], cmd[4]); }