1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-01-09 12:54:23 +01:00

(parse_ccid_descriptor): Make SCM workaround

reader type specific.
(scan_or_find_devices): Do not check the interface subclass in the
SPR532 kludge, as this depends on the firmware version.
(ccid_get_atr): Get the Slot status first.  This solves the
problem with readers hanging on recent Linux 2.6.x.
(bulk_in): Add argument TIMEOUT and changed all callers to pass an
appropriate one.  Change the standard timeout from 10 to 5 seconds.
(ccid_slot_status): Add a retry code with an initial short timeout.
(do_close_reader): Do an usb_reset before closing the reader.
This commit is contained in:
Werner Koch 2005-03-16 19:10:54 +00:00
parent a90637513c
commit 8ba895c763
2 changed files with 76 additions and 28 deletions

View File

@ -1,3 +1,16 @@
2005-03-16 Werner Koch <wk@g10code.com>
* ccid-driver.c (parse_ccid_descriptor): Make SCM workaround
reader type specific.
(scan_or_find_devices): Do not check the interface subclass in the
SPR532 kludge, as this depends on the firmware version.
(ccid_get_atr): Get the Slot status first. This solves the
problem with readers hanging on recent Linux 2.6.x.
(bulk_in): Add argument TIMEOUT and changed all callers to pass an
appropriate one. Change the standard timeout from 10 to 5 seconds.
(ccid_slot_status): Add a retry code with an initial short timeout.
(do_close_reader): Do an usb_reset before closing the reader.
2005-03-14 Werner Koch <wk@g10code.com> 2005-03-14 Werner Koch <wk@g10code.com>
* card-util.c (card_status): Use isotimestamp and not the * card-util.c (card_status): Use isotimestamp and not the

View File

