| 1 | /* |
|---|
| 2 | * IFD reader |
|---|
| 3 | * |
|---|
| 4 | * Copyright (C) 2003, Olaf Kirch <okir@suse.de> |
|---|
| 5 | */ |
|---|
| 6 | |
|---|
| 7 | #include "internal.h" |
|---|
| 8 | #include <stdlib.h> |
|---|
| 9 | #include <string.h> |
|---|
| 10 | #include <signal.h> |
|---|
| 11 | #include <time.h> |
|---|
| 12 | |
|---|
| 13 | static int ifd_recv_atr(ifd_device_t *, ct_buf_t *, unsigned int, int); |
|---|
| 14 | |
|---|
| 15 | /* |
|---|
| 16 | * Initialize a reader and open the device |
|---|
| 17 | */ |
|---|
| 18 | ifd_reader_t *ifd_open(const char *driver_name, const char *device_name) |
|---|
| 19 | { |
|---|
| 20 | const ifd_driver_t *driver; |
|---|
| 21 | ifd_reader_t *reader; |
|---|
| 22 | |
|---|
| 23 | ifd_debug(1, "trying to open %s@%s", driver_name, device_name); |
|---|
| 24 | driver = ifd_driver_get(driver_name); |
|---|
| 25 | if (driver == NULL) { |
|---|
| 26 | ct_error("%s: driver not available", driver_name); |
|---|
| 27 | return NULL; |
|---|
| 28 | } |
|---|
| 29 | |
|---|
| 30 | reader = (ifd_reader_t *) calloc(1, sizeof(*reader)); |
|---|
| 31 | if (!reader) { |
|---|
| 32 | ct_error("out of memory"); |
|---|
| 33 | return NULL; |
|---|
| 34 | } |
|---|
| 35 | reader->driver = driver; |
|---|
| 36 | |
|---|
| 37 | if (driver->ops->open && driver->ops->open(reader, device_name) < 0) { |
|---|
| 38 | ct_error("%s: initialization failed (driver %s)", |
|---|
| 39 | device_name, driver->name); |
|---|
| 40 | free(reader); |
|---|
| 41 | return NULL; |
|---|
| 42 | } |
|---|
| 43 | |
|---|
| 44 | return reader; |
|---|
| 45 | } |
|---|
| 46 | |
|---|
| 47 | /* |
|---|
| 48 | * Select a different protocol for this reader |
|---|
| 49 | */ |
|---|
| 50 | int ifd_set_protocol(ifd_reader_t * reader, unsigned int idx, int prot) |
|---|
| 51 | { |
|---|
| 52 | const ifd_driver_t *drv = reader->driver; |
|---|
| 53 | ifd_slot_t *slot; |
|---|
| 54 | ifd_protocol_t *p; |
|---|
| 55 | |
|---|
| 56 | if (idx > reader->nslots) |
|---|
| 57 | return -1; |
|---|
| 58 | |
|---|
| 59 | if (drv && drv->ops && drv->ops->set_protocol) |
|---|
| 60 | return drv->ops->set_protocol(reader, idx, prot); |
|---|
| 61 | |
|---|
| 62 | if (drv && drv->ops && prot == IFD_PROTOCOL_DEFAULT) |
|---|
| 63 | prot = drv->ops->default_protocol; |
|---|
| 64 | |
|---|
| 65 | slot = &reader->slot[idx]; |
|---|
| 66 | if (slot->proto && slot->proto->ops->id == prot) |
|---|
| 67 | return 0; |
|---|
| 68 | |
|---|
| 69 | if (!(p = ifd_protocol_new(prot, reader, slot->dad))) |
|---|
| 70 | return -1; |
|---|
| 71 | |
|---|
| 72 | if (slot->proto) { |
|---|
| 73 | ifd_protocol_free(slot->proto); |
|---|
| 74 | slot->proto = NULL; |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | slot->proto = p; |
|---|
| 78 | return 0; |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | #if 0 |
|---|
| 82 | /* |
|---|
| 83 | * Set the serial speed at which we communicate with the |
|---|
| 84 | * reader |
|---|
| 85 | */ |
|---|
| 86 | int ifd_set_speed(ifd_reader_t * reader, unsigned int speed) |
|---|
| 87 | { |
|---|
| 88 | const ifd_driver_t *drv = reader->driver; |
|---|
| 89 | int rc = 0; |
|---|
| 90 | |
|---|
| 91 | if (drv && drv->ops && drv->ops->change_speed) |
|---|
| 92 | rc = drv->ops->change_speed(reader, speed); |
|---|
| 93 | else |
|---|
| 94 | rc = IFD_ERROR_NOT_SUPPORTED; |
|---|
| 95 | return rc; |
|---|
| 96 | } |
|---|
| 97 | #endif |
|---|
| 98 | |
|---|
| 99 | /* |
|---|
| 100 | * Activate/Deactivate the reader |
|---|
| 101 | */ |
|---|
| 102 | int ifd_activate(ifd_reader_t * reader) |
|---|
| 103 | { |
|---|
| 104 | const ifd_driver_t *drv = reader->driver; |
|---|
| 105 | int rc = 0; |
|---|
| 106 | |
|---|
| 107 | if (drv && drv->ops && drv->ops->activate) |
|---|
| 108 | rc = drv->ops->activate(reader); |
|---|
| 109 | reader->flags |= IFD_READER_ACTIVE; |
|---|
| 110 | return rc; |
|---|
| 111 | } |
|---|
| 112 | |
|---|
| 113 | int ifd_deactivate(ifd_reader_t * reader) |
|---|
| 114 | { |
|---|
| 115 | const ifd_driver_t *drv = reader->driver; |
|---|
| 116 | int rc = 0; |
|---|
| 117 | |
|---|
| 118 | if (drv && drv->ops && drv->ops->deactivate) |
|---|
| 119 | rc = drv->ops->deactivate(reader); |
|---|
| 120 | reader->flags &= ~IFD_READER_ACTIVE; |
|---|
| 121 | return rc; |
|---|
| 122 | } |
|---|
| 123 | |
|---|
| 124 | /* |
|---|
| 125 | * Output to reader's display |
|---|
| 126 | */ |
|---|
| 127 | int ifd_output(ifd_reader_t * reader, const char *message) |
|---|
| 128 | { |
|---|
| 129 | const ifd_driver_t *drv = reader->driver; |
|---|
| 130 | |
|---|
| 131 | if (!drv || !drv->ops || !drv->ops->output) |
|---|
| 132 | return IFD_ERROR_NOT_SUPPORTED; |
|---|
| 133 | |
|---|
| 134 | return drv->ops->output(reader, message); |
|---|
| 135 | } |
|---|
| 136 | |
|---|
| 137 | /* |
|---|
| 138 | * Detect card status |
|---|
| 139 | */ |
|---|
| 140 | int ifd_card_status(ifd_reader_t * reader, unsigned int idx, int *status) |
|---|
| 141 | { |
|---|
| 142 | const ifd_driver_t *drv = reader->driver; |
|---|
| 143 | int rc; |
|---|
| 144 | |
|---|
| 145 | if (idx > reader->nslots) { |
|---|
| 146 | ct_error("%s: invalid slot number %u", reader->name, idx); |
|---|
| 147 | return -1; |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | *status = 0; |
|---|
| 151 | if (!drv || !drv->ops || !drv->ops->card_status) |
|---|
| 152 | return IFD_ERROR_NOT_SUPPORTED; |
|---|
| 153 | |
|---|
| 154 | if ((rc = drv->ops->card_status(reader, idx, status)) < 0) |
|---|
| 155 | return rc; |
|---|
| 156 | if (*status & IFD_CARD_STATUS_CHANGED) |
|---|
| 157 | reader->slot[idx].atr_len = 0; |
|---|
| 158 | reader->slot[idx].status = *status; |
|---|
| 159 | |
|---|
| 160 | return 0; |
|---|
| 161 | } |
|---|
| 162 | |
|---|
| 163 | /* |
|---|
| 164 | * Reset card and obtain ATR |
|---|
| 165 | */ |
|---|
| 166 | int ifd_card_reset(ifd_reader_t * reader, unsigned int idx, void *atr, |
|---|
| 167 | size_t size) |
|---|
| 168 | { |
|---|
| 169 | return ifd_card_request(reader, idx, 0, NULL, atr, size); |
|---|
| 170 | } |
|---|
| 171 | |
|---|
| 172 | /* |
|---|
| 173 | * Request ICC |
|---|
| 174 | */ |
|---|
| 175 | int ifd_card_request(ifd_reader_t * reader, unsigned int idx, time_t timeout, |
|---|
| 176 | const char *message, void *atr, size_t size) |
|---|
| 177 | { |
|---|
| 178 | const ifd_driver_t *drv = reader->driver; |
|---|
| 179 | ifd_device_t *dev = reader->device; |
|---|
| 180 | ifd_slot_t *slot; |
|---|
| 181 | unsigned int count; |
|---|
| 182 | int n, parity; |
|---|
| 183 | |
|---|
| 184 | if (idx > reader->nslots) { |
|---|
| 185 | ct_error("%s: invalid slot number %u", reader->name, idx); |
|---|
| 186 | return IFD_ERROR_INVALID_ARG; |
|---|
| 187 | } |
|---|
| 188 | |
|---|
| 189 | if (dev == NULL) |
|---|
| 190 | return IFD_ERROR_INVALID_ARG; |
|---|
| 191 | |
|---|
| 192 | if (!drv || !drv->ops || !drv->ops->card_reset) |
|---|
| 193 | return IFD_ERROR_NOT_SUPPORTED; |
|---|
| 194 | |
|---|
| 195 | slot = &reader->slot[idx]; |
|---|
| 196 | slot->atr_len = 0; |
|---|
| 197 | |
|---|
| 198 | if (slot->proto) { |
|---|
| 199 | ifd_protocol_free(slot->proto); |
|---|
| 200 | slot->proto = NULL; |
|---|
| 201 | } |
|---|
| 202 | |
|---|
| 203 | /* Do the reset thing - if the driver supports |
|---|
| 204 | * request ICC, call the function if needed. |
|---|
| 205 | * Otherwise fall back to ordinary reset. |
|---|
| 206 | * |
|---|
| 207 | * For asynchronous cards, the driver's card_reset |
|---|
| 208 | * function should perform the reset, and start to |
|---|
| 209 | * read the ATR. It should either read the first byte |
|---|
| 210 | * of the ATR, and leave it to the caller to read |
|---|
| 211 | * the remaining bytes of it, or it should read the |
|---|
| 212 | * whole ATR (as done by the B1 driver, for instance). |
|---|
| 213 | * |
|---|
| 214 | * When receiving the complete ATR, we will select |
|---|
| 215 | * the default protocol as specified by the card. |
|---|
| 216 | * |
|---|
| 217 | * If the driver was unable to receive the ATR |
|---|
| 218 | * (e.g. because the command timed out) it should |
|---|
| 219 | * return IFD_ERROR_NO_ATR. This will allow us |
|---|
| 220 | * to retry with different parity. |
|---|
| 221 | * |
|---|
| 222 | * For synchronous cards, the driver can call |
|---|
| 223 | * ifd_sync_detect_icc to detect whether the card |
|---|
| 224 | * is synchronous. This will also set the slot's |
|---|
| 225 | * protocol. |
|---|
| 226 | * |
|---|
| 227 | * If the card driver does it's own handling of sync |
|---|
| 228 | * ICCs, it should call ifd_set_protocol to signal |
|---|
| 229 | * that card detection was successful. |
|---|
| 230 | */ |
|---|
| 231 | if (drv->ops->card_request && (timeout || message)) { |
|---|
| 232 | n = drv->ops->card_request(reader, idx, |
|---|
| 233 | timeout, message, slot->atr, |
|---|
| 234 | sizeof(slot->atr)); |
|---|
| 235 | if (n <= 0) |
|---|
| 236 | return n; |
|---|
| 237 | count = n; |
|---|
| 238 | } else |
|---|
| 239 | if (dev->type != IFD_DEVICE_TYPE_SERIAL |
|---|
| 240 | || !drv->ops->change_parity) { |
|---|
| 241 | n = drv->ops->card_reset(reader, idx, |
|---|
| 242 | slot->atr, sizeof(slot->atr)); |
|---|
| 243 | if (n <= 0) |
|---|
| 244 | return n; |
|---|
| 245 | count = n; |
|---|
| 246 | } else { |
|---|
| 247 | parity = IFD_SERIAL_PARITY_EVEN; |
|---|
| 248 | if ((n = drv->ops->change_parity(reader, parity)) < 0) |
|---|
| 249 | return n; |
|---|
| 250 | |
|---|
| 251 | /* Reset the card */ |
|---|
| 252 | n = drv->ops->card_reset(reader, idx, |
|---|
| 253 | slot->atr, sizeof(slot->atr)); |
|---|
| 254 | |
|---|
| 255 | /* If there was no ATR, try again with odd parity */ |
|---|
| 256 | if (n == IFD_ERROR_NO_ATR) { |
|---|
| 257 | parity = IFD_SERIAL_PARITY_TOGGLE(parity); |
|---|
| 258 | if (drv->ops->change_parity(reader, parity) < 0) |
|---|
| 259 | return -1; |
|---|
| 260 | n = drv->ops->card_reset(reader, idx, |
|---|
| 261 | slot->atr, sizeof(slot->atr)); |
|---|
| 262 | } |
|---|
| 263 | |
|---|
| 264 | /* Bail out in case of general error */ |
|---|
| 265 | if (n < 0) |
|---|
| 266 | return -1; |
|---|
| 267 | |
|---|
| 268 | count = n; |
|---|
| 269 | |
|---|
| 270 | /* If we got just the first byte of the (async) ATR, |
|---|
| 271 | * get the rest now */ |
|---|
| 272 | if (count == 1) { |
|---|
| 273 | ct_buf_t rbuf; |
|---|
| 274 | unsigned char c; |
|---|
| 275 | unsigned int num, proto = 0; |
|---|
| 276 | int revert_bits = 0; |
|---|
| 277 | |
|---|
| 278 | if (slot->atr[0] == 0x03) { |
|---|
| 279 | revert_bits = 1; |
|---|
| 280 | slot->atr[0] = 0x3F; |
|---|
| 281 | } |
|---|
| 282 | |
|---|
| 283 | ct_buf_init(&rbuf, slot->atr, sizeof(slot->atr)); |
|---|
| 284 | rbuf.tail++; |
|---|
| 285 | |
|---|
| 286 | if (ifd_recv_atr(dev, &rbuf, 1, revert_bits) < 0) |
|---|
| 287 | return -1; |
|---|
| 288 | |
|---|
| 289 | c = rbuf.base[1]; |
|---|
| 290 | while (1) { |
|---|
| 291 | num = ifd_count_bits(c & 0xF0); |
|---|
| 292 | if (ifd_recv_atr(dev, &rbuf, num, revert_bits) < |
|---|
| 293 | 0) |
|---|
| 294 | return -1; |
|---|
| 295 | |
|---|
| 296 | if (!(c & 0x80)) |
|---|
| 297 | break; |
|---|
| 298 | |
|---|
| 299 | c = rbuf.base[rbuf.tail - 1]; |
|---|
| 300 | proto = c & 0xF; |
|---|
| 301 | } |
|---|
| 302 | |
|---|
| 303 | /* Historical bytes */ |
|---|
| 304 | c = rbuf.base[1] & 0xF; |
|---|
| 305 | if (ifd_recv_atr(dev, &rbuf, c, revert_bits) < 0) |
|---|
| 306 | return -1; |
|---|
| 307 | |
|---|
| 308 | /* If a protocol other than T0 was specified, |
|---|
| 309 | * read check byte */ |
|---|
| 310 | if (proto |
|---|
| 311 | && ifd_recv_atr(dev, &rbuf, 1, revert_bits) < 0) |
|---|
| 312 | return -1; |
|---|
| 313 | |
|---|
| 314 | if (slot->atr[0] == 0x3F) |
|---|
| 315 | parity = IFD_SERIAL_PARITY_TOGGLE(parity); |
|---|
| 316 | count = rbuf.tail - rbuf.head; |
|---|
| 317 | } |
|---|
| 318 | |
|---|
| 319 | ifd_debug(1, "received atr:%s", ct_hexdump(slot->atr, count)); |
|---|
| 320 | |
|---|
| 321 | /* Set the parity in case it was toggled */ |
|---|
| 322 | if (drv->ops->change_parity(reader, parity) < 0) |
|---|
| 323 | return -1; |
|---|
| 324 | } |
|---|
| 325 | |
|---|
| 326 | slot->atr_len = count; |
|---|
| 327 | |
|---|
| 328 | if (count > size) |
|---|
| 329 | size = count; |
|---|
| 330 | if (atr) |
|---|
| 331 | memcpy(atr, slot->atr, count); |
|---|
| 332 | |
|---|
| 333 | /* For synchronous cards, the slot's protocol will already |
|---|
| 334 | * be set when we get here. */ |
|---|
| 335 | if (slot->proto == NULL) { |
|---|
| 336 | if (!ifd_protocol_select(reader, idx, IFD_PROTOCOL_DEFAULT)) |
|---|
| 337 | ct_error("Protocol selection failed"); |
|---|
| 338 | } |
|---|
| 339 | |
|---|
| 340 | return count; |
|---|
| 341 | } |
|---|
| 342 | |
|---|
| 343 | static int ifd_recv_atr(ifd_device_t * dev, ct_buf_t * bp, unsigned int count, |
|---|
| 344 | int revert_bits) |
|---|
| 345 | { |
|---|
| 346 | unsigned char *buf; |
|---|
| 347 | unsigned int n; |
|---|
| 348 | |
|---|
| 349 | if (count > ct_buf_tailroom(bp)) { |
|---|
| 350 | ct_error("ATR buffer too small"); |
|---|
| 351 | return -1; |
|---|
| 352 | } |
|---|
| 353 | |
|---|
| 354 | buf = (unsigned char *)ct_buf_tail(bp); |
|---|
| 355 | for (n = 0; n < count; n++) { |
|---|
| 356 | if (ifd_device_recv(dev, buf + n, 1, 1000) < 0) { |
|---|
| 357 | ct_error("failed to receive ATR"); |
|---|
| 358 | return -1; |
|---|
| 359 | } |
|---|
| 360 | } |
|---|
| 361 | |
|---|
| 362 | if (revert_bits) |
|---|
| 363 | ifd_revert_bits(buf, count); |
|---|
| 364 | |
|---|
| 365 | /* Advance tail pointer */ |
|---|
| 366 | ct_buf_put(bp, NULL, count); |
|---|
| 367 | return count; |
|---|
| 368 | } |
|---|
| 369 | |
|---|
| 370 | /* |
|---|
| 371 | * Check ATR for completeness |
|---|
| 372 | */ |
|---|
| 373 | int ifd_atr_complete(const unsigned char *atr, size_t len) |
|---|
| 374 | { |
|---|
| 375 | unsigned int j = 2, c; |
|---|
| 376 | int proto = 0; |
|---|
| 377 | |
|---|
| 378 | do { |
|---|
| 379 | if (j > len) |
|---|
| 380 | return 0; |
|---|
| 381 | c = atr[j - 1]; |
|---|
| 382 | if (j > 2) |
|---|
| 383 | proto = c & 0xF; |
|---|
| 384 | j += ifd_count_bits(c & 0xF0); |
|---|
| 385 | } while (c & 0x80); |
|---|
| 386 | |
|---|
| 387 | /* Historical bytes */ |
|---|
| 388 | if ((j += (atr[1] & 0xF)) > len) |
|---|
| 389 | return 0; |
|---|
| 390 | |
|---|
| 391 | /* If a protocol other than T0 was specified, |
|---|
| 392 | * read check byte */ |
|---|
| 393 | if (proto && j + 1 > len) |
|---|
| 394 | return 0; |
|---|
| 395 | |
|---|
| 396 | return 1; |
|---|
| 397 | } |
|---|
| 398 | |
|---|
| 399 | /* |
|---|
| 400 | * Eject the card |
|---|
| 401 | */ |
|---|
| 402 | int ifd_card_eject(ifd_reader_t * reader, unsigned int idx, time_t timeout, |
|---|
| 403 | const char *message) |
|---|
| 404 | { |
|---|
| 405 | const ifd_driver_t *drv = reader->driver; |
|---|
| 406 | |
|---|
| 407 | if (idx > reader->nslots) { |
|---|
| 408 | ct_error("%s: invalid slot number %u", reader->name, idx); |
|---|
| 409 | return -1; |
|---|
| 410 | } |
|---|
| 411 | |
|---|
| 412 | if (!drv || !drv->ops || !drv->ops->card_eject) |
|---|
| 413 | return 0; |
|---|
| 414 | |
|---|
| 415 | return drv->ops->card_eject(reader, idx, timeout, message); |
|---|
| 416 | } |
|---|
| 417 | |
|---|
| 418 | /* |
|---|
| 419 | * Perform a PIN verification, using the reader's pin pad |
|---|
| 420 | */ |
|---|
| 421 | int ifd_card_perform_verify(ifd_reader_t * reader, unsigned int idx, |
|---|
| 422 | time_t timeout, const char *message, |
|---|
| 423 | const unsigned char *data, size_t data_len, |
|---|
| 424 | unsigned char *resp, size_t resp_len) |
|---|
| 425 | { |
|---|
| 426 | const ifd_driver_t *drv = reader->driver; |
|---|
| 427 | |
|---|
| 428 | if (idx > reader->nslots) { |
|---|
| 429 | ct_error("%s: invalid slot number %u", reader->name, idx); |
|---|
| 430 | return -1; |
|---|
| 431 | } |
|---|
| 432 | |
|---|
| 433 | if (!drv || !drv->ops || !drv->ops->perform_verify) |
|---|
| 434 | return IFD_ERROR_NOT_SUPPORTED; |
|---|
| 435 | |
|---|
| 436 | return drv->ops->perform_verify(reader, idx, timeout, message, |
|---|
| 437 | data, data_len, resp, resp_len); |
|---|
| 438 | } |
|---|
| 439 | |
|---|
| 440 | /* |
|---|
| 441 | * Send/receive APDU to the ICC |
|---|
| 442 | */ |
|---|
| 443 | int ifd_card_command(ifd_reader_t * reader, unsigned int idx, const void *sbuf, |
|---|
| 444 | size_t slen, void *rbuf, size_t rlen) |
|---|
| 445 | { |
|---|
| 446 | ifd_slot_t *slot; |
|---|
| 447 | |
|---|
| 448 | if (idx > reader->nslots) |
|---|
| 449 | return -1; |
|---|
| 450 | |
|---|
| 451 | /* XXX handle driver specific methods of transmitting |
|---|
| 452 | * commands */ |
|---|
| 453 | |
|---|
| 454 | slot = &reader->slot[idx]; |
|---|
| 455 | if (slot->proto == NULL) { |
|---|
| 456 | ct_error("No communication protocol selected"); |
|---|
| 457 | return -1; |
|---|
| 458 | } |
|---|
| 459 | |
|---|
| 460 | /* An application is talking to the card. Prevent |
|---|
| 461 | * automatic card status updates from slowing down |
|---|
| 462 | * things */ |
|---|
| 463 | slot->next_update = time(NULL) + 1; |
|---|
| 464 | |
|---|
| 465 | return ifd_protocol_transceive(slot->proto, slot->dad, |
|---|
| 466 | sbuf, slen, rbuf, rlen); |
|---|
| 467 | } |
|---|
| 468 | |
|---|
| 469 | /* |
|---|
| 470 | * Read/write synchronous ICCs |
|---|
| 471 | */ |
|---|
| 472 | int ifd_card_read_memory(ifd_reader_t * reader, unsigned int idx, |
|---|
| 473 | unsigned short addr, unsigned char *rbuf, size_t rlen) |
|---|
| 474 | { |
|---|
| 475 | ifd_slot_t *slot; |
|---|
| 476 | |
|---|
| 477 | if (idx > reader->nslots) |
|---|
| 478 | return -1; |
|---|
| 479 | |
|---|
| 480 | slot = &reader->slot[idx]; |
|---|
| 481 | if (slot->proto == NULL) { |
|---|
| 482 | ct_error("No communication protocol selected"); |
|---|
| 483 | return -1; |
|---|
| 484 | } |
|---|
| 485 | |
|---|
| 486 | /* An application is talking to the card. Prevent |
|---|
| 487 | * automatic card status updates from slowing down |
|---|
| 488 | * things */ |
|---|
| 489 | slot->next_update = time(NULL) + 1; |
|---|
| 490 | |
|---|
| 491 | return ifd_protocol_read_memory(slot->proto, idx, addr, rbuf, rlen); |
|---|
| 492 | } |
|---|
| 493 | |
|---|
| 494 | int ifd_card_write_memory(ifd_reader_t * reader, unsigned int idx, |
|---|
| 495 | unsigned short addr, const unsigned char *sbuf, |
|---|
| 496 | size_t slen) |
|---|
| 497 | { |
|---|
| 498 | ifd_slot_t *slot; |
|---|
| 499 | |
|---|
| 500 | if (idx > reader->nslots) |
|---|
| 501 | return -1; |
|---|
| 502 | |
|---|
| 503 | slot = &reader->slot[idx]; |
|---|
| 504 | if (slot->proto == NULL) { |
|---|
| 505 | ct_error("No communication protocol selected"); |
|---|
| 506 | return -1; |
|---|
| 507 | } |
|---|
| 508 | |
|---|
| 509 | /* An application is talking to the card. Prevent |
|---|
| 510 | * automatic card status updates from slowing down |
|---|
| 511 | * things */ |
|---|
| 512 | slot->next_update = time(NULL) + 1; |
|---|
| 513 | |
|---|
| 514 | return ifd_protocol_write_memory(slot->proto, idx, addr, sbuf, slen); |
|---|
| 515 | } |
|---|
| 516 | |
|---|
| 517 | /* |
|---|
| 518 | * Transfer/receive APDU using driver specific mechanisms |
|---|
| 519 | * This functions is called from the protocol (T=0,1,...) layer |
|---|
| 520 | */ |
|---|
| 521 | int ifd_send_command(ifd_protocol_t * prot, const void *buffer, size_t len) |
|---|
| 522 | { |
|---|
| 523 | const ifd_driver_t *drv; |
|---|
| 524 | |
|---|
| 525 | if (!prot || !prot->reader || !(drv = prot->reader->driver) |
|---|
| 526 | || !drv->ops || !drv->ops->send) |
|---|
| 527 | return -1; |
|---|
| 528 | |
|---|
| 529 | return drv->ops->send(prot->reader, prot->dad, |
|---|
| 530 | (const unsigned char *)buffer, len); |
|---|
| 531 | } |
|---|
| 532 | |
|---|
| 533 | int |
|---|
| 534 | ifd_recv_response(ifd_protocol_t * prot, void *buffer, size_t len, long timeout) |
|---|
| 535 | { |
|---|
| 536 | const ifd_driver_t *drv; |
|---|
| 537 | |
|---|
| 538 | if (!prot || !prot->reader || !(drv = prot->reader->driver) |
|---|
| 539 | || !drv->ops || !drv->ops->recv) |
|---|
| 540 | return -1; |
|---|
| 541 | |
|---|
| 542 | return drv->ops->recv(prot->reader, prot->dad, (unsigned char *)buffer, |
|---|
| 543 | len, timeout); |
|---|
| 544 | } |
|---|
| 545 | |
|---|
| 546 | /* |
|---|
| 547 | * Shut down reader |
|---|
| 548 | */ |
|---|
| 549 | void ifd_close(ifd_reader_t * reader) |
|---|
| 550 | { |
|---|
| 551 | ifd_detach(reader); |
|---|
| 552 | |
|---|
| 553 | if (reader->driver->ops->close) |
|---|
| 554 | reader->driver->ops->close(reader); |
|---|
| 555 | |
|---|
| 556 | if (reader->device) |
|---|
| 557 | ifd_device_close(reader->device); |
|---|
| 558 | |
|---|
| 559 | memset(reader, 0, sizeof(*reader)); |
|---|
| 560 | free(reader); |
|---|
| 561 | } |
|---|
| 562 | |
|---|
| 563 | /* |
|---|
| 564 | * Before command |
|---|
| 565 | */ |
|---|
| 566 | int ifd_before_command(ifd_reader_t *reader) |
|---|
| 567 | { |
|---|
| 568 | if (reader->driver->ops->before_command) |
|---|
| 569 | return reader->driver->ops->before_command(reader); |
|---|
| 570 | else |
|---|
| 571 | return 0; |
|---|
| 572 | } |
|---|
| 573 | |
|---|
| 574 | /* |
|---|
| 575 | * After command |
|---|
| 576 | */ |
|---|
| 577 | int ifd_after_command(ifd_reader_t *reader) |
|---|
| 578 | { |
|---|
| 579 | if (reader->driver->ops->after_command) |
|---|
| 580 | return reader->driver->ops->after_command(reader); |
|---|
| 581 | else |
|---|
| 582 | return 0; |
|---|
| 583 | } |
|---|
| 584 | |
|---|
| 585 | /* |
|---|
| 586 | * Get eventfd |
|---|
| 587 | */ |
|---|
| 588 | int ifd_get_eventfd(ifd_reader_t *reader, short *events) |
|---|
| 589 | { |
|---|
| 590 | if (reader->driver->ops->get_eventfd) { |
|---|
| 591 | return reader->driver->ops->get_eventfd(reader, events); |
|---|
| 592 | } |
|---|
| 593 | else { |
|---|
| 594 | return -1; |
|---|
| 595 | } |
|---|
| 596 | } |
|---|
| 597 | |
|---|
| 598 | static void ifd_slot_status_update(ifd_reader_t *reader, int slot, int status) |
|---|
| 599 | { |
|---|
| 600 | static unsigned int card_seq = 1; |
|---|
| 601 | |
|---|
| 602 | ct_info_t *info = reader->status; |
|---|
| 603 | unsigned int prev_seq, new_seq; |
|---|
| 604 | |
|---|
| 605 | new_seq = prev_seq = info->ct_card[slot]; |
|---|
| 606 | |
|---|
| 607 | if (!(status & IFD_CARD_PRESENT)) { |
|---|
| 608 | new_seq = 0; |
|---|
| 609 | } |
|---|
| 610 | else if (!prev_seq || (status & IFD_CARD_STATUS_CHANGED)) { |
|---|
| 611 | new_seq = card_seq++; |
|---|
| 612 | } |
|---|
| 613 | |
|---|
| 614 | if (prev_seq != new_seq) { |
|---|
| 615 | ifd_debug(1, "card status change slot %d: %u -> %u", |
|---|
| 616 | slot, prev_seq, new_seq); |
|---|
| 617 | info->ct_card[slot] = new_seq; |
|---|
| 618 | ct_status_update(info); |
|---|
| 619 | } |
|---|
| 620 | } |
|---|
| 621 | |
|---|
| 622 | void ifd_poll(ifd_reader_t *reader) |
|---|
| 623 | { |
|---|
| 624 | unsigned slot; |
|---|
| 625 | |
|---|
| 626 | /* Check if the card status changed */ |
|---|
| 627 | for (slot = 0; slot < reader->nslots; slot++) { |
|---|
| 628 | time_t now; |
|---|
| 629 | int status; |
|---|
| 630 | |
|---|
| 631 | time(&now); |
|---|
| 632 | if (now < reader->slot[slot].next_update) |
|---|
| 633 | continue; |
|---|
| 634 | |
|---|
| 635 | /* Poll card status at most once a second |
|---|
| 636 | * XXX: make this configurable */ |
|---|
| 637 | reader->slot[slot].next_update = now + 1; |
|---|
| 638 | |
|---|
| 639 | if (ifd_card_status(reader, slot, &status) < 0) { |
|---|
| 640 | /* Don't return error; let the hotplug test |
|---|
| 641 | * pick up the detach |
|---|
| 642 | if (rc == IFD_ERROR_DEVICE_DISCONNECTED) |
|---|
| 643 | return rc; |
|---|
| 644 | */ |
|---|
| 645 | continue; |
|---|
| 646 | } |
|---|
| 647 | |
|---|
| 648 | ifd_slot_status_update(reader, slot, status); |
|---|
| 649 | } |
|---|
| 650 | } |
|---|
| 651 | |
|---|
| 652 | int ifd_error(ifd_reader_t *reader) |
|---|
| 653 | { |
|---|
| 654 | if (reader->driver->ops->error == NULL) { |
|---|
| 655 | return IFD_ERROR_NOT_SUPPORTED; |
|---|
| 656 | } |
|---|
| 657 | |
|---|
| 658 | return reader->driver->ops->error(reader); |
|---|
| 659 | } |
|---|
| 660 | |
|---|
| 661 | int ifd_event(ifd_reader_t *reader) |
|---|
| 662 | { |
|---|
| 663 | int status[OPENCT_MAX_SLOTS]; |
|---|
| 664 | unsigned slot; |
|---|
| 665 | int rc; |
|---|
| 666 | |
|---|
| 667 | if (reader->driver->ops->event == NULL) { |
|---|
| 668 | return IFD_ERROR_NOT_SUPPORTED; |
|---|
| 669 | } |
|---|
| 670 | |
|---|
| 671 | rc = reader->driver->ops->event(reader, status, reader->nslots); |
|---|
| 672 | |
|---|
| 673 | for (slot=0;slot<reader->nslots;slot++) { |
|---|
| 674 | ifd_slot_status_update(reader, slot, status[slot]); |
|---|
| 675 | } |
|---|
| 676 | |
|---|
| 677 | return rc; |
|---|
| 678 | } |
|---|
| 679 | |
|---|