]>
Commit | Line | Data |
---|---|---|
111a38b0 RR |
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 | ||
7267c094 | 49 | reader = (VReader *)g_malloc(sizeof(VReader)); |
111a38b0 RR |
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) { | |
7267c094 | 90 | g_free(reader->name); |
111a38b0 RR |
91 | } |
92 | if (reader->reader_private_free) { | |
93 | reader->reader_private_free(reader->reader_private); | |
94 | } | |
7267c094 | 95 | g_free(reader); |
111a38b0 RR |
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 *) | |
7267c094 | 240 | g_malloc(sizeof(VReaderListEntry)); |
111a38b0 RR |
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); | |
7267c094 | 254 | g_free(entry); |
111a38b0 RR |
255 | } |
256 | ||
257 | ||
258 | static VReaderList * | |
259 | vreader_list_new(void) | |
260 | { | |
261 | VReaderList *new_reader_list; | |
262 | ||
7267c094 | 263 | new_reader_list = (VReaderList *)g_malloc(sizeof(VReaderList)); |
111a38b0 RR |
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; | |
7267c094 | 281 | g_free(list); |
111a38b0 RR |
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 |