pcsc-lite
1.8.2
|
00001 /* 00002 * MUSCLE SmartCard Development ( http://www.linuxnet.com ) 00003 * 00004 * Copyright (C) 2001-2003 00005 * David Corcoran <corcoran@linuxnet.com> 00006 * Copyright (C) 2002-2011 00007 * Ludovic Rousseau <ludovic.rousseau@free.fr> 00008 * 00009 * The USB code was based partly on Johannes Erdfelt 00010 * libusb code found at libusb.sourceforge.net 00011 * 00012 * $Id: hotplug_linux.c 5993 2011-10-04 07:51:33Z rousseau $ 00013 */ 00014 00020 #include "config.h" 00021 #include <string.h> 00022 00023 #if defined(__linux__) && !defined(HAVE_LIBUSB) && !defined(HAVE_LIBUDEV) 00024 #include <sys/types.h> 00025 #include <stdio.h> 00026 #include <dirent.h> 00027 #include <fcntl.h> 00028 #include <time.h> 00029 #include <stdlib.h> 00030 #include <unistd.h> 00031 #include <pthread.h> 00032 00033 #include "misc.h" 00034 #include "pcsclite.h" 00035 #include "pcscd.h" 00036 #include "debuglog.h" 00037 #include "parser.h" 00038 #include "readerfactory.h" 00039 #include "winscard_msg.h" 00040 #include "sys_generic.h" 00041 #include "hotplug.h" 00042 #include "utils.h" 00043 00044 #undef DEBUG_HOTPLUG 00045 #define PCSCLITE_USB_PATH "/proc/bus/usb" 00046 00047 #define FALSE 0 00048 #define TRUE 1 00049 00050 pthread_mutex_t usbNotifierMutex; 00051 00052 struct usb_device_descriptor 00053 { 00054 u_int8_t bLength; 00055 u_int8_t bDescriptorType; 00056 u_int16_t bcdUSB; 00057 u_int8_t bDeviceClass; 00058 u_int8_t bDeviceSubClass; 00059 u_int8_t bDeviceProtocol; 00060 u_int8_t bMaxPacketSize0; 00061 u_int16_t idVendor; 00062 u_int16_t idProduct; 00063 u_int16_t bcdDevice; 00064 u_int8_t iManufacturer; 00065 u_int8_t iProduct; 00066 u_int8_t iSerialNumber; 00067 u_int8_t bNumConfigurations; 00068 } 00069 __attribute__ ((packed)); 00070 00071 static LONG HPAddHotPluggable(int, unsigned long); 00072 static LONG HPRemoveHotPluggable(int, unsigned long); 00073 static LONG HPReadBundleValues(void); 00074 static void HPEstablishUSBNotifications(void); 00075 00076 static pthread_t usbNotifyThread; 00077 static int AraKiriHotPlug = FALSE; 00078 static int bundleSize = 0; 00079 00083 static struct _bundleTracker 00084 { 00085 long manuID; 00086 long productID; 00087 00088 struct _deviceNumber { 00089 int id; 00090 char status; 00091 } deviceNumber[PCSCLITE_MAX_READERS_CONTEXTS]; 00092 00093 char *bundleName; 00094 char *libraryPath; 00095 char *readerName; 00096 } 00097 bundleTracker[PCSCLITE_MAX_READERS_CONTEXTS]; 00098 00099 static LONG HPReadBundleValues(void) 00100 { 00101 LONG rv; 00102 DIR *hpDir; 00103 struct dirent *currFP = 0; 00104 char fullPath[FILENAME_MAX]; 00105 char fullLibPath[FILENAME_MAX]; 00106 unsigned int listCount = 0; 00107 00108 hpDir = opendir(PCSCLITE_HP_DROPDIR); 00109 00110 if (hpDir == NULL) 00111 { 00112 Log1(PCSC_LOG_INFO, 00113 "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR); 00114 Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd."); 00115 return -1; 00116 } 00117 00118 #define GET_KEY(key, values) \ 00119 rv = LTPBundleFindValueWithKey(&plist, key, values); \ 00120 if (rv) \ 00121 { \ 00122 Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \ 00123 fullPath); \ 00124 continue; \ 00125 } 00126 00127 while ((currFP = readdir(hpDir)) != 0) 00128 { 00129 if (strstr(currFP->d_name, ".bundle") != 0) 00130 { 00131 unsigned int alias; 00132 list_t plist, *values; 00133 list_t *manuIDs, *productIDs, *readerNames; 00134 char *libraryPath; 00135 00136 /* 00137 * The bundle exists - let's form a full path name and get the 00138 * vendor and product ID's for this particular bundle 00139 */ 00140 snprintf(fullPath, FILENAME_MAX, "%s/%s/Contents/Info.plist", 00141 PCSCLITE_HP_DROPDIR, currFP->d_name); 00142 fullPath[FILENAME_MAX - 1] = '\0'; 00143 00144 rv = bundleParse(fullPath, &plist); 00145 if (rv) 00146 continue; 00147 00148 /* get CFBundleExecutable */ 00149 GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values) 00150 libraryPath = list_get_at(values, 0); 00151 (void)snprintf(fullLibPath, sizeof(fullLibPath), 00152 "%s/%s/Contents/%s/%s", 00153 PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH, 00154 libraryPath); 00155 fullLibPath[sizeof(fullLibPath) - 1] = '\0'; 00156 00157 GET_KEY(PCSCLITE_HP_CPCTKEY_NAME, &values) 00158 GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs) 00159 GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs) 00160 GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames) 00161 00162 /* while we find a nth ifdVendorID in Info.plist */ 00163 for (alias=0; alias<list_size(manuIDs); alias++) 00164 { 00165 char *value; 00166 00167 /* variables entries */ 00168 value = list_get_at(manuIDs, alias); 00169 bundleTracker[listCount].manuID = strtol(value, NULL, 16); 00170 00171 value = list_get_at(productIDs, alias); 00172 bundleTracker[listCount].productID = strtol(value, NULL, 16); 00173 00174 bundleTracker[listCount].readerName = strdup(list_get_at(readerNames, alias)); 00175 00176 /* constant entries for a same driver */ 00177 bundleTracker[listCount].bundleName = strdup(currFP->d_name); 00178 bundleTracker[listCount].libraryPath = strdup(fullLibPath); 00179 00180 #ifdef DEBUG_HOTPLUG 00181 Log2(PCSC_LOG_INFO, "Found driver for: %s", 00182 bundleTracker[listCount].readerName); 00183 #endif 00184 listCount++; 00185 00186 if (listCount >= sizeof(bundleTracker)/sizeof(bundleTracker[0])) 00187 { 00188 Log2(PCSC_LOG_CRITICAL, "Too many readers declared. Maximum is %zd", sizeof(bundleTracker)/sizeof(bundleTracker[0])); 00189 goto end; 00190 } 00191 } 00192 bundleRelease(&plist); 00193 } 00194 } 00195 00196 end: 00197 bundleSize = listCount; 00198 00199 if (bundleSize == 0) 00200 { 00201 Log1(PCSC_LOG_INFO, 00202 "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR); 00203 Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd"); 00204 } 00205 00206 closedir(hpDir); 00207 return 0; 00208 } 00209 00210 static void HPEstablishUSBNotifications(void) 00211 { 00212 00213 int i, j, usbDeviceStatus; 00214 DIR *dir, *dirB; 00215 struct dirent *entry, *entryB; 00216 int deviceNumber; 00217 int suspectDeviceNumber; 00218 char dirpath[FILENAME_MAX]; 00219 char filename[FILENAME_MAX]; 00220 int fd, ret; 00221 struct usb_device_descriptor usbDescriptor; 00222 00223 usbDeviceStatus = 0; 00224 suspectDeviceNumber = 0; 00225 00226 while (1) 00227 { 00228 for (i = 0; i < bundleSize; i++) 00229 { 00230 usbDeviceStatus = 0; 00231 suspectDeviceNumber = 0; 00232 00233 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++) 00234 /* clear rollcall */ 00235 bundleTracker[i].deviceNumber[j].status = 0; 00236 00237 dir = NULL; 00238 dir = opendir(PCSCLITE_USB_PATH); 00239 if (dir == NULL) 00240 { 00241 Log1(PCSC_LOG_ERROR, 00242 "Cannot open USB path directory: " PCSCLITE_USB_PATH); 00243 return; 00244 } 00245 00246 entry = NULL; 00247 while ((entry = readdir(dir)) != 0) 00248 { 00249 00250 /* 00251 * Skip anything starting with a 00252 */ 00253 if (entry->d_name[0] == '.') 00254 continue; 00255 if (!strchr("0123456789", 00256 entry->d_name[strlen(entry->d_name) - 1])) 00257 { 00258 continue; 00259 } 00260 00261 snprintf(dirpath, sizeof dirpath, "%s/%s", 00262 PCSCLITE_USB_PATH, entry->d_name); 00263 00264 dirB = opendir(dirpath); 00265 00266 if (dirB == NULL) 00267 { 00268 Log2(PCSC_LOG_ERROR, 00269 "USB path seems to have disappeared %s", dirpath); 00270 closedir(dir); 00271 return; 00272 } 00273 00274 while ((entryB = readdir(dirB)) != NULL) 00275 { 00276 /* 00277 * Skip anything starting with a 00278 */ 00279 if (entryB->d_name[0] == '.') 00280 continue; 00281 00282 /* Get the device number so we can distinguish 00283 multiple readers */ 00284 snprintf(filename, sizeof filename, "%s/%s", 00285 dirpath, entryB->d_name); 00286 deviceNumber = atoi(entryB->d_name); 00287 00288 fd = open(filename, O_RDONLY); 00289 if (fd < 0) 00290 continue; 00291 00292 ret = read(fd, (void *) &usbDescriptor, 00293 sizeof(usbDescriptor)); 00294 00295 close(fd); 00296 00297 if (ret < 0) 00298 continue; 00299 00300 /* 00301 * Device is found and we don't know about it 00302 */ 00303 00304 if (usbDescriptor.idVendor == bundleTracker[i].manuID && 00305 usbDescriptor.idProduct == bundleTracker[i].productID && 00306 usbDescriptor.idVendor !=0 && 00307 usbDescriptor.idProduct != 0) 00308 { 00309 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++) 00310 { 00311 if (bundleTracker[i].deviceNumber[j].id == deviceNumber && 00312 bundleTracker[i].deviceNumber[j].id != 0) 00313 { 00314 bundleTracker[i].deviceNumber[j].status = 1; /* i'm here */ 00315 break; 00316 } 00317 } 00318 00319 if (j == PCSCLITE_MAX_READERS_CONTEXTS) 00320 { 00321 usbDeviceStatus = 1; 00322 suspectDeviceNumber = deviceNumber; 00323 } 00324 } 00325 00326 } /* End of while */ 00327 00328 closedir(dirB); 00329 00330 } /* End of while */ 00331 00332 00333 if (usbDeviceStatus == 1) 00334 { 00335 pthread_mutex_lock(&usbNotifierMutex); 00336 00337 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++) 00338 { 00339 if (bundleTracker[i].deviceNumber[j].id == 0) 00340 break; 00341 } 00342 00343 if (j == PCSCLITE_MAX_READERS_CONTEXTS) 00344 Log1(PCSC_LOG_ERROR, 00345 "Too many identical readers plugged in"); 00346 else 00347 { 00348 HPAddHotPluggable(i, j+1); 00349 bundleTracker[i].deviceNumber[j].id = suspectDeviceNumber; 00350 } 00351 00352 pthread_mutex_unlock(&usbNotifierMutex); 00353 } 00354 else 00355 if (usbDeviceStatus == 0) 00356 { 00357 00358 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++) 00359 { 00360 if (bundleTracker[i].deviceNumber[j].id != 0 && 00361 bundleTracker[i].deviceNumber[j].status == 0) 00362 { 00363 pthread_mutex_lock(&usbNotifierMutex); 00364 HPRemoveHotPluggable(i, j+1); 00365 bundleTracker[i].deviceNumber[j].id = 0; 00366 pthread_mutex_unlock(&usbNotifierMutex); 00367 } 00368 } 00369 } 00370 else 00371 { 00372 /* 00373 * Do nothing - no USB devices found 00374 */ 00375 } 00376 00377 if (dir) 00378 closedir(dir); 00379 00380 } /* End of for..loop */ 00381 00382 SYS_Sleep(1); 00383 if (AraKiriHotPlug) 00384 { 00385 int retval; 00386 00387 Log1(PCSC_LOG_INFO, "Hotplug stopped"); 00388 pthread_exit(&retval); 00389 } 00390 00391 } /* End of while loop */ 00392 } 00393 00394 LONG HPSearchHotPluggables(void) 00395 { 00396 int i, j; 00397 00398 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 00399 { 00400 bundleTracker[i].productID = 0; 00401 bundleTracker[i].manuID = 0; 00402 00403 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++) 00404 bundleTracker[i].deviceNumber[j].id = 0; 00405 } 00406 00407 HPReadBundleValues(); 00408 00409 ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED, 00410 (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, 0); 00411 00412 return 0; 00413 } 00414 00415 LONG HPStopHotPluggables(void) 00416 { 00417 AraKiriHotPlug = TRUE; 00418 00419 return 0; 00420 } 00421 00422 static LONG HPAddHotPluggable(int i, unsigned long usbAddr) 00423 { 00424 /* NOTE: The deviceName is an empty string "" until someone implements 00425 * the code to get it */ 00426 RFAddReader(bundleTracker[i].readerName, PCSCLITE_HP_BASE_PORT + usbAddr, 00427 bundleTracker[i].libraryPath, ""); 00428 00429 return 1; 00430 } /* End of function */ 00431 00432 static LONG HPRemoveHotPluggable(int i, unsigned long usbAddr) 00433 { 00434 RFRemoveReader(bundleTracker[i].readerName, PCSCLITE_HP_BASE_PORT + usbAddr); 00435 00436 return 1; 00437 } /* End of function */ 00438 00442 ULONG HPRegisterForHotplugEvents(void) 00443 { 00444 (void)pthread_mutex_init(&usbNotifierMutex, NULL); 00445 return 0; 00446 } 00447 00448 void HPReCheckSerialReaders(void) 00449 { 00450 } 00451 00452 #endif /* __linux__ && !HAVE_LIBUSB */