root / libcacard / vreader.c @ 4d5b97da
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 |
} |
97 |
|
98 |
static VCard *
|
99 |
vreader_get_card(VReader *reader) |
100 |
{ |
101 |
VCard *card; |
102 |
|
103 |
vreader_lock(reader); |
104 |
card = vcard_reference(reader->card); |
105 |
vreader_unlock(reader); |
106 |
return card;
|
107 |
} |
108 |
|
109 |
VReaderStatus |
110 |
vreader_card_is_present(VReader *reader) |
111 |
{ |
112 |
VCard *card = vreader_get_card(reader); |
113 |
|
114 |
if (card == NULL) { |
115 |
return VREADER_NO_CARD;
|
116 |
} |
117 |
vcard_free(card); |
118 |
return VREADER_OK;
|
119 |
} |
120 |
|
121 |
vreader_id_t |
122 |
vreader_get_id(VReader *reader) |
123 |
{ |
124 |
if (reader == NULL) { |
125 |
return (vreader_id_t)-1; |
126 |
} |
127 |
return reader->id;
|
128 |
} |
129 |
|
130 |
VReaderStatus |
131 |
vreader_set_id(VReader *reader, vreader_id_t id) |
132 |
{ |
133 |
if (reader == NULL) { |
134 |
return VREADER_NO_CARD;
|
135 |
} |
136 |
reader->id = id; |
137 |
return VREADER_OK;
|
138 |
} |
139 |
|
140 |
const char * |
141 |
vreader_get_name(VReader *reader) |
142 |
{ |
143 |
if (reader == NULL) { |
144 |
return NULL; |
145 |
} |
146 |
return reader->name;
|
147 |
} |
148 |
|
149 |
VReaderEmul * |
150 |
vreader_get_private(VReader *reader) |
151 |
{ |
152 |
return reader->reader_private;
|
153 |
} |
154 |
|
155 |
static VReaderStatus
|
156 |
vreader_reset(VReader *reader, VCardPower power, unsigned char *atr, int *len) |
157 |
{ |
158 |
VCard *card = vreader_get_card(reader); |
159 |
|
160 |
if (card == NULL) { |
161 |
return VREADER_NO_CARD;
|
162 |
} |
163 |
/*
|
164 |
* clean up our state
|
165 |
*/
|
166 |
vcard_reset(card, power); |
167 |
if (atr) {
|
168 |
vcard_get_atr(card, atr, len); |
169 |
} |
170 |
vcard_free(card); /* free our reference */
|
171 |
return VREADER_OK;
|
172 |
} |
173 |
|
174 |
VReaderStatus |
175 |
vreader_power_on(VReader *reader, unsigned char *atr, int *len) |
176 |
{ |
177 |
return vreader_reset(reader, VCARD_POWER_ON, atr, len);
|
178 |
} |
179 |
|
180 |
VReaderStatus |
181 |
vreader_power_off(VReader *reader) |
182 |
{ |
183 |
return vreader_reset(reader, VCARD_POWER_OFF, NULL, 0); |
184 |
} |
185 |
|
186 |
|
187 |
VReaderStatus |
188 |
vreader_xfr_bytes(VReader *reader, |
189 |
unsigned char *send_buf, int send_buf_len, |
190 |
unsigned char *receive_buf, int *receive_buf_len) |
191 |
{ |
192 |
VCardAPDU *apdu; |
193 |
VCardResponse *response = NULL;
|
194 |
VCardStatus card_status; |
195 |
unsigned short status; |
196 |
VCard *card = vreader_get_card(reader); |
197 |
|
198 |
if (card == NULL) { |
199 |
return VREADER_NO_CARD;
|
200 |
} |
201 |
|
202 |
apdu = vcard_apdu_new(send_buf, send_buf_len, &status); |
203 |
if (apdu == NULL) { |
204 |
response = vcard_make_response(status); |
205 |
card_status = VCARD_DONE; |
206 |
} else {
|
207 |
card_status = vcard_process_apdu(card, apdu, &response); |
208 |
} |
209 |
assert(card_status == VCARD_DONE); |
210 |
if (card_status == VCARD_DONE) {
|
211 |
int size = MIN(*receive_buf_len, response->b_total_len);
|
212 |
memcpy(receive_buf, response->b_data, size); |
213 |
*receive_buf_len = size; |
214 |
} |
215 |
vcard_response_delete(response); |
216 |
vcard_apdu_delete(apdu); |
217 |
vcard_free(card); /* free our reference */
|
218 |
return VREADER_OK;
|
219 |
} |
220 |
|
221 |
struct VReaderListStruct {
|
222 |
VReaderListEntry *head; |
223 |
VReaderListEntry *tail; |
224 |
}; |
225 |
|
226 |
struct VReaderListEntryStruct {
|
227 |
VReaderListEntry *next; |
228 |
VReaderListEntry *prev; |
229 |
VReader *reader; |
230 |
}; |
231 |
|
232 |
|
233 |
static VReaderListEntry *
|
234 |
vreader_list_entry_new(VReader *reader) |
235 |
{ |
236 |
VReaderListEntry *new_reader_list_entry; |
237 |
|
238 |
new_reader_list_entry = (VReaderListEntry *) |
239 |
g_malloc(sizeof(VReaderListEntry));
|
240 |
new_reader_list_entry->next = NULL;
|
241 |
new_reader_list_entry->prev = NULL;
|
242 |
new_reader_list_entry->reader = vreader_reference(reader); |
243 |
return new_reader_list_entry;
|
244 |
} |
245 |
|
246 |
static void |
247 |
vreader_list_entry_delete(VReaderListEntry *entry) |
248 |
{ |
249 |
if (entry == NULL) { |
250 |
return;
|
251 |
} |
252 |
vreader_free(entry->reader); |
253 |
g_free(entry); |
254 |
} |
255 |
|
256 |
|
257 |
static VReaderList *
|
258 |
vreader_list_new(void)
|
259 |
{ |
260 |
VReaderList *new_reader_list; |
261 |
|
262 |
new_reader_list = (VReaderList *)g_malloc(sizeof(VReaderList));
|
263 |
new_reader_list->head = NULL;
|
264 |
new_reader_list->tail = NULL;
|
265 |
return new_reader_list;
|
266 |
} |
267 |
|
268 |
void
|
269 |
vreader_list_delete(VReaderList *list) |
270 |
{ |
271 |
VReaderListEntry *current_entry; |
272 |
VReaderListEntry *next_entry = NULL;
|
273 |
for (current_entry = vreader_list_get_first(list); current_entry;
|
274 |
current_entry = next_entry) { |
275 |
next_entry = vreader_list_get_next(current_entry); |
276 |
vreader_list_entry_delete(current_entry); |
277 |
} |
278 |
list->head = NULL;
|
279 |
list->tail = NULL;
|
280 |
g_free(list); |
281 |
} |
282 |
|
283 |
|
284 |
VReaderListEntry * |
285 |
vreader_list_get_first(VReaderList *list) |
286 |
{ |
287 |
return list ? list->head : NULL; |
288 |
} |
289 |
|
290 |
VReaderListEntry * |
291 |
vreader_list_get_next(VReaderListEntry *current) |
292 |
{ |
293 |
return current ? current->next : NULL; |
294 |
} |
295 |
|
296 |
VReader * |
297 |
vreader_list_get_reader(VReaderListEntry *entry) |
298 |
{ |
299 |
return entry ? vreader_reference(entry->reader) : NULL; |
300 |
} |
301 |
|
302 |
static void |
303 |
vreader_queue(VReaderList *list, VReaderListEntry *entry) |
304 |
{ |
305 |
if (entry == NULL) { |
306 |
return;
|
307 |
} |
308 |
entry->next = NULL;
|
309 |
entry->prev = list->tail; |
310 |
if (list->head) {
|
311 |
list->tail->next = entry; |
312 |
} else {
|
313 |
list->head = entry; |
314 |
} |
315 |
list->tail = entry; |
316 |
} |
317 |
|
318 |
static void |
319 |
vreader_dequeue(VReaderList *list, VReaderListEntry *entry) |
320 |
{ |
321 |
if (entry == NULL) { |
322 |
return;
|
323 |
} |
324 |
if (entry->next == NULL) { |
325 |
list->tail = entry->prev; |
326 |
} else if (entry->prev == NULL) { |
327 |
list->head = entry->next; |
328 |
} else {
|
329 |
entry->prev->next = entry->next; |
330 |
entry->next->prev = entry->prev; |
331 |
} |
332 |
if ((list->tail == NULL) || (list->head == NULL)) { |
333 |
list->head = list->tail = NULL;
|
334 |
} |
335 |
entry->next = entry->prev = NULL;
|
336 |
} |
337 |
|
338 |
static VReaderList *vreader_list;
|
339 |
static QemuMutex vreader_list_mutex;
|
340 |
|
341 |
static void |
342 |
vreader_list_init(void)
|
343 |
{ |
344 |
vreader_list = vreader_list_new(); |
345 |
qemu_mutex_init(&vreader_list_mutex); |
346 |
} |
347 |
|
348 |
static void |
349 |
vreader_list_lock(void)
|
350 |
{ |
351 |
qemu_mutex_lock(&vreader_list_mutex); |
352 |
} |
353 |
|
354 |
static void |
355 |
vreader_list_unlock(void)
|
356 |
{ |
357 |
qemu_mutex_unlock(&vreader_list_mutex); |
358 |
} |
359 |
|
360 |
static VReaderList *
|
361 |
vreader_copy_list(VReaderList *list) |
362 |
{ |
363 |
VReaderList *new_list = NULL;
|
364 |
VReaderListEntry *current_entry = NULL;
|
365 |
|
366 |
new_list = vreader_list_new(); |
367 |
if (new_list == NULL) { |
368 |
return NULL; |
369 |
} |
370 |
for (current_entry = vreader_list_get_first(list); current_entry;
|
371 |
current_entry = vreader_list_get_next(current_entry)) { |
372 |
VReader *reader = vreader_list_get_reader(current_entry); |
373 |
VReaderListEntry *new_entry = vreader_list_entry_new(reader); |
374 |
|
375 |
vreader_free(reader); |
376 |
vreader_queue(new_list, new_entry); |
377 |
} |
378 |
return new_list;
|
379 |
} |
380 |
|
381 |
VReaderList * |
382 |
vreader_get_reader_list(void)
|
383 |
{ |
384 |
VReaderList *new_reader_list; |
385 |
|
386 |
vreader_list_lock(); |
387 |
new_reader_list = vreader_copy_list(vreader_list); |
388 |
vreader_list_unlock(); |
389 |
return new_reader_list;
|
390 |
} |
391 |
|
392 |
VReader * |
393 |
vreader_get_reader_by_id(vreader_id_t id) |
394 |
{ |
395 |
VReader *reader = NULL;
|
396 |
VReaderListEntry *current_entry = NULL;
|
397 |
|
398 |
if (id == (vreader_id_t) -1) { |
399 |
return NULL; |
400 |
} |
401 |
|
402 |
vreader_list_lock(); |
403 |
for (current_entry = vreader_list_get_first(vreader_list); current_entry;
|
404 |
current_entry = vreader_list_get_next(current_entry)) { |
405 |
VReader *creader = vreader_list_get_reader(current_entry); |
406 |
if (creader->id == id) {
|
407 |
reader = creader; |
408 |
break;
|
409 |
} |
410 |
vreader_free(creader); |
411 |
} |
412 |
vreader_list_unlock(); |
413 |
return reader;
|
414 |
} |
415 |
|
416 |
VReader * |
417 |
vreader_get_reader_by_name(const char *name) |
418 |
{ |
419 |
VReader *reader = NULL;
|
420 |
VReaderListEntry *current_entry = NULL;
|
421 |
|
422 |
vreader_list_lock(); |
423 |
for (current_entry = vreader_list_get_first(vreader_list); current_entry;
|
424 |
current_entry = vreader_list_get_next(current_entry)) { |
425 |
VReader *creader = vreader_list_get_reader(current_entry); |
426 |
if (strcmp(creader->name, name) == 0) { |
427 |
reader = creader; |
428 |
break;
|
429 |
} |
430 |
vreader_free(creader); |
431 |
} |
432 |
vreader_list_unlock(); |
433 |
return reader;
|
434 |
} |
435 |
|
436 |
/* called from card_emul to initialize the readers */
|
437 |
VReaderStatus |
438 |
vreader_add_reader(VReader *reader) |
439 |
{ |
440 |
VReaderListEntry *reader_entry; |
441 |
|
442 |
reader_entry = vreader_list_entry_new(reader); |
443 |
if (reader_entry == NULL) { |
444 |
return VREADER_OUT_OF_MEMORY;
|
445 |
} |
446 |
vreader_list_lock(); |
447 |
vreader_queue(vreader_list, reader_entry); |
448 |
vreader_list_unlock(); |
449 |
vevent_queue_vevent(vevent_new(VEVENT_READER_INSERT, reader, NULL));
|
450 |
return VREADER_OK;
|
451 |
} |
452 |
|
453 |
|
454 |
VReaderStatus |
455 |
vreader_remove_reader(VReader *reader) |
456 |
{ |
457 |
VReaderListEntry *current_entry; |
458 |
|
459 |
vreader_list_lock(); |
460 |
for (current_entry = vreader_list_get_first(vreader_list); current_entry;
|
461 |
current_entry = vreader_list_get_next(current_entry)) { |
462 |
if (current_entry->reader == reader) {
|
463 |
break;
|
464 |
} |
465 |
} |
466 |
vreader_dequeue(vreader_list, current_entry); |
467 |
vreader_list_unlock(); |
468 |
vreader_list_entry_delete(current_entry); |
469 |
vevent_queue_vevent(vevent_new(VEVENT_READER_REMOVE, reader, NULL));
|
470 |
return VREADER_OK;
|
471 |
} |
472 |
|
473 |
/*
|
474 |
* Generate VEVENT_CARD_INSERT or VEVENT_CARD_REMOVE based on vreader
|
475 |
* state. Separated from vreader_insert_card to allow replaying events
|
476 |
* for a given state.
|
477 |
*/
|
478 |
void
|
479 |
vreader_queue_card_event(VReader *reader) |
480 |
{ |
481 |
vevent_queue_vevent(vevent_new( |
482 |
reader->card ? VEVENT_CARD_INSERT : VEVENT_CARD_REMOVE, reader, |
483 |
reader->card)); |
484 |
} |
485 |
|
486 |
/*
|
487 |
* insert/remove a new card. for removal, card == NULL
|
488 |
*/
|
489 |
VReaderStatus |
490 |
vreader_insert_card(VReader *reader, VCard *card) |
491 |
{ |
492 |
vreader_lock(reader); |
493 |
if (reader->card) {
|
494 |
/* decrement reference count */
|
495 |
vcard_free(reader->card); |
496 |
reader->card = NULL;
|
497 |
} |
498 |
reader->card = vcard_reference(card); |
499 |
vreader_unlock(reader); |
500 |
vreader_queue_card_event(reader); |
501 |
return VREADER_OK;
|
502 |
} |
503 |
|
504 |
/*
|
505 |
* initialize all the static reader structures
|
506 |
*/
|
507 |
void
|
508 |
vreader_init(void)
|
509 |
{ |
510 |
vreader_list_init(); |
511 |
} |
512 |
|