pcsc-lite  1.8.3
hotplug_linux.c
Go to the documentation of this file.
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 */