source: trunk/csctapi/protocol_t1.c@ 1283

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

Remove dynamic data structures for T0, T1 and T14 protocols

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