pcsc-lite 1.7.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-2010 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 5638 2011-02-25 13:36:57Z 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 %d", 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 sprintf(dirpath, "%s/%s", PCSCLITE_USB_PATH, entry->d_name); 00262 00263 dirB = opendir(dirpath); 00264 00265 if (dirB == NULL) 00266 { 00267 Log2(PCSC_LOG_ERROR, 00268 "USB path seems to have disappeared %s", dirpath); 00269 closedir(dir); 00270 return; 00271 } 00272 00273 while ((entryB = readdir(dirB)) != NULL) 00274 { 00275 /* 00276 * Skip anything starting with a 00277 */ 00278 if (entryB->d_name[0] == '.') 00279 continue; 00280 00281 /* Get the device number so we can distinguish 00282 multiple readers */ 00283 sprintf(filename, "%s/%s", dirpath, entryB->d_name); 00284 sscanf(entryB->d_name, "%d", &deviceNumber); 00285 00286 fd = open(filename, O_RDONLY); 00287 if (fd < 0) 00288 continue; 00289 00290 ret = read(fd, (void *) &usbDescriptor, 00291 sizeof(usbDescriptor)); 00292 00293 close(fd); 00294 00295 if (ret < 0) 00296 continue; 00297 00298 /* 00299 * Device is found and we don't know about it 00300 */ 00301 00302 if (usbDescriptor.idVendor == bundleTracker[i].manuID && 00303 usbDescriptor.idProduct == bundleTracker[i].productID && 00304 usbDescriptor.idVendor !=0 && 00305 usbDescriptor.idProduct != 0) 00306 { 00307 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++) 00308 { 00309 if (bundleTracker[i].deviceNumber[j].id == deviceNumber && 00310 bundleTracker[i].deviceNumber[j].id != 0) 00311 { 00312 bundleTracker[i].deviceNumber[j].status = 1; /* i'm here */ 00313 break; 00314 } 00315 } 00316 00317 if (j == PCSCLITE_MAX_READERS_CONTEXTS) 00318 { 00319 usbDeviceStatus = 1; 00320 suspectDeviceNumber = deviceNumber; 00321 } 00322 } 00323 00324 } /* End of while */ 00325 00326 closedir(dirB); 00327 00328 } /* End of while */ 00329 00330 00331 if (usbDeviceStatus == 1) 00332 { 00333 pthread_mutex_lock(&usbNotifierMutex); 00334 00335 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++) 00336 { 00337 if (bundleTracker[i].deviceNumber[j].id == 0) 00338 break; 00339 } 00340 00341 if (j == PCSCLITE_MAX_READERS_CONTEXTS) 00342 Log1(PCSC_LOG_ERROR, 00343 "Too many identical readers plugged in"); 00344 else 00345 { 00346 HPAddHotPluggable(i, j+1); 00347 bundleTracker[i].deviceNumber[j].id = suspectDeviceNumber; 00348 } 00349 00350 pthread_mutex_unlock(&usbNotifierMutex); 00351 } 00352 else 00353 if (usbDeviceStatus == 0) 00354 { 00355 00356 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++) 00357 { 00358 if (bundleTracker[i].deviceNumber[j].id != 0 && 00359 bundleTracker[i].deviceNumber[j].status == 0) 00360 { 00361 pthread_mutex_lock(&usbNotifierMutex); 00362 HPRemoveHotPluggable(i, j+1); 00363 bundleTracker[i].deviceNumber[j].id = 0; 00364 pthread_mutex_unlock(&usbNotifierMutex); 00365 } 00366 } 00367 } 00368 else 00369 { 00370 /* 00371 * Do nothing - no USB devices found 00372 */ 00373 } 00374 00375 if (dir) 00376 closedir(dir); 00377 00378 } /* End of for..loop */ 00379 00380 SYS_Sleep(1); 00381 if (AraKiriHotPlug) 00382 { 00383 int retval; 00384 00385 Log1(PCSC_LOG_INFO, "Hotplug stopped"); 00386 pthread_exit(&retval); 00387 } 00388 00389 } /* End of while loop */ 00390 } 00391 00392 LONG HPSearchHotPluggables(void) 00393 { 00394 int i, j; 00395 00396 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 00397 { 00398 bundleTracker[i].productID = 0; 00399 bundleTracker[i].manuID = 0; 00400 00401 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++) 00402 bundleTracker[i].deviceNumber[j].id = 0; 00403 } 00404 00405 HPReadBundleValues(); 00406 00407 ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED, 00408 (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, 0); 00409 00410 return 0; 00411 } 00412 00413 LONG HPStopHotPluggables(void) 00414 { 00415 AraKiriHotPlug = TRUE; 00416 00417 return 0; 00418 } 00419 00420 static LONG HPAddHotPluggable(int i, unsigned long usbAddr) 00421 { 00422 /* NOTE: The deviceName is an empty string "" until someone implements 00423 * the code to get it */ 00424 RFAddReader(bundleTracker[i].readerName, PCSCLITE_HP_BASE_PORT + usbAddr, 00425 bundleTracker[i].libraryPath, ""); 00426 00427 return 1; 00428 } /* End of function */ 00429 00430 static LONG HPRemoveHotPluggable(int i, unsigned long usbAddr) 00431 { 00432 RFRemoveReader(bundleTracker[i].readerName, PCSCLITE_HP_BASE_PORT + usbAddr); 00433 00434 return 1; 00435 } /* End of function */ 00436 00440 ULONG HPRegisterForHotplugEvents(void) 00441 { 00442 (void)pthread_mutex_init(&usbNotifierMutex, NULL); 00443 return 0; 00444 } 00445 00446 void HPReCheckSerialReaders(void) 00447 { 00448 } 00449 00450 #endif /* __linux__ && !HAVE_LIBUSB */