[Pcsclite-cvs-commit] Drivers/ccid/src ccid_serial.c,1.1,1.2 ccid_serial.h,1.1,1.2
rousseau@quantz.debian.org
rousseau@quantz.debian.org
Fri, 19 Sep 2003 14:08:11 +0200
Update of /cvsroot/pcsclite/Drivers/ccid/src
In directory quantz:/tmp/cvs-serv31383/src
Modified Files:
ccid_serial.c ccid_serial.h
Log Message:
complete reimplementation of the Twin serial protocol using a finite
state automata (code much simpler)
Index: ccid_serial.c
===================================================================
RCS file: /cvsroot/pcsclite/Drivers/ccid/src/ccid_serial.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- ccid_serial.c 10 Sep 2003 09:17:43 -0000 1.1
+++ ccid_serial.c 19 Sep 2003 12:08:09 -0000 1.2
@@ -40,7 +40,7 @@
#include "utils.h"
/* communication timeout in seconds */
-#define SERIAL_TIMEOUT 10
+#define SERIAL_TIMEOUT 2
#define SYNC 0x03
#define CTRL_ACK 0x06
@@ -67,13 +67,10 @@
* 1 : LRC (0x16)
*
* Card insertion/withdrawal
- * 1 : SYNC
- * 1 : CTRL
* 1 : RDR_to_PC_NotifySlotChange (0x50)
* 1 : bmSlotIccState
* 0x02 if card absent
* 0x03 is card present
- * 1 : LRC
*
* Time request
* T=1 : normal CCID command
@@ -81,6 +78,22 @@
*
*/
+/*
+ * You may get read timeout after a card movement.
+ * This is because you will get the echo of the CCID command
+ * but not the result of the command.
+ *
+ * This is not an applicative issue since the card is either removed (and
+ * powered off) or just inserted (and not yet powered on).
+ */
+
+/* 271 = max size for short APDU
+ * 2 bytes for header
+ * 1 byte checksum
+ * doubled for echo
+ */
+#define GEMPCTWIN_MAXBUF (271 +2 +1) * 2
+
typedef struct
{
/*
@@ -94,6 +107,21 @@
int channel;
/*
+ * serial communication buffer
+ */
+ unsigned char buffer[GEMPCTWIN_MAXBUF];
+
+ /*
+ * next available byte
+ */
+ int buffer_offset;
+
+ /*
+ * number of available bytes
+ */
+ int buffer_offset_last;
+
+ /*
* CCID infos common to USB and serial
*/
_ccid_descriptor ccid;
@@ -107,12 +135,6 @@
[ 0 ... (PCSCLITE_MAX_READERS-1) ] = { -1, -1 }
};
-/* 271 = max size for short APDU
- * 2 bytes for header
- * 1 byte checksum
- * doubled for echo */
-#define GEMPCTWIN_MAXBUF (271 +2 +1) *2
-
/*****************************************************************************
*
* WriteSerial: Send bytes to the card reader
@@ -121,7 +143,6 @@
status_t WriteSerial(int lun, int length, unsigned char *buffer)
{
int i;
- int reader = LunToReaderIndex(lun);
unsigned char lrc;
unsigned char low_level_buffer[GEMPCTWIN_MAXBUF];
@@ -155,7 +176,8 @@
DEBUG_XXD(debug_header, low_level_buffer, length+3);
#endif
- if (write(serialDevice[reader].fd, low_level_buffer, length+3) != length+3)
+ if (write(serialDevice[LunToReaderIndex(lun)].fd, low_level_buffer,
+ length+3) != length+3)
{
DEBUG_CRITICAL2("WriteSerial: write error: %s", strerror(errno));
return STATUS_UNSUCCESSFUL;
@@ -172,108 +194,98 @@
*****************************************************************************/
status_t ReadSerial(int lun, int *length, unsigned char *buffer)
{
- int fd = serialDevice[LunToReaderIndex(lun)].fd;
- static unsigned char low_level_buffer[GEMPCTWIN_MAXBUF];
- int buffer_size, len, rv, already_read, to_read;
- unsigned char *reader_to_pc;
- unsigned char lrc;
- int skipped, i;
-#ifdef DEBUG_LEVEL_COMM
- char debug_header[] = "<- 121234 ";
+ unsigned char c;
+ int rv;
+ int echo;
+ int to_read;
+ int i;
- sprintf(debug_header, "<- %06X ", (int)lun);
-#endif
+ /* we get the echo first */
+ echo = TRUE;
- buffer_size = *length;
+start:
+ if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
+ return rv;
- /* error by default (zero length) */
- *length = 0;
+ if (c == RDR_to_PC_NotifySlotChange)
+ goto slot_change;
- rv = ReadChunk(fd, low_level_buffer, sizeof(low_level_buffer), 3, lun);
- if (rv < 0)
- return STATUS_UNSUCCESSFUL;
+ if (c == SYNC)
+ goto sync;
- /* Nb of bytes already read */
- already_read = rv;
+ if (c >= 0x80)
+ goto start;
-#ifdef DEBUG_LEVEL_COMM
- DEBUG_XXD(debug_header, low_level_buffer, rv);
-#endif
+ DEBUG_CRITICAL2("Got 0x%02X", c);
+ return STATUS_COMM_ERROR;
- /* skip the echo of the previous command */
- skipped = skip_echo(low_level_buffer, sizeof(low_level_buffer));
- if (skipped == 0)
- return STATUS_UNSUCCESSFUL;
+slot_change:
+ if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
+ return rv;
- /* Nb of bytes until the end of the buffer */
- len = sizeof(low_level_buffer) - skipped;
- already_read -= skipped;
- reader_to_pc = low_level_buffer + skipped;
+ if (c == CARD_ABSENT)
+ DEBUG_COMM("Card removed");
+ else
+ if (c == CARD_PRESENT)
+ DEBUG_COMM("Card inserted");
+ else
+ DEBUG_COMM2("Unknown card movement: %d", buffer[3]);
+ goto start;
- to_read = 2 +1; /* minimal frame size */
+sync:
+ if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
+ return rv;
- while (already_read < to_read)
- {
- rv = ReadChunk(fd, reader_to_pc + already_read, len, 1, lun);
- if (rv < 0)
- return STATUS_UNSUCCESSFUL;
+ if (c == CTRL_ACK)
+ goto ack;
- already_read += rv;
- len -= rv;
- }
+ if (c == CTRL_NAK)
+ goto nak;
- if (reader_to_pc[0] != SYNC)
- {
- DEBUG_CRITICAL2("No SYNC byte found: 0x%02X", buffer[0]);
- return STATUS_UNSUCCESSFUL;
- }
+ DEBUG_CRITICAL2("Got 0x%02X instead of ACK/NAK", c);
+ return STATUS_COMM_ERROR;
- if (reader_to_pc[1] != CTRL_ACK)
- {
- DEBUG_CRITICAL2("No ACK byte found: 0x%02X", buffer[0]);
- return 0;
- }
+nak:
+ if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
+ return rv;
- /* read up to CCID frame length */
- to_read = 5; /* bMessageType + dwLength */
- while (already_read < to_read)
+ if (c != (SYNC ^ CTRL_NAK))
{
- rv = ReadChunk(fd, reader_to_pc + already_read, len, 1, lun);
- if (rv < 0)
- return STATUS_UNSUCCESSFUL;
-
- already_read += rv;
- len -= rv;
+ DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
+ return STATUS_COMM_ERROR;
}
+ else
+ goto start;
- /* normal CCID command */
- to_read = 10+3+dw2i(reader_to_pc, 3);
-
- while (already_read < to_read)
- {
- rv = ReadChunk(fd, reader_to_pc + already_read, len, 1, lun);
- if (rv < 0)
- return STATUS_UNSUCCESSFUL;
+ack:
+ /* normal CCID frame */
+ if ((rv = get_bytes(lun, buffer, 5)) != STATUS_SUCCESS)
+ return rv;
- already_read += rv;
- len -= rv;
- }
+ /* total frame size */
+ to_read = 10+dw2i(buffer, 1);
- lrc = 0;
- for (i=0; i<to_read; i++)
- lrc ^= reader_to_pc[i];
+ if ((rv = get_bytes(lun, buffer+5, to_read-5)) != STATUS_SUCCESS)
+ return rv;
- if (lrc != 0)
- DEBUG_CRITICAL2("Wrong lrc: 0x%02X", lrc);
+ /* lrc */
+ if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
+ return rv;
-#ifdef DEBUG_LEVEL_COMM
- DEBUG_XXD(debug_header, reader_to_pc, to_read);
-#endif
+ for (i=0; i<to_read; i++)
+ c ^= buffer[i];
- /* copy up to buffer_size bytes */
- *length = to_read-3;
+ if (c != (SYNC ^ CTRL_ACK))
+ {
+ DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
+ //return STATUS_COMM_ERROR;
+ }
- memcpy(buffer, reader_to_pc+2, *length);
+ if (echo)
+ {
+ echo = FALSE;
+ goto start;
+ }
return STATUS_SUCCESS;
} /* ReadSerial */
@@ -281,57 +293,46 @@
/*****************************************************************************
*
- * skip_echo: skip the echo of the previous command
+ * get_bytes: get n bytes
*
*****************************************************************************/
-int skip_echo(unsigned char *buffer, int buffer_length)
+int get_bytes(int lun, unsigned char *buffer, int length)
{
- unsigned char lrc;
- int i;
-
- if (buffer[0] != SYNC)
- {
- DEBUG_CRITICAL2("No SYNC byte found: 0x%02X", buffer[0]);
- return 0;
- }
+ int offset = serialDevice[LunToReaderIndex(lun)].buffer_offset;
+ int offset_last = serialDevice[LunToReaderIndex(lun)].buffer_offset_last;
- if (buffer[1] != CTRL_ACK)
+ /* enough data are available */
+ if (offset + length <= offset_last)
{
- DEBUG_CRITICAL2("No ACK byte found: 0x%02X", buffer[0]);
- return 0;
+ memcpy(buffer, serialDevice[LunToReaderIndex(lun)].buffer + offset, length);
+ serialDevice[LunToReaderIndex(lun)].buffer_offset += length;
}
-
- if (buffer[2] == RDR_to_PC_NotifySlotChange)
+ else
{
- switch (buffer[3])
- {
- case CARD_PRESENT:
- DEBUG_INFO("Card inserted");
- break;
+ int present, rv;
- case CARD_ABSENT:
- DEBUG_INFO("Card removed");
- break;
+ /* copy available data */
+ present = offset_last - offset;
- default:
- DEBUG_INFO2("Unknown card movement: %d", buffer[3]);
- break;
- }
-
- lrc = 0;
- for (i=0; i<5; i++)
- lrc ^= buffer[i];
+ if (present > 0)
+ memcpy(buffer, serialDevice[LunToReaderIndex(lun)].buffer + offset, present);
- if (lrc != 0)
- DEBUG_CRITICAL2("Wrong lrc: 0x%02", lrc);
+ /* get fresh data */
+ rv = ReadChunk(lun, serialDevice[LunToReaderIndex(lun)].buffer, sizeof(serialDevice[LunToReaderIndex(lun)].buffer), length - present);
+ if (rv < 0)
+ return STATUS_COMM_ERROR;
- /* Card insertion/withdrawal */
- return 5;
+ /* fill the buffer */
+ memcpy(buffer + present, serialDevice[LunToReaderIndex(lun)].buffer,
+ length - present);
+ serialDevice[LunToReaderIndex(lun)].buffer_offset = length - present;
+ serialDevice[LunToReaderIndex(lun)].buffer_offset_last = rv;
}
- /* normal CCID command, 2 for SYNC CTRL, 1 for length offset in CCID cmd */
- return 2 + 10 + dw2i(buffer, 2 +1) +1;
-} /* skip_echo */
+DEBUG_XXD("pouet: ", buffer, length);
+
+ return STATUS_SUCCESS;
+} /* get_bytes */
/*****************************************************************************
@@ -339,8 +340,9 @@
* ReadChunk: read a minimum number of bytes
*
*****************************************************************************/
-int ReadChunk(int fd, unsigned char *buffer, int buffer_length, int min_length, int lun)
+int ReadChunk(int lun, unsigned char *buffer, int buffer_length, int min_length)
{
+ int fd = serialDevice[LunToReaderIndex(lun)].fd;
fd_set fdset;
struct timeval t;
int i, rv;
@@ -350,7 +352,6 @@
sprintf(debug_header, "<- %06X ", (int)lun);
#endif
-time_request:
/* use select() to, eventually, timeout */
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
@@ -377,18 +378,13 @@
return -1;
}
- if ((rv == 1) && (buffer[0] >= 0x80))
- {
- DEBUG_COMM2("Time request: 0x%02X", buffer[0]);
- goto time_request;
- }
+#ifdef DEBUG_LEVEL_COMM
+ DEBUG_XXD(debug_header, buffer, rv);
+#endif
/* too short */
if (rv < min_length)
{
-#ifdef DEBUG_LEVEL_COMM
- DEBUG_XXD(debug_header, buffer, rv);
-#endif
DEBUG_COMM3("ReadSerial: only %d byte(s) read, needed %d", rv,
min_length);
@@ -502,6 +498,9 @@
serialDevice[reader].ccid.readerID = GEMPCTWIN;
serialDevice[reader].ccid.dwMaxCCIDMessageLength = 271;
serialDevice[reader].ccid.dwFeatures = 0x00010230;
+
+ serialDevice[reader].buffer_offset = 0;
+ serialDevice[reader].buffer_offset_last = 0;
ccid_open_hack(lun);
Index: ccid_serial.h
===================================================================
RCS file: /cvsroot/pcsclite/Drivers/ccid/src/ccid_serial.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- ccid_serial.h 10 Sep 2003 09:17:43 -0000 1.1
+++ ccid_serial.h 19 Sep 2003 12:08:09 -0000 1.2
@@ -24,7 +24,7 @@
status_t OpenSerial(int lun, int channel);
status_t WriteSerial(int lun, int length, unsigned char *Buffer);
status_t ReadSerial(int lun, int *length, unsigned char *Buffer);
-int skip_echo(unsigned char *buffer, int buffer_length);
-int ReadChunk(int fd, unsigned char *buffer, int buffer_length, int min_length, int lun);
+int get_bytes(int lun, unsigned char *buffer, int length);
+int ReadChunk(int lun, unsigned char *buffer, int buffer_length, int min_length);
status_t CloseSerial(int lun);