]>
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" | |
1de7afc9 | 9 | #include "qemu/thread.h" |
111a38b0 RR |
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; | |
be168af8 | 52 | reader->name = g_strdup(name); |
111a38b0 RR |
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 | } |
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 *) | |
7267c094 | 239 | g_malloc(sizeof(VReaderListEntry)); |
111a38b0 RR |
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); | |
7267c094 | 253 | g_free(entry); |
111a38b0 RR |
254 | } |
255 | ||
256 | ||
257 | static VReaderList * | |
258 | vreader_list_new(void) | |
259 | { | |
260 | VReaderList *new_reader_list; | |
261 | ||
7267c094 | 262 | new_reader_list = (VReaderList *)g_malloc(sizeof(VReaderList)); |
111a38b0 RR |
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; | |
7267c094 | 280 | g_free(list); |
111a38b0 RR |
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 |