source: trunk/csctapi/protocol_t1.c@ 1279

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

Remove ICC_Async dynamic data structure, cleanup some parameters in t0 and t1

File size: 12.0 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 (T1_Block * block);
52
53static int
54Protocol_T1_ReceiveBlock (Protocol_T1 * t1, T1_Block ** block);
55
56static int
57Protocol_T1_UpdateBWT (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, 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 IFSC */
85 if (ATR_GetInterfaceByte (atr, selected_protocol, ATR_INTERFACE_BYTE_TA, &ta) == ATR_NOT_FOUND)
86 t1->ifsc = PROTOCOL_T1_DEFAULT_IFSC;
87 else if ((ta != 0x00) && (ta != 0xFF))
88 t1->ifsc = ta;
89 else
90 t1->ifsc = PROTOCOL_T1_DEFAULT_IFSC;
91
92 /* Towitoko does not allow IFSC > 251 */
93 t1->ifsc = MIN (t1->ifsc, PROTOCOL_T1_MAX_IFSC);
94
95 /* Set IFSD */
96 t1->ifsd = PROTOCOL_T1_DEFAULT_IFSD;
97
98#ifndef PROTOCOL_T1_USE_DEFAULT_TIMINGS
99 /* Calculate CWI and BWI */
100 if (ATR_GetInterfaceByte (atr, selected_protocol, ATR_INTERFACE_BYTE_TB, &tb) == ATR_NOT_FOUND)
101 {
102#endif
103 cwi = PROTOCOL_T1_DEFAULT_CWI;
104 bwi = PROTOCOL_T1_DEFAULT_BWI;
105#ifndef PROTOCOL_T1_USE_DEFAULT_TIMINGS
106 }
107 else
108 {
109 cwi = tb & 0x0F;
110 bwi = (tb & 0xF0) >> 4;
111 }
112#endif
113
114 /* Work etu = (1000 / baudrate) milliseconds */
115 ICC_Async_GetBaudrate (&baudrate);
116 work_etu = 1000 / (double)baudrate;
117
118 /* Set CWT = (2^CWI + 11) work etu */
119 t1->cwt = 1;
120
121 for (i = 0; i < cwi ; i++)
122 t1->cwt *= 2;
123
124 t1->cwt = (unsigned short) ((t1->cwt + 11) * work_etu);
125
126 /* Set BWT = (2^BWI * 960 + 11) work etu */
127 t1->bwt = 1;
128 for (i = 0; i < bwi; i++)
129 t1->bwt *= 2;
130
131 t1->bwt = (unsigned short) ((t1->bwt * 960 + 11) * work_etu);
132
133 /* Set BGT = 22 * work etu */
134 t1->bgt = (unsigned short) (22 * work_etu);
135
136 /* Set the error detection code type */
137 if (ATR_GetInterfaceByte (atr, selected_protocol, ATR_INTERFACE_BYTE_TC, &tc) == ATR_NOT_FOUND)
138 t1->edc = PROTOCOL_T1_EDC_LRC;
139 else
140 t1->edc = tc & 0x01;
141
142 /* Set initial send sequence (NS) */
143 t1->ns = 1;
144
145 /* Set timings */
146 icc_timings.block_timeout = t1->bwt;
147 icc_timings.char_timeout = t1->cwt;
148 icc_timings.block_delay = t1->bgt;
149 ICC_Async_SetTimings ();
150
151#ifdef DEBUG_PROTOCOL
152 printf ("Protocol: T=1: IFSC=%d, IFSD=%d, CWT=%d, BWT=%d, BGT=%d, EDC=%s\n",
153 t1->ifsc, t1->ifsd, t1->cwt, t1->bwt, t1->bgt,
154 (t1->edc == PROTOCOL_T1_EDC_LRC) ? "LRC" : "CRC");
155#endif
156
157 return PROTOCOL_T1_OK;
158}
159
160int
161Protocol_T1_Command (Protocol_T1 * t1, APDU_Cmd * cmd, APDU_Rsp ** rsp)
162{
163 T1_Block *block;
164 BYTE *buffer, rsp_type, bytes, nr, wtx;
165 unsigned short counter;
166 int ret;
167 bool more;
168 if (APDU_Cmd_Ins(cmd) == T1_BLOCK_S_IFS_REQ)
169 {
170 BYTE inf = APDU_Cmd_P2(cmd);
171
172 /* Create an IFS request S-Block */
173 block = T1_Block_NewSBlock (T1_BLOCK_S_IFS_REQ, 1, &inf);
174
175#ifdef DEBUG_PROTOCOL
176 printf ("Protocol: Sending block S(IFS request, %d)\n", inf);
177#endif
178 /* Send IFSD request */
179 ret = Protocol_T1_SendBlock (block);
180
181 /* Delete block */
182 T1_Block_Delete (block);
183
184 /* Receive a block */
185 ret = Protocol_T1_ReceiveBlock (t1, &block);
186
187 if (ret == PROTOCOL_T1_OK)
188 {
189 rsp_type = T1_Block_GetType (block);
190
191 /* Positive IFS Response S-Block received */
192 if (rsp_type == T1_BLOCK_S_IFS_RES)
193 {
194 /* Update IFSD value */
195 inf = (*T1_Block_GetInf (block));
196 t1->ifsd = inf;
197#ifdef DEBUG_PROTOCOL
198 printf ("Protocol: Received block S(IFS response, %d)\n", inf);
199#endif
200 }
201 }
202
203 return ret;
204 }
205
206 /* Calculate the number of bytes to send */
207 counter = 0;
208 bytes = MIN (APDU_Cmd_RawLen (cmd), t1->ifsc);
209
210 /* See if chaining is needed */
211 more = (APDU_Cmd_RawLen (cmd) > t1->ifsc);
212
213 /* Increment ns */
214 t1->ns = (t1->ns + 1) %2;
215
216 /* Create an I-Block */
217 block = T1_Block_NewIBlock (bytes, APDU_Cmd_Raw (cmd), t1->ns, more);
218
219#ifdef DEBUG_PROTOCOL
220 printf ("Sending block I(%d,%d)\n", t1->ns, more);
221#endif
222
223 /* Send a block */
224 ret = Protocol_T1_SendBlock (block);
225
226 /* Delete I-block */
227 T1_Block_Delete (block);
228
229 while ((ret == PROTOCOL_T1_OK) && more)
230 {
231 /* Receive a block */
232 ret = Protocol_T1_ReceiveBlock (t1, &block);
233
234 if (ret == PROTOCOL_T1_OK)
235 {
236 rsp_type = T1_Block_GetType (block);
237
238 /* Positive ACK R-Block received */
239 if (rsp_type == T1_BLOCK_R_OK)
240 {
241#ifdef DEBUG_PROTOCOL
242 printf ("Protocol: Received block R(%d)\n", T1_Block_GetNR (block));
243#endif
244 /* Delete block */
245 T1_Block_Delete (block);
246
247 /* Increment ns */
248 t1->ns = (t1->ns + 1) % 2;
249
250 /* Calculate the number of bytes to send */
251 counter += bytes;
252 bytes = MIN (APDU_Cmd_RawLen (cmd) - counter, t1->ifsc);
253
254 /* See if chaining is needed */
255 more = (APDU_Cmd_RawLen (cmd) - counter > t1->ifsc);
256
257 /* Create an I-Block */
258 block =
259 T1_Block_NewIBlock (bytes, APDU_Cmd_Raw (cmd) + counter,
260 t1->ns, more);
261#ifdef DEBUG_PROTOCOL
262 printf ("Protocol: Sending block I(%d,%d)\n", t1->ns, more);
263#endif
264 /* Send a block */
265 ret = Protocol_T1_SendBlock (block);
266
267 /* Delete I-block */
268 T1_Block_Delete (block);
269 }
270
271 else
272 {
273 /* Delete block */
274 T1_Block_Delete (block);
275
276 ret = PROTOCOL_T1_NOT_IMPLEMENTED;
277 }
278 }
279
280 else
281 {
282 ret = PROTOCOL_T1_NOT_IMPLEMENTED;
283 }
284 }
285
286 /* Reset counter */
287 buffer = NULL;
288 counter = 0;
289 more = TRUE;
290 wtx = 0;
291
292 while ((ret == PROTOCOL_T1_OK) && more)
293 {
294 if (wtx > 1)
295 Protocol_T1_UpdateBWT (wtx * (t1->bwt));
296
297 /* Receive a block */
298 ret = Protocol_T1_ReceiveBlock (t1, &block);
299
300 if (wtx > 1)
301 {
302 Protocol_T1_UpdateBWT (t1->bwt);
303 wtx = 0;
304 }
305
306 if (ret == PROTOCOL_T1_OK)
307 {
308 rsp_type = T1_Block_GetType (block);
309
310 if (rsp_type == T1_BLOCK_I)
311 {
312#ifdef DEBUG_PROTOCOL
313 printf ("Protocol: Received block I(%d,%d)\n",
314 T1_Block_GetNS(block), T1_Block_GetMore (block));
315#endif
316 /* Calculate nr */
317 nr = (T1_Block_GetNS (block) + 1) % 2;
318
319 /* Save inf field */
320 bytes = T1_Block_GetLen (block);
321 buffer = (BYTE *) realloc(buffer, counter + bytes);
322 memcpy (buffer + counter, T1_Block_GetInf (block), bytes);
323 counter += bytes;
324
325 /* See if chaining is requested */
326 more = T1_Block_GetMore (block);
327
328 /* Delete block */
329 T1_Block_Delete (block);
330
331 if (more)
332 {
333 /* Create an R-Block */
334 block = T1_Block_NewRBlock (T1_BLOCK_R_OK, nr);
335#ifdef DEBUG_PROTOCOL
336 printf ("Protocol: Sending block R(%d)\n", nr);
337#endif
338 /* Send R-Block */
339 ret = Protocol_T1_SendBlock (block);
340
341 /* Delete I-block */
342 T1_Block_Delete (block);
343 }
344 }
345
346 /* WTX Request S-Block received */
347 else if (rsp_type == T1_BLOCK_S_WTX_REQ)
348 {
349 /* Get wtx multiplier */
350 wtx = (*T1_Block_GetInf (block));
351#ifdef DEBUG_PROTOCOL
352 printf ("Protocol: Received block S(WTX request, %d)\n", wtx);
353#endif
354 /* Delete block */
355 T1_Block_Delete (block);
356
357 /* Create an WTX response S-Block */
358 block = T1_Block_NewSBlock (T1_BLOCK_S_WTX_RES, 1, &wtx);
359#ifdef DEBUG_PROTOCOL
360 printf ("Protocol: Sending block S(WTX response, %d)\n", wtx);
361#endif
362 /* Send WTX response */
363 ret = Protocol_T1_SendBlock (block);
364
365 /* Delete block */
366 T1_Block_Delete (block);
367 }
368
369 else
370 {
371 ret = PROTOCOL_T1_NOT_IMPLEMENTED;
372 }
373 }
374 }
375
376 if (ret == PROTOCOL_T1_OK)
377 (*rsp) = APDU_Rsp_New (buffer, counter);
378
379 if (buffer != NULL)
380 free (buffer);
381
382 return ret;
383}
384
385int
386Protocol_T1_Close (Protocol_T1 * t1)
387{
388 Protocol_T1_Clear (t1);
389
390 return PROTOCOL_T1_OK;
391}
392
393void
394Protocol_T1_Delete (Protocol_T1 * t1)
395{
396 free (t1);
397}
398
399/*
400 * Not exported functions definition
401 */
402
403static int
404Protocol_T1_SendBlock (T1_Block * block)
405{
406 BYTE *buffer;
407 int length, ret;
408
409 {
410 /* Send T=1 block */
411 buffer = T1_Block_Raw (block);
412 length = T1_Block_RawLen (block);
413
414 if (ICC_Async_Transmit (length, buffer) != ICC_ASYNC_OK)
415 {
416 ret = PROTOCOL_T1_ICC_ERROR;
417 }
418
419 else
420 ret = PROTOCOL_T1_OK;
421 }
422
423 return ret;
424}
425
426static int
427Protocol_T1_ReceiveBlock (Protocol_T1 * t1, T1_Block ** block)
428{
429 BYTE buffer[T1_BLOCK_MAX_SIZE];
430 int ret;
431
432 /* Receive four mandatory bytes */
433 if (ICC_Async_Receive (4, buffer) != ICC_ASYNC_OK)
434 {
435 ret = PROTOCOL_T1_ICC_ERROR;
436 (*block) = NULL;
437 }
438
439 else
440 {
441 if (buffer[2] != 0x00)
442 {
443 /* Set timings to read the remaining block */
444 Protocol_T1_UpdateBWT (t1->cwt);
445
446 /* Receive remaining bytes */
447 if (ICC_Async_Receive (buffer[2], buffer + 4) !=
448 ICC_ASYNC_OK)
449 {
450 (*block) = NULL;
451 ret = PROTOCOL_T1_ICC_ERROR;
452 }
453
454 else
455 {
456 (*block) = T1_Block_New (buffer, buffer[2] + 4);
457 ret = PROTOCOL_T1_OK;
458 }
459
460 /* Restore timings */
461 Protocol_T1_UpdateBWT (t1->bwt);
462 }
463 else
464 {
465 ret = PROTOCOL_T1_OK;
466 (*block) = T1_Block_New (buffer, 4);
467 }
468 }
469
470 return ret;
471}
472
473static void
474Protocol_T1_Clear (Protocol_T1 * t1)
475{
476 t1->ifsc = 0;
477 t1->ifsd = 0;
478 t1->bgt = 0;
479 t1->bwt = 0;
480 t1->cwt = 0;
481 t1->edc = 0;
482 t1->ns = 0;
483}
484
485static int
486Protocol_T1_UpdateBWT (unsigned short bwt)
487{
488 icc_timings.block_timeout = bwt;
489 ICC_Async_SetTimings ();
490
491 return PROTOCOL_T1_OK;
492}
Note: See TracBrowser for help on using the repository browser.