root / libcacard / vreader.c @ 92f562ec
History | View | Annotate | Download (11.2 kB)
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 |
|
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; |
25 |
}; |
26 |
|
27 |
/* manage locking */
|
28 |
static inline void |
29 |
vreader_lock(VReader *reader) |
30 |
{ |
31 |
qemu_mutex_lock(&reader->lock); |
32 |
} |
33 |
|
34 |
static inline void |
35 |
vreader_unlock(VReader *reader) |
36 |
{ |
37 |
qemu_mutex_unlock(&reader->lock); |
38 |
} |
39 |
|
40 |
/*
|
41 |
* vreader constructor
|
42 |
*/
|
43 |
VReader * |
44 |
vreader_new(const char *name, VReaderEmul *private, |
45 |
VReaderEmulFree private_free) |
46 |
{ |
47 |
VReader *reader; |
48 |
|
49 |
reader = (VReader *)g_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 */
|
61 |
VReader* |
62 |
vreader_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 */
|
74 |
void
|
75 |
vreader_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 |
g_free(reader->name); |
91 |
} |
92 |
if (reader->reader_private_free) {
|
93 |
reader->reader_private_free(reader->reader_private); |
94 |
} |
95 |
g_free(reader); |
96 |
return;
|
97 |
} |
98 |
|
99 |
static VCard *
|
100 |
vreader_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 |
|
110 |
VReaderStatus |
111 |
vreader_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 |
|
122 |
vreader_id_t |
123 |
vreader_get_id(VReader *reader) |
124 |
{ |
125 |
if (reader == NULL) { |
126 |
return (vreader_id_t)-1; |
127 |
} |
128 |
return reader->id;
|
129 |
} |
130 |
|
131 |
VReaderStatus |
132 |
vreader_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 |
|
141 |
const char * |
142 |
vreader_get_name(VReader *reader) |
143 |
{ |
144 |
if (reader == NULL) { |
145 |
return NULL; |
146 |
} |
147 |
return reader->name;
|
148 |
} |
149 |
|
150 |
VReaderEmul * |
151 |
vreader_get_private(VReader *reader) |
152 |
{ |
153 |
return reader->reader_private;
|
154 |
} |
155 |
|
156 |
static VReaderStatus
|
157 |
vreader_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 |
|
175 |
VReaderStatus |
176 |
vreader_power_on(VReader *reader, unsigned char *atr, int *len) |
177 |
{ |
178 |
return vreader_reset(reader, VCARD_POWER_ON, atr, len);
|
179 |
} |
180 |
|
181 |
VReaderStatus |
182 |
vreader_power_off(VReader *reader) |
183 |
{ |
184 |
return vreader_reset(reader, VCARD_POWER_OFF, NULL, 0); |
185 |
} |
186 |
|
187 |
|
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) |
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 |
|
222 |
struct VReaderListStruct {
|
223 |
VReaderListEntry *head; |
224 |
VReaderListEntry *tail; |
225 |
}; |
226 |
|
227 |
struct VReaderListEntryStruct {
|
228 |
VReaderListEntry *next; |
229 |
VReaderListEntry *prev; |
230 |
VReader *reader; |
231 |
}; |
232 |
|
233 |
|
234 |
static VReaderListEntry *
|
235 |
vreader_list_entry_new(VReader *reader) |
236 |
{ |
237 |
VReaderListEntry *new_reader_list_entry; |
238 |
|
239 |
new_reader_list_entry = (VReaderListEntry *) |
240 |
g_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 |
|
247 |
static void |
248 |
vreader_list_entry_delete(VReaderListEntry *entry) |
249 |
{ |
250 |
if (entry == NULL) { |
251 |
return;
|
252 |
} |
253 |
vreader_free(entry->reader); |
254 |
g_free(entry); |
255 |
} |
256 |
|
257 |
|
258 |
static VReaderList *
|
259 |
vreader_list_new(void)
|
260 |
{ |
261 |
VReaderList *new_reader_list; |
262 |
|
263 |
new_reader_list = (VReaderList *)g_malloc(sizeof(VReaderList));
|
264 |
new_reader_list->head = NULL;
|
265 |
new_reader_list->tail = NULL;
|
266 |
return new_reader_list;
|
267 |
} |
268 |
|
269 |
void
|
270 |
vreader_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 |
g_free(list); |
282 |
} |
283 |
|
284 |
|
285 |
VReaderListEntry * |
286 |
vreader_list_get_first(VReaderList *list) |
287 |
{ |
288 |
return list ? list->head : NULL; |
289 |
} |
290 |
|
291 |
VReaderListEntry * |
292 |
vreader_list_get_next(VReaderListEntry *current) |
293 |
{ |
294 |
return current ? current->next : NULL; |
295 |
} |
296 |
|
297 |
VReader * |
298 |
vreader_list_get_reader(VReaderListEntry *entry) |
299 |
{ |
300 |
return entry ? vreader_reference(entry->reader) : NULL; |
301 |
} |
302 |
|
303 |
static void |
304 |
vreader_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 |
|
319 |
static void |
320 |
vreader_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 |
|
339 |
static VReaderList *vreader_list;
|
340 |
static QemuMutex vreader_list_mutex;
|
341 |
|
342 |
static void |
343 |
vreader_list_init(void)
|
344 |
{ |
345 |
vreader_list = vreader_list_new(); |
346 |
qemu_mutex_init(&vreader_list_mutex); |
347 |
} |
348 |
|
349 |
static void |
350 |
vreader_list_lock(void)
|
351 |
{ |
352 |
qemu_mutex_lock(&vreader_list_mutex); |
353 |
} |
354 |
|
355 |
static void |
356 |
vreader_list_unlock(void)
|
357 |
{ |
358 |
qemu_mutex_unlock(&vreader_list_mutex); |
359 |
} |
360 |
|
361 |
static VReaderList *
|
362 |
vreader_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 |
|
382 |
VReaderList * |
383 |
vreader_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 |
|
393 |
VReader * |
394 |
vreader_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 |
|
417 |
VReader * |
418 |
vreader_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 */
|
438 |
VReaderStatus |
439 |
vreader_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 |
|
455 |
VReaderStatus |
456 |
vreader_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 |
*/
|
479 |
void
|
480 |
vreader_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 |
*/
|
490 |
VReaderStatus |
491 |
vreader_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 |
*/
|
508 |
void
|
509 |
vreader_init(void)
|
510 |
{ |
511 |
vreader_list_init(); |
512 |
} |
513 |
|