source: trunk/csctapi/protocol_t1.c@ 1278

Last change on this file since 1278 was 1278, checked in by dingo35, 11 years ago

Cleanup ICC_Async: atr, baudrate, timings, convention

File size: 12.2 KB
Line 
1/*
2 protocol_t1.c
3 Handling of ISO 7816 T=1 protocol
4
5 This file is part of the Unix driver for Towitoko smartcard readers
6 Copyright (C) 2000 Carlos Prados <cprados@yahoo.com>
7
8 This version is modified by doz21 to work in a special manner ;)
9
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
14
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23*/
24
25#include "defines.h"
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include "protocol_t1.h"
30#include "t1_block.h"
31
32/*
33 * Not exported constants definition
34 */
35#define PROTOCOL_T1_DEFAULT_IFSC 32
36#define PROTOCOL_T1_DEFAULT_IFSD 32
37#define PROTOCOL_T1_MAX_IFSC 251 /* Cannot send > 255 buffer */
38#define PROTOCOL_T1_DEFAULT_CWI 13
39#define PROTOCOL_T1_DEFAULT_BWI 4
40#define PROTOCOL_T1_EDC_LRC 0
41#define PROTOCOL_T1_EDC_CRC 1
42
43/*
44 * Not exported functions declaration
45 */
46
47static void
48Protocol_T1_Clear (Protocol_T1 * t1);
49
50static int
51Protocol_T1_SendBlock (Protocol_T1 * t1, T1_Block * block);
52
53static int
54Protocol_T1_ReceiveBlock (Protocol_T1 * t1, T1_Block ** block);
55
56static int
57Protocol_T1_UpdateBWT (Protocol_T1 * t1, unsigned short bwt);
58
59/*
60 * Exproted funtions definition
61 */
62
63Protocol_T1 *
64Protocol_T1_New (void)
65{
66 Protocol_T1 *t1;
67
68 t1 = (Protocol_T1 *) malloc (sizeof (Protocol_T1));
69
70 if (t1 != NULL)
71 Protocol_T1_Clear (t1);
72
73 return t1;
74}
75
76int
77Protocol_T1_Init (Protocol_T1 * t1, ICC_Async * icc, int selected_protocol)
78{
79 BYTE ta, tb, tc, cwi, bwi;
80 unsigned long baudrate;
81 double work_etu;
82 int i;
83
84 /* Set ICC */
85 t1->icc = icc;
86
87 /* Set IFSC */
88 if (ATR_GetInterfaceByte (atr, selected_protocol, ATR_INTERFACE_BYTE_TA, &ta) == ATR_NOT_FOUND)
89 t1->ifsc = PROTOCOL_T1_DEFAULT_IFSC;
90 else if ((ta != 0x00) && (ta != 0xFF))
91 t1->ifsc = ta;
92 else
93 t1->ifsc = PROTOCOL_T1_DEFAULT_IFSC;
94
95 /* Towitoko does not allow IFSC > 251 */
96 t1->ifsc = MIN (t1->ifsc, PROTOCOL_T1_MAX_IFSC);
97
98 /* Set IFSD */
99 t1->ifsd = PROTOCOL_T1_DEFAULT_IFSD;
100
101#ifndef PROTOCOL_T1_USE_DEFAULT_TIMINGS
102 /* Calculate CWI and BWI */
103 if (ATR_GetInterfaceByte (atr, selected_protocol, ATR_INTERFACE_BYTE_TB, &tb) == ATR_NOT_FOUND)
104 {
105#endif
106 cwi = PROTOCOL_T1_DEFAULT_CWI;
107 bwi = PROTOCOL_T1_DEFAULT_BWI;
108#ifndef PROTOCOL_T1_USE_DEFAULT_TIMINGS
109 }
110 else
111 {
112 cwi = tb & 0x0F;
113 bwi = (tb & 0xF0) >> 4;
114 }
115#endif
116
117 /* Work etu = (1000 / baudrate) milliseconds */
118 ICC_Async_GetBaudrate (t1->icc, &baudrate);
119 work_etu = 1000 / (double)baudrate;
120
121 /* Set CWT = (2^CWI + 11) work etu */
122 t1->cwt = 1;
123
124 for (i = 0; i < cwi ; i++)
125 t1->cwt *= 2;
126
127 t1->cwt = (unsigned short) ((t1->cwt + 11) * work_etu);
128
129 /* Set BWT = (2^BWI * 960 + 11) work etu */
130 t1->bwt = 1;
131 for (i = 0; i < bwi; i++)
132 t1->bwt *= 2;
133
134 t1->bwt = (unsigned short) ((t1->bwt * 960 + 11) * work_etu);
135
136 /* Set BGT = 22 * work etu */
137 t1->bgt = (unsigned short) (22 * work_etu);
138
139 /* Set the error detection code type */
140 if (ATR_GetInterfaceByte (atr, selected_protocol, ATR_INTERFACE_BYTE_TC, &tc) == ATR_NOT_FOUND)
141 t1->edc = PROTOCOL_T1_EDC_LRC;
142 else
143 t1->edc = tc & 0x01;
144
145 /* Set initial send sequence (NS) */
146 t1->ns = 1;
147
148 /* Set timings */
149 icc_timings.block_timeout = t1->bwt;
150 icc_timings.char_timeout = t1->cwt;
151 icc_timings.block_delay = t1->bgt;
152 ICC_Async_SetTimings ();
153
154#ifdef DEBUG_PROTOCOL
155 printf ("Protocol: T=1: IFSC=%d, IFSD=%d, CWT=%d, BWT=%d, BGT=%d, EDC=%s\n",
156 t1->ifsc, t1->ifsd, t1->cwt, t1->bwt, t1->bgt,
157 (t1->edc == PROTOCOL_T1_EDC_LRC) ? "LRC" : "CRC");
158#endif
159
160 return PROTOCOL_T1_OK;
161}
162
163int
164Protocol_T1_Command (Protocol_T1 * t1, APDU_Cmd * cmd, APDU_Rsp ** rsp)
165{
166 T1_Block *block;
167 BYTE *buffer, rsp_type, bytes, nr, wtx;
168 unsigned short counter;
169 int ret;
170 bool more;
171 if (APDU_Cmd_Ins(cmd) == T1_BLOCK_S_IFS_REQ)
172 {
173 BYTE inf = APDU_Cmd_P2(cmd);
174
175 /* Create an IFS request S-Block */
176 block = T1_Block_NewSBlock (T1_BLOCK_S_IFS_REQ, 1, &inf);
177
178#ifdef DEBUG_PROTOCOL
179 printf ("Protocol: Sending block S(IFS request, %d)\n", inf);
180#endif
181 /* Send IFSD request */
182 ret = Protocol_T1_SendBlock (t1, block);
183
184 /* Delete block */
185 T1_Block_Delete (block);
186
187 /* Receive a block */
188 ret = Protocol_T1_ReceiveBlock (t1, &block);
189
190 if (ret == PROTOCOL_T1_OK)
191 {
192 rsp_type = T1_Block_GetType (block);
193
194 /* Positive IFS Response S-Block received */
195 if (rsp_type == T1_BLOCK_S_IFS_RES)
196 {
197 /* Update IFSD value */
198 inf = (*T1_Block_GetInf (block));
199 t1->ifsd = inf;
200#ifdef DEBUG_PROTOCOL
201 printf ("Protocol: Received block S(IFS response, %d)\n", inf);
202#endif
203 }
204 }
205
206 return ret;
207 }
208
209 /* Calculate the number of bytes to send */
210 counter = 0;
211 bytes = MIN (APDU_Cmd_RawLen (cmd), t1->ifsc);
212
213 /* See if chaining is needed */
214 more = (APDU_Cmd_RawLen (cmd) > t1->ifsc);
215
216 /* Increment ns */
217 t1->ns = (t1->ns + 1) %2;
218
219 /* Create an I-Block */
220 block = T1_Block_NewIBlock (bytes, APDU_Cmd_Raw (cmd), t1->ns, more);
221
222#ifdef DEBUG_PROTOCOL
223 printf ("Sending block I(%d,%d)\n", t1->ns, more);
224#endif
225
226 /* Send a block */
227 ret = Protocol_T1_SendBlock (t1, block);
228
229 /* Delete I-block */
230 T1_Block_Delete (block);
231
232 while ((ret == PROTOCOL_T1_OK) && more)
233 {
234 /* Receive a block */
235 ret = Protocol_T1_ReceiveBlock (t1, &block);
236
237 if (ret == PROTOCOL_T1_OK)
238 {
239 rsp_type = T1_Block_GetType (block);
240
241 /* Positive ACK R-Block received */
242 if (rsp_type == T1_BLOCK_R_OK)
243 {
244#ifdef DEBUG_PROTOCOL
245 printf ("Protocol: Received block R(%d)\n", T1_Block_GetNR (block));
246#endif
247 /* Delete block */
248 T1_Block_Delete (block);
249
250 /* Increment ns */
251 t1->ns = (t1->ns + 1) % 2;
252
253 /* Calculate the number of bytes to send */
254 counter += bytes;
255 bytes = MIN (APDU_Cmd_RawLen (cmd) - counter, t1->ifsc);
256
257 /* See if chaining is needed */
258 more = (APDU_Cmd_RawLen (cmd) - counter > t1->ifsc);
259
260 /* Create an I-Block */
261 block =
262 T1_Block_NewIBlock (bytes, APDU_Cmd_Raw (cmd) + counter,
263 t1->ns, more);
264#ifdef DEBUG_PROTOCOL
265 printf ("Protocol: Sending block I(%d,%d)\n", t1->ns, more);
266#endif
267 /* Send a block */
268 ret = Protocol_T1_SendBlock (t1, block);
269
270 /* Delete I-block */
271 T1_Block_Delete (block);
272 }
273
274 else
275 {
276 /* Delete block */
277 T1_Block_Delete (block);
278
279 ret = PROTOCOL_T1_NOT_IMPLEMENTED;
280 }
281 }
282
283 else
284 {
285 ret = PROTOCOL_T1_NOT_IMPLEMENTED;
286 }
287 }
288
289 /* Reset counter */
290 buffer = NULL;
291 counter = 0;
292 more = TRUE;
293 wtx = 0;
294
295 while ((ret == PROTOCOL_T1_OK) && more)
296 {
297 if (wtx > 1)
298 Protocol_T1_UpdateBWT (t1, wtx * (t1->bwt));
299
300 /* Receive a block */
301 ret = Protocol_T1_ReceiveBlock (t1, &block);
302
303 if (wtx > 1)
304 {
305 Protocol_T1_UpdateBWT (t1, t1->bwt);
306 wtx = 0;
307 }
308
309 if (ret == PROTOCOL_T1_OK)
310 {
311 rsp_type = T1_Block_GetType (block);
312
313 if (rsp_type == T1_BLOCK_I)
314 {
315#ifdef DEBUG_PROTOCOL
316 printf ("Protocol: Received block I(%d,%d)\n",
317 T1_Block_GetNS(block), T1_Block_GetMore (block));
318#endif
319 /* Calculate nr */
320 nr = (T1_Block_GetNS (block) + 1) % 2;
321
322 /* Save inf field */
323 bytes = T1_Block_GetLen (block);
324 buffer = (BYTE *) realloc(buffer, counter + bytes);
325 memcpy (buffer + counter, T1_Block_GetInf (block), bytes);
326 counter += bytes;
327
328 /* See if chaining is requested */
329 more = T1_Block_GetMore (block);
330
331 /* Delete block */
332 T1_Block_Delete (block);
333
334 if (more)
335 {
336 /* Create an R-Block */
337 block = T1_Block_NewRBlock (T1_BLOCK_R_OK, nr);
338#ifdef DEBUG_PROTOCOL
339 printf ("Protocol: Sending block R(%d)\n", nr);
340#endif
341 /* Send R-Block */
342 ret = Protocol_T1_SendBlock (t1, block);
343
344 /* Delete I-block */
345 T1_Block_Delete (block);
346 }
347 }
348
349 /* WTX Request S-Block received */
350 else if (rsp_type == T1_BLOCK_S_WTX_REQ)
351 {
352 /* Get wtx multiplier */
353 wtx = (*T1_Block_GetInf (block));
354#ifdef DEBUG_PROTOCOL
355 printf ("Protocol: Received block S(WTX request, %d)\n", wtx);
356#endif
357 /* Delete block */
358 T1_Block_Delete (block);
359
360 /* Create an WTX response S-Block */
361 block = T1_Block_NewSBlock (T1_BLOCK_S_WTX_RES, 1, &wtx);
362#ifdef DEBUG_PROTOCOL
363 printf ("Protocol: Sending block S(WTX response, %d)\n", wtx);
364#endif
365 /* Send WTX response */
366 ret = Protocol_T1_SendBlock (t1, block);
367
368 /* Delete block */
369 T1_Block_Delete (block);
370 }
371
372 else
373 {
374 ret = PROTOCOL_T1_NOT_IMPLEMENTED;
375 }
376 }
377 }
378
379 if (ret == PROTOCOL_T1_OK)
380 (*rsp) = APDU_Rsp_New (buffer, counter);
381
382 if (buffer != NULL)
383 free (buffer);
384
385 return ret;
386}
387
388int
389Protocol_T1_Close (Protocol_T1 * t1)
390{
391 Protocol_T1_Clear (t1);
392
393 return PROTOCOL_T1_OK;
394}
395
396void
397Protocol_T1_Delete (Protocol_T1 * t1)
398{
399 free (t1);
400}
401
402/*
403 * Not exported functions definition
404 */
405
406static int
407Protocol_T1_SendBlock (Protocol_T1 * t1, T1_Block * block)
408{
409 BYTE *buffer;
410 int length, ret;
411
412 {
413 /* Send T=1 block */
414 buffer = T1_Block_Raw (block);
415 length = T1_Block_RawLen (block);
416
417 if (ICC_Async_Transmit (length, buffer) != ICC_ASYNC_OK)
418 {
419 ret = PROTOCOL_T1_ICC_ERROR;
420 }
421
422 else
423 ret = PROTOCOL_T1_OK;
424 }
425
426 return ret;
427}
428
429static int
430Protocol_T1_ReceiveBlock (Protocol_T1 * t1, T1_Block ** block)
431{
432 BYTE buffer[T1_BLOCK_MAX_SIZE];
433 int ret;
434
435 /* Receive four mandatory bytes */
436 if (ICC_Async_Receive (4, buffer) != ICC_ASYNC_OK)
437 {
438 ret = PROTOCOL_T1_ICC_ERROR;
439 (*block) = NULL;
440 }
441
442 else
443 {
444 if (buffer[2] != 0x00)
445 {
446 /* Set timings to read the remaining block */
447 Protocol_T1_UpdateBWT (t1, t1->cwt);
448
449 /* Receive remaining bytes */
450 if (ICC_Async_Receive (buffer[2], buffer + 4) !=
451 ICC_ASYNC_OK)
452 {
453 (*block) = NULL;
454 ret = PROTOCOL_T1_ICC_ERROR;
455 }
456
457 else
458 {
459 (*block) = T1_Block_New (buffer, buffer[2] + 4);
460 ret = PROTOCOL_T1_OK;
461 }
462
463 /* Restore timings */
464 Protocol_T1_UpdateBWT (t1, t1->bwt);
465 }
466 else
467 {
468 ret = PROTOCOL_T1_OK;
469 (*block) = T1_Block_New (buffer, 4);
470 }
471 }
472
473 return ret;
474}
475
476static void
477Protocol_T1_Clear (Protocol_T1 * t1)
478{
479 t1->icc = NULL;
480 t1->ifsc = 0;
481 t1->ifsd = 0;
482 t1->bgt = 0;
483 t1->bwt = 0;
484 t1->cwt = 0;
485 t1->edc = 0;
486 t1->ns = 0;
487}
488
489static int
490Protocol_T1_UpdateBWT (Protocol_T1 * t1, unsigned short bwt)
491{
492 icc_timings.block_timeout = bwt;
493 ICC_Async_SetTimings ();
494
495 return PROTOCOL_T1_OK;
496}
Note: See TracBrowser for help on using the repository browser.