1 /*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 2011
5 * Ludovic Rousseau <ludovic.rousseau@free.fr>
6 * Copyright (C) 2014
7 * Stefani Seibold <stefani@seibold.net>
8 *
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12
13 1. Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15 2. Redistributions in binary form must reproduce the above copyright
16 notice, this list of conditions and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
18 3. The name of the author may not be used to endorse or promote products
19 derived from this software without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /**
34 * @file
35 * @brief This provides a search API for hot plugable devices using libudev
36 */
37
38 #include "config.h"
39 #if defined(HAVE_LIBUDEV) && defined(USE_USB)
40
41 #define _GNU_SOURCE /* for asprintf(3) */
42 #include <string.h>
43 #include <stdio.h>
44 #include <dirent.h>
45 #include <stdlib.h>
46 #include <pthread.h>
47 #include <libudev.h>
48 #include <poll.h>
49 #include <ctype.h>
50
51 #include "debuglog.h"
52 #include "parser.h"
53 #include "readerfactory.h"
54 #include "sys_generic.h"
55 #include "hotplug.h"
56 #include "utils.h"
57
58 #ifndef TEMP_FAILURE_RETRY
59 #define TEMP_FAILURE_RETRY(expression) \
60 (__extension__ \
61 ({ long int __result; \
62 do __result = (long int) (expression); \
63 while (__result == -1L && errno == EINTR); \
64 __result; }))
65 #endif
66
67 #undef DEBUG_HOTPLUG
68
69 #define FALSE 0
70 #define TRUE 1
71
72 extern char Add_Interface_In_Name;
73 extern char Add_Serial_In_Name;
74
75 static pthread_t usbNotifyThread;
76 static int driverSize = -1;
77 static struct udev *Udev;
78
79
80 /**
81 * keep track of drivers in a dynamically allocated array
82 */
83 static struct _driverTracker
84 {
85 unsigned int manuID;
86 unsigned int productID;
87
88 char *bundleName;
89 char *libraryPath;
90 char *readerName;
91 char *CFBundleName;
92 } *driverTracker = NULL;
93 #define DRIVER_TRACKER_SIZE_STEP 10
94
95 /* The CCID driver already supports 176 readers.
96 * We start with a big array size to avoid reallocation. */
97 #define DRIVER_TRACKER_INITIAL_SIZE 200
98
99 /**
100 * keep track of PCSCLITE_MAX_READERS_CONTEXTS simultaneous readers
101 */
102 static struct _readerTracker
103 {
104 char *devpath; /**< device name seen by udev */
105 char *fullName; /**< full reader name (including serial number) */
106 char *sysname; /**< sysfs path */
107 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
108
109
HPReadBundleValues(void)110 static LONG HPReadBundleValues(void)
111 {
112 LONG rv;
113 DIR *hpDir;
114 struct dirent *currFP = NULL;
115 char fullPath[FILENAME_MAX];
116 char fullLibPath[FILENAME_MAX];
117 int listCount = 0;
118
119 hpDir = opendir(PCSCLITE_HP_DROPDIR);
120
121 if (NULL == hpDir)
122 {
123 Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
124 Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
125 return -1;
126 }
127
128 /* allocate a first array */
129 driverSize = DRIVER_TRACKER_INITIAL_SIZE;
130 driverTracker = calloc(driverSize, sizeof(*driverTracker));
131 if (NULL == driverTracker)
132 {
133 Log1(PCSC_LOG_CRITICAL, "Not enough memory");
134 (void)closedir(hpDir);
135 return -1;
136 }
137
138 #define GET_KEY(key, values) \
139 rv = LTPBundleFindValueWithKey(&plist, key, values); \
140 if (rv) \
141 { \
142 Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
143 fullPath); \
144 continue; \
145 }
146
147 while ((currFP = readdir(hpDir)) != 0)
148 {
149 if (strstr(currFP->d_name, ".bundle") != 0)
150 {
151 unsigned int alias;
152 list_t plist, *values;
153 list_t *manuIDs, *productIDs, *readerNames;
154 char *CFBundleName;
155 char *libraryPath;
156
157 /*
158 * The bundle exists - let's form a full path name and get the
159 * vendor and product ID's for this particular bundle
160 */
161 (void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
162 PCSCLITE_HP_DROPDIR, currFP->d_name);
163 fullPath[sizeof(fullPath) - 1] = '\0';
164
165 rv = bundleParse(fullPath, &plist);
166 if (rv)
167 continue;
168
169 /* get CFBundleExecutable */
170 GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
171 libraryPath = list_get_at(values, 0);
172 (void)snprintf(fullLibPath, sizeof(fullLibPath),
173 "%s/%s/Contents/%s/%s",
174 PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
175 libraryPath);
176 fullLibPath[sizeof(fullLibPath) - 1] = '\0';
177
178 GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
179 GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
180 GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
181
182 if ((list_size(manuIDs) != list_size(productIDs))
183 || (list_size(manuIDs) != list_size(readerNames)))
184 {
185 Log2(PCSC_LOG_CRITICAL, "Error parsing %s", fullPath);
186 (void)closedir(hpDir);
187 return -1;
188 }
189
190 /* Get CFBundleName */
191 rv = LTPBundleFindValueWithKey(&plist, PCSCLITE_HP_CFBUNDLE_NAME,
192 &values);
193 if (rv)
194 CFBundleName = NULL;
195 else
196 CFBundleName = strdup(list_get_at(values, 0));
197
198 /* while we find a nth ifdVendorID in Info.plist */
199 for (alias=0; alias<list_size(manuIDs); alias++)
200 {
201 char *value;
202
203 /* variables entries */
204 value = list_get_at(manuIDs, alias);
205 driverTracker[listCount].manuID = strtol(value, NULL, 16);
206
207 value = list_get_at(productIDs, alias);
208 driverTracker[listCount].productID = strtol(value, NULL, 16);
209
210 driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
211
212 /* constant entries for a same driver */
213 driverTracker[listCount].bundleName = strdup(currFP->d_name);
214 driverTracker[listCount].libraryPath = strdup(fullLibPath);
215 driverTracker[listCount].CFBundleName = CFBundleName;
216
217 #ifdef DEBUG_HOTPLUG
218 Log2(PCSC_LOG_INFO, "Found driver for: %s",
219 driverTracker[listCount].readerName);
220 #endif
221 listCount++;
222 if (listCount >= driverSize)
223 {
224 int i;
225
226 /* increase the array size */
227 driverSize += DRIVER_TRACKER_SIZE_STEP;
228 #ifdef DEBUG_HOTPLUG
229 Log2(PCSC_LOG_INFO,
230 "Increase driverTracker to %d entries", driverSize);
231 #endif
232
233 void* tmp = realloc(driverTracker,
234 driverSize * sizeof(*driverTracker));
235
236 if (NULL == tmp)
237 {
238 free(driverTracker);
239 Log1(PCSC_LOG_CRITICAL, "Not enough memory");
240 driverSize = -1;
241 (void)closedir(hpDir);
242 return -1;
243 }
244 driverTracker = tmp;
245
246 /* clean the newly allocated entries */
247 for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
248 {
249 driverTracker[i].manuID = 0;
250 driverTracker[i].productID = 0;
251 driverTracker[i].bundleName = NULL;
252 driverTracker[i].libraryPath = NULL;
253 driverTracker[i].readerName = NULL;
254 driverTracker[i].CFBundleName = NULL;
255 }
256 }
257 }
258 bundleRelease(&plist);
259 }
260 }
261
262 driverSize = listCount;
263 (void)closedir(hpDir);
264
265 #ifdef DEBUG_HOTPLUG
266 Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
267 #endif
268
269 return 0;
270 } /* HPReadBundleValues */
271
272
get_driver(struct udev_device * dev,const char * devpath,struct _driverTracker ** classdriver)273 /*@null@*/ static struct _driverTracker *get_driver(struct udev_device *dev,
274 const char *devpath, struct _driverTracker **classdriver)
275 {
276 int i;
277 unsigned int idVendor, idProduct;
278 static struct _driverTracker *driver;
279 const char *str;
280
281 str = udev_device_get_sysattr_value(dev, "idVendor");
282 if (!str)
283 {
284 Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
285 return NULL;
286 }
287 idVendor = strtol(str, NULL, 16);
288
289 str = udev_device_get_sysattr_value(dev, "idProduct");
290 if (!str)
291 {
292 Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
293 return NULL;
294 }
295 idProduct = strtol(str, NULL, 16);
296
297 #ifdef NO_LOG
298 (void)devpath;
299 #endif
300 Log4(PCSC_LOG_DEBUG,
301 "Looking for a driver for VID: 0x%04X, PID: 0x%04X, path: %s",
302 idVendor, idProduct, devpath);
303
304 *classdriver = NULL;
305 driver = NULL;
306 /* check if the device is supported by one driver */
307 for (i=0; i<driverSize; i++)
308 {
309 if (driverTracker[i].libraryPath != NULL &&
310 idVendor == driverTracker[i].manuID &&
311 idProduct == driverTracker[i].productID)
312 {
313 if ((driverTracker[i].CFBundleName != NULL)
314 && (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
315 *classdriver = &driverTracker[i];
316 else
317 /* it is not a CCID Class driver */
318 driver = &driverTracker[i];
319 }
320 }
321
322 /* if we found a specific driver */
323 if (driver)
324 return driver;
325
326 /* else return the Class driver (if any) */
327 return *classdriver;
328 }
329
330
HPRemoveDevice(struct udev_device * dev)331 static void HPRemoveDevice(struct udev_device *dev)
332 {
333 int i;
334 const char *devpath;
335 struct udev_device *parent;
336 const char *sysname;
337
338 /* The device pointed to by dev contains information about
339 the interface. In order to get information about the USB
340 device, get the parent device with the subsystem/devtype pair
341 of "usb"/"usb_device". This will be several levels up the
342 tree, but the function will find it.*/
343 parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
344 "usb_device");
345 if (!parent)
346 return;
347
348 devpath = udev_device_get_devnode(parent);
349 if (!devpath)
350 {
351 /* the device disapeared? */
352 Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
353 return;
354 }
355
356 sysname = udev_device_get_sysname(dev);
357 if (!sysname)
358 {
359 Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
360 return;
361 }
362
363 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
364 {
365 if (readerTracker[i].fullName && !strcmp(sysname, readerTracker[i].sysname))
366 {
367 Log4(PCSC_LOG_INFO, "Removing USB device[%d]: %s at %s", i,
368 readerTracker[i].fullName, readerTracker[i].devpath);
369
370 RFRemoveReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i);
371
372 free(readerTracker[i].devpath);
373 readerTracker[i].devpath = NULL;
374 free(readerTracker[i].fullName);
375 readerTracker[i].fullName = NULL;
376 free(readerTracker[i].sysname);
377 readerTracker[i].sysname = NULL;
378 break;
379 }
380 }
381 }
382
383
HPAddDevice(struct udev_device * dev)384 static void HPAddDevice(struct udev_device *dev)
385 {
386 int index, a;
387 char *deviceName = NULL;
388 char *fullname = NULL;
389 struct _driverTracker *driver, *classdriver;
390 const char *sSerialNumber = NULL, *sInterfaceName = NULL;
391 const char *sInterfaceNumber;
392 LONG ret;
393 int bInterfaceNumber;
394 const char *devpath;
395 struct udev_device *parent;
396 const char *sysname;
397
398 /* The device pointed to by dev contains information about
399 the interface. In order to get information about the USB
400 device, get the parent device with the subsystem/devtype pair
401 of "usb"/"usb_device". This will be several levels up the
402 tree, but the function will find it.*/
403 parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
404 "usb_device");
405 if (!parent)
406 return;
407
408 devpath = udev_device_get_devnode(parent);
409 if (!devpath)
410 {
411 /* the device disapeared? */
412 Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
413 return;
414 }
415
416 driver = get_driver(parent, devpath, &classdriver);
417 if (NULL == driver)
418 {
419 /* not a smart card reader */
420 #ifdef DEBUG_HOTPLUG
421 Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader",
422 devpath);
423 #endif
424 return;
425 }
426
427 sysname = udev_device_get_sysname(dev);
428 if (!sysname)
429 {
430 Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
431 return;
432 }
433
434 /* check for duplicated add */
435 for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
436 {
437 if (readerTracker[index].fullName && !strcmp(sysname, readerTracker[index].sysname))
438 return;
439 }
440
441 Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
442
443 sInterfaceNumber = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
444 if (sInterfaceNumber)
445 bInterfaceNumber = atoi(sInterfaceNumber);
446 else
447 bInterfaceNumber = 0;
448
449 a = asprintf(&deviceName, "usb:%04x/%04x:libudev:%d:%s",
450 driver->manuID, driver->productID, bInterfaceNumber, devpath);
451 if (-1 == a)
452 {
453 Log1(PCSC_LOG_ERROR, "asprintf() failed");
454 return;
455 }
456
457 /* find a free entry */
458 for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
459 {
460 if (NULL == readerTracker[index].fullName)
461 break;
462 }
463
464 if (PCSCLITE_MAX_READERS_CONTEXTS == index)
465 {
466 Log2(PCSC_LOG_ERROR,
467 "Not enough reader entries. Already found %d readers", index);
468 return;
469 }
470
471 if (Add_Interface_In_Name)
472 sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
473
474 if (Add_Serial_In_Name)
475 sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
476
477 /* name from the Info.plist file */
478 fullname = strdup(driver->readerName);
479
480 /* interface name from the device (if any) */
481 if (sInterfaceName)
482 {
483 char *result;
484
485 char *tmpInterfaceName = strdup(sInterfaceName);
486
487 /* check the interface name contains only valid ASCII codes */
488 for (size_t i=0; i<strlen(tmpInterfaceName); i++)
489 {
490 if (! isascii(tmpInterfaceName[i]))
491 tmpInterfaceName[i] = '.';
492 }
493
494 /* create a new name */
495 a = asprintf(&result, "%s [%s]", fullname, tmpInterfaceName);
496 if (-1 == a)
497 {
498 Log1(PCSC_LOG_ERROR, "asprintf() failed");
499 free(tmpInterfaceName);
500 goto exit;
501 }
502
503 free(fullname);
504 free(tmpInterfaceName);
505 fullname = result;
506 }
507
508 /* serial number from the device (if any) */
509 if (sSerialNumber)
510 {
511 /* only add the serial number if it is not already present in the
512 * interface name */
513 if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
514 {
515 char *result;
516
517 /* create a new name */
518 a = asprintf(&result, "%s (%s)", fullname, sSerialNumber);
519 if (-1 == a)
520 {
521 Log1(PCSC_LOG_ERROR, "asprintf() failed");
522 goto exit;
523 }
524
525 free(fullname);
526 fullname = result;
527 }
528 }
529
530 readerTracker[index].fullName = strdup(fullname);
531 readerTracker[index].devpath = strdup(devpath);
532 readerTracker[index].sysname = strdup(sysname);
533
534 ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
535 driver->libraryPath, deviceName);
536 if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
537 {
538 Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
539 driver->readerName);
540
541 if (classdriver && driver != classdriver)
542 {
543 /* the reader can also be used by the a class driver */
544 ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
545 classdriver->libraryPath, deviceName);
546 if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
547 {
548 Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
549 driver->readerName);
550 (void)CheckForOpenCT();
551 }
552 }
553 else
554 {
555 (void)CheckForOpenCT();
556 }
557 }
558
559 if (SCARD_S_SUCCESS != ret)
560 {
561 /* adding the reader failed */
562 free(readerTracker[index].devpath);
563 readerTracker[index].devpath = NULL;
564 free(readerTracker[index].fullName);
565 readerTracker[index].fullName = NULL;
566 free(readerTracker[index].sysname);
567 readerTracker[index].sysname = NULL;
568 }
569
570 exit:
571 free(fullname);
572 free(deviceName);
573 } /* HPAddDevice */
574
575
HPScanUSB(struct udev * udev)576 static void HPScanUSB(struct udev *udev)
577 {
578 struct udev_enumerate *enumerate;
579 struct udev_list_entry *devices, *dev_list_entry;
580
581 /* Create a list of the devices in the 'usb' subsystem. */
582 enumerate = udev_enumerate_new(udev);
583 udev_enumerate_add_match_subsystem(enumerate, "usb");
584 udev_enumerate_scan_devices(enumerate);
585 devices = udev_enumerate_get_list_entry(enumerate);
586
587 /* For each item enumerated */
588 udev_list_entry_foreach(dev_list_entry, devices)
589 {
590 struct udev_device *dev;
591 const char *devpath;
592
593 /* Get the filename of the /sys entry for the device
594 and create a udev_device object (dev) representing it */
595 devpath = udev_list_entry_get_name(dev_list_entry);
596 dev = udev_device_new_from_syspath(udev, devpath);
597
598 #ifdef DEBUG_HOTPLUG
599 Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
600 #endif
601 HPAddDevice(dev);
602
603 /* free device */
604 udev_device_unref(dev);
605 }
606
607 /* Free the enumerator object */
608 udev_enumerate_unref(enumerate);
609 }
610
611
HPEstablishUSBNotifications(void * arg)612 static void * HPEstablishUSBNotifications(void *arg)
613 {
614 struct udev_monitor *udev_monitor = arg;
615 int r;
616 int fd;
617 struct pollfd pfd;
618
619 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
620 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
621
622 /* udev monitor file descriptor */
623 fd = udev_monitor_get_fd(udev_monitor);
624 if (fd < 0)
625 {
626 Log2(PCSC_LOG_ERROR, "udev_monitor_get_fd() error: %d", fd);
627 pthread_exit(NULL);
628 }
629
630 pfd.fd = fd;
631 pfd.events = POLLIN;
632
633 for (;;)
634 {
635 struct udev_device *dev;
636
637 #ifdef DEBUG_HOTPLUG
638 Log0(PCSC_LOG_INFO);
639 #endif
640 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
641
642 /* wait for a udev event */
643 r = TEMP_FAILURE_RETRY(poll(&pfd, 1, -1));
644 if (r < 0)
645 {
646 Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno));
647 pthread_exit(NULL);
648 }
649
650 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
651
652 dev = udev_monitor_receive_device(udev_monitor);
653 if (dev)
654 {
655 const char *action = udev_device_get_action(dev);
656
657 if (action)
658 {
659 if (!strcmp("remove", action))
660 {
661 Log1(PCSC_LOG_INFO, "USB Device removed");
662 HPRemoveDevice(dev);
663 }
664 else
665 if (!strcmp("add", action))
666 {
667 Log1(PCSC_LOG_INFO, "USB Device add");
668 HPAddDevice(dev);
669 }
670 }
671
672 /* free device */
673 udev_device_unref(dev);
674 }
675 }
676
677 pthread_exit(NULL);
678 } /* HPEstablishUSBNotifications */
679
680
681 /***
682 * Start a thread waiting for hotplug events
683 */
HPSearchHotPluggables(void)684 LONG HPSearchHotPluggables(void)
685 {
686 int i;
687
688 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
689 {
690 readerTracker[i].devpath = NULL;
691 readerTracker[i].fullName = NULL;
692 readerTracker[i].sysname = NULL;
693 }
694
695 return HPReadBundleValues();
696 } /* HPSearchHotPluggables */
697
698
699 /**
700 * Stop the hotplug thread
701 */
HPStopHotPluggables(void)702 LONG HPStopHotPluggables(void)
703 {
704 int i;
705
706 if (driverSize <= 0)
707 return 0;
708
709 if (!Udev)
710 return 0;
711
712 pthread_cancel(usbNotifyThread);
713 pthread_join(usbNotifyThread, NULL);
714
715 for (i=0; i<driverSize; i++)
716 {
717 /* free strings allocated by strdup() */
718 free(driverTracker[i].bundleName);
719 free(driverTracker[i].libraryPath);
720 free(driverTracker[i].readerName);
721 }
722 free(driverTracker);
723
724 udev_unref(Udev);
725
726 Udev = NULL;
727 driverSize = -1;
728
729 Log1(PCSC_LOG_INFO, "Hotplug stopped");
730 return 0;
731 } /* HPStopHotPluggables */
732
733
734 /**
735 * Sets up callbacks for device hotplug events.
736 */
HPRegisterForHotplugEvents(void)737 ULONG HPRegisterForHotplugEvents(void)
738 {
739 struct udev_monitor *udev_monitor;
740 int r;
741
742 if (driverSize <= 0)
743 {
744 Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: "
745 PCSCLITE_HP_DROPDIR);
746 Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
747 return 0;
748 }
749
750 /* Create the udev object */
751 Udev = udev_new();
752 if (!Udev)
753 {
754 Log1(PCSC_LOG_ERROR, "udev_new() failed");
755 return SCARD_F_INTERNAL_ERROR;
756 }
757
758 udev_monitor = udev_monitor_new_from_netlink(Udev, "udev");
759 if (NULL == udev_monitor)
760 {
761 Log1(PCSC_LOG_ERROR, "udev_monitor_new_from_netlink() error");
762 pthread_exit(NULL);
763 }
764
765 /* filter only the interfaces */
766 r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb",
767 "usb_interface");
768 if (r)
769 {
770 Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
771 pthread_exit(NULL);
772 }
773
774 r = udev_monitor_enable_receiving(udev_monitor);
775 if (r)
776 {
777 Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
778 pthread_exit(NULL);
779 }
780
781 /* scan the USB bus at least once before accepting client connections */
782 HPScanUSB(Udev);
783
784 if (ThreadCreate(&usbNotifyThread, 0,
785 (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, udev_monitor))
786 {
787 Log1(PCSC_LOG_ERROR, "ThreadCreate() failed");
788 return SCARD_F_INTERNAL_ERROR;
789 }
790
791 return 0;
792 } /* HPRegisterForHotplugEvents */
793
794
HPReCheckSerialReaders(void)795 void HPReCheckSerialReaders(void)
796 {
797 /* nothing to do here */
798 #ifdef DEBUG_HOTPLUG
799 Log0(PCSC_LOG_ERROR);
800 #endif
801 } /* HPReCheckSerialReaders */
802
803 #endif
804
805