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:
parent
3598504854
commit
25430119e8
@ -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.
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user