spiceccid.c revision d514b0f3
1d514b0f3Smrg/* 2d514b0f3Smrg * Copyright (C) 2014 CodeWeavers, Inc. 3d514b0f3Smrg * 4d514b0f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5d514b0f3Smrg * copy of this software and associated documentation files (the "Software"), 6d514b0f3Smrg * to deal in the Software without restriction, including without limitation 7d514b0f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8d514b0f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 9d514b0f3Smrg * Software is furnished to do so, subject to the following conditions: 10d514b0f3Smrg * 11d514b0f3Smrg * The above copyright notice and this permission notice (including the next 12d514b0f3Smrg * paragraph) shall be included in all copies or substantial portions of the 13d514b0f3Smrg * Software. 14d514b0f3Smrg * 15d514b0f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16d514b0f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17d514b0f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18d514b0f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19d514b0f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20d514b0f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21d514b0f3Smrg * SOFTWARE. 22d514b0f3Smrg * 23d514b0f3Smrg * Authors: 24d514b0f3Smrg * Jeremy White <jwhite@codeweavers.com> 25d514b0f3Smrg */ 26d514b0f3Smrg 27d514b0f3Smrg/*---------------------------------------------------------------------------- 28d514b0f3Smrg Chip/Smart Card Interface Devices driver for Spice 29d514b0f3Smrg 30d514b0f3Smrg This driver is built to interface to pcsc-lite as a serial smartcard 31d514b0f3Smrg device. 32d514b0f3Smrg It translates the IFD (Interface device) ABI into the Spice protocol. 33d514b0f3Smrg----------------------------------------------------------------------------*/ 34d514b0f3Smrg 35d514b0f3Smrg#include <stdio.h> 36d514b0f3Smrg#include <string.h> 37d514b0f3Smrg#include <stdlib.h> 38d514b0f3Smrg#include <sys/types.h> 39d514b0f3Smrg#include <sys/stat.h> 40d514b0f3Smrg#include <fcntl.h> 41d514b0f3Smrg#include <unistd.h> 42d514b0f3Smrg#include <pthread.h> 43d514b0f3Smrg#include <errno.h> 44d514b0f3Smrg#include <sys/socket.h> 45d514b0f3Smrg#include <sys/un.h> 46d514b0f3Smrg 47d514b0f3Smrg#include "vscard_common.h" 48d514b0f3Smrg#include "ifdhandler.h" 49d514b0f3Smrg#include <arpa/inet.h> 50d514b0f3Smrg 51d514b0f3Smrgtypedef struct apdu_list { 52d514b0f3Smrg void *data; 53d514b0f3Smrg int len; 54d514b0f3Smrg struct apdu_list *next; 55d514b0f3Smrg} apdu_t; 56d514b0f3Smrg 57d514b0f3Smrg#define MAX_LUNS 2 58d514b0f3Smrgtypedef struct smartcard_ccid { 59d514b0f3Smrg int fd; 60d514b0f3Smrg int lun; 61d514b0f3Smrg pthread_t tid; 62d514b0f3Smrg int state; 63d514b0f3Smrg char atr[36]; 64d514b0f3Smrg int atr_len; 65d514b0f3Smrg pthread_mutex_t apdu_lock; 66d514b0f3Smrg apdu_t *apdu_list; 67d514b0f3Smrg} smartcard_ccid_t; 68d514b0f3Smrg 69d514b0f3Smrg#define STATE_OPEN 1 70d514b0f3Smrg#define STATE_READER_ADDED 2 71d514b0f3Smrg#define STATE_READER_REMOVED 4 72d514b0f3Smrg 73d514b0f3Smrg#if ! defined(MIN) 74d514b0f3Smrg#define MIN(x, y) (((x) < (y)) ? (x) : (y)) 75d514b0f3Smrg#endif 76d514b0f3Smrg 77d514b0f3Smrg 78d514b0f3Smrgsmartcard_ccid_t luns[MAX_LUNS] = { { -1 }, { -1 } }; 79d514b0f3Smrg 80d514b0f3SmrgRESPONSECODE IFDHCloseChannel(DWORD Lun); 81d514b0f3Smrg 82d514b0f3Smrgstatic void push_apdu(smartcard_ccid_t *ccid, void *data, int len) 83d514b0f3Smrg{ 84d514b0f3Smrg apdu_t *a = malloc(sizeof(*a)); 85d514b0f3Smrg apdu_t **p; 86d514b0f3Smrg 87d514b0f3Smrg a->data = malloc(len); 88d514b0f3Smrg a->len = len; 89d514b0f3Smrg a->next = NULL; 90d514b0f3Smrg memcpy(a->data, data, len); 91d514b0f3Smrg 92d514b0f3Smrg pthread_mutex_lock(&ccid->apdu_lock); 93d514b0f3Smrg for (p = &ccid->apdu_list; *p; p = &(*p)->next) 94d514b0f3Smrg ; 95d514b0f3Smrg *p = a; 96d514b0f3Smrg 97d514b0f3Smrg pthread_mutex_unlock(&ccid->apdu_lock); 98d514b0f3Smrg} 99d514b0f3Smrg 100d514b0f3Smrgstatic apdu_t * pop_apdu(smartcard_ccid_t *ccid) 101d514b0f3Smrg{ 102d514b0f3Smrg apdu_t *p; 103d514b0f3Smrg pthread_mutex_lock(&ccid->apdu_lock); 104d514b0f3Smrg p = ccid->apdu_list; 105d514b0f3Smrg if (ccid->apdu_list) 106d514b0f3Smrg ccid->apdu_list = p->next; 107d514b0f3Smrg pthread_mutex_unlock(&ccid->apdu_lock); 108d514b0f3Smrg return p; 109d514b0f3Smrg} 110d514b0f3Smrg 111d514b0f3Smrgstatic void free_apdu(apdu_t *a) 112d514b0f3Smrg{ 113d514b0f3Smrg free(a->data); 114d514b0f3Smrg free(a); 115d514b0f3Smrg} 116d514b0f3Smrg 117d514b0f3Smrgstatic void send_reply(smartcard_ccid_t *ccid, uint32_t code) 118d514b0f3Smrg{ 119d514b0f3Smrg uint32_t reply[4]; 120d514b0f3Smrg 121d514b0f3Smrg reply[0] = htonl(VSC_Error); // type 122d514b0f3Smrg reply[1] = htonl(ccid->lun); // reader id 123d514b0f3Smrg reply[2] = htonl(sizeof(uint32_t)); // length 124d514b0f3Smrg reply[3] = htonl(code); // Error code 125d514b0f3Smrg 126d514b0f3Smrg if (write(ccid->fd, (char *) reply, sizeof(reply)) != sizeof(reply)) { 127d514b0f3Smrg fprintf(stderr, "Error: lun %d fd %d write failed; errno %d\n", ccid->lun, ccid->fd, errno); 128d514b0f3Smrg IFDHCloseChannel(ccid->lun); 129d514b0f3Smrg } 130d514b0f3Smrg} 131d514b0f3Smrg 132d514b0f3Smrgstatic int send_tx_buffer(smartcard_ccid_t *ccid, void *data, int len) 133d514b0f3Smrg{ 134d514b0f3Smrg uint32_t *reply, *p; 135d514b0f3Smrg int write_len = sizeof(*reply) * 3 + len; 136d514b0f3Smrg 137d514b0f3Smrg reply = malloc(write_len); 138d514b0f3Smrg p = reply; 139d514b0f3Smrg 140d514b0f3Smrg *p++ = htonl(VSC_APDU); // type 141d514b0f3Smrg *p++ = htonl(ccid->lun); // reader id 142d514b0f3Smrg *p++ = htonl(len); 143d514b0f3Smrg memcpy(p, data, len); 144d514b0f3Smrg 145d514b0f3Smrg if (write(ccid->fd, (char *) reply, write_len) != write_len) { 146d514b0f3Smrg fprintf(stderr, "Error: lun %d fd %d write failed; errno %d\n", ccid->lun, ccid->fd, errno); 147d514b0f3Smrg IFDHCloseChannel(ccid->lun); 148d514b0f3Smrg free(reply); 149d514b0f3Smrg return 0; 150d514b0f3Smrg } 151d514b0f3Smrg free(reply); 152d514b0f3Smrg return 1; 153d514b0f3Smrg} 154d514b0f3Smrg 155d514b0f3Smrgstatic void process_reader_add(smartcard_ccid_t *ccid, VSCMsgHeader *h, char *data) 156d514b0f3Smrg{ 157d514b0f3Smrg if (ccid->state & STATE_READER_ADDED) { 158d514b0f3Smrg send_reply(ccid, VSC_GENERAL_ERROR); 159d514b0f3Smrg return; 160d514b0f3Smrg } 161d514b0f3Smrg 162d514b0f3Smrg ccid->state |= STATE_READER_ADDED; 163d514b0f3Smrg ccid->state &= ~STATE_READER_REMOVED; 164d514b0f3Smrg 165d514b0f3Smrg pthread_mutex_init(&ccid->apdu_lock, NULL); 166d514b0f3Smrg ccid->apdu_list = NULL; 167d514b0f3Smrg 168d514b0f3Smrg send_reply(ccid, VSC_SUCCESS); 169d514b0f3Smrg} 170d514b0f3Smrg 171d514b0f3Smrgstatic void process_reader_remove(smartcard_ccid_t *ccid, VSCMsgHeader *h) 172d514b0f3Smrg{ 173d514b0f3Smrg apdu_t *p; 174d514b0f3Smrg 175d514b0f3Smrg if (ccid->state & STATE_READER_REMOVED) { 176d514b0f3Smrg send_reply(ccid, VSC_GENERAL_ERROR); 177d514b0f3Smrg return; 178d514b0f3Smrg } 179d514b0f3Smrg 180d514b0f3Smrg ccid->state |= STATE_READER_REMOVED; 181d514b0f3Smrg ccid->state &= ~STATE_READER_ADDED; 182d514b0f3Smrg 183d514b0f3Smrg while (p = pop_apdu(ccid)) 184d514b0f3Smrg free_apdu(p); 185d514b0f3Smrg 186d514b0f3Smrg pthread_mutex_destroy(&ccid->apdu_lock); 187d514b0f3Smrg 188d514b0f3Smrg send_reply(ccid, VSC_SUCCESS); 189d514b0f3Smrg} 190d514b0f3Smrg 191d514b0f3Smrgstatic void process_atr(smartcard_ccid_t *ccid, VSCMsgHeader *h, char *data) 192d514b0f3Smrg{ 193d514b0f3Smrg ccid->atr_len = h->length; 194d514b0f3Smrg if (h->length > sizeof(ccid->atr)) { 195d514b0f3Smrg fprintf(stderr, "Supplied ATR of length %d exceeds %d maximum\n", 196d514b0f3Smrg h->length, sizeof(ccid->atr)); 197d514b0f3Smrg send_reply(ccid, VSC_GENERAL_ERROR); 198d514b0f3Smrg return; 199d514b0f3Smrg } 200d514b0f3Smrg 201d514b0f3Smrg memset(ccid->atr, 0, sizeof(ccid->atr)); 202d514b0f3Smrg memcpy(ccid->atr, data, ccid->atr_len); 203d514b0f3Smrg 204d514b0f3Smrg send_reply(ccid, VSC_SUCCESS); 205d514b0f3Smrg} 206d514b0f3Smrg 207d514b0f3Smrgstatic void process_apdu(smartcard_ccid_t *ccid, VSCMsgHeader *h, char *data) 208d514b0f3Smrg{ 209d514b0f3Smrg if (ccid->state & STATE_READER_ADDED) 210d514b0f3Smrg push_apdu(ccid, data, h->length); 211d514b0f3Smrg else 212d514b0f3Smrg fprintf(stderr, "apdu of length %d discarded; inactive reader\n", h->length); 213d514b0f3Smrg} 214d514b0f3Smrg 215d514b0f3Smrgstatic void process_card_remove(smartcard_ccid_t *ccid, VSCMsgHeader *h) 216d514b0f3Smrg{ 217d514b0f3Smrg ccid->atr_len = 0; 218d514b0f3Smrg memset(ccid->atr, 0, sizeof(ccid->atr)); 219d514b0f3Smrg send_reply(ccid, VSC_SUCCESS); 220d514b0f3Smrg} 221d514b0f3Smrg 222d514b0f3Smrgstatic int process_message(smartcard_ccid_t *ccid, char *buf, int len) 223d514b0f3Smrg{ 224d514b0f3Smrg VSCMsgHeader h; 225d514b0f3Smrg uint32_t *p = (uint32_t *) buf; 226d514b0f3Smrg 227d514b0f3Smrg h.type = ntohl(*p++); 228d514b0f3Smrg h.reader_id = ntohl(*p++); 229d514b0f3Smrg h.length = ntohl(*p++); 230d514b0f3Smrg 231d514b0f3Smrg if (len < sizeof(h) || len < sizeof(h) + h.length) 232d514b0f3Smrg return 0; 233d514b0f3Smrg 234d514b0f3Smrg switch (h.type) { 235d514b0f3Smrg case VSC_ReaderAdd: 236d514b0f3Smrg process_reader_add(ccid, &h, h.length > 0 ? buf + sizeof(h) : NULL); 237d514b0f3Smrg break; 238d514b0f3Smrg 239d514b0f3Smrg case VSC_ReaderRemove: 240d514b0f3Smrg process_reader_remove(ccid, &h); 241d514b0f3Smrg break; 242d514b0f3Smrg 243d514b0f3Smrg case VSC_ATR: 244d514b0f3Smrg process_atr(ccid, &h, h.length > 0 ? buf + sizeof(h) : NULL); 245d514b0f3Smrg break; 246d514b0f3Smrg 247d514b0f3Smrg case VSC_CardRemove: 248d514b0f3Smrg process_card_remove(ccid, &h); 249d514b0f3Smrg break; 250d514b0f3Smrg 251d514b0f3Smrg case VSC_APDU: 252d514b0f3Smrg process_apdu(ccid, &h, h.length > 0 ? buf + sizeof(h) : NULL); 253d514b0f3Smrg break; 254d514b0f3Smrg 255d514b0f3Smrg default: 256d514b0f3Smrg fprintf(stderr, "spiceccid %s: unknown smartcard message %d / %d\n", __FUNCTION__, h.type, sizeof(h) + h.length); 257d514b0f3Smrg 258d514b0f3Smrg } 259d514b0f3Smrg 260d514b0f3Smrg return(h.length + sizeof(h)); 261d514b0f3Smrg} 262d514b0f3Smrg 263d514b0f3Smrgstatic void * lun_thread(void *arg) 264d514b0f3Smrg{ 265d514b0f3Smrg char buf[8096]; 266d514b0f3Smrg int pos = 0; 267d514b0f3Smrg smartcard_ccid_t *ccid = (smartcard_ccid_t *) arg; 268d514b0f3Smrg int rc; 269d514b0f3Smrg 270d514b0f3Smrg while (1) { 271d514b0f3Smrg rc = read(ccid->fd, buf + pos, sizeof(buf) - pos); 272d514b0f3Smrg if (rc == -1) 273d514b0f3Smrg if (errno == EINTR) 274d514b0f3Smrg continue; 275d514b0f3Smrg else 276d514b0f3Smrg break; 277d514b0f3Smrg 278d514b0f3Smrg if (rc == 0) 279d514b0f3Smrg break; 280d514b0f3Smrg 281d514b0f3Smrg pos += rc; 282d514b0f3Smrg 283d514b0f3Smrg do { 284d514b0f3Smrg rc = process_message(ccid, buf, pos); 285d514b0f3Smrg pos -= rc; 286d514b0f3Smrg 287d514b0f3Smrg if (rc > 0 && pos > 0) 288d514b0f3Smrg memmove(buf, buf + rc, pos); 289d514b0f3Smrg } while (rc > 0 && pos > 0); 290d514b0f3Smrg } 291d514b0f3Smrg 292d514b0f3Smrg fprintf(stderr, "LUN %d thread exiting: %s\n", ccid->lun, 293d514b0f3Smrg rc == 0 ? "normally" : strerror(errno)); 294d514b0f3Smrg close(ccid->fd); 295d514b0f3Smrg ccid->fd = -1; 296d514b0f3Smrg ccid->lun = 0; 297d514b0f3Smrg ccid->atr_len = 0; 298d514b0f3Smrg ccid->state &= ~STATE_OPEN; 299d514b0f3Smrg 300d514b0f3Smrg return NULL; 301d514b0f3Smrg} 302d514b0f3Smrg 303d514b0f3Smrg 304d514b0f3Smrgstatic void send_init(smartcard_ccid_t *ccid) 305d514b0f3Smrg{ 306d514b0f3Smrg uint32_t msg[6]; 307d514b0f3Smrg 308d514b0f3Smrg msg[0] = htonl(VSC_Init); // type 309d514b0f3Smrg msg[1] = htonl(ccid->lun); // reader id 310d514b0f3Smrg msg[2] = htonl(sizeof(uint32_t) * 3); // length 311d514b0f3Smrg msg[3] = htonl(VSCARD_MAGIC); // VSCD 312d514b0f3Smrg msg[4] = htonl(VSCARD_VERSION); // VSCD 313d514b0f3Smrg msg[5] = 0; // capabilities 314d514b0f3Smrg 315d514b0f3Smrg if (write(ccid->fd, (char *) msg, sizeof(msg)) != sizeof(msg)) { 316d514b0f3Smrg fprintf(stderr, "Error: lun %d fd %d write failed; errno %d\n", ccid->lun, ccid->fd, errno); 317d514b0f3Smrg IFDHCloseChannel(ccid->lun); 318d514b0f3Smrg } 319d514b0f3Smrg} 320d514b0f3Smrg 321d514b0f3Smrg/*---------------------------------------------------------------------------- 322d514b0f3Smrg IFDHCreateChannelByName 323d514b0f3Smrg The pcsc daemon should invoke this function passing in the path name 324d514b0f3Smrg configured in reader.conf. 325d514b0f3Smrg*/ 326d514b0f3SmrgRESPONSECODE IFDHCreateChannelByName(DWORD Lun, LPSTR DeviceName) 327d514b0f3Smrg{ 328d514b0f3Smrg int i; 329d514b0f3Smrg struct sockaddr_un addr; 330d514b0f3Smrg 331d514b0f3Smrg for (i = 0; i < MAX_LUNS; i++) 332d514b0f3Smrg if (luns[i].fd != -1 && luns[i].lun == Lun) 333d514b0f3Smrg return IFD_COMMUNICATION_ERROR; 334d514b0f3Smrg 335d514b0f3Smrg for (i = 0; i < MAX_LUNS; i++) 336d514b0f3Smrg if (luns[i].fd == -1) 337d514b0f3Smrg break; 338d514b0f3Smrg 339d514b0f3Smrg if (i >= MAX_LUNS) 340d514b0f3Smrg return IFD_COMMUNICATION_ERROR; 341d514b0f3Smrg 342d514b0f3Smrg luns[i].fd = socket(AF_UNIX, SOCK_STREAM, 0); 343d514b0f3Smrg if (luns[i].fd < 0) 344d514b0f3Smrg return IFD_NO_SUCH_DEVICE; 345d514b0f3Smrg 346d514b0f3Smrg memset(&addr, 0, sizeof(addr)); 347d514b0f3Smrg addr.sun_family = AF_UNIX; 348d514b0f3Smrg strncpy(addr.sun_path, DeviceName, sizeof(addr.sun_path) - 1); 349d514b0f3Smrg if (connect(luns[i].fd, (struct sockaddr *) &addr, sizeof(addr))) { 350d514b0f3Smrg close(luns[i].fd); 351d514b0f3Smrg return IFD_COMMUNICATION_ERROR; 352d514b0f3Smrg } 353d514b0f3Smrg 354d514b0f3Smrg if (pthread_create(&luns[i].tid, NULL, &lun_thread, &luns[i])) { 355d514b0f3Smrg close(luns[i].fd); 356d514b0f3Smrg return IFD_COMMUNICATION_ERROR; 357d514b0f3Smrg } 358d514b0f3Smrg 359d514b0f3Smrg luns[i].lun = Lun; 360d514b0f3Smrg luns[i].state = STATE_OPEN; 361d514b0f3Smrg 362d514b0f3Smrg return IFD_SUCCESS; 363d514b0f3Smrg} 364d514b0f3Smrg 365d514b0f3SmrgRESPONSECODE IFDHCreateChannel(DWORD Lun, DWORD Channel) 366d514b0f3Smrg{ 367d514b0f3Smrg fprintf(stderr, "spiceccid %s unsupported: Lun %ld, Channel %ld\n", __FUNCTION__, Lun, Channel); 368d514b0f3Smrg return IFD_ERROR_NOT_SUPPORTED; 369d514b0f3Smrg} 370d514b0f3Smrg 371d514b0f3SmrgRESPONSECODE IFDHCloseChannel(DWORD Lun) 372d514b0f3Smrg{ 373d514b0f3Smrg int i; 374d514b0f3Smrg 375d514b0f3Smrg for (i = 0; i < MAX_LUNS; i++) { 376d514b0f3Smrg if (luns[i].fd != -1 && luns[i].lun == Lun) { 377d514b0f3Smrg pthread_cancel(luns[i].tid); 378d514b0f3Smrg close(luns[i].fd); 379d514b0f3Smrg luns[i].fd = -1; 380d514b0f3Smrg luns[i].lun = 0; 381d514b0f3Smrg luns[i].atr_len = 0; 382d514b0f3Smrg luns[i].state &= ~STATE_OPEN; 383d514b0f3Smrg break; 384d514b0f3Smrg } 385d514b0f3Smrg } 386d514b0f3Smrg 387d514b0f3Smrg if (i == MAX_LUNS) 388d514b0f3Smrg return IFD_NO_SUCH_DEVICE; 389d514b0f3Smrg 390d514b0f3Smrg return IFD_SUCCESS; 391d514b0f3Smrg} 392d514b0f3Smrg 393d514b0f3SmrgRESPONSECODE IFDHGetCapabilities(DWORD Lun, DWORD Tag, PDWORD Length, PUCHAR Value) 394d514b0f3Smrg{ 395d514b0f3Smrg fprintf(stderr, "spiceccid %s unsupported: Lun %ld, Tag %ld, Length %ld, Value %p\n", __FUNCTION__, Lun, Tag, *Length, Value); 396d514b0f3Smrg /* TODO - explore supporting TAG_IFD_POLLING_THREAD */ 397d514b0f3Smrg return IFD_ERROR_NOT_SUPPORTED; 398d514b0f3Smrg} 399d514b0f3Smrg 400d514b0f3SmrgRESPONSECODE IFDHSetCapabilities(DWORD Lun, DWORD Tag, DWORD Length, PUCHAR Value) 401d514b0f3Smrg{ 402d514b0f3Smrg return IFD_ERROR_NOT_SUPPORTED; 403d514b0f3Smrg} 404d514b0f3Smrg 405d514b0f3SmrgRESPONSECODE IFDHPowerICC(DWORD Lun, DWORD Action, PUCHAR Atr, PDWORD AtrLength) 406d514b0f3Smrg{ 407d514b0f3Smrg int i; 408d514b0f3Smrg 409d514b0f3Smrg for (i = 0; i < MAX_LUNS; i++) 410d514b0f3Smrg if (luns[i].fd != -1 && luns[i].lun == Lun) 411d514b0f3Smrg if (Action == IFD_POWER_UP || Action == IFD_RESET) { 412d514b0f3Smrg if (*AtrLength >= luns[i].atr_len) { 413d514b0f3Smrg memcpy(Atr, luns[i].atr, luns[i].atr_len); 414d514b0f3Smrg *AtrLength = luns[i].atr_len; 415d514b0f3Smrg } 416d514b0f3Smrg send_init(&luns[i]); 417d514b0f3Smrg return IFD_SUCCESS; 418d514b0f3Smrg } 419d514b0f3Smrg 420d514b0f3Smrg fprintf(stderr, "spiceccid %s unsupported: Lun %ld, Action %ld\n", __FUNCTION__, Lun, Action); 421d514b0f3Smrg return IFD_ERROR_NOT_SUPPORTED; 422d514b0f3Smrg} 423d514b0f3Smrg 424d514b0f3Smrg#define TX_MAX_SLEEP 5000 425d514b0f3Smrg#define TX_SLEEP_INTERVAL 1000 426d514b0f3SmrgRESPONSECODE IFDHTransmitToICC(DWORD Lun, SCARD_IO_HEADER SendPci, 427d514b0f3Smrg PUCHAR TxBuffer, DWORD TxLength, PUCHAR RxBuffer, PDWORD 428d514b0f3Smrg RxLength, PSCARD_IO_HEADER RecvPci) 429d514b0f3Smrg{ 430d514b0f3Smrg apdu_t *p; 431d514b0f3Smrg int i, j; 432d514b0f3Smrg 433d514b0f3Smrg for (i = 0; i < MAX_LUNS; i++) 434d514b0f3Smrg if (luns[i].fd != -1 && luns[i].lun == Lun) { 435d514b0f3Smrg while (p = pop_apdu(&luns[i])) 436d514b0f3Smrg free_apdu(p); 437d514b0f3Smrg 438d514b0f3Smrg if (send_tx_buffer(&luns[i], TxBuffer, TxLength)) { 439d514b0f3Smrg for (j = 0; j < TX_MAX_SLEEP; j++) 440d514b0f3Smrg if (p = pop_apdu(&luns[i])) 441d514b0f3Smrg break; 442d514b0f3Smrg else 443d514b0f3Smrg usleep(TX_SLEEP_INTERVAL); 444d514b0f3Smrg 445d514b0f3Smrg if (p) { 446d514b0f3Smrg memcpy(RxBuffer, p->data, MIN(p->len, *RxLength)); 447d514b0f3Smrg *RxLength = MIN(p->len, *RxLength); 448d514b0f3Smrg free_apdu(p); 449d514b0f3Smrg return IFD_SUCCESS; 450d514b0f3Smrg } 451d514b0f3Smrg 452d514b0f3Smrg return IFD_RESPONSE_TIMEOUT; 453d514b0f3Smrg } 454d514b0f3Smrg } 455d514b0f3Smrg return IFD_NO_SUCH_DEVICE; 456d514b0f3Smrg} 457d514b0f3Smrg 458d514b0f3SmrgRESPONSECODE IFDHICCPresence(DWORD Lun) 459d514b0f3Smrg{ 460d514b0f3Smrg int i; 461d514b0f3Smrg 462d514b0f3Smrg for (i = 0; i < MAX_LUNS; i++) 463d514b0f3Smrg if (luns[i].fd != -1 && luns[i].lun == Lun) { 464d514b0f3Smrg if (luns[i].atr_len > 0 && luns[i].state & STATE_READER_ADDED) 465d514b0f3Smrg return IFD_SUCCESS; 466d514b0f3Smrg 467d514b0f3Smrg return IFD_ICC_NOT_PRESENT; 468d514b0f3Smrg } 469d514b0f3Smrg 470d514b0f3Smrg return IFD_NO_SUCH_DEVICE; 471d514b0f3Smrg} 472d514b0f3Smrg 473d514b0f3SmrgRESPONSECODE IFDHSetProtocolParameters(DWORD Lun, DWORD Protocol, UCHAR Flags, 474d514b0f3Smrg UCHAR PTS1, UCHAR PTS2, UCHAR PTS3) 475d514b0f3Smrg{ 476d514b0f3Smrg if (Protocol == SCARD_PROTOCOL_T1) 477d514b0f3Smrg return IFD_SUCCESS; 478d514b0f3Smrg 479d514b0f3Smrg return IFD_NOT_SUPPORTED; 480d514b0f3Smrg} 481d514b0f3Smrg 482d514b0f3SmrgRESPONSECODE IFDHControl(DWORD Lun, DWORD dwControlCode, PUCHAR 483d514b0f3Smrg TxBuffer, DWORD TxLength, PUCHAR RxBuffer, DWORD RxLength, 484d514b0f3Smrg LPDWORD pdwBytesReturned) 485d514b0f3Smrg{ 486d514b0f3Smrg fprintf(stderr, "spiceccid %s unsupported: Lun %ld\n", __FUNCTION__, Lun); 487d514b0f3Smrg return IFD_ERROR_NOT_SUPPORTED; 488d514b0f3Smrg} 489