@ -1,5 +1,5 @@
/* ccid-driver.c - USB ChipCardInterfaceDevices driver /* ccid-driver.c - USB ChipCardInterfaceDevices driver
* Copyright (C) 2003, 2004 Free Software Foundation, Inc. * Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
* Written by Werner Koch. * Written by Werner Koch.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
@ -52,7 +52,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* $Id$ * $Date$
*/ */
@ -223,7 +223,7 @@ static unsigned int compute_edc (const unsigned char *data, size_t datalen,
int use_crc); int use_crc);
static int bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen); static int bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen);
static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
size_t *nread, int expected_type, int seqno); size_t *nread, int expected_type, int seqno, int timeout);
/* Convert a little endian stored 4 byte value into an unsigned /* Convert a little endian stored 4 byte value into an unsigned
integer. */ integer. */
@ -403,7 +403,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
if (buf[49] == 0xff) if (buf[49] == 0xff)
DEBUGOUT_CONT ("echo\n"); DEBUGOUT_CONT ("echo\n");
else else
DEBUGOUT_1 (" %02X\n", buf[48]); DEBUGOUT_CONT_1 (" %02X\n", buf[48]);
DEBUGOUT ( " wlcdLayout "); DEBUGOUT ( " wlcdLayout ");
if (!buf[50] && !buf[51]) if (!buf[50] && !buf[51])
@ -446,12 +446,20 @@ parse_ccid_descriptor (ccid_driver_t handle,
send a frame of n*wMaxPacketSize back to us. Given that send a frame of n*wMaxPacketSize back to us. Given that
wMaxPacketSize is 64 for these readers we set the IFSD to a value wMaxPacketSize is 64 for these readers we set the IFSD to a value
lower than that: lower than that:
64 - 10 CCID header - 4 T1frame - 2 reserved = 48 */ 64 - 10 CCID header - 4 T1frame - 2 reserved = 48
Product Ids:
0xe001 - SCR 331
0x5111 - SCR 331-DI
0x5115 - SCR 335
0xe003 - SPR 532
*/
if (handle->id_vendor == VENDOR_SCM if (handle->id_vendor == VENDOR_SCM
/* FIXME: check whether it is the same && handle->max_ifsd > 48
firmware version for all drivers. */ && ( (handle->id_product == 0xe001 && handle->bcd_device < 0x0516)
&& handle->bcd_device < 0x0519 ||(handle->id_product == 0x5111 && handle->bcd_device < 0x0620)
&& handle->max_ifsd > 48) ||(handle->id_product == 0x5115 && handle->bcd_device < 0x0519)
||(handle->id_product == 0xe003 && handle->bcd_device < 0x0504)
))
{ {
DEBUGOUT ("enabling workaround for buggy SCM readers\n"); DEBUGOUT ("enabling workaround for buggy SCM readers\n");
handle->max_ifsd = 48; handle->max_ifsd = 48;
@ -699,9 +707,7 @@ scan_or_find_devices (int readerno, const char *readerid,
&& ifcdesc->bInterfaceProtocol == 0) && ifcdesc->bInterfaceProtocol == 0)
|| (ifcdesc->bInterfaceClass == 255 || (ifcdesc->bInterfaceClass == 255
&& dev->descriptor.idVendor == 0x04e6 && dev->descriptor.idVendor == 0x04e6
&& dev->descriptor.idProduct == 0xe003 && dev->descriptor.idProduct == 0xe003)))
&& ifcdesc->bInterfaceSubClass == 1
&& ifcdesc->bInterfaceProtocol == 1)))
{ {
idev = usb_open (dev); idev = usb_open (dev);
if (!idev) if (!idev)
@ -974,11 +980,13 @@ do_close_reader (ccid_driver_t handle)
rc = bulk_out (handle, msg, msglen); rc = bulk_out (handle, msg, msglen);
if (!rc) if (!rc)
bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,seqno); bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
seqno, 2000);
handle->powered_off = 1; handle->powered_off = 1;
} }
if (handle->idev) if (handle->idev)
{ {
usb_reset (handle->idev);
usb_release_interface (handle->idev, handle->ifc_no); usb_release_interface (handle->idev, handle->ifc_no);
usb_close (handle->idev); usb_close (handle->idev);
handle->idev = NULL; handle->idev = NULL;
@ -1102,10 +1110,10 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
BUFFER and return the actual read number if bytes in NREAD. SEQNO BUFFER and return the actual read number if bytes in NREAD. SEQNO
is the sequence number used to send the request and EXPECTED_TYPE is the sequence number used to send the request and EXPECTED_TYPE
the type of message we expect. Does checks on the ccid the type of message we expect. Does checks on the ccid
header. Returns 0 on success. */ header. TIMEOUT is the timeout value in ms. 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, int expected_type, int seqno) size_t *nread, int expected_type, int seqno, int timeout)
{ {
int i, rc; int i, rc;
size_t msglen; size_t msglen;
@ -1117,9 +1125,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
rc = usb_bulk_read (handle->idev, rc = usb_bulk_read (handle->idev,
handle->ep_bulk_in, handle->ep_bulk_in,
buffer, length, buffer, length,
10000 /* ms timeout */ ); timeout);
/* Fixme: instead of using a 10 second timeout we should better
handle the timeout here and retry if appropriate. */
if (rc < 0) if (rc < 0)
{ {
DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno)); DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
@ -1175,7 +1181,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
} }
/* Note that this fucntion won't return the error codes NO_CARD or /* Note that this function won't return the error codes NO_CARD or
CARD_INACTIVE */ CARD_INACTIVE */
static int static int
send_escape_cmd (ccid_driver_t handle, send_escape_cmd (ccid_driver_t handle,
@ -1206,7 +1212,8 @@ send_escape_cmd (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, RDR_to_PC_Escape, seqno); rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape,
seqno, 5000);
return rc; return rc;
} }
@ -1276,7 +1283,9 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits)
unsigned char msg[100]; unsigned char msg[100];
size_t msglen; size_t msglen;
unsigned char seqno; unsigned char seqno;
int retries = 0;
retry:
msg[0] = PC_to_RDR_GetSlotStatus; msg[0] = PC_to_RDR_GetSlotStatus;
msg[5] = 0; /* slot */ msg[5] = 0; /* slot */
msg[6] = seqno = handle->seqno++; msg[6] = seqno = handle->seqno++;
@ -1288,7 +1297,21 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits)
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, RDR_to_PC_SlotStatus, seqno); rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
seqno, retries? 1000 : 200);
if (rc == CCID_DRIVER_ERR_CARD_IO_ERROR && retries < 3)
{
if (!retries)
{
fprintf (stderr, "CALLING USB_CLEAR_HALT\n");
usb_clear_halt (handle->idev, handle->ep_bulk_in);
usb_clear_halt (handle->idev, handle->ep_bulk_out);
}
else
fprintf (stderr, "RETRYING AGIAN\n");
retries++;
goto retry;
}
if (rc && rc != CCID_DRIVER_ERR_NO_CARD if (rc && rc != CCID_DRIVER_ERR_NO_CARD
&& rc != CCID_DRIVER_ERR_CARD_INACTIVE) && rc != CCID_DRIVER_ERR_CARD_INACTIVE)
return rc; return rc;
@ -1303,6 +1326,7 @@ ccid_get_atr (ccid_driver_t handle,
unsigned char *atr, size_t maxatrlen, size_t *atrlen) unsigned char *atr, size_t maxatrlen, size_t *atrlen)
{ {
int rc; int rc;
int statusbits;
unsigned char msg[100]; unsigned char msg[100];
unsigned char *tpdu; unsigned char *tpdu;
size_t msglen, tpdulen; size_t msglen, tpdulen;
@ -1311,6 +1335,15 @@ ccid_get_atr (ccid_driver_t handle,
unsigned int edc; unsigned int edc;
int i; int i;
/* First check whether a card is available. */
rc = ccid_slot_status (handle, &statusbits);
if (rc)
return rc;
if (statusbits == 2)
return CCID_DRIVER_ERR_NO_CARD;
/* For an inactive and also for an active card, issue the PowerOn
command to get the ATR. */
msg[0] = PC_to_RDR_IccPowerOn; msg[0] = PC_to_RDR_IccPowerOn;
msg[5] = 0; /* slot */ msg[5] = 0; /* slot */
msg[6] = seqno = handle->seqno++; msg[6] = seqno = handle->seqno++;
@ -1323,7 +1356,8 @@ 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, RDR_to_PC_DataBlock, seqno); rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock,
seqno, 5000);
if (rc) if (rc)
return rc; return rc;
@ -1367,7 +1401,8 @@ ccid_get_atr (ccid_driver_t handle,
if (rc) if (rc)
return rc; return rc;
/* Note that we ignore the error code on purpose. */ /* Note that we ignore the error code on purpose. */
bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, seqno); bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters,
seqno, 5000);
handle->t1_ns = 0; handle->t1_ns = 0;
handle->t1_nr = 0; handle->t1_nr = 0;
@ -1414,7 +1449,7 @@ ccid_get_atr (ccid_driver_t handle,
rc = bulk_in (handle, msg, sizeof msg, &msglen, rc = bulk_in (handle, msg, sizeof msg, &msglen,
RDR_to_PC_DataBlock, seqno); RDR_to_PC_DataBlock, seqno, 5000);
if (rc) if (rc)
return rc; return rc;
@ -1510,7 +1545,7 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
msg = recv_buffer; msg = recv_buffer;
rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen, rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
RDR_to_PC_DataBlock, seqno); RDR_to_PC_DataBlock, seqno, 5000);
if (rc) if (rc)
return rc; return rc;
@ -1683,7 +1718,7 @@ ccid_transceive (ccid_driver_t handle,
msg = recv_buffer; msg = recv_buffer;
rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen, rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
RDR_to_PC_DataBlock, seqno); RDR_to_PC_DataBlock, seqno, 5000);
if (rc) if (rc)
return rc; return rc;
@ -1692,7 +1727,7 @@ ccid_transceive (ccid_driver_t handle,
if (tpdulen < 4) if (tpdulen < 4)
{ {
usb_clear_halt (handle->idev, 0x82); usb_clear_halt (handle->idev, handle->ep_bulk_in);
return CCID_DRIVER_ERR_ABORTED; return CCID_DRIVER_ERR_ABORTED;
} }
#ifdef DEBUG_T1 #ifdef DEBUG_T1
@ -1960,7 +1995,7 @@ ccid_transceive_secure (ccid_driver_t handle,
msg = recv_buffer; msg = recv_buffer;
rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen, rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
RDR_to_PC_DataBlock, seqno); RDR_to_PC_DataBlock, seqno, 5000);
if (rc) if (rc)
return rc; return rc;