* ccid-driver.c: More work, data can now actually be retrieved.
authorWerner Koch <wk@gnupg.org>
Fri, 5 Sep 2003 07:40:41 +0000 (07:40 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 5 Sep 2003 07:40:41 +0000 (07:40 +0000)
* ccid-driver.c, ccid-driver.h: Alternativley allow use under BSD
conditions.

scd/ChangeLog
scd/ccid-driver.c
scd/ccid-driver.h

index 28dc4a7..5ffad34 100644 (file)
@@ -1,3 +1,9 @@
+2003-09-05  Werner Koch  <wk@gnupg.org>
+
+       * ccid-driver.c: More work, data can now actually be retrieved.
+       * ccid-driver.c, ccid-driver.h: Alternativley allow use under BSD
+       conditions.
+
 2003-09-02  Werner Koch  <wk@gnupg.org>
 
        * scdaemon.c, scdaemon.h: New option --pcsc-ccid.
index 03c9bcb..b18b055 100644 (file)
@@ -1,5 +1,6 @@
 /* ccid-driver.c - USB ChipCardInterfaceDevices driver
  *     Copyright (C) 2003 Free Software Foundation, Inc.
+ *      Written by Werner Koch.
  *
  * This file is part of GnuPG.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * ALTERNATIVELY, this file may be distributed under the terms of the
+ * following license, in which case the provisions of this license are
+ * required INSTEAD OF the GNU General Public License. If you wish to
+ * allow use of your version of this file only under the terms of the
+ * GNU General Public License, and not to allow others to use your
+ * version of this file under the terms of the following license,
+ * indicate your decision by deleting this paragraph and the license
+ * below.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 
@@ -38,6 +73,7 @@
 #endif
 
 #if defined(HAVE_LIBUSB) || defined(TEST)
+
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 #include <usb.h>
 
-
 #include "ccid-driver.h"
 
+#define DRVNAME "ccid-driver: "
+
+
+#ifdef GNUPG_DEFAULT_SCDAEMON /* This source is used within the
+                                 gnupg>=1.9 source tree. */
+# include "scdaemon.h"
+
+# define DEBUGOUT(t)         do { if (DBG_CARD_IO) \
+                                  log_debug (DRVNAME t); } while (0)
+# define DEBUGOUT_1(t,a)     do { if (DBG_CARD_IO) \
+                                  log_debug (DRVNAME t,(a)); } while (0)
+# define DEBUGOUT_2(t,a,b)   do { if (DBG_CARD_IO) \
+                                  log_debug (DRVNAME t,(a),(b)); } while (0)
+# define DEBUGOUT_3(t,a,b,c) do { if (DBG_CARD_IO) \
+                                  log_debug (DRVNAME t,(a),(b),(c));} while (0)
+# define DEBUGOUT_CONT_1(t,a)  do { if (DBG_CARD_IO) \
+                                  log_printf (t,(a)); } while (0)
+# define DEBUGOUT_CONT_3(t,a,b,c) do { if (DBG_CARD_IO) \
+                                  log_printf (t,(a),(b),(c)); } while (0)
+# define DEBUGOUT_LF()       do { if (DBG_CARD_IO) \
+                                  log_printf ("\n"); } while (0)
+
+#else /* Other usage of this source - don't use gnupg specifics. */
+
+# define DEBUGOUT(t)          fprintf (stderr, DRVNAME t)
+# define DEBUGOUT_1(t,a)      fprintf (stderr, DRVNAME t, (a))
+# define DEBUGOUT_2(t,a,b)    fprintf (stderr, DRVNAME t, (a), (b))
+# define DEBUGOUT_3(t,a,b,c)  fprintf (stderr, DRVNAME t, (a), (b), (c))
+# define DEBUGOUT_CONT_1(t,a)      fprintf (stderr, t, (a))
+# define DEBUGOUT_CONT_3(t,a,b,c)  fprintf (stderr, t, (a), (b), (c))
+# define DEBUGOUT_LF()        putc ('\n', stderr)
+
+#endif /* This source not used by scdaemon. */
+
+
 enum {
   RDR_to_PC_NotifySlotChange= 0x50,
   RDR_to_PC_HardwareError   = 0x51,
@@ -81,7 +151,8 @@ enum {
 struct ccid_driver_s {
   usb_dev_handle *idev;
   int seqno;
-  unsigned char t1_seqno;
+  unsigned char t1_ns;
+  unsigned char t1_nr;
 };
 
 
@@ -109,35 +180,34 @@ ccid_open_reader (ccid_driver_t *handle, int readerno)
   rc = usb_create_match (&match, -1, -1, 11, -1, -1);
   if (rc)
     {
-      fprintf (stderr, "ccid-driver: usb_create_match failed: %d\n", rc);
+      DEBUGOUT_1 ("usb_create_match failed: %d\n", rc);
       return -1;
     }
 
   while (usb_find_device(match, dev, &dev) >= 0) 
     {
-      fprintf(stderr, "ccid-driver: %-40s %04X/%04X\n", dev->filename,
-              dev->descriptor->idVendor, dev->descriptor->idProduct);
+      DEBUGOUT_3 ("%-40s %04X/%04X\n", dev->filename,
+                  dev->descriptor->idVendor, dev->descriptor->idProduct);
       if (!readerno)
         {
           rc = usb_open (dev, &idev);
           if (rc)
             {
-              fprintf (stderr, "ccid-driver: usb_open failed: %d\n", rc);
+              DEBUGOUT_1 ("usb_open failed: %d\n", rc);
               goto leave;
             }
 
           rc = usb_claim_interface (idev, 0);
           if (rc)
             {
-              fprintf (stderr, "ccid-driver: usb_claim_interface failed: %d\n",
-                       rc);
+              DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
               goto leave;
             }
 
           *handle = calloc (1, sizeof **handle);
           if (!*handle)
             {
-              fprintf (stderr, "ccid-driver: out of memory\n");
+              DEBUGOUT ("out of memory\n");
               rc = -1;
               goto leave;
             }
@@ -194,22 +264,24 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
     return 0;
 
   if (rc == -1)
-    fprintf (stderr, "ccid-driver: usb_bulk_write error: %s\n",
-             strerror (errno));
+    DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
   else
-    fprintf (stderr, "ccid-driver: usb_bulk_write failed: %d\n", rc);
+    DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc);
   return -1;
 }
 
 
 /* Read a maximum of LENGTH bytes from the bulk in endpoint into
-   BUFFER and return the actual read number if bytes in NREAD.
-   Returns 0 on success. */
+   BUFFER and return the actual read number if bytes in NREAD. SEQNO
+   is the sequence number used to send the request and EXPECTED_TYPE
+   the type of message we expect. Does checks on the ccid
+   header. Returns 0 on success. */
 static int
 bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
-         size_t *nread)
+         size_t *nread, int expected_type, int seqno)
 {
-  int rc;
+  int i, rc;
+  size_t msglen;
 
   rc = usb_bulk_read (handle->idev, 
                       0x82,
@@ -217,12 +289,40 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
                       1000 /* ms timeout */ );
   if (rc < 0)
     {
-      fprintf (stderr, "ccid-driver: usb_bulk_read error: %s\n",
-               strerror (errno));
+      DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
+      return -1;
+    }
+
+  *nread = msglen = rc;
+
+  if (msglen < 10)
+    {
+      DEBUGOUT_1 ("bulk-in msg too short (%u)\n", (unsigned int)msglen);
+      return -1;
+    }
+  if (buffer[0] != expected_type)
+    {
+      DEBUGOUT_1 ("unexpected bulk-in msg type (%02x)\n", buffer[0]);
+      return -1;
+    }
+  if (buffer[5] != 0)    
+    {
+      DEBUGOUT_1 ("unexpected bulk-in slot (%d)\n", buffer[5]);
+      return -1;
+    }
+  if (buffer[6] != seqno)    
+    {
+      DEBUGOUT_2 ("bulk-in seqno does not match (%d/%d)\n",
+                  seqno, buffer[6]);
       return -1;
     }
 
-  *nread = rc;
+  DEBUGOUT_3 ("status: %02X  error: %02X clock-status: %02X\n"
+              "               data:",  buffer[7], buffer[8], buffer[9] );
+  for (i=10; i < msglen; i++)
+    DEBUGOUT_CONT_1 (" %02X", buffer[i]);
+  DEBUGOUT_LF ();
+
   return 0;
 }
 
