1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-01-18 14:17:03 +01:00

* ccid-driver.c: More work, data can now actually be retrieved.

* ccid-driver.c, ccid-driver.h: Alternativley allow use under BSD
conditions.
This commit is contained in:
Werner Koch 2003-09-05 07:40:41 +00:00
parent 3598504854
commit 25430119e8
3 changed files with 321 additions and 165 deletions

View 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> 2003-09-02 Werner Koch <wk@gnupg.org>
* scdaemon.c, scdaemon.h: New option --pcsc-ccid. * scdaemon.c, scdaemon.h: New option --pcsc-ccid.

View File

@ -1,5 +1,6 @@
/* ccid-driver.c - USB ChipCardInterfaceDevices driver /* ccid-driver.c - USB ChipCardInterfaceDevices driver
* Copyright (C) 2003 Free Software Foundation, Inc. * Copyright (C) 2003 Free Software Foundation, Inc.
* Written by Werner Koch.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -16,6 +17,40 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * 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 #endif
#if defined(HAVE_LIBUSB) || defined(TEST) #if defined(HAVE_LIBUSB) || defined(TEST)
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -46,9 +82,43 @@
#include <usb.h> #include <usb.h>
#include "ccid-driver.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 { enum {
RDR_to_PC_NotifySlotChange= 0x50, RDR_to_PC_NotifySlotChange= 0x50,
RDR_to_PC_HardwareError = 0x51, RDR_to_PC_HardwareError = 0x51,
@ -81,7 +151,8 @@ enum {
struct ccid_driver_s { struct ccid_driver_s {
usb_dev_handle *idev; usb_dev_handle *idev;
int seqno; 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); rc = usb_create_match (&match, -1, -1, 11, -1, -1);
if (rc) if (rc)
{ {
fprintf (stderr, "ccid-driver: usb_create_match failed: %d\n", rc); DEBUGOUT_1 ("usb_create_match failed: %d\n", rc);
return -1; return -1;
} }
while (usb_find_device(match, dev, &dev) >= 0) while (usb_find_device(match, dev, &dev) >= 0)
{ {
fprintf(stderr, "ccid-driver: %-40s %04X/%04X\n", dev->filename, DEBUGOUT_3 ("%-40s %04X/%04X\n", dev->filename,
dev->descriptor->idVendor, dev->descriptor->idProduct); dev->descriptor->idVendor, dev->descriptor->idProduct);
if (!readerno) if (!readerno)
{ {
rc = usb_open (dev, &idev); rc = usb_open (dev, &idev);
if (rc) if (rc)
{ {
fprintf (stderr, "ccid-driver: usb_open failed: %d\n", rc); DEBUGOUT_1 ("usb_open failed: %d\n", rc);
goto leave; goto leave;
} }
rc = usb_claim_interface (idev, 0); rc = usb_claim_interface (idev, 0);
if (rc) if (rc)
{ {
fprintf (stderr, "ccid-driver: usb_claim_interface failed: %d\n", DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
rc);
goto leave; goto leave;
} }
*handle = calloc (1, sizeof **handle); *handle = calloc (1, sizeof **handle);
if (!*handle) if (!*handle)
{ {
fprintf (stderr, "ccid-driver: out of memory\n"); DEBUGOUT ("out of memory\n");
rc = -1; rc = -1;
goto leave; goto leave;
} }
@ -194,22 +264,24 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
return 0; return 0;
if (rc == -1) if (rc == -1)
fprintf (stderr, "ccid-driver: usb_bulk_write error: %s\n", DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
strerror (errno));
else else
fprintf (stderr, "ccid-driver: usb_bulk_write failed: %d\n", rc); DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc);
return -1; return -1;
} }
/* Read a maximum of LENGTH bytes from the bulk in endpoint into /* Read a maximum of LENGTH bytes from the bulk in endpoint into
BUFFER and return the actual read number if bytes in NREAD. BUFFER and return the actual read number if bytes in NREAD. SEQNO
Returns 0 on success. */ 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 static int
bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, 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, rc = usb_bulk_read (handle->idev,
0x82, 0x82,
@ -217,12 +289,40 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
1000 /* ms timeout */ ); 1000 /* ms timeout */ );
if (rc < 0) if (rc < 0)
{ {
fprintf (stderr, "ccid-driver: usb_bulk_read error: %s\n", DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
strerror (errno));
return -1; return -1;
} }
*nread = rc; *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;
}
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; return 0;
} }
@ -245,8 +345,7 @@ ccid_poll (ccid_driver_t handle)
if (rc < 0) if (rc < 0)
{ {
fprintf (stderr, "ccid-driver: usb_intr_read error: %s\n", DEBUGOUT_1 ("usb_intr_read error: %s\n", strerror (errno));
strerror (errno));
return -1; return -1;
} }
@ -255,29 +354,28 @@ ccid_poll (ccid_driver_t handle)
if (msglen < 1) if (msglen < 1)
{ {
fprintf (stderr, "ccid-driver: intr-in msg too short\n"); DEBUGOUT ("intr-in msg too short\n");
return -1; return -1;
} }
if (msg[0] == RDR_to_PC_NotifySlotChange) 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 (i=1; i < msglen; i++)
for (j=0; j < 4; j++) for (j=0; j < 4; j++)
fprintf (stderr, " %d:%c%c", DEBUGOUT_CONT_3 (" %d:%c%c",
(i-1)*4+j, (i-1)*4+j,
(msg[i] & (1<<(j*2)))? 'p':'-', (msg[i] & (1<<(j*2)))? 'p':'-',
(msg[i] & (2<<(j*2)))? '*':' '); (msg[i] & (2<<(j*2)))? '*':' ');
putc ('\n', stderr); DEBUGOUT_LF ();
} }
else if (msg[0] == RDR_to_PC_HardwareError) else if (msg[0] == RDR_to_PC_HardwareError)
{ {
fprintf (stderr, "ccid-driver: hardware error occured\n"); DEBUGOUT ("hardware error occured\n");
} }
else else
{ {
fprintf (stderr, "ccid-driver: unknown intr-in msg of type %02X\n", DEBUGOUT_1 ("unknown intr-in msg of type %02X\n", msg[0]);
msg[0]);
} }
return 0; return 0;
@ -304,37 +402,9 @@ ccid_slot_status (ccid_driver_t handle)
rc = bulk_out (handle, msg, 10); rc = bulk_out (handle, msg, 10);
if (rc) if (rc)
return 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) if (rc)
return 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; return 0;
} }
@ -348,7 +418,6 @@ ccid_get_atr (ccid_driver_t handle,
unsigned char msg[100]; unsigned char msg[100];
size_t msglen; size_t msglen;
unsigned char seqno; unsigned char seqno;
int i;
msg[0] = PC_to_RDR_IccPowerOn; msg[0] = PC_to_RDR_IccPowerOn;
msg[5] = 0; /* slot */ msg[5] = 0; /* slot */
@ -362,40 +431,9 @@ ccid_get_atr (ccid_driver_t handle,
rc = bulk_out (handle, msg, msglen); rc = bulk_out (handle, msg, msglen);
if (rc) if (rc)
return 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) if (rc)
return 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) 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 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 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 have different values (0 for one is okay); that first block sets up
the addresses of the node. the addresses of the nodes.
PCB: PCB:
Information Block (I-Block): Information Block (I-Block):
@ -470,20 +508,29 @@ ccid_transceive (ccid_driver_t handle,
unsigned char *resp, size_t maxresplen, size_t *nresp) unsigned char *resp, size_t maxresplen, size_t *nresp)
{ {
int rc; int rc;
unsigned char msg[10+258], *tpdu, *p; unsigned char send_buffer[10+258], recv_buffer[10+258];
size_t msglen; unsigned char *msg, *tpdu, *p;
size_t msglen, tpdulen, n;
unsigned char seqno; unsigned char seqno;
int i; int i;
unsigned char crc; unsigned char crc;
size_t dummy_nresp;
int sending = 1;
if (!nresp)
nresp = &dummy_nresp;
*nresp = 0;
/* Construct an I-Block. */ /* Construct an I-Block. */
if (apdulen > 254) if (apdulen > 254)
return -1; /* Invalid length. */ return -1; /* Invalid length. */
msg = send_buffer;
tpdu = msg+10; tpdu = msg+10;
tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */ 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; tpdu[2] = apdulen;
memcpy (tpdu+3, apdu, apdulen); memcpy (tpdu+3, apdu, apdulen);
crc = 0; crc = 0;
@ -491,79 +538,148 @@ ccid_transceive (ccid_driver_t handle,
crc ^= *p++; crc ^= *p++;
tpdu[3+apdulen] = crc; tpdu[3+apdulen] = crc;
handle->t1_seqno ^= 1; tpdulen = apdulen + 4;
msg[0] = PC_to_RDR_XfrBlock; for (;;)
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;
fprintf (stderr, "ccid-driver: sending");
for (i=0; i < msglen; i++)
fprintf (stderr, " %02X", msg[i]);
putc ('\n', stderr);
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", msg[0] = PC_to_RDR_XfrBlock;
(unsigned int)msglen); msg[5] = 0; /* slot */
return -1; msg[6] = seqno = handle->seqno++;
} msg[7] = 4; /* bBWI */
if (msg[0] != RDR_to_PC_DataBlock) msg[8] = 0; /* RFU */
{ msg[9] = 0; /* RFU */
fprintf (stderr, "ccid-driver: unexpected bulk-in msg type (%02x)\n", set_msg_len (msg, tpdulen);
msg[0]); msglen = 10 + tpdulen;
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, DEBUGOUT ("sending");
"ccid-driver: status: %02X error: %02X clock-status: %02X\n" for (i=0; i < msglen; i++)
" data:", msg[7], msg[8], msg[9] ); DEBUGOUT_CONT_1 (" %02X", msg[i]);
for (i=10; i < msglen; i++) DEBUGOUT_LF ();
fprintf (stderr, " %02X", msg[i]);
putc ('\n', stderr);
if (resp) fprintf (stderr, "T1: put %c-block seq=%d\n",
{ ((msg[11] & 0xc0) == 0x80)? 'R' :
size_t n = msglen - 10; (msg[11] & 0x80)? 'S' : 'I',
((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)));
if (n < 4) rc = bulk_out (handle, msg, msglen);
n = 0; /* fixme: this is an empty I-block or some other block if (rc)
- we ignore it for now until we have implemented the return rc;
T=1 machinery. */
else 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)
{ {
p = msg + 10 + 3; /* Skip ccid header and prologue field. */ DEBUGOUT ("cannot yet handle short block!!\n");
n -= 3; return -1;
n--; /* Strip the epilogue field. */
if (n > maxresplen)
n = maxresplen; /* fixme: return an error instead of truncating. */
memcpy (resp, p, n);
} }
*nresp = n;
} 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;
}
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;
}
handle->t1_nr ^= 1;
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;
}
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; return 0;
} }

View File

@ -16,6 +16,40 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * 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 #ifndef CCID_DRIVER_H