/* * Get/set parmaters for T1 protocol */ int t1_set_param(t1_state_t * t1, int type, long value) { switch (type) { case IFD_PROTOCOL_T1_CHECKSUM_LRC: case IFD_PROTOCOL_T1_CHECKSUM_CRC: t1_set_checksum(t1, type); break; case IFD_PROTOCOL_T1_IFSC: t1->ifsc = value; break; case IFD_PROTOCOL_T1_IFSD: t1->ifsd = value; break; case IFD_PROTOCOL_T1_STATE: t1->state = value; break; case IFD_PROTOCOL_T1_MORE: t1->more = value; break; default: DEBUG_INFO2("Unsupported parameter %d", type); return -1; } return 0; }
/***************************************************************************** * * OpenUSBByName * ****************************************************************************/ status_t OpenUSBByName(unsigned int reader_index, /*@null@*/ char *device) { unsigned int alias; struct libusb_device_handle *dev_handle; char infofile[FILENAME_MAX]; #ifndef __APPLE__ unsigned int device_vendor, device_product; #endif int interface_number = -1; int i; static int previous_reader_index = -1; libusb_device **devs, *dev; ssize_t cnt; list_t plist, *values, *ifdVendorID, *ifdProductID, *ifdFriendlyName; int rv; int claim_failed = FALSE; int return_value = STATUS_SUCCESS; DEBUG_COMM3("Reader index: %X, Device: %s", reader_index, device); #ifndef __APPLE__ /* device name specified */ if (device) { char *dirname; /* format: usb:%04x/%04x, vendor, product */ if (strncmp("usb:", device, 4) != 0) { DEBUG_CRITICAL2("device name does not start with \"usb:\": %s", device); return STATUS_UNSUCCESSFUL; } if (sscanf(device, "usb:%x/%x", &device_vendor, &device_product) != 2) { DEBUG_CRITICAL2("device name can't be parsed: %s", device); return STATUS_UNSUCCESSFUL; } /* format usb:%04x/%04x:libudev:%d:%s * with %d set to * 01 (or whatever the interface number is) * and %s set to * /dev/bus/usb/008/004 */ if ((dirname = strstr(device, "libudev:")) != NULL) { /* convert the interface number */ interface_number = atoi(dirname + 8 /* "libudev:" */); DEBUG_COMM2("interface_number: %d", interface_number); } } #endif /* is the reader_index already used? */ if (usbDevice[reader_index].dev_handle != NULL) { DEBUG_CRITICAL2("USB driver with index %X already in use", reader_index); return STATUS_UNSUCCESSFUL; } /* Info.plist full patch filename */ (void)snprintf(infofile, sizeof(infofile), "%s/%s/Contents/Info.plist", PCSCLITE_HP_DROPDIR, BUNDLE); DEBUG_INFO2("Using: %s", infofile); rv = bundleParse(infofile, &plist); if (rv) return STATUS_UNSUCCESSFUL; #define GET_KEY(key, values) \ rv = LTPBundleFindValueWithKey(&plist, key, &values); \ if (rv) \ { \ DEBUG_CRITICAL2("Value/Key not defined for " key " in %s", infofile); \ return_value = STATUS_UNSUCCESSFUL; \ goto end1; \ } \ else \ DEBUG_INFO2(key ": %s", (char *)list_get_at(values, 0)); /* general driver info */ GET_KEY("ifdManufacturerString", values) GET_KEY("ifdProductString", values) GET_KEY("Copyright", values) if (NULL == ctx) { rv = libusb_init(&ctx); if (rv != 0) { DEBUG_CRITICAL2("libusb_init failed: %d", rv); return_value = STATUS_UNSUCCESSFUL; goto end1; } } cnt = libusb_get_device_list(ctx, &devs); if (cnt < 0) { DEBUG_CRITICAL("libusb_get_device_list() failed\n"); return_value = STATUS_UNSUCCESSFUL; goto end1; } #define GET_KEYS(key, values) \ rv = LTPBundleFindValueWithKey(&plist, key, values); \ if (rv) \ { \ DEBUG_CRITICAL2("Value/Key not defined for " key " in %s", infofile); \ return_value = STATUS_UNSUCCESSFUL; \ goto end2; \ } GET_KEYS("ifdVendorID", &ifdVendorID) GET_KEYS("ifdProductID", &ifdProductID); GET_KEYS("ifdFriendlyName", &ifdFriendlyName) /* The 3 lists do not have the same size */ if ((list_size(ifdVendorID) != list_size(ifdProductID)) || (list_size(ifdVendorID) != list_size(ifdFriendlyName))) { DEBUG_CRITICAL2("Error parsing %s", infofile); return_value = STATUS_UNSUCCESSFUL; goto end1; } /* for any supported reader */ for (alias=0; alias<list_size(ifdVendorID); alias++) { unsigned int vendorID, productID; char *friendlyName; vendorID = strtoul(list_get_at(ifdVendorID, alias), NULL, 0); productID = strtoul(list_get_at(ifdProductID, alias), NULL, 0); friendlyName = list_get_at(ifdFriendlyName, alias); #ifndef __APPLE__ /* the device was specified but is not the one we are trying to find */ if (device && (vendorID != device_vendor || productID != device_product)) continue; #else /* Leopard puts the friendlyname in the device argument */ if (device && strcmp(device, friendlyName)) continue; #endif /* for every device */ i = 0; while ((dev = devs[i++]) != NULL) { struct libusb_device_descriptor desc; struct libusb_config_descriptor *config_desc; uint8_t bus_number = libusb_get_bus_number(dev); uint8_t device_address = libusb_get_device_address(dev); int r = libusb_get_device_descriptor(dev, &desc); if (r < 0) { DEBUG_INFO3("failed to get device descriptor for %d/%d", bus_number, device_address); continue; } if (desc.idVendor == vendorID && desc.idProduct == productID) { int already_used; const struct libusb_interface *usb_interface = NULL; int interface; int num = 0; const unsigned char *device_descriptor; #if defined(USE_COMPOSITE_AS_MULTISLOT) || defined(__APPLE__) int readerID = (vendorID << 16) + productID; #endif #ifdef USE_COMPOSITE_AS_MULTISLOT static int static_interface = 1; /* simulate a composite device as when libudev is used */ if ((GEMALTOPROXDU == readerID) || (GEMALTOPROXSU == readerID)) { /* * We can't talk to the two CCID interfaces * at the same time (the reader enters a * dead lock). So we simulate a multi slot * reader. By default multi slot readers * can't use the slots at the same time. See * TAG_IFD_SLOT_THREAD_SAFE * * One side effect is that the two readers * are seen by pcscd as one reader so the * interface name is the same for the two. * * So we have: * 0: Gemalto Prox-DU [Prox-DU Contact_09A00795] (09A00795) 00 00 * 1: Gemalto Prox-DU [Prox-DU Contact_09A00795] (09A00795) 00 01 * instead of * 0: Gemalto Prox-DU [Prox-DU Contact_09A00795] (09A00795) 00 00 * 1: Gemalto Prox-DU [Prox-DU Contactless_09A00795] (09A00795) 01 00 */ /* the CCID interfaces are 1 and 2 */ interface_number = static_interface; } #endif /* is it already opened? */ already_used = FALSE; DEBUG_COMM3("Checking device: %d/%d", bus_number, device_address); for (r=0; r<CCID_DRIVER_MAX_READERS; r++) { if (usbDevice[r].dev_handle) { /* same bus, same address */ if (usbDevice[r].bus_number == bus_number && usbDevice[r].device_address == device_address) already_used = TRUE; } } /* this reader is already managed by us */ if (already_used) { if ((previous_reader_index != -1) && usbDevice[previous_reader_index].dev_handle && (usbDevice[previous_reader_index].bus_number == bus_number) && (usbDevice[previous_reader_index].device_address == device_address) && usbDevice[previous_reader_index].ccid.bCurrentSlotIndex < usbDevice[previous_reader_index].ccid.bMaxSlotIndex) { /* we reuse the same device * and the reader is multi-slot */ usbDevice[reader_index] = usbDevice[previous_reader_index]; /* the other slots do not have the same data rates */ if ((GEMCOREPOSPRO == usbDevice[reader_index].ccid.readerID) || (GEMCORESIMPRO == usbDevice[reader_index].ccid.readerID)) { usbDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialCustomDataRates; usbDevice[reader_index].ccid.dwMaxDataRate = 125000; } *usbDevice[reader_index].nb_opened_slots += 1; usbDevice[reader_index].ccid.bCurrentSlotIndex++; usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; DEBUG_INFO2("Opening slot: %d", usbDevice[reader_index].ccid.bCurrentSlotIndex); goto end; } else { /* if an interface number is given by HAL we * continue with this device. */ if (-1 == interface_number) { DEBUG_INFO3("USB device %d/%d already in use." " Checking next one.", bus_number, device_address); continue; } } } DEBUG_COMM3("Trying to open USB bus/device: %d/%d", bus_number, device_address); r = libusb_open(dev, &dev_handle); if (r < 0) { DEBUG_CRITICAL4("Can't libusb_open(%d/%d): %d", bus_number, device_address, r); continue; } again: #ifdef __APPLE__ /* Some early Gemalto Ezio CB+ readers have * bDeviceClass, bDeviceSubClass and bDeviceProtocol set * to 0xFF (proprietary) instead of 0x00. * * So on Mac OS X the reader configuration is not done * by the OS/kernel and we do it ourself. */ if (GEMALTO_EZIO_CBP == readerID) { r = libusb_set_configuration(dev_handle, 1); if (r < 0) { (void)libusb_close(dev_handle); DEBUG_CRITICAL4("Can't set configuration on %d/%d: %d", bus_number, device_address, r); continue; } } #endif r = libusb_get_active_config_descriptor(dev, &config_desc); if (r < 0) { (void)libusb_close(dev_handle); DEBUG_CRITICAL4("Can't get config descriptor on %d/%d: %d", bus_number, device_address, r); continue; } usb_interface = get_ccid_usb_interface(config_desc, &num); if (usb_interface == NULL) { (void)libusb_close(dev_handle); if (0 == num) DEBUG_CRITICAL3("Can't find a CCID interface on %d/%d", bus_number, device_address); interface_number = -1; continue; } device_descriptor = get_ccid_device_descriptor(usb_interface); if (NULL == device_descriptor) { (void)libusb_close(dev_handle); DEBUG_CRITICAL3("Unable to find the device descriptor for %d/%d", bus_number, device_address); return_value = STATUS_UNSUCCESSFUL; goto end2; } interface = usb_interface->altsetting->bInterfaceNumber; if (interface_number >= 0 && interface != interface_number) { /* an interface was specified and it is not the * current one */ DEBUG_INFO3("Found interface %d but expecting %d", interface_number, interface); DEBUG_INFO3("Wrong interface for USB device %d/%d." " Checking next one.", bus_number, device_address); /* check for another CCID interface on the same device */ num++; goto again; } r = libusb_claim_interface(dev_handle, interface); if (r < 0) { (void)libusb_close(dev_handle); DEBUG_CRITICAL4("Can't claim interface %d/%d: %d", bus_number, device_address, r); claim_failed = TRUE; interface_number = -1; continue; } DEBUG_INFO4("Found Vendor/Product: %04X/%04X (%s)", desc.idVendor, desc.idProduct, friendlyName); DEBUG_INFO3("Using USB bus/device: %d/%d", bus_number, device_address); /* check for firmware bugs */ if (ccid_check_firmware(&desc)) { (void)libusb_close(dev_handle); return_value = STATUS_UNSUCCESSFUL; goto end2; } #ifdef USE_COMPOSITE_AS_MULTISLOT /* use the next interface for the next "slot" */ static_interface++; /* reset for a next reader */ if (static_interface > 2) static_interface = 1; #endif /* Get Endpoints values*/ (void)get_end_points(config_desc, &usbDevice[reader_index], num); /* store device information */ usbDevice[reader_index].dev_handle = dev_handle; usbDevice[reader_index].bus_number = bus_number; usbDevice[reader_index].device_address = device_address; usbDevice[reader_index].interface = interface; usbDevice[reader_index].real_nb_opened_slots = 1; usbDevice[reader_index].nb_opened_slots = &usbDevice[reader_index].real_nb_opened_slots; usbDevice[reader_index].polling_transfer = NULL; /* CCID common informations */ usbDevice[reader_index].ccid.real_bSeq = 0; usbDevice[reader_index].ccid.pbSeq = &usbDevice[reader_index].ccid.real_bSeq; usbDevice[reader_index].ccid.readerID = (desc.idVendor << 16) + desc.idProduct; usbDevice[reader_index].ccid.dwFeatures = dw2i(device_descriptor, 40); usbDevice[reader_index].ccid.wLcdLayout = (device_descriptor[51] << 8) + device_descriptor[50]; usbDevice[reader_index].ccid.bPINSupport = device_descriptor[52]; usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = dw2i(device_descriptor, 44); usbDevice[reader_index].ccid.dwMaxIFSD = dw2i(device_descriptor, 28); usbDevice[reader_index].ccid.dwDefaultClock = dw2i(device_descriptor, 10); usbDevice[reader_index].ccid.dwMaxDataRate = dw2i(device_descriptor, 23); usbDevice[reader_index].ccid.bMaxSlotIndex = device_descriptor[4]; usbDevice[reader_index].ccid.bCurrentSlotIndex = 0; usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT; usbDevice[reader_index].ccid.arrayOfSupportedDataRates = get_data_rates(reader_index, config_desc, num); usbDevice[reader_index].ccid.bInterfaceProtocol = usb_interface->altsetting->bInterfaceProtocol; usbDevice[reader_index].ccid.bNumEndpoints = usb_interface->altsetting->bNumEndpoints; usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; usbDevice[reader_index].ccid.bVoltageSupport = device_descriptor[5]; usbDevice[reader_index].ccid.sIFD_serial_number = NULL; usbDevice[reader_index].ccid.gemalto_firmware_features = NULL; if (desc.iSerialNumber) { unsigned char serial[128]; int ret; ret = libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, serial, sizeof(serial)); if (ret > 0) usbDevice[reader_index].ccid.sIFD_serial_number = strdup((char *)serial); } usbDevice[reader_index].ccid.sIFD_iManufacturer = NULL; if (desc.iManufacturer) { unsigned char iManufacturer[128]; int ret; ret = libusb_get_string_descriptor_ascii(dev_handle, desc.iManufacturer, iManufacturer, sizeof(iManufacturer)); if (ret > 0) usbDevice[reader_index].ccid.sIFD_iManufacturer = strdup((char *)iManufacturer); } usbDevice[reader_index].ccid.IFD_bcdDevice = desc.bcdDevice; goto end; } } } end: if (usbDevice[reader_index].dev_handle == NULL) { /* does not work for libusb <= 1.0.8 */ /* libusb_exit(ctx); */ if (claim_failed) return STATUS_COMM_ERROR; return STATUS_NO_SUCH_DEVICE; } /* memorise the current reader_index so we can detect * a new OpenUSBByName on a multi slot reader */ previous_reader_index = reader_index; end2: /* free the libusb allocated list & devices */ libusb_free_device_list(devs, 1); end1: /* free bundle list */ bundleRelease(&plist); return return_value; } /* OpenUSBByName */
/***************************************************************************** * * dump_gemalto_firmware_features * ****************************************************************************/ static void dump_gemalto_firmware_features(struct GEMALTO_FIRMWARE_FEATURES *gff) { DEBUG_INFO2("Dumping Gemalto firmware features (%zd bytes):", sizeof(struct GEMALTO_FIRMWARE_FEATURES)); #define YESNO(x) (x) ? "yes" : "no" DEBUG_INFO2(" bLogicalLCDLineNumber: %d", gff->bLogicalLCDLineNumber); DEBUG_INFO2(" bLogicalLCDRowNumber: %d", gff->bLogicalLCDRowNumber); DEBUG_INFO2(" bLcdInfo: 0x%02X", gff->bLcdInfo); DEBUG_INFO2(" bEntryValidationCondition: 0x%02X", gff->bEntryValidationCondition); DEBUG_INFO1(" Reader supports PC/SCv2 features:"); DEBUG_INFO2(" VerifyPinStart: %s", YESNO(gff->VerifyPinStart)); DEBUG_INFO2(" VerifyPinFinish: %s", YESNO(gff->VerifyPinFinish)); DEBUG_INFO2(" ModifyPinStart: %s", YESNO(gff->ModifyPinStart)); DEBUG_INFO2(" ModifyPinFinish: %s", YESNO(gff->ModifyPinFinish)); DEBUG_INFO2(" GetKeyPressed: %s", YESNO(gff->GetKeyPressed)); DEBUG_INFO2(" VerifyPinDirect: %s", YESNO(gff->VerifyPinDirect)); DEBUG_INFO2(" ModifyPinDirect: %s", YESNO(gff->ModifyPinDirect)); DEBUG_INFO2(" Abort: %s", YESNO(gff->Abort)); DEBUG_INFO2(" GetKey: %s", YESNO(gff->GetKey)); DEBUG_INFO2(" WriteDisplay: %s", YESNO(gff->WriteDisplay)); DEBUG_INFO2(" SetSpeMessage: %s", YESNO(gff->SetSpeMessage)); DEBUG_INFO2(" bTimeOut2: %s", YESNO(gff->bTimeOut2)); DEBUG_INFO2(" bPPDUSupportOverXferBlock: %s", YESNO(gff->bPPDUSupportOverXferBlock)); DEBUG_INFO2(" bPPDUSupportOverEscape: %s", YESNO(gff->bPPDUSupportOverEscape)); DEBUG_INFO2(" bListSupportedLanguages: %s", YESNO(gff->bListSupportedLanguages)); DEBUG_INFO2(" bNumberMessageFix: %s", YESNO(gff->bNumberMessageFix)); DEBUG_INFO2(" VersionNumber: 0x%02X", gff->VersionNumber); DEBUG_INFO2(" MinimumPINSize: %d", gff->MinimumPINSize); DEBUG_INFO2(" MaximumPINSize: %d", gff->MaximumPINSize); DEBUG_INFO2(" Firewall: %s", YESNO(gff->Firewall)); if (gff->Firewall && gff->FirewalledCommand_SW1 && gff->FirewalledCommand_SW2) { DEBUG_INFO2(" FirewalledCommand_SW1: 0x%02X", gff->FirewalledCommand_SW1); DEBUG_INFO2(" FirewalledCommand_SW2: 0x%02X", gff->FirewalledCommand_SW2); } } /* dump_gemalto_firmware_features */
/***************************************************************************** * * OpenUSBByName * ****************************************************************************/ status_t OpenUSBByName(unsigned int reader_index, /*@null@*/ char *device) { static struct usb_bus *busses = NULL; int alias = 0; struct usb_bus *bus; struct usb_dev_handle *dev_handle; char keyValue[TOKEN_MAX_VALUE_SIZE]; unsigned int vendorID, productID; char infofile[FILENAME_MAX]; #ifndef __APPLE__ unsigned int device_vendor, device_product; #endif char *dirname = NULL, *filename = NULL; int interface_number = -1; static int previous_reader_index = -1; DEBUG_COMM3("Reader index: %X, Device: %s", reader_index, device); #ifndef __APPLE__ /* device name specified */ if (device) { /* format: usb:%04x/%04x, vendor, product */ if (strncmp("usb:", device, 4) != 0) { DEBUG_CRITICAL2("device name does not start with \"usb:\": %s", device); return STATUS_UNSUCCESSFUL; } if (sscanf(device, "usb:%x/%x", &device_vendor, &device_product) != 2) { DEBUG_CRITICAL2("device name can't be parsed: %s", device); return STATUS_UNSUCCESSFUL; } /* format usb:%04x/%04x:libusb:%s * with %s set to %s:%s, dirname, filename */ if ((dirname = strstr(device, "libusb:")) != NULL) { /* dirname points to the first char after libusb: */ dirname += strlen("libusb:"); /* search the : (separation) char */ filename = strchr(dirname, ':'); if (filename) { /* end the dirname string */ *filename = '\0'; /* filename points to the first char after : */ filename++; } else { /* parse failed */ dirname = NULL; DEBUG_CRITICAL2("can't parse using libusb scheme: %s", device); } } /* format usb:%04x/%04x:libhal:%s * with %s set to * /org/freedesktop/Hal/devices/usb_device_VID_PID_SERIAL_ifX * VID is VendorID * PID is ProductID * SERIAL is device serial number * X is the interface number */ if ((dirname = strstr(device, "libhal:")) != NULL) { const char *p; #define HAL_HEADER "usb_device_" /* parse the hal string */ if ( /* search the last '/' char */ (p = strrchr(dirname, '/')) /* if the string starts with "usb_device_" we continue */ && (0 == strncmp(++p, HAL_HEADER, sizeof(HAL_HEADER)-1)) /* skip the HAL header */ && (p += sizeof(HAL_HEADER)-1) /* search the last '_' */ && (p = strrchr(++p, '_')) && (0 == strncmp(++p, "if", 2)) ) { /* convert the interface number */ interface_number = atoi(p+2); } else DEBUG_CRITICAL2("can't parse using libhal scheme: %s", device); /* dirname was just a temporary variable */ dirname = NULL; } } #endif if (busses == NULL) usb_init(); (void)usb_find_busses(); (void)usb_find_devices(); busses = usb_get_busses(); if (busses == NULL) { DEBUG_CRITICAL("No USB busses found"); return STATUS_UNSUCCESSFUL; } /* is the reader_index already used? */ if (usbDevice[reader_index].handle != NULL) { DEBUG_CRITICAL2("USB driver with index %X already in use", reader_index); return STATUS_UNSUCCESSFUL; } /* Info.plist full patch filename */ (void)snprintf(infofile, sizeof(infofile), "%s/%s/Contents/Info.plist", PCSCLITE_HP_DROPDIR, BUNDLE); /* general driver info */ if (!LTPBundleFindValueWithKey(infofile, "ifdManufacturerString", keyValue, 0)) { DEBUG_INFO2("Manufacturer: %s", keyValue); } else { DEBUG_INFO2("LTPBundleFindValueWithKey error. Can't find %s?", infofile); return STATUS_UNSUCCESSFUL; } if (!LTPBundleFindValueWithKey(infofile, "ifdProductString", keyValue, 0)) { DEBUG_INFO2("ProductString: %s", keyValue); } else return STATUS_UNSUCCESSFUL; if (!LTPBundleFindValueWithKey(infofile, "Copyright", keyValue, 0)) { DEBUG_INFO2("Copyright: %s", keyValue); } else return STATUS_UNSUCCESSFUL; vendorID = strlen(keyValue); alias = 0x1C; for (; vendorID--;) alias ^= keyValue[vendorID]; /* for any supported reader */ while (LTPBundleFindValueWithKey(infofile, PCSCLITE_MANUKEY_NAME, keyValue, alias) == 0) { vendorID = strtoul(keyValue, NULL, 0); if (LTPBundleFindValueWithKey(infofile, PCSCLITE_PRODKEY_NAME, keyValue, alias)) goto end; productID = strtoul(keyValue, NULL, 0); if (LTPBundleFindValueWithKey(infofile, PCSCLITE_NAMEKEY_NAME, keyValue, alias)) goto end; /* go to next supported reader for next round */ alias++; #ifndef __APPLE__ /* the device was specified but is not the one we are trying to find */ if (device && (vendorID != device_vendor || productID != device_product)) continue; #else /* Leopard puts the friendlyname in the device argument */ if (device && strcmp(device, keyValue)) continue; #endif /* on any USB buses */ for (bus = busses; bus; bus = bus->next) { struct usb_device *dev; /* any device on this bus */ for (dev = bus->devices; dev; dev = dev->next) { /* device defined by name? */ if (dirname && (strcmp(dirname, bus->dirname) || strcmp(filename, dev->filename))) continue; if (dev->descriptor.idVendor == vendorID && dev->descriptor.idProduct == productID) { int r, already_used; struct usb_interface *usb_interface = NULL; int interface; int num = 0; #ifdef USE_COMPOSITE_AS_MULTISLOT static int static_interface = 1; { /* simulate a composite device as when libhal is * used */ int readerID = (vendorID << 16) + productID; if ((GEMALTOPROXDU == readerID) || (GEMALTOPROXSU == readerID)) { if(interface_number >= 0) { DEBUG_CRITICAL("USE_COMPOSITE_AS_MULTISLOT can't be used with libhal"); continue; } /* the CCID interfaces are 1 and 2 */ interface_number = static_interface; } } #endif /* is it already opened? */ already_used = FALSE; DEBUG_COMM3("Checking device: %s/%s", bus->dirname, dev->filename); for (r=0; r<CCID_DRIVER_MAX_READERS; r++) { if (usbDevice[r].handle) { /* same busname, same filename */ if (strcmp(usbDevice[r].dirname, bus->dirname) == 0 && strcmp(usbDevice[r].filename, dev->filename) == 0) already_used = TRUE; } } /* this reader is already managed by us */ if (already_used) { if ((previous_reader_index != -1) && usbDevice[previous_reader_index].handle && (strcmp(usbDevice[previous_reader_index].dirname, bus->dirname) == 0) && (strcmp(usbDevice[previous_reader_index].filename, dev->filename) == 0) && usbDevice[previous_reader_index].ccid.bCurrentSlotIndex < usbDevice[previous_reader_index].ccid.bMaxSlotIndex) { /* we reuse the same device * and the reader is multi-slot */ usbDevice[reader_index] = usbDevice[previous_reader_index]; /* the other slots do not have the same data rates */ if ((GEMCOREPOSPRO == usbDevice[reader_index].ccid.readerID) || (GEMCORESIMPRO == usbDevice[reader_index].ccid.readerID)) { usbDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialCustomDataRates; usbDevice[reader_index].ccid.dwMaxDataRate = 125000; } *usbDevice[reader_index].nb_opened_slots += 1; usbDevice[reader_index].ccid.bCurrentSlotIndex++; usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; DEBUG_INFO2("Opening slot: %d", usbDevice[reader_index].ccid.bCurrentSlotIndex); goto end; } else { /* if an interface number is given by HAL we * continue with this device. */ if (-1 == interface_number) { DEBUG_INFO3("USB device %s/%s already in use." " Checking next one.", bus->dirname, dev->filename); continue; } } } DEBUG_COMM3("Trying to open USB bus/device: %s/%s", bus->dirname, dev->filename); dev_handle = usb_open(dev); if (dev_handle == NULL) { DEBUG_CRITICAL4("Can't usb_open(%s/%s): %s", bus->dirname, dev->filename, strerror(errno)); continue; } /* now we found a free reader and we try to use it */ if (dev->config == NULL) { (void)usb_close(dev_handle); DEBUG_CRITICAL3("No dev->config found for %s/%s", bus->dirname, dev->filename); return STATUS_UNSUCCESSFUL; } again: usb_interface = get_ccid_usb_interface(dev, &num); if (usb_interface == NULL) { (void)usb_close(dev_handle); if (0 == num) DEBUG_CRITICAL3("Can't find a CCID interface on %s/%s", bus->dirname, dev->filename); interface_number = -1; continue; } if (usb_interface->altsetting->extralen != 54) { (void)usb_close(dev_handle); DEBUG_CRITICAL4("Extra field for %s/%s has a wrong length: %d", bus->dirname, dev->filename, usb_interface->altsetting->extralen); return STATUS_UNSUCCESSFUL; } interface = usb_interface->altsetting->bInterfaceNumber; if (interface_number >= 0 && interface != interface_number) { /* an interface was specified and it is not the * current one */ DEBUG_INFO3("Wrong interface for USB device %s/%s." " Checking next one.", bus->dirname, dev->filename); /* check for another CCID interface on the same device */ num++; goto again; } if (usb_claim_interface(dev_handle, interface) < 0) { (void)usb_close(dev_handle); DEBUG_CRITICAL4("Can't claim interface %s/%s: %s", bus->dirname, dev->filename, strerror(errno)); interface_number = -1; continue; } DEBUG_INFO4("Found Vendor/Product: %04X/%04X (%s)", dev->descriptor.idVendor, dev->descriptor.idProduct, keyValue); DEBUG_INFO3("Using USB bus/device: %s/%s", bus->dirname, dev->filename); /* check for firmware bugs */ if (ccid_check_firmware(dev)) { (void)usb_close(dev_handle); return STATUS_UNSUCCESSFUL; } #ifdef USE_COMPOSITE_AS_MULTISLOT /* use the next interface for the next "slot" */ static_interface++; /* reset for a next reader */ if (static_interface > 2) static_interface = 1; #endif /* Get Endpoints values*/ (void)get_end_points(dev, &usbDevice[reader_index], num); /* store device information */ usbDevice[reader_index].handle = dev_handle; usbDevice[reader_index].dirname = strdup(bus->dirname); usbDevice[reader_index].filename = strdup(dev->filename); usbDevice[reader_index].interface = interface; usbDevice[reader_index].real_nb_opened_slots = 1; usbDevice[reader_index].nb_opened_slots = &usbDevice[reader_index].real_nb_opened_slots; /* CCID common informations */ usbDevice[reader_index].ccid.real_bSeq = 0; usbDevice[reader_index].ccid.pbSeq = &usbDevice[reader_index].ccid.real_bSeq; usbDevice[reader_index].ccid.readerID = (dev->descriptor.idVendor << 16) + dev->descriptor.idProduct; usbDevice[reader_index].ccid.dwFeatures = dw2i(usb_interface->altsetting->extra, 40); usbDevice[reader_index].ccid.wLcdLayout = (usb_interface->altsetting->extra[51] << 8) + usb_interface->altsetting->extra[50]; usbDevice[reader_index].ccid.bPINSupport = usb_interface->altsetting->extra[52]; usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = dw2i(usb_interface->altsetting->extra, 44); usbDevice[reader_index].ccid.dwMaxIFSD = dw2i(usb_interface->altsetting->extra, 28); usbDevice[reader_index].ccid.dwDefaultClock = dw2i(usb_interface->altsetting->extra, 10); usbDevice[reader_index].ccid.dwMaxDataRate = dw2i(usb_interface->altsetting->extra, 23); usbDevice[reader_index].ccid.bMaxSlotIndex = usb_interface->altsetting->extra[4]; usbDevice[reader_index].ccid.bCurrentSlotIndex = 0; usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT; usbDevice[reader_index].ccid.arrayOfSupportedDataRates = get_data_rates(reader_index, dev, num); usbDevice[reader_index].ccid.bInterfaceProtocol = usb_interface->altsetting->bInterfaceProtocol; usbDevice[reader_index].ccid.bNumEndpoints = usb_interface->altsetting->bNumEndpoints; usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; usbDevice[reader_index].ccid.bVoltageSupport = usb_interface->altsetting->extra[5]; goto end; } } } } end: if (usbDevice[reader_index].handle == NULL) return STATUS_NO_SUCH_DEVICE; /* memorise the current reader_index so we can detect * a new OpenUSBByName on a multi slot reader */ previous_reader_index = reader_index; return STATUS_SUCCESS; } /* OpenUSBByName */
double delayImpl(DATA* data, int exprNumber, double exprValue, double time, double delayTime, double delayMax) { RINGBUFFER* delayStruct = data->simulationInfo.delayStructure[exprNumber]; int length = ringBufferLength(delayStruct); DEBUG_INFO4(LOG_EVENTS, "delayImpl: exprNumber = %d, exprValue = %g, time = %g, delayTime = %g", exprNumber, exprValue, time, delayTime); /* Check for errors */ ASSERT1(0 <= exprNumber, "invalid exprNumber = %d", exprNumber); ASSERT1(exprNumber < data->modelData.nDelayExpressions, "invalid exprNumber = %d", exprNumber); if(time <= data->simulationInfo.tStart) { DEBUG_INFO1(LOG_EVENTS, "delayImpl: Entered at time < starting time: %g.", exprValue); return (exprValue); } if(delayTime < 0.0) { ASSERT1(0.0 < delayTime, "Negative delay requested: delayTime = %g", delayTime); THROW("Negative delay requested"); } if(length == 0) { /* This occurs in the initialization phase */ DEBUG_INFO1(LOG_EVENTS, "delayImpl: Missing initial value, using argument value %g instead.", exprValue); return (exprValue); } /* * Returns: expr(time?delayTime) for time>time.start + delayTime and * expr(time.start) for time <= time.start + delayTime. * The arguments, i.e., expr, delayTime and delayMax, need to be subtypes of Real. * DelayMax needs to be additionally a parameter expression. * The following relation shall hold: 0 <= delayTime <= delayMax, * otherwise an error occurs. If delayMax is not supplied in the argument list, * delayTime need to be a parameter expression. See also Section 3.7.2.1. * For non-scalar arguments the function is vectorized according to Section 10.6.12. */ if(time <= data->simulationInfo.tStart + delayTime) { double res = ((TIME_AND_VALUE*)getRingData(delayStruct, 0))->value; DEBUG_INFO2(LOG_EVENTS, "findTime: time <= tStart + delayTime: [%d] = %g",exprNumber, res); return res; } else { /* return expr(time-delayTime) */ double timeStamp = time - delayTime; double time0, time1, value0, value1; int i; ASSERT1(0.0 <= delayTime, "Negative delay requested: delayTime = %g", delayTime); /* find the row for the lower limit */ if(timeStamp > ((TIME_AND_VALUE*)getRingData(delayStruct, length - 1))->time) { /* delay between the last accepted time step and the current time */ time0 = ((TIME_AND_VALUE*)getRingData(delayStruct, length - 1))->time; value0 = ((TIME_AND_VALUE*)getRingData(delayStruct, length - 1))->value; time1 = time; value1 = exprValue; } else { i = findTime(timeStamp, delayStruct); ASSERT2(i < length, "%d = i < length = %d", i, length); time0 = ((TIME_AND_VALUE*)getRingData(delayStruct, i))->time; value0 = ((TIME_AND_VALUE*)getRingData(delayStruct, i))->value; /* was it the last value? */ if(i+1 == length) { if(0 < i && delayMax == delayTime) dequeueNFirstRingDatas(delayStruct, i-1); DEBUG_INFO3(LOG_EVENTS, "delayImpl: dequeueNFirstRingDatas[%d] %g = %g", i, delayMax, delayTime); return value0; } time1 = ((TIME_AND_VALUE*)getRingData(delayStruct, i+1))->time; value1 = ((TIME_AND_VALUE*)getRingData(delayStruct, i+1))->value; if(0 < i && delayMax == delayTime) dequeueNFirstRingDatas(delayStruct, i-1); } /* was it an exact match?*/ if(time0 == timeStamp){ DEBUG_INFO2(LOG_EVENTS, "delayImpl: Exact match at %g = %g", timeStamp, value0); return value0; } else if(time1 == timeStamp) { DEBUG_INFO2(LOG_EVENTS, "delayImpl: Exact match at %g = %g", timeStamp, value1); return value1; } else { /* linear interpolation */ double timedif = time1 - time0; double dt0 = time1 - timeStamp; double dt1 = timeStamp - time0; double retVal = (value0 * dt0 + value1 * dt1) / timedif; DEBUG_INFO3(LOG_EVENTS, "delayImpl: Linear interpolation of %g between %g and %g", timeStamp, time0, time1); DEBUG_INFO4(LOG_EVENTS, "delayImpl: Linear interpolation of %g value: %g and %g = %g", timeStamp, value0, value1, retVal); return retVal; } } }
/***************************************************************************** * * OpenSerialByName: open the port * *****************************************************************************/ status_t OpenSerialByName(unsigned int reader_index, char *dev_name) { struct termios current_termios; unsigned int reader = reader_index; /* 255 is MAX_DEVICENAME in pcscd.h */ char reader_name[255] = "GemPCTwin"; char *p; status_t ret; DEBUG_COMM3("Reader index: %X, Device: %s", reader_index, dev_name); /* parse dev_name using the pattern "device:name" */ p = strchr(dev_name, ':'); if (p) { /* copy the second part of the string */ strlcpy(reader_name, p+1, sizeof(reader_name)); /* replace ':' by '\0' so that dev_name only contains the device name */ *p = '\0'; } ret = set_ccid_descriptor(reader_index, reader_name, dev_name); if (STATUS_UNSUCCESSFUL == ret) return STATUS_UNSUCCESSFUL; /* secondary slot so do not physically open the device */ if (STATUS_SECONDARY_SLOT == ret) return STATUS_SUCCESS; serialDevice[reader].fd = open(dev_name, O_RDWR | O_NOCTTY); if (-1 == serialDevice[reader].fd) { DEBUG_CRITICAL3("open %s: %s", dev_name, strerror(errno)); return STATUS_UNSUCCESSFUL; } /* Set RTS signal to low to prevent the smart card reader * from sending its plug and play string. */ { int flags; if (ioctl(serialDevice[reader].fd, TIOCMGET, &flags) < 0) { DEBUG_CRITICAL2("Get RS232 signals state failed: %s", strerror(errno)); } else { flags &= ~TIOCM_RTS; if (ioctl(serialDevice[reader].fd, TIOCMSET, &flags) < 0) { DEBUG_CRITICAL2("Set RTS to low failed: %s", strerror(errno)); } else { DEBUG_COMM("Plug-n-Play inhibition successful"); } } } /* set channel used */ serialDevice[reader].device = strdup(dev_name); /* empty in and out serial buffers */ if (tcflush(serialDevice[reader].fd, TCIOFLUSH)) DEBUG_INFO2("tcflush() function error: %s", strerror(errno)); /* get config attributes */ if (tcgetattr(serialDevice[reader].fd, ¤t_termios) == -1) { DEBUG_INFO2("tcgetattr() function error: %s", strerror(errno)); (void)close(serialDevice[reader].fd); serialDevice[reader].fd = -1; return STATUS_UNSUCCESSFUL; } /* IGNBRK: ignore BREAK condition on input * IGNPAR: ignore framing errors and parity errors. */ current_termios.c_iflag = IGNBRK | IGNPAR; current_termios.c_oflag = 0; /* Raw output modes */ /* CS8: 8-bits character size * CSTOPB: set two stop bits * CREAD: enable receiver * CLOCAL: ignore modem control lines */ current_termios.c_cflag = CS8 | CSTOPB | CREAD | CLOCAL; /* Do not echo characters because if you connect to a host it or your modem * will echo characters for you. Don't generate signals. */ current_termios.c_lflag = 0; #ifndef ANDROID /* set serial port speed to 115200 bauds */ (void)cfsetspeed(¤t_termios, B115200); DEBUG_INFO("Set serial port baudrate to 115200 and correct configuration"); #endif if (tcsetattr(serialDevice[reader].fd, TCSANOW, ¤t_termios) == -1) { (void)close(serialDevice[reader].fd); serialDevice[reader].fd = -1; DEBUG_INFO2("tcsetattr error: %s", strerror(errno)); return STATUS_UNSUCCESSFUL; } /* perform a command to be sure a Gemalto reader is connected * get the reader firmware */ { unsigned char tx_buffer[] = { 0x02 }; unsigned char rx_buffer[50]; unsigned int rx_length = sizeof(rx_buffer); /* 2 seconds timeout to not wait too long if no reader is connected */ serialDevice[reader].ccid.readTimeout = 2*1000; if (IFD_SUCCESS != CmdEscape(reader_index, tx_buffer, sizeof(tx_buffer), rx_buffer, &rx_length)) { DEBUG_CRITICAL("Get firmware failed. Maybe the reader is not connected"); (void)CloseSerial(reader_index); return STATUS_UNSUCCESSFUL; } /* normal timeout: 2 seconds */ serialDevice[reader].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT ; rx_buffer[rx_length] = '\0'; DEBUG_INFO2("Firmware: %s", rx_buffer); } /* perform a command to configure GemPC Twin reader card movement * notification to synchronous mode: the card movement is notified _after_ * the host command and _before_ the reader anwser */ { unsigned char tx_buffer[] = { 0x01, 0x01, 0x01}; unsigned char rx_buffer[50]; unsigned int rx_length = sizeof(rx_buffer); if (IFD_SUCCESS != CmdEscape(reader_index, tx_buffer, sizeof(tx_buffer), rx_buffer, &rx_length)) { DEBUG_CRITICAL("Change card movement notification failed."); (void)CloseSerial(reader_index); return STATUS_UNSUCCESSFUL; } } serialDevice[reader_index].ccid.sIFD_serial_number = NULL; serialDevice[reader_index].ccid.sIFD_iManufacturer = NULL; serialDevice[reader_index].ccid.IFD_bcdDevice = 0; return STATUS_SUCCESS; } /* OpenSerialByName */
/***************************************************************************** * * set_ccid_descriptor: init ccid descriptor * depending on reader type specified in device. * * return: STATUS_UNSUCCESSFUL, * STATUS_SUCCESS, * -1 (Reader already used) * *****************************************************************************/ static status_t set_ccid_descriptor(unsigned int reader_index, const char *reader_name, const char *dev_name) { int readerID; int i; int already_used = FALSE; static int previous_reader_index = -1; readerID = GEMPCTWIN; if (0 == strcasecmp(reader_name,"GemCorePOSPro")) readerID = GEMCOREPOSPRO; else if (0 == strcasecmp(reader_name,"GemCoreSIMPro")) readerID = GEMCORESIMPRO; else if (0 == strcasecmp(reader_name,"GemPCPinPad")) readerID = GEMPCPINPAD; /* check if the same channel is not already used to manage multi-slots readers*/ for (i = 0; i < CCID_DRIVER_MAX_READERS; i++) { if (serialDevice[i].device && strcmp(serialDevice[i].device, dev_name) == 0) { already_used = TRUE; DEBUG_COMM2("%s already used. Multi-slot reader?", dev_name); break; } } /* this reader is already managed by us */ if (already_used) { if ((previous_reader_index != -1) && serialDevice[previous_reader_index].device && (strcmp(serialDevice[previous_reader_index].device, dev_name) == 0) && serialDevice[previous_reader_index].ccid.bCurrentSlotIndex < serialDevice[previous_reader_index].ccid.bMaxSlotIndex) { /* we reuse the same device and the reader is multi-slot */ serialDevice[reader_index] = serialDevice[previous_reader_index]; *serialDevice[reader_index].nb_opened_slots += 1; serialDevice[reader_index].ccid.bCurrentSlotIndex++; serialDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; DEBUG_INFO2("Opening slot: %d", serialDevice[reader_index].ccid.bCurrentSlotIndex); switch (readerID) { case GEMCOREPOSPRO: case GEMCORESIMPRO: serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialCustomDataRates; serialDevice[reader_index].ccid.dwMaxDataRate = 125000; break; /* GemPC Twin or GemPC Card */ default: serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialTwinDataRates; serialDevice[reader_index].ccid.dwMaxDataRate = 344086; break; } goto end; } else { DEBUG_CRITICAL2("Trying to open too many slots on %s", dev_name); return STATUS_UNSUCCESSFUL; } } /* Common to all readers */ serialDevice[reader_index].ccid.real_bSeq = 0; serialDevice[reader_index].ccid.pbSeq = &serialDevice[reader_index].ccid.real_bSeq; serialDevice[reader_index].real_nb_opened_slots = 1; serialDevice[reader_index].nb_opened_slots = &serialDevice[reader_index].real_nb_opened_slots; serialDevice[reader_index].ccid.bCurrentSlotIndex = 0; serialDevice[reader_index].ccid.dwMaxCCIDMessageLength = 271; serialDevice[reader_index].ccid.dwMaxIFSD = 254; serialDevice[reader_index].ccid.dwFeatures = 0x00010230; serialDevice[reader_index].ccid.dwDefaultClock = 4000; serialDevice[reader_index].buffer_offset = 0; serialDevice[reader_index].buffer_offset_last = 0; serialDevice[reader_index].ccid.readerID = readerID; serialDevice[reader_index].ccid.bPINSupport = 0x0; serialDevice[reader_index].ccid.dwMaxDataRate = 344086; serialDevice[reader_index].ccid.bMaxSlotIndex = 0; serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialTwinDataRates; serialDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; serialDevice[reader_index].ccid.bVoltageSupport = 0x07; /* 1.8V, 3V and 5V */ serialDevice[reader_index].ccid.gemalto_firmware_features = NULL; serialDevice[reader_index].echo = TRUE; /* change some values depending on the reader */ switch (readerID) { case GEMCOREPOSPRO: serialDevice[reader_index].ccid.bMaxSlotIndex = 4; /* 5 slots */ serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialExtendedDataRates; serialDevice[reader_index].echo = FALSE; serialDevice[reader_index].ccid.dwMaxDataRate = 500000; break; case GEMCORESIMPRO: serialDevice[reader_index].ccid.bMaxSlotIndex = 1; /* 2 slots */ serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialExtendedDataRates; serialDevice[reader_index].echo = FALSE; serialDevice[reader_index].ccid.dwMaxDataRate = 500000; break; case GEMPCPINPAD: serialDevice[reader_index].ccid.bPINSupport = 0x03; serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialExtendedDataRates; serialDevice[reader_index].ccid.dwMaxDataRate = 500000; break; } end: /* memorise the current reader_index so we can detect * a new OpenSerialByName on a multi slot reader */ previous_reader_index = reader_index; /* we just created a secondary slot on a multi-slot reader */ if (already_used) return STATUS_SECONDARY_SLOT; return STATUS_SUCCESS; } /* set_ccid_descriptor */
/* * Send/receive block */ static int t1_xcv(t1_state_t * t1, unsigned char *block, size_t slen, size_t rmax) { int n, m; _ccid_descriptor *ccid_desc ; int oldReadTimeout; unsigned int rmax_int; DEBUG_XXD("sending: ", block, slen); ccid_desc = get_ccid_descriptor(t1->lun); oldReadTimeout = ccid_desc->readTimeout; if (t1->wtx > 1) { /* set the new temporary timeout at WTX card request */ ccid_desc->readTimeout *= t1->wtx; DEBUG_INFO2("New timeout at WTX request: %d sec", ccid_desc->readTimeout); } if (isCharLevel(t1->lun)) { rmax = 3; n = CCID_Transmit(t1 -> lun, slen, block, rmax, t1->wtx); if (n != IFD_SUCCESS) return n; /* the second argument of CCID_Receive() is (unsigned int *) * so we can't use &rmax since &rmax is a (size_t *) and may not * be the same on 64-bits architectures for example (iMac G5) */ rmax_int = rmax; n = CCID_Receive(t1 -> lun, &rmax_int, block, NULL); rmax = rmax_int; if (n == IFD_PARITY_ERROR) return -2; if (n != IFD_SUCCESS) return -1; rmax = block[2] + 1; n = CCID_Transmit(t1 -> lun, 0, block, rmax, t1->wtx); if (n != IFD_SUCCESS) return n; rmax_int = rmax; n = CCID_Receive(t1 -> lun, &rmax_int, &block[3], NULL); rmax = rmax_int; if (n == IFD_PARITY_ERROR) return -2; if (n != IFD_SUCCESS) return -1; n = rmax + 3; } else { n = CCID_Transmit(t1 -> lun, slen, block, 0, t1->wtx); t1->wtx = 0; /* reset to default value */ if (n != IFD_SUCCESS) return n; /* Get the response en bloc */ rmax_int = rmax; n = CCID_Receive(t1 -> lun, &rmax_int, block, NULL); rmax = rmax_int; if (n == IFD_PARITY_ERROR) return -2; if (n != IFD_SUCCESS) return -1; n = rmax; } if (n >= 0) { m = block[2] + 3 + t1->rc_bytes; if (m < n) n = m; } if (n >= 0) DEBUG_XXD("received: ", block, n); /* Restore initial timeout */ ccid_desc->readTimeout = oldReadTimeout; return n; }