pcsc-lite  1.7.4
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 5711 2011-05-05 09:02:08Z 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 */