File: | libcacard/vreader.c |
Location: | line 288, column 20 |
Description: | Access to field 'b_total_len' results in a dereference of a null pointer (loaded from variable 'response') |
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 | #ifdef G_LOG_DOMAIN"libcacard" | |||||
9 | #undef G_LOG_DOMAIN"libcacard" | |||||
10 | #endif | |||||
11 | #define G_LOG_DOMAIN"libcacard" "libcacard" | |||||
12 | #include <glib.h> | |||||
13 | ||||||
14 | #include "qemu-common.h" | |||||
15 | #include "qemu/thread.h" | |||||
16 | ||||||
17 | #include "vcard.h" | |||||
18 | #include "vcard_emul.h" | |||||
19 | #include "card_7816.h" | |||||
20 | #include "vreader.h" | |||||
21 | #include "vevent.h" | |||||
22 | #include "cac.h" /* just for debugging defines */ | |||||
23 | ||||||
24 | #define LIBCACARD_LOG_DOMAIN"libcacard" "libcacard" | |||||
25 | ||||||
26 | struct VReaderStruct { | |||||
27 | int reference_count; | |||||
28 | VCard *card; | |||||
29 | char *name; | |||||
30 | vreader_id_t id; | |||||
31 | QemuMutex lock; | |||||
32 | VReaderEmul *reader_private; | |||||
33 | VReaderEmulFree reader_private_free; | |||||
34 | }; | |||||
35 | ||||||
36 | /* | |||||
37 | * Debug helpers | |||||
38 | */ | |||||
39 | ||||||
40 | static const char * | |||||
41 | apdu_ins_to_string(int ins) | |||||
42 | { | |||||
43 | switch (ins) { | |||||
44 | case VCARD7816_INS_MANAGE_CHANNEL0x70: | |||||
45 | return "manage channel"; | |||||
46 | case VCARD7816_INS_EXTERNAL_AUTHENTICATE0x82: | |||||
47 | return "external authenticate"; | |||||
48 | case VCARD7816_INS_GET_CHALLENGE0x84: | |||||
49 | return "get challenge"; | |||||
50 | case VCARD7816_INS_INTERNAL_AUTHENTICATE0x88: | |||||
51 | return "internal authenticate"; | |||||
52 | case VCARD7816_INS_ERASE_BINARY0x0e: | |||||
53 | return "erase binary"; | |||||
54 | case VCARD7816_INS_READ_BINARY0xb0: | |||||
55 | return "read binary"; | |||||
56 | case VCARD7816_INS_WRITE_BINARY0xd0: | |||||
57 | return "write binary"; | |||||
58 | case VCARD7816_INS_UPDATE_BINARY0xd6: | |||||
59 | return "update binary"; | |||||
60 | case VCARD7816_INS_READ_RECORD0xb2: | |||||
61 | return "read record"; | |||||
62 | case VCARD7816_INS_WRITE_RECORD0xd2: | |||||
63 | return "write record"; | |||||
64 | case VCARD7816_INS_UPDATE_RECORD0xdc: | |||||
65 | return "update record"; | |||||
66 | case VCARD7816_INS_APPEND_RECORD0xe2: | |||||
67 | return "append record"; | |||||
68 | case VCARD7816_INS_ENVELOPE0xc2: | |||||
69 | return "envelope"; | |||||
70 | case VCARD7816_INS_PUT_DATA0xda: | |||||
71 | return "put data"; | |||||
72 | case VCARD7816_INS_GET_DATA0xca: | |||||
73 | return "get data"; | |||||
74 | case VCARD7816_INS_SELECT_FILE0xa4: | |||||
75 | return "select file"; | |||||
76 | case VCARD7816_INS_VERIFY0x20: | |||||
77 | return "verify"; | |||||
78 | case VCARD7816_INS_GET_RESPONSE0xc0: | |||||
79 | return "get response"; | |||||
80 | case CAC_GET_PROPERTIES0x56: | |||||
81 | return "get properties"; | |||||
82 | case CAC_GET_ACR0x4c: | |||||
83 | return "get acr"; | |||||
84 | case CAC_READ_BUFFER0x52: | |||||
85 | return "read buffer"; | |||||
86 | case CAC_UPDATE_BUFFER0x58: | |||||
87 | return "update buffer"; | |||||
88 | case CAC_SIGN_DECRYPT0x42: | |||||
89 | return "sign decrypt"; | |||||
90 | case CAC_GET_CERTIFICATE0x36: | |||||
91 | return "get certificate"; | |||||
92 | } | |||||
93 | return "unknown"; | |||||
94 | } | |||||
95 | ||||||
96 | /* manage locking */ | |||||
97 | static inline void | |||||
98 | vreader_lock(VReader *reader) | |||||
99 | { | |||||
100 | qemu_mutex_lock(&reader->lock); | |||||
101 | } | |||||
102 | ||||||
103 | static inline void | |||||
104 | vreader_unlock(VReader *reader) | |||||
105 | { | |||||
106 | qemu_mutex_unlock(&reader->lock); | |||||
107 | } | |||||
108 | ||||||
109 | /* | |||||
110 | * vreader constructor | |||||
111 | */ | |||||
112 | VReader * | |||||
113 | vreader_new(const char *name, VReaderEmul *private, | |||||
114 | VReaderEmulFree private_free) | |||||
115 | { | |||||
116 | VReader *reader; | |||||
117 | ||||||
118 | reader = (VReader *)g_malloc(sizeof(VReader)); | |||||
119 | qemu_mutex_init(&reader->lock); | |||||
120 | reader->reference_count = 1; | |||||
121 | reader->name = g_strdup(name); | |||||
122 | reader->card = NULL((void*)0); | |||||
123 | reader->id = (vreader_id_t)-1; | |||||
124 | reader->reader_private = private; | |||||
125 | reader->reader_private_free = private_free; | |||||
126 | return reader; | |||||
127 | } | |||||
128 | ||||||
129 | /* get a reference */ | |||||
130 | VReader* | |||||
131 | vreader_reference(VReader *reader) | |||||
132 | { | |||||
133 | if (reader == NULL((void*)0)) { | |||||
134 | return NULL((void*)0); | |||||
135 | } | |||||
136 | vreader_lock(reader); | |||||
137 | reader->reference_count++; | |||||
138 | vreader_unlock(reader); | |||||
139 | return reader; | |||||
140 | } | |||||
141 | ||||||
142 | /* free a reference */ | |||||
143 | void | |||||
144 | vreader_free(VReader *reader) | |||||
145 | { | |||||
146 | if (reader == NULL((void*)0)) { | |||||
147 | return; | |||||
148 | } | |||||
149 | vreader_lock(reader); | |||||
150 | if (reader->reference_count-- > 1) { | |||||
151 | vreader_unlock(reader); | |||||
152 | return; | |||||
153 | } | |||||
154 | vreader_unlock(reader); | |||||
155 | if (reader->card) { | |||||
156 | vcard_free(reader->card); | |||||
157 | } | |||||
158 | if (reader->name) { | |||||
159 | g_free(reader->name); | |||||
160 | } | |||||
161 | if (reader->reader_private_free) { | |||||
162 | reader->reader_private_free(reader->reader_private); | |||||
163 | } | |||||
164 | g_free(reader); | |||||
165 | } | |||||
166 | ||||||
167 | static VCard * | |||||
168 | vreader_get_card(VReader *reader) | |||||
169 | { | |||||
170 | VCard *card; | |||||
171 | ||||||
172 | vreader_lock(reader); | |||||
173 | card = vcard_reference(reader->card); | |||||
174 | vreader_unlock(reader); | |||||
175 | return card; | |||||
176 | } | |||||
177 | ||||||
178 | VReaderStatus | |||||
179 | vreader_card_is_present(VReader *reader) | |||||
180 | { | |||||
181 | VCard *card = vreader_get_card(reader); | |||||
182 | ||||||
183 | if (card == NULL((void*)0)) { | |||||
184 | return VREADER_NO_CARD; | |||||
185 | } | |||||
186 | vcard_free(card); | |||||
187 | return VREADER_OK; | |||||
188 | } | |||||
189 | ||||||
190 | vreader_id_t | |||||
191 | vreader_get_id(VReader *reader) | |||||
192 | { | |||||
193 | if (reader == NULL((void*)0)) { | |||||
194 | return (vreader_id_t)-1; | |||||
195 | } | |||||
196 | return reader->id; | |||||
197 | } | |||||
198 | ||||||
199 | VReaderStatus | |||||
200 | vreader_set_id(VReader *reader, vreader_id_t id) | |||||
201 | { | |||||
202 | if (reader == NULL((void*)0)) { | |||||
203 | return VREADER_NO_CARD; | |||||
204 | } | |||||
205 | reader->id = id; | |||||
206 | return VREADER_OK; | |||||
207 | } | |||||
208 | ||||||
209 | const char * | |||||
210 | vreader_get_name(VReader *reader) | |||||
211 | { | |||||
212 | if (reader == NULL((void*)0)) { | |||||
213 | return NULL((void*)0); | |||||
214 | } | |||||
215 | return reader->name; | |||||
216 | } | |||||
217 | ||||||
218 | VReaderEmul * | |||||
219 | vreader_get_private(VReader *reader) | |||||
220 | { | |||||
221 | return reader->reader_private; | |||||
222 | } | |||||
223 | ||||||
224 | static VReaderStatus | |||||
225 | vreader_reset(VReader *reader, VCardPower power, unsigned char *atr, int *len) | |||||
226 | { | |||||
227 | VCard *card = vreader_get_card(reader); | |||||
228 | ||||||
229 | if (card == NULL((void*)0)) { | |||||
230 | return VREADER_NO_CARD; | |||||
231 | } | |||||
232 | /* | |||||
233 | * clean up our state | |||||
234 | */ | |||||
235 | vcard_reset(card, power); | |||||
236 | if (atr) { | |||||
237 | vcard_get_atr(card, atr, len); | |||||
238 | } | |||||
239 | vcard_free(card); /* free our reference */ | |||||
240 | return VREADER_OK; | |||||
241 | } | |||||
242 | ||||||
243 | VReaderStatus | |||||
244 | vreader_power_on(VReader *reader, unsigned char *atr, int *len) | |||||
245 | { | |||||
246 | return vreader_reset(reader, VCARD_POWER_ON, atr, len); | |||||
247 | } | |||||
248 | ||||||
249 | VReaderStatus | |||||
250 | vreader_power_off(VReader *reader) | |||||
251 | { | |||||
252 | return vreader_reset(reader, VCARD_POWER_OFF, NULL((void*)0), 0); | |||||
253 | } | |||||
254 | ||||||
255 | ||||||
256 | VReaderStatus | |||||
257 | vreader_xfr_bytes(VReader *reader, | |||||
258 | unsigned char *send_buf, int send_buf_len, | |||||
259 | unsigned char *receive_buf, int *receive_buf_len) | |||||
260 | { | |||||
261 | VCardAPDU *apdu; | |||||
262 | VCardResponse *response = NULL((void*)0); | |||||
263 | VCardStatus card_status; | |||||
264 | unsigned short status; | |||||
265 | VCard *card = vreader_get_card(reader); | |||||
266 | ||||||
267 | if (card == NULL((void*)0)) { | |||||
| ||||||
268 | return VREADER_NO_CARD; | |||||
269 | } | |||||
270 | ||||||
271 | apdu = vcard_apdu_new(send_buf, send_buf_len, &status); | |||||
272 | if (apdu == NULL((void*)0)) { | |||||
273 | response = vcard_make_response(status); | |||||
274 | card_status = VCARD_DONE; | |||||
275 | } else { | |||||
276 | g_debug("%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s\n",g_log ("libcacard", G_LOG_LEVEL_DEBUG, "%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s\n" , __func__, apdu->u.header->ah_cla, apdu->u.header-> ah_ins, apdu->u.header->ah_p1, apdu->u.header->ah_p2 , apdu->a_Lc, apdu->a_Le, apdu_ins_to_string(apdu->u .header->ah_ins)) | |||||
277 | __func__, apdu->a_cla, apdu->a_ins, apdu->a_p1, apdu->a_p2,g_log ("libcacard", G_LOG_LEVEL_DEBUG, "%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s\n" , __func__, apdu->u.header->ah_cla, apdu->u.header-> ah_ins, apdu->u.header->ah_p1, apdu->u.header->ah_p2 , apdu->a_Lc, apdu->a_Le, apdu_ins_to_string(apdu->u .header->ah_ins)) | |||||
278 | apdu->a_Lc, apdu->a_Le, apdu_ins_to_string(apdu->a_ins))g_log ("libcacard", G_LOG_LEVEL_DEBUG, "%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s\n" , __func__, apdu->u.header->ah_cla, apdu->u.header-> ah_ins, apdu->u.header->ah_p1, apdu->u.header->ah_p2 , apdu->a_Lc, apdu->a_Le, apdu_ins_to_string(apdu->u .header->ah_ins)); | |||||
279 | card_status = vcard_process_apdu(card, apdu, &response); | |||||
280 | if (response) { | |||||
281 | g_debug("%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)\n",g_log ("libcacard", G_LOG_LEVEL_DEBUG, "%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)\n" , __func__, response->b_status, response->b_sw1, response ->b_sw2, response->b_len, response->b_total_len) | |||||
282 | __func__, response->b_status, response->b_sw1,g_log ("libcacard", G_LOG_LEVEL_DEBUG, "%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)\n" , __func__, response->b_status, response->b_sw1, response ->b_sw2, response->b_len, response->b_total_len) | |||||
283 | response->b_sw2, response->b_len, response->b_total_len)g_log ("libcacard", G_LOG_LEVEL_DEBUG, "%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)\n" , __func__, response->b_status, response->b_sw1, response ->b_sw2, response->b_len, response->b_total_len); | |||||
284 | } | |||||
285 | } | |||||
286 | assert(card_status == VCARD_DONE)((card_status == VCARD_DONE) ? (void) (0) : __assert_fail ("card_status == VCARD_DONE" , "/home/stefan/src/qemu/qemu.org/qemu/libcacard/vreader.c", 286 , __PRETTY_FUNCTION__)); | |||||
287 | if (card_status == VCARD_DONE) { | |||||
288 | int size = MIN(*receive_buf_len, response->b_total_len)(((*receive_buf_len) < (response->b_total_len)) ? (*receive_buf_len ) : (response->b_total_len)); | |||||
| ||||||
289 | memcpy(receive_buf, response->b_data, size); | |||||
290 | *receive_buf_len = size; | |||||
291 | } | |||||
292 | vcard_response_delete(response); | |||||
293 | vcard_apdu_delete(apdu); | |||||
294 | vcard_free(card); /* free our reference */ | |||||
295 | return VREADER_OK; | |||||
296 | } | |||||
297 | ||||||
298 | struct VReaderListStruct { | |||||
299 | VReaderListEntry *head; | |||||
300 | VReaderListEntry *tail; | |||||
301 | }; | |||||
302 | ||||||
303 | struct VReaderListEntryStruct { | |||||
304 | VReaderListEntry *next; | |||||
305 | VReaderListEntry *prev; | |||||
306 | VReader *reader; | |||||
307 | }; | |||||
308 | ||||||
309 | ||||||
310 | static VReaderListEntry * | |||||
311 | vreader_list_entry_new(VReader *reader) | |||||
312 | { | |||||
313 | VReaderListEntry *new_reader_list_entry; | |||||
314 | ||||||
315 | new_reader_list_entry = (VReaderListEntry *) | |||||
316 | g_malloc(sizeof(VReaderListEntry)); | |||||
317 | new_reader_list_entry->next = NULL((void*)0); | |||||
318 | new_reader_list_entry->prev = NULL((void*)0); | |||||
319 | new_reader_list_entry->reader = vreader_reference(reader); | |||||
320 | return new_reader_list_entry; | |||||
321 | } | |||||
322 | ||||||
323 | static void | |||||
324 | vreader_list_entry_delete(VReaderListEntry *entry) | |||||
325 | { | |||||
326 | if (entry == NULL((void*)0)) { | |||||
327 | return; | |||||
328 | } | |||||
329 | vreader_free(entry->reader); | |||||
330 | g_free(entry); | |||||
331 | } | |||||
332 | ||||||
333 | ||||||
334 | static VReaderList * | |||||
335 | vreader_list_new(void) | |||||
336 | { | |||||
337 | VReaderList *new_reader_list; | |||||
338 | ||||||
339 | new_reader_list = (VReaderList *)g_malloc(sizeof(VReaderList)); | |||||
340 | new_reader_list->head = NULL((void*)0); | |||||
341 | new_reader_list->tail = NULL((void*)0); | |||||
342 | return new_reader_list; | |||||
343 | } | |||||
344 | ||||||
345 | void | |||||
346 | vreader_list_delete(VReaderList *list) | |||||
347 | { | |||||
348 | VReaderListEntry *current_entry; | |||||
349 | VReaderListEntry *next_entry = NULL((void*)0); | |||||
350 | for (current_entry = vreader_list_get_first(list); current_entry; | |||||
351 | current_entry = next_entry) { | |||||
352 | next_entry = vreader_list_get_next(current_entry); | |||||
353 | vreader_list_entry_delete(current_entry); | |||||
354 | } | |||||
355 | list->head = NULL((void*)0); | |||||
356 | list->tail = NULL((void*)0); | |||||
357 | g_free(list); | |||||
358 | } | |||||
359 | ||||||
360 | ||||||
361 | VReaderListEntry * | |||||
362 | vreader_list_get_first(VReaderList *list) | |||||
363 | { | |||||
364 | return list ? list->head : NULL((void*)0); | |||||
365 | } | |||||
366 | ||||||
367 | VReaderListEntry * | |||||
368 | vreader_list_get_next(VReaderListEntry *current) | |||||
369 | { | |||||
370 | return current ? current->next : NULL((void*)0); | |||||
371 | } | |||||
372 | ||||||
373 | VReader * | |||||
374 | vreader_list_get_reader(VReaderListEntry *entry) | |||||
375 | { | |||||
376 | return entry ? vreader_reference(entry->reader) : NULL((void*)0); | |||||
377 | } | |||||
378 | ||||||
379 | static void | |||||
380 | vreader_queue(VReaderList *list, VReaderListEntry *entry) | |||||
381 | { | |||||
382 | if (entry == NULL((void*)0)) { | |||||
383 | return; | |||||
384 | } | |||||
385 | entry->next = NULL((void*)0); | |||||
386 | entry->prev = list->tail; | |||||
387 | if (list->head) { | |||||
388 | list->tail->next = entry; | |||||
389 | } else { | |||||
390 | list->head = entry; | |||||
391 | } | |||||
392 | list->tail = entry; | |||||
393 | } | |||||
394 | ||||||
395 | static void | |||||
396 | vreader_dequeue(VReaderList *list, VReaderListEntry *entry) | |||||
397 | { | |||||
398 | if (entry == NULL((void*)0)) { | |||||
399 | return; | |||||
400 | } | |||||
401 | if (entry->next == NULL((void*)0)) { | |||||
402 | list->tail = entry->prev; | |||||
403 | } else if (entry->prev == NULL((void*)0)) { | |||||
404 | list->head = entry->next; | |||||
405 | } else { | |||||
406 | entry->prev->next = entry->next; | |||||
407 | entry->next->prev = entry->prev; | |||||
408 | } | |||||
409 | if ((list->tail == NULL((void*)0)) || (list->head == NULL((void*)0))) { | |||||
410 | list->head = list->tail = NULL((void*)0); | |||||
411 | } | |||||
412 | entry->next = entry->prev = NULL((void*)0); | |||||
413 | } | |||||
414 | ||||||
415 | static VReaderList *vreader_list; | |||||
416 | static QemuMutex vreader_list_mutex; | |||||
417 | ||||||
418 | static void | |||||
419 | vreader_list_init(void) | |||||
420 | { | |||||
421 | vreader_list = vreader_list_new(); | |||||
422 | qemu_mutex_init(&vreader_list_mutex); | |||||
423 | } | |||||
424 | ||||||
425 | static void | |||||
426 | vreader_list_lock(void) | |||||
427 | { | |||||
428 | qemu_mutex_lock(&vreader_list_mutex); | |||||
429 | } | |||||
430 | ||||||
431 | static void | |||||
432 | vreader_list_unlock(void) | |||||
433 | { | |||||
434 | qemu_mutex_unlock(&vreader_list_mutex); | |||||
435 | } | |||||
436 | ||||||
437 | static VReaderList * | |||||
438 | vreader_copy_list(VReaderList *list) | |||||
439 | { | |||||
440 | VReaderList *new_list = NULL((void*)0); | |||||
441 | VReaderListEntry *current_entry = NULL((void*)0); | |||||
442 | ||||||
443 | new_list = vreader_list_new(); | |||||
444 | if (new_list == NULL((void*)0)) { | |||||
445 | return NULL((void*)0); | |||||
446 | } | |||||
447 | for (current_entry = vreader_list_get_first(list); current_entry; | |||||
448 | current_entry = vreader_list_get_next(current_entry)) { | |||||
449 | VReader *reader = vreader_list_get_reader(current_entry); | |||||
450 | VReaderListEntry *new_entry = vreader_list_entry_new(reader); | |||||
451 | ||||||
452 | vreader_free(reader); | |||||
453 | vreader_queue(new_list, new_entry); | |||||
454 | } | |||||
455 | return new_list; | |||||
456 | } | |||||
457 | ||||||
458 | VReaderList * | |||||
459 | vreader_get_reader_list(void) | |||||
460 | { | |||||
461 | VReaderList *new_reader_list; | |||||
462 | ||||||
463 | vreader_list_lock(); | |||||
464 | new_reader_list = vreader_copy_list(vreader_list); | |||||
465 | vreader_list_unlock(); | |||||
466 | return new_reader_list; | |||||
467 | } | |||||
468 | ||||||
469 | VReader * | |||||
470 | vreader_get_reader_by_id(vreader_id_t id) | |||||
471 | { | |||||
472 | VReader *reader = NULL((void*)0); | |||||
473 | VReaderListEntry *current_entry = NULL((void*)0); | |||||
474 | ||||||
475 | if (id == (vreader_id_t) -1) { | |||||
476 | return NULL((void*)0); | |||||
477 | } | |||||
478 | ||||||
479 | vreader_list_lock(); | |||||
480 | for (current_entry = vreader_list_get_first(vreader_list); current_entry; | |||||
481 | current_entry = vreader_list_get_next(current_entry)) { | |||||
482 | VReader *creader = vreader_list_get_reader(current_entry); | |||||
483 | if (creader->id == id) { | |||||
484 | reader = creader; | |||||
485 | break; | |||||
486 | } | |||||
487 | vreader_free(creader); | |||||
488 | } | |||||
489 | vreader_list_unlock(); | |||||
490 | return reader; | |||||
491 | } | |||||
492 | ||||||
493 | VReader * | |||||
494 | vreader_get_reader_by_name(const char *name) | |||||
495 | { | |||||
496 | VReader *reader = NULL((void*)0); | |||||
497 | VReaderListEntry *current_entry = NULL((void*)0); | |||||
498 | ||||||
499 | vreader_list_lock(); | |||||
500 | for (current_entry = vreader_list_get_first(vreader_list); current_entry; | |||||
501 | current_entry = vreader_list_get_next(current_entry)) { | |||||
502 | VReader *creader = vreader_list_get_reader(current_entry); | |||||
503 | if (strcmp(creader->name, name) == 0) { | |||||
504 | reader = creader; | |||||
505 | break; | |||||
506 | } | |||||
507 | vreader_free(creader); | |||||
508 | } | |||||
509 | vreader_list_unlock(); | |||||
510 | return reader; | |||||
511 | } | |||||
512 | ||||||
513 | /* called from card_emul to initialize the readers */ | |||||
514 | VReaderStatus | |||||
515 | vreader_add_reader(VReader *reader) | |||||
516 | { | |||||
517 | VReaderListEntry *reader_entry; | |||||
518 | ||||||
519 | reader_entry = vreader_list_entry_new(reader); | |||||
520 | if (reader_entry == NULL((void*)0)) { | |||||
521 | return VREADER_OUT_OF_MEMORY; | |||||
522 | } | |||||
523 | vreader_list_lock(); | |||||
524 | vreader_queue(vreader_list, reader_entry); | |||||
525 | vreader_list_unlock(); | |||||
526 | vevent_queue_vevent(vevent_new(VEVENT_READER_INSERT, reader, NULL((void*)0))); | |||||
527 | return VREADER_OK; | |||||
528 | } | |||||
529 | ||||||
530 | ||||||
531 | VReaderStatus | |||||
532 | vreader_remove_reader(VReader *reader) | |||||
533 | { | |||||
534 | VReaderListEntry *current_entry; | |||||
535 | ||||||
536 | vreader_list_lock(); | |||||
537 | for (current_entry = vreader_list_get_first(vreader_list); current_entry; | |||||
538 | current_entry = vreader_list_get_next(current_entry)) { | |||||
539 | if (current_entry->reader == reader) { | |||||
540 | break; | |||||
541 | } | |||||
542 | } | |||||
543 | vreader_dequeue(vreader_list, current_entry); | |||||
544 | vreader_list_unlock(); | |||||
545 | vreader_list_entry_delete(current_entry); | |||||
546 | vevent_queue_vevent(vevent_new(VEVENT_READER_REMOVE, reader, NULL((void*)0))); | |||||
547 | return VREADER_OK; | |||||
548 | } | |||||
549 | ||||||
550 | /* | |||||
551 | * Generate VEVENT_CARD_INSERT or VEVENT_CARD_REMOVE based on vreader | |||||
552 | * state. Separated from vreader_insert_card to allow replaying events | |||||
553 | * for a given state. | |||||
554 | */ | |||||
555 | void | |||||
556 | vreader_queue_card_event(VReader *reader) | |||||
557 | { | |||||
558 | vevent_queue_vevent(vevent_new( | |||||
559 | reader->card ? VEVENT_CARD_INSERT : VEVENT_CARD_REMOVE, reader, | |||||
560 | reader->card)); | |||||
561 | } | |||||
562 | ||||||
563 | /* | |||||
564 | * insert/remove a new card. for removal, card == NULL | |||||
565 | */ | |||||
566 | VReaderStatus | |||||
567 | vreader_insert_card(VReader *reader, VCard *card) | |||||
568 | { | |||||
569 | vreader_lock(reader); | |||||
570 | if (reader->card) { | |||||
571 | /* decrement reference count */ | |||||
572 | vcard_free(reader->card); | |||||
573 | reader->card = NULL((void*)0); | |||||
574 | } | |||||
575 | reader->card = vcard_reference(card); | |||||
576 | vreader_unlock(reader); | |||||
577 | vreader_queue_card_event(reader); | |||||
578 | return VREADER_OK; | |||||
579 | } | |||||
580 | ||||||
581 | /* | |||||
582 | * initialize all the static reader structures | |||||
583 | */ | |||||
584 | void | |||||
585 | vreader_init(void) | |||||
586 | { | |||||
587 | vreader_list_init(); | |||||
588 | } | |||||
589 |