qemu/libcacard/vreader.c
<<
>>
Prefs
   1/*
   2 * emulate the reader
   3 *
   4 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
   5 * See the COPYING.LIB file in the top-level directory.
   6 */
   7
   8#include "qemu-common.h"
   9#include "qemu-thread.h"
  10
  11#include "vcard.h"
  12#include "vcard_emul.h"
  13#include "card_7816.h"
  14#include "vreader.h"
  15#include "vevent.h"
  16
  17struct VReaderStruct {
  18    int    reference_count;
  19    VCard *card;
  20    char *name;
  21    vreader_id_t id;
  22    QemuMutex lock;
  23    VReaderEmul  *reader_private;
  24    VReaderEmulFree reader_private_free;
  25};
  26
  27/* manage locking */
  28static inline void
  29vreader_lock(VReader *reader)
  30{
  31    qemu_mutex_lock(&reader->lock);
  32}
  33
  34static inline void
  35vreader_unlock(VReader *reader)
  36{
  37    qemu_mutex_unlock(&reader->lock);
  38}
  39
  40/*
  41 * vreader constructor
  42 */
  43VReader *
  44vreader_new(const char *name, VReaderEmul *private,
  45            VReaderEmulFree private_free)
  46{
  47    VReader *reader;
  48
  49    reader = (VReader *)qemu_malloc(sizeof(VReader));
  50    qemu_mutex_init(&reader->lock);
  51    reader->reference_count = 1;
  52    reader->name = name ? strdup(name) : NULL;
  53    reader->card = NULL;
  54    reader->id = (vreader_id_t)-1;
  55    reader->reader_private = private;
  56    reader->reader_private_free = private_free;
  57    return reader;
  58}
  59
  60/* get a reference */
  61VReader*
  62vreader_reference(VReader *reader)
  63{
  64    if (reader == NULL) {
  65        return NULL;
  66    }
  67    vreader_lock(reader);
  68    reader->reference_count++;
  69    vreader_unlock(reader);
  70    return reader;
  71}
  72
  73/* free a reference */
  74void
  75vreader_free(VReader *reader)
  76{
  77    if (reader == NULL) {
  78        return;
  79    }
  80    vreader_lock(reader);
  81    if (reader->reference_count-- > 1) {
  82        vreader_unlock(reader);
  83        return;
  84    }
  85    vreader_unlock(reader);
  86    if (reader->card) {
  87        vcard_free(reader->card);
  88    }
  89    if (reader->name) {
  90        qemu_free(reader->name);
  91    }
  92    if (reader->reader_private_free) {
  93        reader->reader_private_free(reader->reader_private);
  94    }
  95    qemu_free(reader);
  96    return;
  97}
  98
  99static VCard *
 100vreader_get_card(VReader *reader)
 101{
 102    VCard *card;
 103
 104    vreader_lock(reader);
 105    card = vcard_reference(reader->card);
 106    vreader_unlock(reader);
 107    return card;
 108}
 109
 110VReaderStatus
 111vreader_card_is_present(VReader *reader)
 112{
 113    VCard *card = vreader_get_card(reader);
 114
 115    if (card == NULL) {
 116        return VREADER_NO_CARD;
 117    }
 118    vcard_free(card);
 119    return VREADER_OK;
 120}
 121
 122vreader_id_t
 123vreader_get_id(VReader *reader)
 124{
 125    if (reader == NULL) {
 126        return (vreader_id_t)-1;
 127    }
 128    return reader->id;
 129}
 130
 131VReaderStatus
 132vreader_set_id(VReader *reader, vreader_id_t id)
 133{
 134    if (reader == NULL) {
 135        return VREADER_NO_CARD;
 136    }
 137    reader->id = id;
 138    return VREADER_OK;
 139}
 140
 141const char *
 142vreader_get_name(VReader *reader)
 143{
 144    if (reader == NULL) {
 145        return NULL;
 146    }
 147    return reader->name;
 148}
 149
 150VReaderEmul *
 151vreader_get_private(VReader *reader)
 152{
 153    return reader->reader_private;
 154}
 155
 156static VReaderStatus
 157vreader_reset(VReader *reader, VCardPower power, unsigned char *atr, int *len)
 158{
 159    VCard *card = vreader_get_card(reader);
 160
 161    if (card == NULL) {
 162        return VREADER_NO_CARD;
 163    }
 164    /*
 165     * clean up our state
 166     */
 167    vcard_reset(card, power);
 168    if (atr) {
 169        vcard_get_atr(card, atr, len);
 170    }
 171    vcard_free(card); /* free our reference */
 172    return VREADER_OK;
 173}
 174
 175VReaderStatus
 176vreader_power_on(VReader *reader, unsigned char *atr, int *len)
 177{
 178    return vreader_reset(reader, VCARD_POWER_ON, atr, len);
 179}
 180
 181VReaderStatus
 182vreader_power_off(VReader *reader)
 183{
 184    return vreader_reset(reader, VCARD_POWER_OFF, NULL, 0);
 185}
 186
 187
 188VReaderStatus
 189vreader_xfr_bytes(VReader *reader,
 190                  unsigned char *send_buf, int send_buf_len,
 191                  unsigned char *receive_buf, int *receive_buf_len)
 192{
 193    VCardAPDU *apdu;
 194    VCardResponse *response = NULL;
 195    VCardStatus card_status;
 196    unsigned short status;
 197    VCard *card = vreader_get_card(reader);
 198
 199    if (card == NULL) {
 200        return VREADER_NO_CARD;
 201    }
 202
 203    apdu = vcard_apdu_new(send_buf, send_buf_len, &status);
 204    if (apdu == NULL) {
 205        response = vcard_make_response(status);
 206        card_status = VCARD_DONE;
 207    } else {
 208        card_status = vcard_process_apdu(card, apdu, &response);
 209    }
 210    assert(card_status == VCARD_DONE);
 211    if (card_status == VCARD_DONE) {
 212        int size = MIN(*receive_buf_len, response->b_total_len);
 213        memcpy(receive_buf, response->b_data, size);
 214        *receive_buf_len = size;
 215    }
 216    vcard_response_delete(response);
 217    vcard_apdu_delete(apdu);
 218    vcard_free(card); /* free our reference */
 219    return VREADER_OK;
 220}
 221
 222struct VReaderListStruct {
 223    VReaderListEntry *head;
 224    VReaderListEntry *tail;
 225};
 226
 227struct VReaderListEntryStruct {
 228    VReaderListEntry *next;
 229    VReaderListEntry *prev;
 230    VReader *reader;
 231};
 232
 233
 234static VReaderListEntry *
 235vreader_list_entry_new(VReader *reader)
 236{
 237    VReaderListEntry *new_reader_list_entry;
 238
 239    new_reader_list_entry = (VReaderListEntry *)
 240                               qemu_malloc(sizeof(VReaderListEntry));
 241    new_reader_list_entry->next = NULL;
 242    new_reader_list_entry->prev = NULL;
 243    new_reader_list_entry->reader = vreader_reference(reader);
 244    return new_reader_list_entry;
 245}
 246
 247static void
 248vreader_list_entry_delete(VReaderListEntry *entry)
 249{
 250    if (entry == NULL) {
 251        return;
 252    }
 253    vreader_free(entry->reader);
 254    qemu_free(entry);
 255}
 256
 257
 258static VReaderList *
 259vreader_list_new(void)
 260{
 261    VReaderList *new_reader_list;
 262
 263    new_reader_list = (VReaderList *)qemu_malloc(sizeof(VReaderList));
 264    new_reader_list->head = NULL;
 265    new_reader_list->tail = NULL;
 266    return new_reader_list;
 267}
 268
 269void
 270vreader_list_delete(VReaderList *list)
 271{
 272    VReaderListEntry *current_entry;
 273    VReaderListEntry *next_entry = NULL;
 274    for (current_entry = vreader_list_get_first(list); current_entry;
 275         current_entry = next_entry) {
 276        next_entry = vreader_list_get_next(current_entry);
 277        vreader_list_entry_delete(current_entry);
 278    }
 279    list->head = NULL;
 280    list->tail = NULL;
 281    qemu_free(list);
 282}
 283
 284
 285VReaderListEntry *
 286vreader_list_get_first(VReaderList *list)
 287{
 288    return list ? list->head : NULL;
 289}
 290
 291VReaderListEntry *
 292vreader_list_get_next(VReaderListEntry *current)
 293{
 294    return current ? current->next : NULL;
 295}
 296
 297VReader *
 298vreader_list_get_reader(VReaderListEntry *entry)
 299{
 300    return entry ? vreader_reference(entry->reader) : NULL;
 301}
 302
 303static void
 304vreader_queue(VReaderList *list, VReaderListEntry *entry)
 305{
 306    if (entry == NULL) {
 307        return;
 308    }
 309    entry->next = NULL;
 310    entry->prev = list->tail;
 311    if (list->head) {
 312        list->tail->next = entry;
 313    } else {
 314        list->head = entry;
 315    }
 316    list->tail = entry;
 317}
 318
 319static void
 320vreader_dequeue(VReaderList *list, VReaderListEntry *entry)
 321{
 322    if (entry == NULL) {
 323        return;
 324    }
 325    if (entry->next == NULL) {
 326        list->tail = entry->prev;
 327    } else if (entry->prev == NULL) {
 328        list->head = entry->next;
 329    } else {
 330        entry->prev->next = entry->next;
 331        entry->next->prev = entry->prev;
 332    }
 333    if ((list->tail == NULL) || (list->head == NULL)) {
 334        list->head = list->tail = NULL;
 335    }
 336    entry->next = entry->prev = NULL;
 337}
 338
 339static VReaderList *vreader_list;
 340static QemuMutex vreader_list_mutex;
 341
 342static void
 343vreader_list_init(void)
 344{
 345    vreader_list = vreader_list_new();
 346    qemu_mutex_init(&vreader_list_mutex);
 347}
 348
 349static void
 350vreader_list_lock(void)
 351{
 352    qemu_mutex_lock(&vreader_list_mutex);
 353}
 354
 355static void
 356vreader_list_unlock(void)
 357{
 358    qemu_mutex_unlock(&vreader_list_mutex);
 359}
 360
 361static VReaderList *
 362vreader_copy_list(VReaderList *list)
 363{
 364    VReaderList *new_list = NULL;
 365    VReaderListEntry *current_entry = NULL;
 366
 367    new_list = vreader_list_new();
 368    if (new_list == NULL) {
 369        return NULL;
 370    }
 371    for (current_entry = vreader_list_get_first(list); current_entry;
 372         current_entry = vreader_list_get_next(current_entry)) {
 373        VReader *reader = vreader_list_get_reader(current_entry);
 374        VReaderListEntry *new_entry = vreader_list_entry_new(reader);
 375
 376        vreader_free(reader);
 377        vreader_queue(new_list, new_entry);
 378    }
 379    return new_list;
 380}
 381
 382VReaderList *
 383vreader_get_reader_list(void)
 384{
 385    VReaderList *new_reader_list;
 386
 387    vreader_list_lock();
 388    new_reader_list = vreader_copy_list(vreader_list);
 389    vreader_list_unlock();
 390    return new_reader_list;
 391}
 392
 393VReader *
 394vreader_get_reader_by_id(vreader_id_t id)
 395{
 396    VReader *reader = NULL;
 397    VReaderListEntry *current_entry = NULL;
 398
 399    if (id == (vreader_id_t) -1) {
 400        return NULL;
 401    }
 402
 403    vreader_list_lock();
 404    for (current_entry = vreader_list_get_first(vreader_list); current_entry;
 405            current_entry = vreader_list_get_next(current_entry)) {
 406        VReader *creader = vreader_list_get_reader(current_entry);
 407        if (creader->id == id) {
 408            reader = creader;
 409            break;
 410        }
 411        vreader_free(creader);
 412    }
 413    vreader_list_unlock();
 414    return reader;
 415}
 416
 417VReader *
 418vreader_get_reader_by_name(const char *name)
 419{
 420    VReader *reader = NULL;
 421    VReaderListEntry *current_entry = NULL;
 422
 423    vreader_list_lock();
 424    for (current_entry = vreader_list_get_first(vreader_list); current_entry;
 425            current_entry = vreader_list_get_next(current_entry)) {
 426        VReader *creader = vreader_list_get_reader(current_entry);
 427        if (strcmp(creader->name, name) == 0) {
 428            reader = creader;
 429            break;
 430        }
 431        vreader_free(creader);
 432    }
 433    vreader_list_unlock();
 434    return reader;
 435}
 436
 437/* called from card_emul to initialize the readers */
 438VReaderStatus
 439vreader_add_reader(VReader *reader)
 440{
 441    VReaderListEntry *reader_entry;
 442
 443    reader_entry = vreader_list_entry_new(reader);
 444    if (reader_entry == NULL) {
 445        return VREADER_OUT_OF_MEMORY;
 446    }
 447    vreader_list_lock();
 448    vreader_queue(vreader_list, reader_entry);
 449    vreader_list_unlock();
 450    vevent_queue_vevent(vevent_new(VEVENT_READER_INSERT, reader, NULL));
 451    return VREADER_OK;
 452}
 453
 454
 455VReaderStatus
 456vreader_remove_reader(VReader *reader)
 457{
 458    VReaderListEntry *current_entry;
 459
 460    vreader_list_lock();
 461    for (current_entry = vreader_list_get_first(vreader_list); current_entry;
 462         current_entry = vreader_list_get_next(current_entry)) {
 463        if (current_entry->reader == reader) {
 464            break;
 465        }
 466    }
 467    vreader_dequeue(vreader_list, current_entry);
 468    vreader_list_unlock();
 469    vreader_list_entry_delete(current_entry);
 470    vevent_queue_vevent(vevent_new(VEVENT_READER_REMOVE, reader, NULL));
 471    return VREADER_OK;
 472}
 473
 474/*
 475 * Generate VEVENT_CARD_INSERT or VEVENT_CARD_REMOVE based on vreader
 476 * state. Separated from vreader_insert_card to allow replaying events
 477 * for a given state.
 478 */
 479void
 480vreader_queue_card_event(VReader *reader)
 481{
 482    vevent_queue_vevent(vevent_new(
 483        reader->card ? VEVENT_CARD_INSERT : VEVENT_CARD_REMOVE, reader,
 484        reader->card));
 485}
 486
 487/*
 488 * insert/remove a new card. for removal, card == NULL
 489 */
 490VReaderStatus
 491vreader_insert_card(VReader *reader, VCard *card)
 492{
 493    vreader_lock(reader);
 494    if (reader->card) {
 495        /* decrement reference count */
 496        vcard_free(reader->card);
 497        reader->card = NULL;
 498    }
 499    reader->card = vcard_reference(card);
 500    vreader_unlock(reader);
 501    vreader_queue_card_event(reader);
 502    return VREADER_OK;
 503}
 504
 505/*
 506 * initialize all the static reader structures
 507 */
 508void
 509vreader_init(void)
 510{
 511    vreader_list_init();
 512}
 513
 514