source: trunk/src/ifd/ifd-egate.c @ 964

Revision 964, 7.0 KB checked in by aj, 5 years ago (diff)

indent changes only.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * e-gate driver
3 *
4 * Copyright (C) 2003, Chaskiel Grundman <cg2v@andrew.cmu.edu>
5 */
6
7#include "internal.h"
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
11
12#define EG_TIMEOUT      1000
13
14#define EGATE_CMD_SEND_APDU     0x80
15#define EGATE_CMD_READ          0x81
16#define EGATE_CMD_WRITE         0x82
17#define EGATE_CMD_READ_ATR      0x83
18#define EGATE_CMD_RESET         0x90
19#define EGATE_CMD_STATUS        0xA0
20
21#define EGATE_STATUS_READY      0x00
22#define EGATE_STATUS_DATA       0x10
23#define EGATE_STATUS_SW         0x20
24#define EGATE_STATUS_BUSY       0x40
25#define EGATE_STATUS_MASK       0xF0
26
27#define EGATE_ATR_MAXSIZE       0x23
28
29#ifdef IFD_USB_ENDPOINT_IN
30#define EGATE_DIR_OUT (IFD_USB_ENDPOINT_OUT | \
31                       IFD_USB_TYPE_VENDOR | \
32                       IFD_USB_RECIP_DEVICE)
33#define EGATE_DIR_IN  (IFD_USB_ENDPOINT_IN | \
34                       IFD_USB_TYPE_VENDOR | \
35                       IFD_USB_RECIP_DEVICE)
36#else
37#define EGATE_DIR_OUT 0x40
38#define EGATE_DIR_IN  0xc0
39#endif
40/*
41 * Initialize the device
42 */
43static int eg_open(ifd_reader_t * reader, const char *device_name)
44{
45        ifd_device_t *dev;
46        ifd_device_params_t params;
47
48        ifd_debug(1, "device=%s", device_name);
49        reader->name = "Schlumberger E-Gate";
50        reader->nslots = 1;
51        if (!(dev = ifd_device_open(device_name)))
52                return -1;
53        if (ifd_device_type(dev) != IFD_DEVICE_TYPE_USB) {
54                ct_error("egate: device %s is not a USB device", device_name);
55                ifd_device_close(dev);
56                return -1;
57        }
58
59        params = dev->settings;
60        params.usb.interface = 0;
61        if (ifd_device_set_parameters(dev, &params) < 0) {
62                ct_error("egate: setting parameters failed", device_name);
63                ifd_device_close(dev);
64                return -1;
65        }
66
67        reader->device = dev;
68
69        return 0;
70}
71
72/*
73 * Power up the reader
74 */
75static int eg_activate(ifd_reader_t * reader)
76{
77        ifd_debug(1, "called.");
78        return 0;
79}
80
81static int eg_deactivate(ifd_reader_t * reader)
82{
83        ifd_debug(1, "called.");
84        return 0;
85}
86
87/*
88 * Card status - always present
89 */
90static int eg_card_status(ifd_reader_t * reader, int slot, int *status)
91{
92        ifd_debug(3, "slot=%d", slot);
93        *status = IFD_CARD_PRESENT;
94        return 0;
95}
96
97static int eg_card_reset(ifd_reader_t * reader, int slot, void *atr,
98                         size_t size)
99{
100        ifd_device_t *dev = reader->device;
101        unsigned char buffer[EGATE_ATR_MAXSIZE];
102        int rc, atrlen, stat;
103
104        ifd_debug(1, "called.");
105        usleep(100000);
106        /* Reset the device */
107        rc = ifd_usb_control(dev, EGATE_DIR_OUT, EGATE_CMD_RESET,
108                             0, 0, NULL, 0, EG_TIMEOUT * 2);
109        if (rc < 0) {
110              failed:
111                ct_error("egate: failed to activate token");
112                return IFD_ERROR_COMM_ERROR;
113        }
114
115        usleep(100000);
116        rc = ifd_usb_control(reader->device, EGATE_DIR_IN, EGATE_CMD_STATUS,
117                             0, 0, &stat, 1, EG_TIMEOUT);
118        if (rc != 1)
119                return IFD_ERROR_COMM_ERROR;
120
121        /* Fetch the ATR */
122        usleep(100000);
123        rc = ifd_usb_control(dev, EGATE_DIR_IN, EGATE_CMD_READ_ATR,
124                             0, 0, buffer, EGATE_ATR_MAXSIZE, EG_TIMEOUT);
125        if (rc <= 0)
126                goto failed;
127
128        if (rc > IFD_MAX_ATR_LEN)
129                goto failed;
130
131        if (rc > size)
132                rc = size;
133        atrlen = rc;
134        memcpy(atr, buffer, atrlen);
135
136        return atrlen;
137
138}
139
140static int eg_set_protocol(ifd_reader_t * reader, int s, int proto)
141{
142        ifd_slot_t *slot;
143        ifd_protocol_t *p;
144
145        ifd_debug(1, "proto=%d", proto);
146        if (proto != IFD_PROTOCOL_T0 && proto != IFD_PROTOCOL_TRANSPARENT) {
147                ct_error("%s: protocol %d not supported", reader->name, proto);
148                return IFD_ERROR_NOT_SUPPORTED;
149        }
150        slot = &reader->slot[s];
151        p = ifd_protocol_new(IFD_PROTOCOL_TRANSPARENT, reader, slot->dad);
152        if (p == NULL) {
153                ct_error("%s: internal error", reader->name);
154                return IFD_ERROR_GENERIC;
155        }
156        if (slot->proto) {
157                ifd_protocol_free(slot->proto);
158                slot->proto = NULL;
159        }
160        slot->proto = p;
161        return 0;
162}
163
164static unsigned char eg_status(ifd_reader_t * reader)
165{
166        int rc;
167        unsigned char stat;
168
169        /* Shouldn't there be a retry counter that prevents the command
170         * from hanging indefinitely? Are there scenarios where the
171         * egate would be busy for more than say 180 secs?    --okir
172         */
173        while (1) {
174                rc = ifd_usb_control(reader->device, EGATE_DIR_IN,
175                                     EGATE_CMD_STATUS, 0, 0, &stat, 1,
176                                     EG_TIMEOUT);
177                if (rc != 1)
178                        return -1;
179                stat &= EGATE_STATUS_MASK;
180                if (stat != EGATE_STATUS_BUSY) {
181                        return stat;
182                }
183                usleep(100);
184        }
185
186}
187
188/*
189 * Send/receive routines
190 */
191static int eg_transparent(ifd_reader_t * reader, int dad, const void *inbuffer,
192                          size_t inlen, void *outbuffer, size_t outlen)
193{
194        int rc, bytesread;
195        unsigned char stat;
196        ifd_iso_apdu_t iso;
197        unsigned char cmdbuf[5];
198        int i;
199
200        stat = eg_status(reader);
201        if (stat != EGATE_STATUS_READY) {
202                for (i = 0; i < 4; i++) {
203                        ifd_debug(2, "device not ready, attempting reset");
204                        rc = ifd_usb_control(reader->device, EGATE_DIR_OUT,
205                                             EGATE_CMD_RESET, 0, 0, NULL, 0,
206                                             EG_TIMEOUT);
207                        if (rc < 0)
208                                return IFD_ERROR_COMM_ERROR;
209                        usleep(100);
210                        stat = eg_status(reader);
211                        if (stat == EGATE_STATUS_READY) {
212                                ifd_debug(2, "reset succeeded");
213                                /* FIXME: we need a better error code */
214                                return IFD_ERROR_COMM_ERROR;
215                        }
216                        ifd_debug(2, "reset failed");
217                }
218                ifd_debug(2, "giving up on reset");
219                return IFD_ERROR_COMM_ERROR;
220        }
221
222        if (ifd_iso_apdu_parse(inbuffer, inlen, &iso) < 0)
223                return IFD_ERROR_INVALID_ARG;
224        if (inlen >= 5 && inlen < 5 + iso.lc)
225                return IFD_ERROR_BUFFER_TOO_SMALL;
226        if (outlen < 2 + iso.le)
227                return IFD_ERROR_BUFFER_TOO_SMALL;
228        memset(cmdbuf, 0, 5);
229        memmove(cmdbuf, inbuffer, inlen < 5 ? inlen : 5);
230        rc = ifd_usb_control(reader->device, EGATE_DIR_OUT, EGATE_CMD_SEND_APDU,
231                             0, 0, (void *)cmdbuf, 5, -1);
232        if (rc != 5)
233                return IFD_ERROR_COMM_ERROR;
234        stat = eg_status(reader);
235        if (inlen > 5 && stat == EGATE_STATUS_DATA) {
236                rc = ifd_usb_control(reader->device, EGATE_DIR_OUT,
237                                     EGATE_CMD_WRITE, 0, 0,
238                                     (void *)(((unsigned char *)inbuffer) + 5),
239                                     iso.lc, -1);
240                if (rc < 0)
241                        return IFD_ERROR_COMM_ERROR;
242                if (rc != iso.lc) {
243                        ifd_debug(1, "short USB write (%u of %u bytes)", rc,
244                                  iso.lc);
245                        return IFD_ERROR_COMM_ERROR;
246                }
247                ifd_debug(3, "sent %d bytes of data", iso.lc);
248                stat = eg_status(reader);
249        }
250        bytesread = 0;
251
252        while (stat == EGATE_STATUS_DATA && bytesread < iso.le) {
253                rc = ifd_usb_control(reader->device, EGATE_DIR_IN,
254                                     EGATE_CMD_READ, 0, 0,
255                                     (void *)(((unsigned char *)outbuffer) +
256                                              bytesread),
257                                     iso.le - bytesread, EG_TIMEOUT);
258                if (rc < 0)
259                        return IFD_ERROR_COMM_ERROR;
260                bytesread += rc;
261                ifd_debug(3, "received %d bytes of data", rc);
262                stat = eg_status(reader);
263        }
264        iso.le = bytesread;
265        if (stat != EGATE_STATUS_SW)
266                return IFD_ERROR_DEVICE_DISCONNECTED;
267        rc = ifd_usb_control(reader->device, EGATE_DIR_IN, EGATE_CMD_READ, 0, 0,
268                             (void *)(((unsigned char *)outbuffer) + iso.le), 2,
269                             EG_TIMEOUT);
270        if (rc != 2)
271                return IFD_ERROR_COMM_ERROR;
272        ifd_debug(2, "returning a %d byte response", iso.le + 2);
273        return iso.le + 2;
274}
275
276/*
277 * Driver operations
278 */
279static struct ifd_driver_ops egate_driver;
280
281/*
282 * Initialize this module
283 */
284void ifd_egate_register(void)
285{
286        egate_driver.open = eg_open;
287        egate_driver.activate = eg_activate;
288        egate_driver.deactivate = eg_deactivate;
289        egate_driver.card_status = eg_card_status;
290        egate_driver.card_reset = eg_card_reset;
291        egate_driver.set_protocol = eg_set_protocol;
292        egate_driver.transparent = eg_transparent;
293
294        ifd_driver_register("egate", &egate_driver);
295}
Note: See TracBrowser for help on using the repository browser.