@@ -245,8 +345,7 @@ ccid_poll (ccid_driver_t handle)
 
   if (rc < 0)
     {
-        fprintf (stderr, "ccid-driver: usb_intr_read error: %s\n",
-                 strerror (errno));
+      DEBUGOUT_1 ("usb_intr_read error: %s\n", strerror (errno));
       return -1;
     }
 
@@ -255,29 +354,28 @@ ccid_poll (ccid_driver_t handle)
 
   if (msglen < 1)
     {
-      fprintf (stderr, "ccid-driver: intr-in msg too short\n");
+      DEBUGOUT ("intr-in msg too short\n");
       return -1;
     }
 
   if (msg[0] == RDR_to_PC_NotifySlotChange)
     {
-      fprintf (stderr, "ccid-driver: notify slot change:");
+      DEBUGOUT ("notify slot change:");
       for (i=1; i < msglen; i++)
         for (j=0; j < 4; j++)
-          fprintf (stderr, " %d:%c%c",
-                   (i-1)*4+j, 
-                   (msg[i] & (1<<(j*2)))? 'p':'-',
-                   (msg[i] & (2<<(j*2)))? '*':' ');
-      putc ('\n', stderr);
+          DEBUGOUT_CONT_3 (" %d:%c%c",
+                           (i-1)*4+j, 
+                           (msg[i] & (1<<(j*2)))? 'p':'-',
+                           (msg[i] & (2<<(j*2)))? '*':' ');
+      DEBUGOUT_LF ();
     }
   else if (msg[0] == RDR_to_PC_HardwareError)    
     {
-      fprintf (stderr, "ccid-driver: hardware error occured\n");
+      DEBUGOUT ("hardware error occured\n");
     }
   else
     {
-      fprintf (stderr, "ccid-driver: unknown intr-in msg of type %02X\n",
-               msg[0]);
+      DEBUGOUT_1 ("unknown intr-in msg of type %02X\n", msg[0]);
     }
 
   return 0;
