1 /*
2 * Implementation of T=0
3 *
4 * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
5 */
6
7 #include "internal.h"
8 #include <sys/poll.h>
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 typedef struct {
14 ifd_protocol_t base;
15
16 int state;
17 long timeout;
18 unsigned int block_oriented;
19 unsigned int max_nulls;
20 } t0_state_t;
21
22 enum {
23 IDLE, SENDING, RECEIVING, CONFUSED
24 };
25
26 static int t0_xcv(ifd_protocol_t *, const void *, size_t, void *, size_t);
27 static int t0_send(ifd_protocol_t *, ct_buf_t *, int);
28 static int t0_recv(ifd_protocol_t *, ct_buf_t *, int, long);
29 static int t0_resynch(t0_state_t *);
30
31 /*
32 * Set default T=1 protocol parameters
33 */
t0_set_defaults(t0_state_t * t0)34 static void t0_set_defaults(t0_state_t * t0)
35 {
36 t0->state = IDLE;
37 t0->timeout = 2000;
38 t0->max_nulls = 800;
39 }
40
41 /*
42 * Attach t0 protocol
43 */
t0_init(ifd_protocol_t * prot)44 static int t0_init(ifd_protocol_t * prot)
45 {
46 t0_set_defaults((t0_state_t *) prot);
47 return 0;
48 }
49
50 /*
51 * Detach t0 protocol
52 */
t0_release(ifd_protocol_t * prot)53 static void t0_release(ifd_protocol_t * prot)
54 {
55 /* NOP */
56 }
57
58 /*
59 * Get/set parmaters for T1 protocol
60 */
t0_set_param(ifd_protocol_t * prot,int type,long value)61 static int t0_set_param(ifd_protocol_t * prot, int type, long value)
62 {
63 t0_state_t *t0 = (t0_state_t *) prot;
64
65 switch (type) {
66 case IFD_PROTOCOL_RECV_TIMEOUT:
67 t0->timeout = value;
68 break;
69 case IFD_PROTOCOL_BLOCK_ORIENTED:
70 t0->block_oriented = value;
71 break;
72 default:
73 ct_error("Unsupported parameter %d", type);
74 return -1;
75 }
76
77 return 0;
78 }
79
t0_get_param(ifd_protocol_t * prot,int type,long * result)80 static int t0_get_param(ifd_protocol_t * prot, int type, long *result)
81 {
82 t0_state_t *t0 = (t0_state_t *) prot;
83 long value;
84
85 switch (type) {
86 case IFD_PROTOCOL_RECV_TIMEOUT:
87 value = t0->timeout;
88 break;
89 case IFD_PROTOCOL_BLOCK_ORIENTED:
90 value = t0->block_oriented;
91 break;
92 default:
93 ct_error("Unsupported parameter %d", type);
94 return -1;
95 }
96
97 if (result)
98 *result = value;
99
100 return 0;
101 }
102
103 /*
104 * Send an APDU through T=0
105 */
t0_transceive(ifd_protocol_t * prot,int dad,const void * sbuf,size_t slen,void * rbuf,size_t rlen)106 static int t0_transceive(ifd_protocol_t * prot, int dad, const void *sbuf,
107 size_t slen, void *rbuf, size_t rlen)
108 {
109 t0_state_t *t0 = (t0_state_t *) prot;
110 ifd_iso_apdu_t iso;
111 unsigned char sdata[5];
112 unsigned int cla, cse, lc, le;
113 int rc;
114
115 if (t0->state != IDLE) {
116 if (t0_resynch(t0) < 0)
117 return -1;
118 t0->state = IDLE;
119 }
120
121 if (slen < 4 || rlen < 2)
122 return -1;
123
124 /* Check the APDU case etc */
125 if ((rc = ifd_iso_apdu_parse(sbuf, slen, &iso)) < 0)
126 return rc;
127
128 cse = iso.cse;
129 cla = iso.cla;
130 lc = iso.lc;
131 le = iso.le;
132
133 switch (cse) {
134 case IFD_APDU_CASE_1:
135 /* Include a NUL lc byte */
136 memcpy(sdata, sbuf, 4);
137 sdata[4] = 0;
138 sbuf = sdata;
139 slen = 5;
140 break;
141 case IFD_APDU_CASE_2S:
142 case IFD_APDU_CASE_3S:
143 break;
144 case IFD_APDU_CASE_4S:
145 /* Strip off the Le byte */
146 slen--;
147 break;
148 default:
149 /* We don't handle ext APDUs */
150 return -1;
151 }
152
153 /*
154 if (le + 2 > slen) {
155 ct_error("t0_transceive: recv buffer too small");
156 return -1;
157 }
158 */
159
160 if (lc) {
161 t0->state = SENDING;
162 if ((rc = t0_xcv(prot, sbuf, slen, rbuf, 2)) < 0)
163 return rc;
164
165 /* Can this happen? */
166 if (rc != 2)
167 return IFD_ERROR_COMM_ERROR;
168
169 /* Case 4 APDU - check whether we should
170 * try to get the response */
171 if (cse == IFD_APDU_CASE_4S) {
172 unsigned char *sw;
173
174 sw = (unsigned char *)rbuf;
175
176 if (sw[0] == 0x61) {
177 /* additional length info */
178 if (sw[1] != 0 && sw[1] < le)
179 le = sw[1];
180 } else if ((sw[0] & 0xF0) == 0x60) {
181 /* Command not accepted, do not
182 * retrieve response
183 */
184 goto done;
185 }
186
187 /* Transmit a Get Response command */
188 sdata[0] = cla;
189 sdata[1] = 0xC0;
190 sdata[2] = 0x00;
191 sdata[3] = 0x00;
192 sdata[4] = le;
193
194 t0->state = RECEIVING;
195 rc = t0_xcv(prot, sdata, 5, rbuf, le + 2);
196 }
197 } else {
198 t0->state = RECEIVING;
199 rc = t0_xcv(prot, sbuf, slen, rbuf, le + 2);
200 }
201
202 done:t0->state = IDLE;
203 return rc;
204 }
205
t0_xcv(ifd_protocol_t * prot,const void * sdata,size_t slen,void * rdata,size_t rlen)206 static int t0_xcv(ifd_protocol_t * prot, const void *sdata, size_t slen,
207 void *rdata, size_t rlen)
208 {
209 t0_state_t *t0 = (t0_state_t *) prot;
210 ct_buf_t sbuf, rbuf;
211 unsigned int null_count = 0;
212 unsigned int ins;
213
214 /* Let the driver handle any chunking etc */
215 if (t0->block_oriented) {
216 int rc;
217
218 if ((rc = ifd_send_command(prot, sdata, slen)) >= 0)
219 rc = ifd_recv_response(prot, rdata, rlen, t0->timeout);
220 return rc;
221 }
222
223 /* Set up the send buffer */
224 ct_buf_set(&sbuf, (void *)sdata, slen);
225 ct_buf_init(&rbuf, rdata, rlen);
226
227 /* Get the INS */
228 ins = sbuf.base[1];
229
230 if (t0_send(prot, &sbuf, 5) < 0)
231 goto failed;
232
233 while (1) {
234 unsigned char byte;
235 int count;
236
237 if (ifd_recv_response(prot, &byte, 1, t0->timeout) < 0)
238 goto failed;
239
240 /* Null byte to extend wait time */
241 if (byte == 0x60) {
242 usleep(100000);
243 if (++null_count > t0->max_nulls)
244 goto failed;
245 continue;
246 }
247
248 /* ICC sends SW1 SW2 */
249 if ((byte & 0xF0) == 0x60 || (byte & 0xF0) == 0x90) {
250 /* Store SW1, then get SW2 and store it */
251 if (ct_buf_put(&rbuf, &byte, 1) < 0
252 || t0_recv(prot, &rbuf, 1, t0->timeout) < 0)
253 goto failed;
254
255 break;
256 }
257
258 /* Send/receive data.
259 * ACK byte means transfer everything in one go,
260 * ~ACK means do it octet by octet.
261 * SCEZ masks off using 0xFE, but the Towitoko
262 * driver uses 0x0E.
263 * Do we need to make this configurable?
264 */
265 if (((byte ^ ins) & 0xFE) == 0) {
266 /* Send/recv as much as we can */
267 count = -1;
268 } else if (((~byte ^ ins) & 0xFE) == 0) {
269 count = 1;
270 } else {
271 ifd_debug(2, "unexpected byte 0x%02x", byte);
272 return -1;
273 }
274
275 if (t0->state == SENDING) {
276 if (t0_send(prot, &sbuf, count) < 0)
277 goto failed;
278 } else {
279 if (t0_recv(prot, &rbuf, count, t0->timeout) < 0)
280 goto failed;
281 if (ct_buf_tailroom(&rbuf) == 0)
282 break;
283 }
284 }
285
286 return ct_buf_avail(&rbuf);
287
288 failed:t0->state = CONFUSED;
289 return -1;
290 }
291
t0_send(ifd_protocol_t * prot,ct_buf_t * bp,int count)292 static int t0_send(ifd_protocol_t * prot, ct_buf_t * bp, int count)
293 {
294 int n, avail;
295
296 avail = ct_buf_avail(bp);
297 if (count < 0)
298 count = avail;
299 if (count > avail || !avail)
300 return -1;
301 n = ifd_send_command(prot, ct_buf_head(bp), count);
302 if (n >= 0)
303 ct_buf_get(bp, NULL, count);
304 return n;
305 }
306
t0_recv(ifd_protocol_t * prot,ct_buf_t * bp,int count,long timeout)307 static int t0_recv(ifd_protocol_t * prot, ct_buf_t * bp, int count,
308 long timeout)
309 {
310 int n;
311
312 if (count < 0)
313 count = ct_buf_tailroom(bp);
314 n = ifd_recv_response(prot, ct_buf_tail(bp), count, timeout);
315 if (n >= 0)
316 ct_buf_put(bp, NULL, count);
317 return n;
318 }
319
t0_resynch(t0_state_t * t0)320 static int t0_resynch(t0_state_t * t0)
321 {
322 return -1;
323 }
324
325 /*
326 * Protocol struct
327 */
328 struct ifd_protocol_ops ifd_protocol_t0 = {
329 IFD_PROTOCOL_T0, /* id */
330 "T=0", /* name */
331 sizeof(t0_state_t), /* size */
332 t0_init, /* init */
333 t0_release, /* release */
334 t0_set_param, /* set_param */
335 t0_get_param, /* get_param */
336 NULL, /* resynchronize */
337 t0_transceive, /* transceive */
338 NULL, /* sync_read */
339 NULL, /* sync_write */
340 };
341