Merge remote-tracking branch 'alon/pull-libcacard-1' into staging
[qemu.git] / libcacard / vreader.c
blob4a0125b0e2a9d1fd809cea05dab42ec7b27c50b7
1 /*
2 * emulate the reader
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 */
8 #include "qemu-common.h"
9 #include "qemu-thread.h"
11 #include "vcard.h"
12 #include "vcard_emul.h"
13 #include "card_7816.h"
14 #include "vreader.h"
15 #include "vevent.h"
17 struct 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;
27 /* manage locking */
28 static inline void
29 vreader_lock(VReader *reader)
31 qemu_mutex_lock(&reader->lock);
34 static inline void
35 vreader_unlock(VReader *reader)
37 qemu_mutex_unlock(&reader->lock);
41 * vreader constructor
43 VReader *
44 vreader_new(const char *name, VReaderEmul *private,
45 VReaderEmulFree private_free)
47 VReader *reader;
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;
60 /* get a reference */
61 VReader*
62 vreader_reference(VReader *reader)
64 if (reader == NULL) {
65 return NULL;
67 vreader_lock(reader);
68 reader->reference_count++;
69 vreader_unlock(reader);
70 return reader;
73 /* free a reference */
74 void
75 vreader_free(VReader *reader)
77 if (reader == NULL) {
78 return;
80 vreader_lock(reader);
81 if (reader->reference_count-- > 1) {
82 vreader_unlock(reader);
83 return;
85 vreader_unlock(reader);
86 if (reader->card) {
87 vcard_free(reader->card);
89 if (reader->name) {
90 qemu_free(reader->name);
92 if (reader->reader_private_free) {
93 reader->reader_private_free(reader->reader_private);
95 qemu_free(reader);
96 return;
99 static VCard *
100 vreader_get_card(VReader *reader)
102 VCard *card;
104 vreader_lock(reader);
105 card = vcard_reference(reader->card);
106 vreader_unlock(reader);
107 return card;
110 VReaderStatus
111 vreader_card_is_present(VReader *reader)
113 VCard *card = vreader_get_card(reader);
115 if (card == NULL) {
116 return VREADER_NO_CARD;
118 vcard_free(card);
119 return VREADER_OK;
122 vreader_id_t
123 vreader_get_id(VReader *reader)
125 if (reader == NULL) {
126 return (vreader_id_t)-1;
128 return reader->id;
131 VReaderStatus
132 vreader_set_id(VReader *reader, vreader_id_t id)
134 if (reader == NULL) {
135 return VREADER_NO_CARD;
137 reader->id = id;
138 return VREADER_OK;
141 const char *
142 vreader_get_name(VReader *reader)
144 if (reader == NULL) {
145 return NULL;
147 return reader->name;
150 VReaderEmul *
151 vreader_get_private(VReader *reader)
153 return reader->reader_private;
156 static VReaderStatus
157 vreader_reset(VReader *reader, VCardPower power, unsigned char *atr, int *len)
159 VCard *card = vreader_get_card(reader);
161 if (card == NULL) {
162 return VREADER_NO_CARD;
165 * clean up our state
167 vcard_reset(card, power);
168 if (atr) {
169 vcard_get_atr(card, atr, len);
171 vcard_free(card); /* free our reference */
172 return VREADER_OK;
175 VReaderStatus
176 vreader_power_on(VReader *reader, unsigned char *atr, int *len)
178 return vreader_reset(reader, VCARD_POWER_ON, atr, len);
181 VReaderStatus
182 vreader_power_off(VReader *reader)
184 return vreader_reset(reader, VCARD_POWER_OFF, NULL, 0);
188 VReaderStatus
189 vreader_xfr_bytes(VReader *reader,
190 unsigned char *send_buf, int send_buf_len,
191 unsigned char *receive_buf, int *receive_buf_len)
193 VCardAPDU *apdu;
194 VCardResponse *response = NULL;
195 VCardStatus card_status;
196 unsigned short status;
197 VCard *card = vreader_get_card(reader);
199 if (card == NULL) {
200 return VREADER_NO_CARD;
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);
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;
216 vcard_response_delete(response);
217 vcard_apdu_delete(apdu);
218 vcard_free(card); /* free our reference */
219 return VREADER_OK;
222 struct VReaderListStruct {
223 VReaderListEntry *head;
224 VReaderListEntry *tail;
227 struct VReaderListEntryStruct {
228 VReaderListEntry *next;
229 VReaderListEntry *prev;
230 VReader *reader;
234 static VReaderListEntry *
235 vreader_list_entry_new(VReader *reader)
237 VReaderListEntry *new_reader_list_entry;
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;
247 static void
248 vreader_list_entry_delete(VReaderListEntry *entry)
250 if (entry == NULL) {
251 return;
253 vreader_free(entry->reader);
254 qemu_free(entry);
258 static VReaderList *
259 vreader_list_new(void)
261 VReaderList *new_reader_list;
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;
269 void
270 vreader_list_delete(VReaderList *list)
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);
279 list->head = NULL;
280 list->tail = NULL;
281 qemu_free(list);
285 VReaderListEntry *
286 vreader_list_get_first(VReaderList *list)
288 return list ? list->head : NULL;
291 VReaderListEntry *
292 vreader_list_get_next(VReaderListEntry *current)
294 return current ? current->next : NULL;
297 VReader *
298 vreader_list_get_reader(VReaderListEntry *entry)
300 return entry ? vreader_reference(entry->reader) : NULL;
303 static void
304 vreader_queue(VReaderList *list, VReaderListEntry *entry)
306 if (entry == NULL) {
307 return;
309 entry->next = NULL;
310 entry->prev = list->tail;
311 if (list->head) {
312 list->tail->next = entry;
313 } else {
314 list->head = entry;
316 list->tail = entry;
319 static void
320 vreader_dequeue(VReaderList *list, VReaderListEntry *entry)
322 if (entry == NULL) {
323 return;
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;
333 if ((list->tail == NULL) || (list->head == NULL)) {
334 list->head = list->tail = NULL;
336 entry->next = entry->prev = NULL;
339 static VReaderList *vreader_list;
340 static QemuMutex vreader_list_mutex;
342 static void
343 vreader_list_init(void)
345 vreader_list = vreader_list_new();
346 qemu_mutex_init(&vreader_list_mutex);
349 static void
350 vreader_list_lock(void)
352 qemu_mutex_lock(&vreader_list_mutex);
355 static void
356 vreader_list_unlock(void)
358 qemu_mutex_unlock(&vreader_list_mutex);
361 static VReaderList *
362 vreader_copy_list(VReaderList *list)
364 VReaderList *new_list = NULL;
365 VReaderListEntry *current_entry = NULL;
367 new_list = vreader_list_new();
368 if (new_list == NULL) {
369 return NULL;
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);
376 vreader_free(reader);
377 vreader_queue(new_list, new_entry);
379 return new_list;
382 VReaderList *
383 vreader_get_reader_list(void)
385 VReaderList *new_reader_list;
387 vreader_list_lock();
388 new_reader_list = vreader_copy_list(vreader_list);
389 vreader_list_unlock();
390 return new_reader_list;
393 VReader *
394 vreader_get_reader_by_id(vreader_id_t id)
396 VReader *reader = NULL;
397 VReaderListEntry *current_entry = NULL;
399 if (id == (vreader_id_t) -1) {
400 return NULL;
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;
411 vreader_free(creader);
413 vreader_list_unlock();
414 return reader;
417 VReader *
418 vreader_get_reader_by_name(const char *name)
420 VReader *reader = NULL;
421 VReaderListEntry *current_entry = NULL;
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;
431 vreader_free(creader);
433 vreader_list_unlock();
434 return reader;
437 /* called from card_emul to initialize the readers */
438 VReaderStatus
439 vreader_add_reader(VReader *reader)
441 VReaderListEntry *reader_entry;
443 reader_entry = vreader_list_entry_new(reader);
444 if (reader_entry == NULL) {
445 return VREADER_OUT_OF_MEMORY;
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;
455 VReaderStatus
456 vreader_remove_reader(VReader *reader)
458 VReaderListEntry *current_entry;
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;
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;
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.
479 void
480 vreader_queue_card_event(VReader *reader)
482 vevent_queue_vevent(vevent_new(
483 reader->card ? VEVENT_CARD_INSERT : VEVENT_CARD_REMOVE, reader,
484 reader->card));
488 * insert/remove a new card. for removal, card == NULL
490 VReaderStatus
491 vreader_insert_card(VReader *reader, VCard *card)
493 vreader_lock(reader);
494 if (reader->card) {
495 /* decrement reference count */
496 vcard_free(reader->card);
497 reader->card = NULL;
499 reader->card = vcard_reference(card);
500 vreader_unlock(reader);
501 vreader_queue_card_event(reader);
502 return VREADER_OK;
506 * initialize all the static reader structures
508 void
509 vreader_init(void)
511 vreader_list_init();