@@ -304,37 +402,9 @@ ccid_slot_status (ccid_driver_t handle)
   rc = bulk_out (handle, msg, 10);
   if (rc)
     return rc;
-  rc = bulk_in (handle, msg, sizeof msg, &msglen);
+  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, seqno);
   if (rc)
     return rc;
-  if (msglen < 10)
-    {
-      fprintf (stderr, "ccid-driver: bulk-in msg too short (%u)\n",
-               (unsigned int)msglen);
-      return -1;
-    }
-  if (msg[0] != RDR_to_PC_SlotStatus)
-    {
-      fprintf (stderr, "ccid-driver: unexpected bulk-in msg type (%02x)\n",
-               msg[0]);
-      return -1;
-    }
-  if (msg[5] != 0)    
-    {
-      fprintf (stderr, "ccid-driver: unexpected bulk-in slot (%d)\n",
-               msg[5]);
-      return -1;
-    }
-  if (msg[6] != seqno)    
-    {
-      fprintf (stderr, "ccid-driver: bulk-in seqno does not match (%d/%d)\n",
-               seqno, msg[6]);
-      return -1;
-    }
-
-  fprintf (stderr,
-           "ccid-driver: status: %02X  error: %02X clock-status: %02X\n",
-           msg[7], msg[8], msg[9] );
 
   return 0;
 }
