/[pcsclite]/trunk/Drivers/ccid/src/ccid_serial.c
ViewVC logotype

Contents of /trunk/Drivers/ccid/src/ccid_serial.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1399 - (show annotations) (download)
Mon Mar 14 18:56:53 2005 UTC (8 years, 2 months ago) by rousseau
File MIME type: text/plain
File size: 15449 byte(s)
change licence from GNU GPL to GNU LGPL
1 /*
2 * ccid_serial.c: communicate with a GemPC Twin smart card reader
3 * Copyright (C) 2001-2004 Ludovic Rousseau <ludovic.rousseau@free.fr>
4 *
5 * Thanks to Niki W. Waibel <niki.waibel@gmx.net> for a prototype version
6 *
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 /*
23 * $Id$
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <termios.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <PCSC/ifdhandler.h>
36
37 #include "defs.h"
38 #include "ccid_ifdhandler.h"
39 #include "config.h"
40 #include "debug.h"
41 #include "ccid.h"
42 #include "utils.h"
43 #include "commands.h"
44
45 /* communication timeout in seconds
46 * the value is set at the end of OpenSerialByName() */
47 int SerialTimeout;
48
49 #define SYNC 0x03
50 #define CTRL_ACK 0x06
51 #define CTRL_NAK 0x15
52 #define RDR_to_PC_NotifySlotChange 0x50
53 #define CARD_ABSENT 0x02
54 #define CARD_PRESENT 0x03
55
56 /*
57 * normal command:
58 * 1 : SYNC
59 * 1 : CTRL
60 * 10 +data length : CCID command
61 * 1 : LRC
62 *
63 * SYNC : 0x03
64 * CTRL : ACK (0x06) or NAK (0x15)
65 * CCID command : see USB CCID specs
66 * LRC : xor of all the previous byes
67 *
68 * Error message:
69 * 1 : SYNC (0x03)
70 * 1 : CTRL (NAK: 0x15)
71 * 1 : LRC (0x16)
72 *
73 * Card insertion/withdrawal
74 * 1 : RDR_to_PC_NotifySlotChange (0x50)
75 * 1 : bmSlotIccState
76 * 0x02 if card absent
77 * 0x03 is card present
78 *
79 * Time request
80 * T=1 : normal CCID command
81 * T=0 : 1 byte (value between 0x80 and 0xFF)
82 *
83 */
84
85 /*
86 * You may get read timeout after a card movement.
87 * This is because you will get the echo of the CCID command
88 * but not the result of the command.
89 *
90 * This is not an applicative issue since the card is either removed (and
91 * powered off) or just inserted (and not yet powered on).
92 */
93
94 /* 271 = max size for short APDU
95 * 2 bytes for header
96 * 1 byte checksum
97 * doubled for echo
98 */
99 #define GEMPCTWIN_MAXBUF (271 +2 +1) * 2
100
101 typedef struct
102 {
103 /*
104 * File handle on the serial port
105 */
106 int fd;
107
108 /*
109 * device used ("/dev/ttyS?" under Linux)
110 */
111 /*@null@*/ char *device;
112
113 /*
114 * serial communication buffer
115 */
116 unsigned char buffer[GEMPCTWIN_MAXBUF];
117
118 /*
119 * next available byte
120 */
121 int buffer_offset;
122
123 /*
124 * number of available bytes
125 */
126 int buffer_offset_last;
127
128 /*
129 * CCID infos common to USB and serial
130 */
131 _ccid_descriptor ccid;
132
133 } _serialDevice;
134
135 /* The _serialDevice structure must be defined before including ccid_serial.h */
136 #include "ccid_serial.h"
137
138 /* no need to initialize to 0 since it is static */
139 static _serialDevice serialDevice[CCID_DRIVER_MAX_READERS];
140
141 /* unexported functions */
142 static int ReadChunk(unsigned int reader_index, unsigned char *buffer,
143 int buffer_length, int min_length);
144
145 static int get_bytes(unsigned int reader_index, unsigned char *buffer,
146 int length);
147
148
149 /*****************************************************************************
150 *
151 * WriteSerial: Send bytes to the card reader
152 *
153 *****************************************************************************/
154 status_t WriteSerial(unsigned int reader_index, unsigned int length,
155 unsigned char *buffer)
156 {
157 int i;
158 unsigned char lrc;
159 unsigned char low_level_buffer[GEMPCTWIN_MAXBUF];
160
161 #ifdef DEBUG_LEVEL_COMM
162 char debug_header[] = "-> 123456 ";
163
164 sprintf(debug_header, "-> %06X ", reader_index);
165 #endif
166
167 if (length > GEMPCTWIN_MAXBUF-3)
168 {
169 DEBUG_CRITICAL3("command too long: %d for max %d",
170 length, GEMPCTWIN_MAXBUF-3);
171 return STATUS_UNSUCCESSFUL;
172 }
173
174 /* header */
175 low_level_buffer[0] = 0x03; /* SYNC */
176 low_level_buffer[1] = 0x06; /* ACK */
177
178 /* CCID command */
179 memcpy(low_level_buffer+2, buffer, length);
180
181 /* checksum */
182 lrc = 0;
183 for(i=0; i<length+2; i++)
184 lrc ^= low_level_buffer[i];
185 low_level_buffer[length+2] = lrc;
186
187 #ifdef DEBUG_LEVEL_COMM
188 DEBUG_XXD(debug_header, low_level_buffer, length+3);
189 #endif
190
191 if (write(serialDevice[reader_index].fd, low_level_buffer,
192 length+3) != length+3)
193 {
194 DEBUG_CRITICAL2("write error: %s", strerror(errno));
195 return STATUS_UNSUCCESSFUL;
196 }
197
198 return STATUS_SUCCESS;
199 } /* WriteSerial */
200
201
202 /*****************************************************************************
203 *
204 * ReadSerial: Receive bytes from the card reader
205 *
206 *****************************************************************************/
207 status_t ReadSerial(unsigned int reader_index,
208 /*@unused@*/ unsigned int *length, unsigned char *buffer)
209 {
210 unsigned char c;
211 int rv;
212 int echo;
213 int to_read;
214 int i;
215
216 /* we get the echo first */
217 echo = TRUE;
218
219 start:
220 DEBUG_COMM("start");
221 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
222 return rv;
223
224 if (c == RDR_to_PC_NotifySlotChange)
225 goto slot_change;
226
227 if (c == SYNC)
228 goto sync;
229
230 if (c >= 0x80)
231 {
232 DEBUG_COMM2("time request: 0x%02X", c);
233 goto start;
234 }
235
236 DEBUG_CRITICAL2("Got 0x%02X", c);
237 return STATUS_COMM_ERROR;
238
239 slot_change:
240 DEBUG_COMM("slot change");
241 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
242 return rv;
243
244 if (c == CARD_ABSENT)
245 {
246 DEBUG_COMM("Card removed");
247 }
248 else
249 if (c == CARD_PRESENT)
250 {
251 DEBUG_COMM("Card inserted");
252 }
253 else
254 {
255 DEBUG_COMM2("Unknown card movement: %d", c);
256 }
257 goto start;
258
259 sync:
260 DEBUG_COMM("sync");
261 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
262 return rv;
263
264 if (c == CTRL_ACK)
265 goto ack;
266
267 if (c == CTRL_NAK)
268 goto nak;
269
270 DEBUG_CRITICAL2("Got 0x%02X instead of ACK/NAK", c);
271 return STATUS_COMM_ERROR;
272
273 nak:
274 DEBUG_COMM("nak");
275 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
276 return rv;
277
278 if (c != (SYNC ^ CTRL_NAK))
279 {
280 DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
281 return STATUS_COMM_ERROR;
282 }
283 else
284 goto start;
285
286 ack:
287 DEBUG_COMM("ack");
288 /* normal CCID frame */
289 if ((rv = get_bytes(reader_index, buffer, 5)) != STATUS_SUCCESS)
290 return rv;
291
292 /* total frame size */
293 to_read = 10+dw2i(buffer, 1);
294
295 DEBUG_COMM2("frame size: %d", to_read);
296 if ((rv = get_bytes(reader_index, buffer+5, to_read-5)) != STATUS_SUCCESS)
297 return rv;
298
299 #ifdef DEBUG_LEVEL_COMM
300 DEBUG_XXD("frame: ", buffer, to_read);
301 #endif
302
303 /* lrc */
304 DEBUG_COMM("lrc");
305 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
306 return rv;
307
308 DEBUG_COMM2("lrc: 0x%02X", c);
309 for (i=0; i<to_read; i++)
310 c ^= buffer[i];
311
312 if (c != (SYNC ^ CTRL_ACK))
313 DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
314
315 if (echo)
316 {
317 echo = FALSE;
318 goto start;
319 }
320
321 return STATUS_SUCCESS;
322 } /* ReadSerial */
323
324
325 /*****************************************************************************
326 *
327 * get_bytes: get n bytes
328 *
329 *****************************************************************************/
330 int get_bytes(unsigned int reader_index, unsigned char *buffer, int length)
331 {
332 int offset = serialDevice[reader_index].buffer_offset;
333 int offset_last = serialDevice[reader_index].buffer_offset_last;
334
335 DEBUG_COMM3("available: %d, needed: %d", offset_last-offset,
336 length);
337 /* enough data are available */
338 if (offset + length <= offset_last)
339 {
340 DEBUG_COMM("data available");
341 memcpy(buffer, serialDevice[reader_index].buffer + offset, length);
342 serialDevice[reader_index].buffer_offset += length;
343 }
344 else
345 {
346 int present, rv;
347
348 /* copy available data */
349 present = offset_last - offset;
350
351 if (present > 0)
352 {
353 DEBUG_COMM2("some data available: %d", present);
354 memcpy(buffer, serialDevice[reader_index].buffer + offset,
355 present);
356 }
357
358 /* get fresh data */
359 DEBUG_COMM2("get more data: %d", length - present);
360 rv = ReadChunk(reader_index, serialDevice[reader_index].buffer,
361 sizeof(serialDevice[reader_index].buffer), length - present);
362 if (rv < 0)
363 return STATUS_COMM_ERROR;
364
365 /* fill the buffer */
366 memcpy(buffer + present, serialDevice[reader_index].buffer,
367 length - present);
368 serialDevice[reader_index].buffer_offset = length - present;
369 serialDevice[reader_index].buffer_offset_last = rv;
370 DEBUG_COMM3("offset: %d, last_offset: %d",
371 serialDevice[reader_index].buffer_offset,
372 serialDevice[reader_index].buffer_offset_last);
373 }
374
375 return STATUS_SUCCESS;
376 } /* get_bytes */
377
378
379 /*****************************************************************************
380 *
381 * ReadChunk: read a minimum number of bytes
382 *
383 *****************************************************************************/
384 static int ReadChunk(unsigned int reader_index, unsigned char *buffer,
385 int buffer_length, int min_length)
386 {
387 int fd = serialDevice[reader_index].fd;
388 # ifndef S_SPLINT_S
389 fd_set fdset;
390 # endif
391 struct timeval t;
392 int i, rv = 0;
393 int already_read;
394 #ifdef DEBUG_LEVEL_COMM
395 char debug_header[] = "<- 123456 ";
396
397 sprintf(debug_header, "<- %06X ", reader_index);
398 #endif
399
400 already_read = 0;
401 while (already_read < min_length)
402 {
403 /* use select() to, eventually, timeout */
404 FD_ZERO(&fdset);
405 FD_SET(fd, &fdset);
406 t.tv_sec = SerialTimeout;
407 t.tv_usec = 0;
408
409 i = select(fd+1, &fdset, NULL, NULL, &t);
410 if (i == -1)
411 {
412 DEBUG_CRITICAL2("select: %s", strerror(errno));
413 return -1;
414 }
415 else
416 if (i == 0)
417 {
418 DEBUG_COMM2("Timeout! (%d sec)", SerialTimeout);
419 return -1;
420 }
421
422 rv = read(fd, buffer + already_read, buffer_length - already_read);
423 if (rv < 0)
424 {
425 DEBUG_COMM2("read error: %s", strerror(errno));
426 return -1;
427 }
428
429 #ifdef DEBUG_LEVEL_COMM
430 DEBUG_XXD(debug_header, buffer + already_read, rv);
431 #endif
432
433 already_read += rv;
434 DEBUG_COMM3("read: %d, to read: %d", already_read,
435 min_length);
436 }
437
438 return already_read;
439 } /* ReadChunk */
440
441
442 /*****************************************************************************
443 *
444 * OpenSerial: open the port
445 *
446 *****************************************************************************/
447 status_t OpenSerial(unsigned int reader_index, int channel)
448 {
449 char dev_name[FILENAME_MAX];
450
451 DEBUG_COMM3("Reader index: %X, Channel: %d", reader_index, channel);
452
453 /*
454 * Conversion of old-style ifd-hanler 1.0 CHANNELID
455 */
456 if (channel == 0x0103F8)
457 channel = 1;
458 else
459 if (channel == 0x0102F8)
460 channel = 2;
461 else
462 if (channel == 0x0103E8)
463 channel = 3;
464 else
465 if (channel == 0x0102E8)
466 channel = 4;
467
468 if (channel < 0)
469 {
470 DEBUG_CRITICAL2("wrong port number: %d", (int) channel);
471 return STATUS_UNSUCCESSFUL;
472 }
473
474 sprintf(dev_name, "/dev/pcsc/%d", (int) channel);
475
476 return OpenSerialByName(reader_index, dev_name);
477 } /* OpenSerial */
478
479 /*****************************************************************************
480 *
481 * OpenSerialByName: open the port
482 *
483 *****************************************************************************/
484 status_t OpenSerialByName(unsigned int reader_index, char *dev_name)
485 {
486 struct termios current_termios;
487 int i;
488 unsigned int reader = reader_index;
489
490 DEBUG_COMM3("Reader index: %X, Device: %s", reader_index, dev_name);
491
492 /* check if the same channel is not already used */
493 for (i=0; i<CCID_DRIVER_MAX_READERS; i++)
494 {
495 if (serialDevice[i].device &&
496 strcmp(serialDevice[i].device, dev_name) == 0)
497 {
498 DEBUG_CRITICAL2("Device %s already in use", dev_name);
499 return STATUS_UNSUCCESSFUL;
500 }
501 }
502
503 serialDevice[reader].fd = open(dev_name, O_RDWR | O_NOCTTY);
504
505 if (-1 == serialDevice[reader].fd)
506 {
507 DEBUG_CRITICAL3("open %s: %s", dev_name, strerror(errno));
508 return STATUS_UNSUCCESSFUL;
509 }
510
511 /* set channel used */
512 serialDevice[reader].device = strdup(dev_name);
513
514 /* empty in and out serial buffers */
515 if (tcflush(serialDevice[reader].fd, TCIOFLUSH))
516 DEBUG_INFO2("tcflush() function error: %s", strerror(errno));
517
518 /* get config attributes */
519 if (tcgetattr(serialDevice[reader].fd, &current_termios) == -1)
520 {
521 DEBUG_INFO2("tcgetattr() function error: %s", strerror(errno));
522 close(serialDevice[reader].fd);
523 serialDevice[reader].fd = -1;
524
525 return STATUS_UNSUCCESSFUL;
526 }
527
528 /* IGNBRK: ignore BREAK condition on input
529 * IGNPAR: ignore framing errors and parity errors. */
530 current_termios.c_iflag = IGNBRK | IGNPAR;
531 current_termios.c_oflag = 0; /* Raw output modes */
532 /* CS8: 8-bits character size
533 * CSTOPB: set two stop bits
534 * CREAD: enable receiver
535 * CLOCAL: ignore modem control lines */
536 current_termios.c_cflag = CS8 | CSTOPB | CREAD | CLOCAL;
537
538 /* Do not echo characters because if you connect to a host it or your modem
539 * will echo characters for you. Don't generate signals. */
540 current_termios.c_lflag = 0;
541
542 /* set serial port speed to 115200 bauds */
543 cfsetspeed(&current_termios, B115200);
544
545 DEBUG_INFO("Set serial port baudrate to 115200 and correct configuration");
546 if (tcsetattr(serialDevice[reader].fd, TCSANOW, &current_termios) == -1)
547 {
548 close(serialDevice[reader].fd);
549 serialDevice[reader].fd = -1;
550 DEBUG_INFO2("tcsetattr error: %s", strerror(errno));
551
552 return STATUS_UNSUCCESSFUL;
553 }
554
555 serialDevice[reader].ccid.real_bSeq = 0;
556 serialDevice[reader].ccid.pbSeq = &serialDevice[reader].ccid.real_bSeq;
557 serialDevice[reader].ccid.readerID = GEMPCTWIN;
558 serialDevice[reader].ccid.dwMaxCCIDMessageLength = 271;
559 serialDevice[reader].ccid.dwMaxIFSD = 254;
560 serialDevice[reader].ccid.dwFeatures = 0x00010230;
561 serialDevice[reader].ccid.bPINSupport = 0x0;
562 serialDevice[reader].ccid.dwDefaultClock = 4000;
563 serialDevice[reader].ccid.dwMaxDataRate = 344086;
564 serialDevice[reader].ccid.bMaxSlotIndex = 0;
565 serialDevice[reader].ccid.bCurrentSlotIndex = 0;
566
567 serialDevice[reader].buffer_offset = 0;
568 serialDevice[reader].buffer_offset_last = 0;
569
570 /* perform a command to be sure a GemPC Twin reader is connected
571 * get the reader firmware */
572 {
573 unsigned char tx_buffer[] = { 0x02 };
574 unsigned char rx_buffer[50];
575 unsigned int rx_length = sizeof(rx_buffer);
576
577 /* 2 seconds timeout to not wait too long if no reader is connected */
578 SerialTimeout = 2;
579
580 if (IFD_SUCCESS != CmdEscape(reader_index, tx_buffer, sizeof(tx_buffer),
581 rx_buffer, &rx_length))
582 {
583 DEBUG_CRITICAL("Get firmware failed. Maybe the reader is not connected");
584 return STATUS_UNSUCCESSFUL;
585 }
586
587 /* normal timeout: 1 minute to allow long time APDU */
588 SerialTimeout = 60;
589
590 rx_buffer[rx_length] = '\0';
591 DEBUG_INFO2("Firmware: %s", rx_buffer);
592 }
593
594 return STATUS_SUCCESS;
595 } /* OpenSerialByName */
596
597
598 /*****************************************************************************
599 *
600 * CloseSerial: close the port
601 *
602 *****************************************************************************/
603 status_t CloseSerial(unsigned int reader_index)
604 {
605 unsigned int reader = reader_index;
606
607 close(serialDevice[reader].fd);
608 serialDevice[reader].fd = -1;
609
610 free(serialDevice[reader].device);
611 serialDevice[reader].device = NULL;
612
613 return STATUS_SUCCESS;
614 } /* CloseSerial */
615
616
617 /*****************************************************************************
618 *
619 * get_ccid_descriptor
620 *
621 ****************************************************************************/
622 _ccid_descriptor *get_ccid_descriptor(unsigned int reader_index)
623 {
624 return &serialDevice[reader_index].ccid;
625 } /* get_ccid_descriptor */
626
627

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.5