comparison 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
comparison
equal deleted inserted replaced
42:6cc3eea720cb 43:be27d1c85861
1 /*
2 * This module implements the main function of our back end:
3 * exchanging APDUs with the SIM.
4 */
5
6 #include <sys/types.h>
7 #include <stdio.h>
8
9 static
10 collect_one_byte()
11 {
12 u_char buf;
13 int rc;
14
15 rc = collect_bytes_from_sim(&buf, 1);
16 if (rc < 0)
17 return rc;
18 else
19 return buf;
20 }
21
22 static void
23 finish_sw(sw1, data, datalen)
24 unsigned sw1, datalen;
25 u_char *data;
26 {
27 unsigned sw2, n;
28 int rc;
29
30 rc = collect_one_byte();
31 if (rc < 0) {
32 printf("back end error at SW2 Rx step\n");
33 return;
34 }
35 sw2 = rc;
36 for (n = 0; n < datalen; n++)
37 printf("%02X", data[n]);
38 printf("%02X%02X\n", sw1, sw2);
39 }
40
41 static void
42 exchange_data_out(ins, data, datalen)
43 unsigned ins, datalen;
44 u_char *data;
45 {
46 int rc;
47 unsigned null_count, bytes_sent, ack, ack1;
48
49 ack = ins & 0xFE;
50 ack1 = ~ins & 0xFE;
51 bytes_sent = 0;
52 null_count = 0;
53 for (;;) {
54 rc = collect_one_byte();
55 if (rc < 0) {
56 printf("back end error at procedure byte step\n");
57 return;
58 }
59 if (rc == 0x60) {
60 null_count++;
61 if (null_count >= 32) {
62 printf(
63 "ERROR: too many stalling NULL bytes received from SIM\n");
64 return;
65 }
66 continue;
67 }
68 if ((rc & 0xF0) == 0x60 || (rc & 0xF0) == 0x90) {
69 finish_sw(rc, 0, 0);
70 return;
71 }
72 if ((rc & 0xFE) == ack) {
73 if (bytes_sent >= datalen) {
74 bad_xfer_req: printf(
75 "ERROR: SIM requests more xfer after we sent everything\n");
76 return;
77 }
78 rc = send_bytes_to_sim(data + bytes_sent,
79 datalen - bytes_sent);
80 if (rc < 0) {
81 printf("back end error at data output step\n");
82 return;
83 }
84 bytes_sent = datalen;
85 continue;
86 }
87 if ((rc & 0xFE) == ack1) {
88 if (bytes_sent >= datalen)
89 goto bad_xfer_req;
90 rc = send_bytes_to_sim(data + bytes_sent, 1);
91 if (rc < 0) {
92 printf("back end error at data output step\n");
93 return;
94 }
95 bytes_sent++;
96 continue;
97 }
98 printf("ERROR: non-understood procedure byte %02X\n", rc);
99 return;
100 }
101 }
102
103 static void
104 exchange_data_in(ins, datalen)
105 unsigned ins, datalen;
106 {
107 int rc;
108 unsigned null_count, bytes_rcvd, ack, ack1;
109 u_char data[256];
110
111 if (!datalen)
112 datalen = 256;
113 ack = ins & 0xFE;
114 ack1 = ~ins & 0xFE;
115 bytes_rcvd = 0;
116 null_count = 0;
117 for (;;) {
118 rc = collect_one_byte();
119 if (rc < 0) {
120 printf("back end error at procedure byte step\n");
121 return;
122 }
123 if (rc == 0x60) {
124 null_count++;
125 if (null_count >= 32) {
126 printf(
127 "ERROR: too many stalling NULL bytes received from SIM\n");
128 return;
129 }
130 continue;
131 }
132 if ((rc & 0xF0) == 0x60 || (rc & 0xF0) == 0x90) {
133 finish_sw(rc, data, bytes_rcvd);
134 return;
135 }
136 if ((rc & 0xFE) == ack) {
137 if (bytes_rcvd >= datalen) {
138 bad_xfer_req: printf(
139 "ERROR: SIM requests more xfer after we received all expected data\n");
140 return;
141 }
142 rc = collect_bytes_from_sim(data + bytes_rcvd,
143 datalen - bytes_rcvd);
144 if (rc < 0) {
145 printf("back end error at data input step\n");
146 return;
147 }
148 bytes_rcvd = datalen;
149 continue;
150 }
151 if ((rc & 0xFE) == ack1) {
152 if (bytes_rcvd >= datalen)
153 goto bad_xfer_req;
154 rc = collect_one_byte();
155 if (rc < 0) {
156 printf("back end error at data input step\n");
157 return;
158 }
159 data[bytes_rcvd++] = rc;
160 continue;
161 }
162 printf("ERROR: non-understood procedure byte %02X\n", rc);
163 return;
164 }
165 }
166
167 void
168 apdu_exchange(cmd_apdu, cmd_apdu_len)
169 u_char *cmd_apdu;
170 unsigned cmd_apdu_len;
171 {
172 int rc;
173
174 rc = send_bytes_to_sim(cmd_apdu, 5);
175 if (rc < 0) {
176 printf("back end error at the command sending step\n");
177 return;
178 }
179 if (cmd_apdu_len > 5)
180 exchange_data_out(cmd_apdu[1], cmd_apdu + 5, cmd_apdu_len - 5);
181 else
182 exchange_data_in(cmd_apdu[1], cmd_apdu[4]);
183 }