@@ -348,7 +418,6 @@ ccid_get_atr (ccid_driver_t handle,
   unsigned char msg[100];
   size_t msglen;
   unsigned char seqno;
-  int i;
 
   msg[0] = PC_to_RDR_IccPowerOn;
   msg[5] = 0; /* slot */
@@ -362,40 +431,9 @@ ccid_get_atr (ccid_driver_t handle,
   rc = bulk_out (handle, msg, msglen);
   if (rc)
     return rc;
-  rc = bulk_in (handle, msg, sizeof msg, &msglen);
+  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, seqno);
   if (rc)
     return rc;
-  if (msglen < 10)
-    {
-      fprintf (stderr, "ccid-driver: bulk-in msg too short (%u)\n",
-               (unsigned int)msglen);
-      return -1;
-    }
-  if (msg[0] != RDR_to_PC_DataBlock)
-    {
-      fprintf (stderr, "ccid-driver: unexpected bulk-in msg type (%02x)\n",
-               msg[0]);
-      return -1;
-    }
-  if (msg[5] != 0)    
-    {
-      fprintf (stderr, "ccid-driver: unexpected bulk-in slot (%d)\n",
-               msg[5]);
-      return -1;
-    }
-  if (msg[6] != seqno)    
-    {
-      fprintf (stderr, "ccid-driver: bulk-in seqno does not match (%d/%d)\n",
-               seqno, msg[6]);
-      return -1;
-    }
-
-  fprintf (stderr,
-           "ccid-driver: status: %02X  error: %02X clock-status: %02X\n"
-           "               data:",  msg[7], msg[8], msg[9] );
-  for (i=10; i < msglen; i++)
-    fprintf (stderr, " %02X", msg[i]);
-  putc ('\n', stderr);
   
   if (atr)
     {
@@ -434,7 +472,7 @@ ccid_get_atr (ccid_driver_t handle,
    If node adresses are not used, SAD and DAD should be set to 0 on
    the first block sent to the card.  If they are used they should
    have different values (0 for one is okay); that first block sets up
-   the addresses of the node.
+   the addresses of the nodes.
 
   PCB:
    Information Block (I-Block):
@@ -470,20 +508,29 @@ ccid_transceive (ccid_driver_t handle,
                  unsigned char *resp, size_t maxresplen, size_t *nresp)
 {
   int rc;
-  unsigned char msg[10+258], *tpdu, *p;
-  size_t msglen;
+  unsigned char send_buffer[10+258], recv_buffer[10+258];
+  unsigned char *msg, *tpdu, *p;
+  size_t msglen, tpdulen, n;
   unsigned char seqno;
   int i;
   unsigned char crc;
+  size_t dummy_nresp;
+  int sending = 1;
+
+  if (!nresp)
+    nresp = &dummy_nresp;
 
+  *nresp = 0;
   
   /* Construct an I-Block. */
   if (apdulen > 254)
     return -1; /* Invalid length. */
 
+  msg = send_buffer;
+
   tpdu = msg+10;
   tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */
-  tpdu[1] = ((handle->t1_seqno & 1) << 6); /* I-block */
+  tpdu[1] = ((handle->t1_ns & 1) << 6); /* I-block */
   tpdu[2] = apdulen;
   memcpy (tpdu+3, apdu, apdulen);
   crc = 0;
@@ -491,79 +538,148 @@ ccid_transceive (ccid_driver_t handle,
     crc ^= *p++;
   tpdu[3+apdulen] = crc;
 
-  handle->t1_seqno ^= 1;
+  tpdulen = apdulen + 4;
 
-  msg[0] = PC_to_RDR_XfrBlock;
-  msg[5] = 0; /* slot */
-  msg[6] = seqno = handle->seqno++;
-  msg[7] = 4; /* bBWI */
-  msg[8] = 0; /* RFU */
-  msg[9] = 0; /* RFU */
-  set_msg_len (msg, apdulen+4);
-  msglen = 10 + apdulen + 4;
+  for (;;)
+    {
+      msg[0] = PC_to_RDR_XfrBlock;
+      msg[5] = 0; /* slot */
+      msg[6] = seqno = handle->seqno++;
+      msg[7] = 4; /* bBWI */
+      msg[8] = 0; /* RFU */
+      msg[9] = 0; /* RFU */
+      set_msg_len (msg, tpdulen);
+      msglen = 10 + tpdulen;
+
+      DEBUGOUT ("sending");
+      for (i=0; i < msglen; i++)
+        DEBUGOUT_CONT_1 (" %02X", msg[i]);
+      DEBUGOUT_LF ();
+      
+      fprintf (stderr, "T1: put %c-block seq=%d\n",
+               ((msg[11] & 0xc0) == 0x80)? 'R' :
+               (msg[11] & 0x80)? 'S' : 'I',
+        ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)));
+  
+      rc = bulk_out (handle, msg, msglen);
+      if (rc)
+        return rc;
+
+      msg = recv_buffer;
+      rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
+                    RDR_to_PC_DataBlock, seqno);
+      if (rc)
+        return rc;
+      
+      tpdu = msg + 10;
+      tpdulen = msglen - 10;
+      
+      if (tpdulen < 4) 
+        {
+          DEBUGOUT ("cannot yet handle short block!!\n");
+          return -1; 
+        }
 
-  fprintf (stderr, "ccid-driver: sending");
-  for (i=0; i < msglen; i++)
-    fprintf (stderr, " %02X", msg[i]);
-  putc ('\n', stderr);
+      fprintf (stderr, "T1: got %c-block seq=%d err=%d\n",
+               ((msg[11] & 0xc0) == 0x80)? 'R' :
+               (msg[11] & 0x80)? 'S' : 'I',
+        ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)),
+               ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0
+               );
+
+      if (!(tpdu[1] & 0x80))
+        { /* This is an I-block. */
+          
+          if (sending)
+            { /* last block sent was successful. */
+              handle->t1_ns ^= 1;
+              sending = 0;
+            }
 
-  rc = bulk_out (handle, msg, msglen);
-  if (rc)
-    return rc;
-  rc = bulk_in (handle, msg, sizeof msg, &msglen);
-  if (rc)
-    return rc;
-  if (msglen < 10)
-    {
-      fprintf (stderr, "ccid-driver: bulk-in msg too short (%u)\n",
-               (unsigned int)msglen);
-      return -1;
-    }
-  if (msg[0] != RDR_to_PC_DataBlock)
-    {
-      fprintf (stderr, "ccid-driver: unexpected bulk-in msg type (%02x)\n",
-               msg[0]);
-      return -1;
-    }
-  if (msg[5] != 0)    
-    {
-      fprintf (stderr, "ccid-driver: unexpected bulk-in slot (%d)\n",
-               msg[5]);
-      return -1;
-    }
-  if (msg[6] != seqno)    
-    {
-      fprintf (stderr, "ccid-driver: bulk-in seqno does not match (%d/%d)\n",
-               seqno, msg[6]);
-      return -1;
-    }
+          if (!!(tpdu[1] & 0x40) != handle->t1_nr)
+            { /* Reponse does not match our sequence number. */
+              msg = send_buffer;
+              tpdu = msg+10;
+              tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */
+              tpdu[1] = (0x80 | (handle->t1_nr & 1) << 4 | 2); /* R-block */
+              tpdu[2] = 0;
+              tpdulen = 3;
+              for (crc=0,i=0,p=tpdu; i < tpdulen; i++)
+                crc ^= *p++;
+              tpdu[tpdulen++] = crc;
+
+              continue;
+            }
 
-  fprintf (stderr,
-           "ccid-driver: status: %02X  error: %02X clock-status: %02X\n"
-           "               data:",  msg[7], msg[8], msg[9] );
-  for (i=10; i < msglen; i++)
-    fprintf (stderr, " %02X", msg[i]);
-  putc ('\n', stderr);
+          handle->t1_nr ^= 1;
 
-  if (resp)
-    {
-      size_t n = msglen - 10;
-      
-      if (n < 4)
-        n = 0; /* fixme: this is an empty I-block or some other block
-                  - we ignore it for now until we have implemented the
-                  T=1 machinery. */
-      else
-        {
-          p = msg + 10 + 3; /* Skip ccid header and prologue field. */
-          n -= 3;
-          n--; /* Strip the epilogue field. */
-          if (n > maxresplen)
-            n = maxresplen; /* fixme: return an error instead of truncating. */
-          memcpy (resp, p, n);
+          p = tpdu + 3; /* Skip the prologue field. */
+          n = tpdulen - 3 - 1; /* Strip the epilogue field. */
+          /* fixme: verify the checksum. */
+          if (resp)
+            {
+              if (n > maxresplen)
+                {
+                  DEBUGOUT ("provided buffer too short for received data\n");
+                  return -1;
+                }
+              
+              memcpy (resp, p, n); 
+              resp += n;
+              *nresp += n;
+              maxresplen -= n;
+            }
+          
+          if (!(tpdu[1] & 0x20))
+            return 0; /* No chaining requested - ready. */
+          
+          msg = send_buffer;
+          tpdu = msg+10;
+          tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */
+          tpdu[1] = (0x80 | (handle->t1_nr & 1) << 4); /* R-block */
+          tpdu[2] = 0;
+          tpdulen = 3;
+          for (crc=0,i=0,p=tpdu; i < tpdulen; i++)
+            crc ^= *p++;
+          tpdu[tpdulen++] = crc;
+          
         }
-      *nresp = n;
-    }
+      else if ((tpdu[1] & 0xc0) == 0x80)
+        { /* This is a R-block. */
+          if ( (tpdu[1] & 0x0f)) 
+            { /* Error: repeat last block */
+              msg = send_buffer;
+            }
+          else
+            {
+              DEBUGOUT ("unxpectec ACK R-block received\n");
+              return -1;
+            }
+        }
+      else 
+        { /* This is a S-block. */
+          DEBUGOUT_2 ("T1 S-block %s received cmd=%d\n",
+                      (tpdu[1] & 0x20)? "response": "request",
+                      (tpdu[1] & 0x1f));
+          if ( !(tpdu[1] & 0x20) && (tpdu[1] & 0x1f) == 3 && tpdu[2])
+            { /* Wait time extension request. */
+              unsigned char bwi = tpdu[3];
+              msg = send_buffer;
+              tpdu = msg+10;
+              tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */
+              tpdu[1] = (0xc0 | 0x20 | 3); /* S-block response */
+              tpdu[2] = 1;
+              tpdu[3] = bwi;
+              tpdulen = 4;
+              for (crc=0,i=0,p=tpdu; i < tpdulen; i++)
+                crc ^= *p++;
+              tpdu[tpdulen++] = crc;
+              DEBUGOUT_1 ("T1 waittime extension of bwi=%d\n", bwi);
+            }
+          else
+            return -1;
+        }
+    } /* end T=1 protocol loop. */
 
   return 0;
 }
index 8c2d1fe..4d12d88 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * ALTERNATIVELY, this file may be distributed under the terms of the
+ * following license, in which case the provisions of this license are
+ * required INSTEAD OF the GNU General Public License. If you wish to
+ * allow use of your version of this file only under the terms of the
+ * GNU General Public License, and not to allow others to use your
+ * version of this file under the terms of the following license,
+ * indicate your decision by deleting this paragraph and the license
+ * below.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef CCID_DRIVER_H