2008/12/19 Ludovic Rousseau <[email protected]>:
> I will try to merge my T=1 code in OpenCT. But not before a few weeks.
> I remembered some objections when I proposed to do this a few years
> ago. Maybe the situation has changed.

I patched the OpenSC version of src/ifd/proto-t1.c (patch attached)

THIS PATCH DOES NOT WORK. It is just a preview.

Notes:
- the t1_* functions use a "ifd_protocol_t * prot" parameter but I
need a "t1_state_t * t1" since some fields are only present in the
t1_state_t structure
- t1_negotiate_ifsd() is declared in src/ifd/internal.h and the only
external source using it is src/ifd/ifd-eutron.c. This function is
never used elsewhere. This function could be used by the CCID driver
if the reader does not negotiate the IFSD itself for example
- I changed my version of proto-t1.c in my CCID handler to make
comparison more easy

I can integrate some patches from my CCID driver. But integrating all
the error cases management will be very hard without major changes in
OpenCT.

What should I do?

Bye

-- 
 Dr. Ludovic Rousseau
Index: proto-t1.c
===================================================================
--- proto-t1.c  (révision 1127)
+++ proto-t1.c  (copie de travail)
@@ -8,6 +8,8 @@
  */
 
 #include "internal.h"
+#include "openct/buffer.h"
+
 #include <sys/poll.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -15,6 +17,7 @@
 
 typedef struct {
        ifd_protocol_t base;
+       int lun;
        int state;
        int block_oriented;
 
@@ -29,6 +32,9 @@ typedef struct {
 
        unsigned int (*checksum) (const unsigned char *,
                                  size_t, unsigned char *);
+
+       char more;      /* more data bit */
+       unsigned char previous_block[4];        /* to store the last R-block */
 } t1_state_t;
 
 /* T=1 protocol constants */
@@ -56,24 +62,40 @@ typedef struct {
 #define T1_S_WTX               0x03
 
 #define T1_BUFFER_SIZE         (3 + 254 + 2)
+#define swap_nibbles(x) ( (x >> 4) | ((x & 0xF) << 4) )
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
 
 #define NAD 0
 #define PCB 1
 #define LEN 2
 #define DATA 3
 
+#define DEBUG_INFO2(a, b) ifd_debug(1, a, b)
+#define DEBUG_CRITICAL(a) ifd_debug(1, a)
+#define DEBUG_CRITICAL2(a, b) ifd_debug(1, a, b)
+#define DEBUG_COMM(a) ifd_debug(3, a)
+#define DEBUG_COMM2(a, b) ifd_debug(3, a, b)
+#define DEBUG_COMM4(a, b, c, d) ifd_debug(3, a, b, c, d)
+#define DEBUG_XXD(a, b, c) do{}while(0)
+
 /* internal state, do not mess with it. */
 /* should be != DEAD after reset/init */
 enum {
        SENDING, RECEIVING, RESYNCH, DEAD
 };
 
+static int t1_set_param(t1_state_t * t1, int type, long value);
 static void t1_set_checksum(t1_state_t *, int);
 static unsigned int t1_block_type(unsigned char);
 static unsigned int t1_seq(unsigned char);
-static unsigned int t1_build(t1_state_t *, unsigned char *,
-                            unsigned char, unsigned char,
-                            ct_buf_t *, size_t *);
+unsigned int t1_build(t1_state_t * t1, unsigned char *block,
+       unsigned char dad, unsigned char pcb,
+       ct_buf_t *bp, size_t *lenp);
+static unsigned int t1_rebuild(t1_state_t *t1, unsigned char *block);
 static unsigned int t1_compute_checksum(t1_state_t *, unsigned char *, size_t);
 static int t1_verify_checksum(t1_state_t *, unsigned char *, size_t);
 static int t1_xcv(t1_state_t *, unsigned char *, size_t, size_t);
@@ -111,24 +133,22 @@ static void t1_set_checksum(t1_state_t *
 /*
  * Attach t1 protocol
  */
-static int t1_init(ifd_protocol_t * prot)
+static int t1_init(t1_state_t * t1, int lun)
 {
-       t1_state_t *t1 = (t1_state_t *) prot;
-
        t1_set_defaults(t1);
-       t1_set_checksum(t1, IFD_PROTOCOL_T1_CHECKSUM_LRC);
+       t1_set_param(t1, IFD_PROTOCOL_T1_CHECKSUM_LRC, 0);
+       t1_set_param(t1, IFD_PROTOCOL_T1_STATE, SENDING);
+       t1_set_param(t1, IFD_PROTOCOL_T1_MORE, FALSE);
+
+       t1->lun = lun;
 
-       /* If the device is attached through USB etc, assume the
-        * device will do the framing for us */
-       if (prot->reader->device->type != IFD_DEVICE_TYPE_SERIAL)
-               t1->block_oriented = 1;
        return 0;
 }
 
 /*
  * Detach t1 protocol
  */
-static void t1_release(ifd_protocol_t * prot)
+static void t1_release(t1_state_t * t1)
 {
        /* NOP */
 }
@@ -136,17 +156,12 @@ static void t1_release(ifd_protocol_t * 
 /*
  * Get/set parmaters for T1 protocol
  */
-static int t1_set_param(ifd_protocol_t * prot, int type, long value)
+static int t1_set_param(t1_state_t * t1, int type, long value)
 {
-       t1_state_t *t1 = (t1_state_t *) prot;
-
        switch (type) {
        case IFD_PROTOCOL_RECV_TIMEOUT:
                t1->timeout = value;
                break;
-       case IFD_PROTOCOL_BLOCK_ORIENTED:
-               t1->block_oriented = value;
-               break;
        case IFD_PROTOCOL_T1_CHECKSUM_LRC:
        case IFD_PROTOCOL_T1_CHECKSUM_CRC:
                t1_set_checksum(t1, type);
@@ -157,8 +172,14 @@ static int t1_set_param(ifd_protocol_t *
        case IFD_PROTOCOL_T1_IFSD:
                t1->ifsd = value;
                break;
+       case IFD_PROTOCOL_T1_STATE:
+               t1->state = value;
+               break;
+       case IFD_PROTOCOL_T1_MORE:
+               t1->more = value;
+               break;
        default:
-               ct_error("Unsupported parameter %d", type);
+               DEBUG_INFO2("Unsupported parameter %d", type);
                return -1;
        }
 
@@ -191,10 +212,10 @@ static int t1_get_param(ifd_protocol_t *
 /*
  * Send an APDU through T=1
  */
-static int t1_transceive(ifd_protocol_t * prot, int dad, const void *snd_buf,
-                        size_t snd_len, void *rcv_buf, size_t rcv_len)
+static int t1_transceive(t1_state_t * t1, unsigned int dad,
+               const void *snd_buf, size_t snd_len,
+               void *rcv_buf, size_t rcv_len)
 {
-       t1_state_t *t1 = (t1_state_t *) prot;
        ct_buf_t sbuf, rbuf, tbuf;
        unsigned char sdata[T1_BUFFER_SIZE], sblk[5];
        unsigned int slen, retries, resyncs, sent_length = 0;
@@ -205,7 +226,10 @@ static int t1_transceive(ifd_protocol_t 
 
        /* we can't talk to a dead card / reader. Reset it! */
        if (t1->state == DEAD)
+       {
+               DEBUG_CRITICAL("T=1 state machine is DEAD. Reset the card 
first.");
                return -1;
+       }
 
        t1->state = SENDING;
        retries = t1->retries;
@@ -224,34 +248,140 @@ static int t1_transceive(ifd_protocol_t 
 
                retries--;
 
-               if ((n = t1_xcv(t1, sdata, slen, sizeof(sdata))) < 0) {
-                       ifd_debug(1, "fatal: transmit/receive failed");
+               n = t1_xcv(t1, sdata, slen, sizeof(sdata));
+               if (-2 == n)
+               {
+                       DEBUG_COMM("Parity error");
+                       /* ISO 7816-3 Rule 7.4.2 */
+                       if (retries == 0)
+                               goto resync;
+
+                       /* ISO 7816-3 Rule 7.2 */
+                       if (T1_R_BLOCK == 
t1_block_type(t1->previous_block[PCB]))
+                       {
+                               DEBUG_COMM("Rule 7.2");
+                               slen = t1_rebuild(t1, sdata);
+                               continue;
+                       }
+
+                       slen = t1_build(t1, sdata,
+                                       dad, T1_R_BLOCK | T1_EDC_ERROR,
+                                       NULL, NULL);
+                       continue;
+               }
+
+               if (n < 0) {
+                       DEBUG_CRITICAL("fatal: transmit/receive failed");
                        t1->state = DEAD;
                        goto error;
                }
 
-               if (!t1_verify_checksum(t1, sdata, n)) {
-                       ifd_debug(1, "checksum failed");
-                       if (retries == 0 || sent_length)
+               if ((sdata[NAD] != swap_nibbles(dad)) /* wrong NAD */
+                       || (sdata[LEN] == 0xFF))        /* length == 0xFF 
(illegal) */
+               {
+                       DEBUG_COMM("R-BLOCK required");
+                       /* ISO 7816-3 Rule 7.4.2 */
+                       if (retries == 0)
                                goto resync;
+
+                       /* ISO 7816-3 Rule 7.2 */
+                       if (T1_R_BLOCK == 
t1_block_type(t1->previous_block[PCB]))
+                       {
+                               DEBUG_COMM("Rule 7.2");
+                               slen = t1_rebuild(t1, sdata);
+                               continue;
+                       }
+
                        slen = t1_build(t1, sdata,
-                                       dad, T1_R_BLOCK | T1_EDC_ERROR,
+                                       dad, T1_R_BLOCK | T1_OTHER_ERROR,
                                        NULL, NULL);
                        continue;
                }
 
+               if (!t1_verify_checksum(t1, sdata, n)) {
+                       DEBUG_COMM("checksum failed");
+                       /* ISO 7816-3 Rule 7.4.2 */
+                       if (retries == 0)
+                               goto resync;
+
+                       /* ISO 7816-3 Rule 7.2 */
+                       if (T1_R_BLOCK == 
t1_block_type(t1->previous_block[PCB]))
+                       {
+                               DEBUG_COMM("Rule 7.2");
+                               slen = t1_rebuild(t1, sdata);
+                               continue;
+                       }
+
+                       slen = t1_build(t1, sdata,
+                               dad, T1_R_BLOCK | T1_EDC_ERROR,
+                               NULL, NULL);
+                       continue;
+               }
+
                pcb = sdata[PCB];
                switch (t1_block_type(pcb)) {
                case T1_R_BLOCK:
-                       if (T1_IS_ERROR(pcb)) {
-                               ifd_debug(1, "received error block, err=%d",
-                                         T1_IS_ERROR(pcb));
-                               goto resync;
+                       if ((sdata[LEN] != 0x00)        /* length != 0x00 
(illegal) */
+                               || (pcb & 0x20)                 /* b6 of pcb is 
set */
+                          )
+                       {
+                               DEBUG_COMM("R-Block required");
+                               /* ISO 7816-3 Rule 7.4.2 */
+                               if (retries == 0)
+                                       goto resync;
+
+                               /* ISO 7816-3 Rule 7.2 */
+                               if (T1_R_BLOCK == 
t1_block_type(t1->previous_block[1]))
+                               {
+                                       DEBUG_COMM("Rule 7.2");
+                                       slen = t1_rebuild(t1, sdata);
+                                       continue;
+                               }
+
+                               slen = t1_build(t1, sdata,
+                                               dad, T1_R_BLOCK | 
T1_OTHER_ERROR,
+                                               NULL, NULL);
+                               continue;
+                       }
+
+                       if (((t1_seq(pcb) != t1->ns)    /* wrong sequence 
number & no bit more */
+                                       && ! t1->more)
+                          )
+                       {
+                               DEBUG_COMM4("received: %d, expected: %d, more: 
%d",
+                                       t1_seq(pcb), t1->ns, t1->more);
+
+                               /* ISO 7816-3 Rule 7.2 */
+                               if (T1_R_BLOCK == 
t1_block_type(t1->previous_block[PCB]))
+                               {
+                                       DEBUG_COMM("Rule 7.2");
+                                       slen = t1_rebuild(t1, sdata);
+                                       continue;
+                               }
+
+                               DEBUG_COMM("R-Block required");
+                               /* ISO 7816-3 Rule 7.4.2 */
+                               if (retries == 0)
+                                       goto resync;
+                               slen = t1_build(t1, sdata,
+                                               dad, T1_R_BLOCK | 
T1_OTHER_ERROR,
+                                               NULL, NULL);
+                               continue;
                        }
 
                        if (t1->state == RECEIVING) {
+                               /* ISO 7816-3 Rule 7.2 */
+                               if (T1_R_BLOCK == 
t1_block_type(t1->previous_block[1]))
+                               {
+                                       DEBUG_COMM("Rule 7.2");
+                                       slen = t1_rebuild(t1, sdata);
+                                       continue;
+                               }
+
+                               DEBUG_COMM("");
                                slen = t1_build(t1, sdata,
-                                               dad, T1_R_BLOCK, NULL, NULL);
+                                               dad, T1_R_BLOCK,
+                                               NULL, NULL);
                                break;
                        }
 
@@ -278,6 +408,7 @@ static int t1_transceive(ifd_protocol_t 
                        /* The first I-block sent by the ICC indicates
                         * the last block we sent was received successfully. */
                        if (t1->state == SENDING) {
+                               DEBUG_COMM("");
                                ct_buf_get(&sbuf, NULL, last_send);
                                last_send = 0;
                                t1->ns ^= 1;
@@ -289,6 +420,7 @@ static int t1_transceive(ifd_protocol_t 
                         * what we expected it to send, reply with
                         * an R block */
                        if (t1_seq(pcb) != t1->nr) {
+                               DEBUG_COMM("wrong nr");
                                slen = t1_build(t1, sdata, dad,
                                                T1_R_BLOCK | T1_OTHER_ERROR,
                                                NULL, NULL);
@@ -298,7 +430,10 @@ static int t1_transceive(ifd_protocol_t 
                        t1->nr ^= 1;
 
                        if (ct_buf_put(&rbuf, sdata + 3, sdata[LEN]) < 0)
+                       {
+                               DEBUG_CRITICAL2("buffer overrun by %d bytes", 
sdata[LEN] - (rbuf.size - rbuf.tail));
                                goto error;
+                       }
 
                        if ((pcb & T1_MORE_BLOCKS) == 0)
                                goto done;
@@ -308,6 +443,9 @@ static int t1_transceive(ifd_protocol_t 
 
                case T1_S_BLOCK:
                        if (T1_S_IS_RESPONSE(pcb) && t1->state == RESYNCH) {
+                               /* ISO 7816-3 Rule 6.2 */
+                               DEBUG_COMM("S-Block answer received");
+                               /* ISO 7816-3 Rule 6.3 */
                                t1->state = SENDING;
                                sent_length = 0;
                                last_send = 0;
@@ -320,65 +458,126 @@ static int t1_transceive(ifd_protocol_t 
                        }
 
                        if (T1_S_IS_RESPONSE(pcb))
-                               goto resync;
+                       {
+                               /* ISO 7816-3 Rule 7.4.2 */
+                               if (retries == 0)
+                                       goto resync;
+
+                               /* ISO 7816-3 Rule 7.2 */
+                               if (T1_R_BLOCK == 
t1_block_type(t1->previous_block[PCB]))
+                               {
+                                       DEBUG_COMM("Rule 7.2");
+                                       slen = t1_rebuild(t1, sdata);
+                                       continue;
+                               }
+
+                               DEBUG_CRITICAL("wrong response S-BLOCK 
received");
+                               slen = t1_build(t1, sdata,
+                                               dad, T1_R_BLOCK | 
T1_OTHER_ERROR,
+                                               NULL, NULL);
+                               continue;
+                       }
 
                        ct_buf_init(&tbuf, sblk, sizeof(sblk));
 
+                       DEBUG_COMM("S-Block request received");
                        switch (T1_S_TYPE(pcb)) {
                        case T1_S_RESYNC:
+                               if (sdata[LEN] != 0)
+                               {
+                                       DEBUG_COMM2("Wrong length: %d", 
sdata[LEN]);
+                                       slen = t1_build(t1, sdata, dad,
+                                               T1_R_BLOCK | T1_OTHER_ERROR,
+                                               NULL, NULL);
+                                       continue;
+                               }
+
+                               DEBUG_COMM("Resync requested");
                                /* the card is not allowed to send a resync. */
                                goto resync;
+
                        case T1_S_ABORT:
-                               ifd_debug(1, "abort requested");
+                               if (sdata[LEN] != 0)
+                               {
+                                       DEBUG_COMM2("Wrong length: %d", 
sdata[LEN]);
+                                       slen = t1_build(t1, sdata, dad,
+                                               T1_R_BLOCK | T1_OTHER_ERROR,
+                                               NULL, NULL);
+                                       continue;
+                               }
+
+                               /* ISO 7816-3 Rule 9 */
+                               DEBUG_CRITICAL("abort requested");
                                break;
+
                        case T1_S_IFS:
-                               ifd_debug(1, "CT sent S-block with ifs=%u",
-                                         sdata[DATA]);
+                               if (sdata[LEN] != 1)
+                               {
+                                       DEBUG_COMM2("Wrong length: %d", 
sdata[LEN]);
+                                       slen = t1_build(t1, sdata, dad,
+                                               T1_R_BLOCK | T1_OTHER_ERROR,
+                                               NULL, NULL);
+                                       continue;
+                               }
+
+                               DEBUG_CRITICAL2("CT sent S-block with ifs=%u", 
sdata[DATA]);
                                if (sdata[DATA] == 0)
                                        goto resync;
                                t1->ifsc = sdata[DATA];
                                ct_buf_putc(&tbuf, sdata[DATA]);
                                break;
+
                        case T1_S_WTX:
-                               /* We don't handle the wait time extension
-                                * yet */
-                               ifd_debug(1, "CT sent S-block with wtx=%u",
-                                         sdata[DATA]);
+                               if (sdata[LEN] != 1)
+                               {
+                                       DEBUG_COMM2("Wrong length: %d", 
sdata[LEN]);
+                                       slen = t1_build(t1, sdata, dad,
+                                               T1_R_BLOCK | T1_OTHER_ERROR,
+                                               NULL, NULL);
+                                       continue;
+                               }
+
+                               DEBUG_CRITICAL2("CT sent S-block with wtx=%u", 
sdata[DATA]);
                                t1->wtx = sdata[DATA];
                                ct_buf_putc(&tbuf, sdata[DATA]);
                                break;
+
                        default:
-                               ct_error("T=1: Unknown S block type 0x%02x",
-                                        T1_S_TYPE(pcb));
+                               DEBUG_CRITICAL2("T=1: Unknown S block type 
0x%02x", T1_S_TYPE(pcb));
                                goto resync;
                        }
 
                        slen = t1_build(t1, sdata, dad,
-                                       T1_S_BLOCK | T1_S_RESPONSE |
-                                       T1_S_TYPE(pcb), &tbuf, NULL);
+                               T1_S_BLOCK | T1_S_RESPONSE | T1_S_TYPE(pcb),
+                               &tbuf, NULL);
                }
 
                /* Everything went just splendid */
                retries = t1->retries;
                continue;
 
-             resync:
+resync:
                /* the number or resyncs is limited, too */
+               /* ISO 7816-3 Rule 6.4 */
                if (resyncs == 0)
                        goto error;
+
+               /* ISO 7816-3 Rule 6 */
                resyncs--;
                t1->ns = 0;
                t1->nr = 0;
                slen = t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_RESYNC, NULL,
                                NULL);
                t1->state = RESYNCH;
+               t1->more = FALSE;
+               retries = 1;
                continue;
        }
 
-      done:
+done:
        return ct_buf_avail(&rbuf);
 
-      error:
+error:
        t1->state = DEAD;
        return -1;
 }
@@ -443,16 +642,18 @@ static unsigned int t1_seq(unsigned char
        }
 }
 
-static unsigned int t1_build(t1_state_t * t1, unsigned char *block,
-                            unsigned char dad, unsigned char pcb,
-                            ct_buf_t * bp, size_t * lenp)
+unsigned int t1_build(t1_state_t * t1, unsigned char *block,
+       unsigned char dad, unsigned char pcb,
+       ct_buf_t *bp, size_t *lenp)
 {
        unsigned int len;
+       char more = FALSE;
 
        len = bp ? ct_buf_avail(bp) : 0;
        if (len > t1->ifsc) {
                pcb |= T1_MORE_BLOCKS;
                len = t1->ifsc;
+               more = TRUE;
        }
 
        /* Add the sequence number */
@@ -462,6 +663,8 @@ static unsigned int t1_build(t1_state_t 
                break;
        case T1_I_BLOCK:
                pcb |= t1->ns << T1_I_SEQ_SHIFT;
+               t1->more = more;
+               DEBUG_COMM2("more bit: %d", more);
                break;
        }
 
@@ -474,7 +677,13 @@ static unsigned int t1_build(t1_state_t 
        if (lenp)
                *lenp = len;
 
-       return t1_compute_checksum(t1, block, len + 3);
+       len = t1_compute_checksum(t1, block, len + 3);
+
+       /* memorize the last sent block */
+       /* only 4 bytes since we are only interesed in R-blocks */
+       memcpy(t1->previous_block, block, 4);
+
+       return len;
 }
 
 /*
@@ -494,16 +703,34 @@ struct ifd_protocol_ops ifd_protocol_t1 
        NULL,                   /* sync_write */
 };
 
+static unsigned int
+t1_rebuild(t1_state_t *t1, unsigned char *block)
+{
+       unsigned char pcb = t1 -> previous_block[1];
+
+       /* copy the last sent block */
+       if (T1_R_BLOCK == t1_block_type(pcb))
+               memcpy(block, t1 -> previous_block, 4);
+       else
+       {
+               DEBUG_CRITICAL2("previous block was not R-Block: %02X", pcb);
+               return 0;
+       }
+
+       return 4;
+}
+
 /*
  * Build/verify checksum
  */
-static unsigned int t1_compute_checksum(t1_state_t * t1, unsigned char *data,
-                                       size_t len)
+static unsigned int t1_compute_checksum(t1_state_t * t1,
+       unsigned char *data, size_t len)
 {
        return len + t1->checksum(data, len, data + len);
 }
 
-static int t1_verify_checksum(t1_state_t * t1, unsigned char *rbuf, size_t len)
+static int t1_verify_checksum(t1_state_t * t1, unsigned char *rbuf,
+       size_t len)
 {
        unsigned char csum[2];
        int m, n;
@@ -525,76 +752,103 @@ static int t1_verify_checksum(t1_state_t
  * Send/receive block
  */
 static int t1_xcv(t1_state_t * t1, unsigned char *block, size_t slen,
-                 size_t rmax)
+       size_t rmax)
 {
        ifd_protocol_t *prot = &t1->base;
-       unsigned int rlen, timeout;
        int n, m;
+       unsigned int rmax_int;
 
-       if (ct_config.debug >= 3)
-               ifd_debug(3, "sending %s", ct_hexdump(block, slen));
-
-       n = ifd_send_command(prot, block, slen);
-       if (n < 0)
-               return n;
-
-       /* Maximum amount of data we'll receive - some devices
-        * such as the eToken need this. If you request more, it'll
-        * just barf */
-       rlen = 3 + t1->ifsd + t1->rc_bytes;
+       DEBUG_XXD("sending: ", block, slen);
 
-       /* timeout. For now our WTX treatment is very dumb */
-       timeout = t1->timeout + 1000 * t1->wtx;
-       t1->wtx = 0;
+       if (t1->wtx > 1)
+       {
+               /* set the new temporary timeout at WTX card request */
+               t1->timeout *=  t1->wtx;
+               DEBUG_INFO2("New timeout at WTX request: %d sec",
+                       t1->timeout);
+       }
+
+#if 0
+       if (isCharLevel(t1->lun))
+       {
+               rmax = 3;
+
+               n = CCID_Transmit(t1 -> lun, slen, block, rmax, t1->wtx);
+               if (n != IFD_SUCCESS)
+                       return n;
+
+               /* the second argument of CCID_Receive() is (unsigned int *)
+                * so we can't use &rmax since &rmax is a (size_t *) and may not
+                * be the same on 64-bits architectures for example (iMac G5) */
+               rmax_int = rmax;
+               n = CCID_Receive(t1 -> lun, &rmax_int, block, NULL);
+               rmax = rmax_int;
+
+               if (n == IFD_PARITY_ERROR)
+                       return -2;
+               if (n != IFD_SUCCESS)
+                       return -1;
 
-       if (t1->block_oriented) {
-               /* Note - Linux USB seems to have an off by one error, you
-                * actually need the + 1 to get the RC byte */
-               rlen++;
-               if (rlen < rmax)
-                       rmax = rlen;
+               rmax = block[2] + 1;
 
-               /* Get the response en bloc */
-               n = ifd_recv_response(prot, block, rmax, timeout);
-               if (n >= 0) {
-                       m = block[2] + 3 + t1->rc_bytes;
-                       if (m < n)
-                               n = m;
-               }
-       } else {
-               /* Get the header */
-               if (ifd_recv_response(prot, block, 3, timeout) < 0)
+               n = CCID_Transmit(t1 -> lun, 0, block, rmax, t1->wtx);
+               if (n != IFD_SUCCESS)
+                       return n;
+
+               rmax_int = rmax;
+               n = CCID_Receive(t1 -> lun, &rmax_int, &block[3], NULL);
+               rmax = rmax_int;
+               if (n == IFD_PARITY_ERROR)
+                       return -2;
+               if (n != IFD_SUCCESS)
                        return -1;
 
-               n = block[2] + t1->rc_bytes;
-               if (n + 3 > rmax || block[2] >= 254) {
-                       ct_error("receive buffer too small");
-                       return -1;
-               }
+               n = rmax + 3;
+       }
+       else
+#endif
+       {
+               /*n = CCID_Transmit(t1 -> lun, slen, block, 0, t1->wtx);*/
+               n = ifd_send_command(prot, block, slen);
+               t1->wtx = 0;    /* reset to default value */
+               if (n != IFD_SUCCESS)
+                       return n;
 
-               /* Now get the rest */
-               if (ifd_recv_response(prot, block + 3, n, t1->timeout) < 0)
+               /* Get the response en bloc */
+               rmax_int = rmax;
+               /*n = CCID_Receive(t1 -> lun, &rmax_int, block, NULL);*/
+               n = ifd_recv_response(prot, block, rmax_int, t1->timeout);
+               rmax = rmax_int;
+               /*if (n == IFD_PARITY_ERROR)
+                       return -2;*/
+               if (n != IFD_SUCCESS)
                        return -1;
 
-               n += 3;
+               n = rmax;
+       }
+
+       if (n >= 0)
+       {
+               m = block[2] + 3 + t1->rc_bytes;
+               if (m < n)
+                       n = m;
        }
 
-       if (n >= 0 && ct_config.debug >= 3)
-               ifd_debug(3, "received %s", ct_hexdump(block, n));
+       if (n >= 0)
+               DEBUG_XXD("received: ", block, n);
 
        return n;
 }
 
-int t1_negotiate_ifsd(ifd_protocol_t * proto, unsigned int dad, int ifsd)
+int t1_negotiate_ifsd(t1_state_t * t1, unsigned int dad, int ifsd)
 {
-       t1_state_t *t1 = (t1_state_t *) proto;
        ct_buf_t sbuf;
        unsigned char sdata[T1_BUFFER_SIZE];
        unsigned int slen;
        unsigned int retries;
        size_t snd_len;
        int n;
-       unsigned char snd_buf[1], pcb;
+       unsigned char snd_buf[1];
 
        retries = t1->retries;
 
@@ -605,38 +859,42 @@ int t1_negotiate_ifsd(ifd_protocol_t * p
        /* Initialize send/recv buffer */
        ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
 
-       while (1) {
+       while (TRUE)
+       {
                /* Build the block */
-               slen =
-                   t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_IFS, &sbuf,
-                            NULL);
+               slen = t1_build(t1, sdata, 0, T1_S_BLOCK | T1_S_IFS, &sbuf, 
NULL);
 
-               if ((n = t1_xcv(t1, sdata, slen, sizeof(sdata))) < 0) {
-                       ifd_debug(1, "fatal: transmit/receive failed");
-                       t1->state = DEAD;
+               /* Send the block */
+               n = t1_xcv(t1, sdata, slen, sizeof(sdata));
+
+               retries--;
+               /* ISO 7816-3 Rule 7.4.2 */
+               if (retries == 0)
+                       goto error;
+
+               if (-1 == n)
+               {
+                       DEBUG_CRITICAL("fatal: transmit/receive failed");
                        goto error;
                }
 
-               if (!t1_verify_checksum(t1, sdata, n)) {
-                       ifd_debug(1, "checksum failed");
-                       if (retries == 0)
-                               goto error;
+               if ((-2 == n)                                                   
        /* Parity error */
+                       || (sdata[DATA] != ifsd)                                
/* Wrong ifsd received */
+                       || (sdata[NAD] != swap_nibbles(dad))    /* wrong NAD */
+                       || (!t1_verify_checksum(t1, sdata, n))  /* checksum 
failed */
+                       || (n != 4 + t1->rc_bytes)                              
/* wrong frame length */
+                       || (sdata[LEN] != 1)                                    
/* wrong data length */
+                       || (sdata[PCB] != (T1_S_BLOCK | T1_S_RESPONSE | 
T1_S_IFS))) /* wrong PCB */
                        continue;
-               }
-               pcb = sdata[1];
-               if (t1_block_type(pcb) == T1_S_BLOCK &&
-                   T1_S_TYPE(pcb) == T1_S_IFS && T1_S_IS_RESPONSE(pcb)) {
-                       if (sdata[LEN] != 1 || sdata[DATA] != ifsd)
-                               goto error;
-                       break;
-               }
-               if (retries == 0)
-                       goto error;
+
+               /* no more error */
+               goto done;
        }
 
+done:
        return n;
 
-      error:
-       t1_resynchronize(proto, dad);
+error:
+       t1->state = DEAD;
        return -1;
 }
Index: internal.h
===================================================================
--- internal.h  (révision 1127)
+++ internal.h  (copie de travail)
@@ -202,6 +202,6 @@ extern int ifd_sync_detect_icc(ifd_reade
 extern unsigned int ifd_protocols_list(const char **, unsigned int);
 
 /* proto-t1.c */
-extern int t1_negotiate_ifsd(ifd_protocol_t *, unsigned int, int);
+//extern int t1_negotiate_ifsd(ifd_protocol_t *, unsigned int, int);
 
 #endif                         /* IFD_INTERNAL_H */
Index: ifd-eutron.c
===================================================================
--- ifd-eutron.c        (révision 1127)
+++ ifd-eutron.c        (copie de travail)
@@ -291,11 +291,13 @@ static int eutron_set_protocol(ifd_reade
        if (proto == IFD_PROTOCOL_T1 && atr_info.TA[2] != -1) {
                ifd_protocol_set_parameter(slot->proto, IFD_PROTOCOL_T1_IFSC,
                                           atr_info.TA[2]);
+#if 0
                if (t1_negotiate_ifsd(slot->proto, slot->dad, atr_info.TA[2]) >
                    0)
                        ifd_protocol_set_parameter(slot->proto,
                                                   IFD_PROTOCOL_T1_IFSD,
                                                   atr_info.TA[2]);
+#endif
 
        }
        return 0;
_______________________________________________
opensc-devel mailing list
[email protected]
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to