New CCID 1.4.0 and card movement notification mechanism

Card movement detection in the ancient times

Before the mechanism I will describe in this blog post was implemented and used, the only way pcsc-lite detected a card movement (card insertion or removal) was to poll the driver every 200ms to ask if a card was present or not in the reader and to compare with the previous state.

Advantages

Every driver (i.e. the old ones) implements the IFDHICCPresence function:
This function returns the status of the card inserted in the reader/slot specified by Lun.

Problems

Active polling

The driver is then continuously asking the reader. This is host CPU "intensive" and will prevent the CPU to go in sleep state to limit its power consumption. You can use the powertop tool to see that. This is BAD.

Performances

Another problem is that the pcscd is notified up to 200ms after the card status has changed. So if your application is waiting for a card insertion you can waste up to 200ms between the card insertion and the application being notified.

libccid 1.4.0

4 days ago I released a new version 1.4.0 of my CCID driver (libccid).

Changes

1.4.0 - 4 August 2010, Ludovic Rousseau

  • add support of Kingtrust Multi-Reader, Dectel CI692, Todos CX00,
    C3PO LTC36, ACS AET65, Broadcom 5880, Tianyu Smart Card Reader,
    Gemalto Hybrid Smartcard Reader
  • Add support of the SCM SDI 010 again. At least the contact
    interface can be used.
  • Use libusb-1.0 instead of libusb-0.1
  • add support of TAG_IFD_STOP_POLLING_THREAD and use of the asynchronous libusb API to be able to stop a transfer.
  • Request pcsc-lite 1.6.2 minimum (instead of 1.6.0) to have TAG_IFD_STOP_POLLING_THREAD defined
  • The O2MICRO OZ776 patch (for OZ776, OZ776_7772, REINER_SCT and BLUDRIVEII_CCID) is no more supported with libusb-1.0
  • correctly get the IFSC from the ATR (ATR parsing was not always correct)
  • some minor bugs removed

The change that will interest us here is the support of TAG_IFD_STOP_POLLING_THREAD. This is used so that pcscd can ask the driver to stop its polling function.

But the support of TAG_IFD_STOP_POLLING_THREAD has only be included in pcsc-lite 1.6.2. This is why you need pcsc-lite 1.6.2 to compile libccid 1.4.0.

pcsc-lite 1.6.2

The same day of the libcid 1.4.0 release I also released pcsc-lite 1.6.2.

Changes

pcsc-lite-1.6.2: Ludovic Rousseau
4 August 2010
  • implement a "Forced suicide" mechanism. After 3 Ctrl-C without much reaction from pcscd (in fact the drivers) we force the suicide. Sometimes libusb is blocked in a kind of dead-lock and kill -9 was the only option.
  • Add support of TAG_IFD_STOP_POLLING_THREAD to request the stop of the driver polling function.
  • Avoid a division by 0. Closes [#312555] "simclist bug in pcsc-lite"
  • if pcscd is started by libpcsclite then close all file handles except stdin, stdout and stderr so that pcscd does not confiscate resources allocated by the application
  • in case of auto exit create a new session so that Ctrl-C on the application will not also quit pcscd
  • src/hotplug_libusb.c: port from libusb-0.1 to libusb-1.0
  • default configuration is now $sysconfdir/reader.conf.d
  • fix crash with empty config dir
  • src/PCSC/winscard.h: Remove definitions of SCARD_READERSTATE_A PSCARD_READERSTATE_A and LPSCARD_READERSTATE_A types
  • some other minor improvements and bug corrections

Card movement notification

How does the card movement notification works with the CCID protocol?

USB interrupt end point

Some readers (but not all) provides an interrupt endpoint at the USB level. This endpoint is used to signal a card movement to the host even if the host does not send a CCID command to be notified. The host just has to read the interrupt endpoint.

From the CCID specification 1.1 § 5.2.3 Interrupt-IN Endpoint:
The interrupt pipe is mandatory for a CCID that supports ICC insertion/removal. It is optional for a CCID with ICCs that are always inserted and are not removable. If there is an Interrupt-In endpoint, then the RDR_to_PC_NotifySlotChange message is required and all other messages are optional.

RDR_to_PC_NotifySlotChange message

The first byte is bMessageType and its value is 0x50 indicating RDR_to_PC_NotifySlotChange.

The next bytes are bmSlotICCState:
This field is reported on byte granularity.
The size is ( 2 bits * number of slots ) rounded up to the nearest byte.
Each slot has 2 bits. The least significant bit reports the current state of the slot (0b = no ICC present, 1b = ICC present). The most significant bit reports whether the slot has changed state since the last RDR_to_PC_NotifySlotChange message was sent (0b = no change, 1b = change).
If no slot exists for a given location, the field returns 00b in those 2 bits.
Example: A 3 slot CCID reports a single byte with the following format:
Bit 0 = Slot 0 current state
Bit 1 = Slot 0 changed status
Bit 2 = Slot 1 current state
Bit 3 = Slot 1 changed status
Bit 4 = Slot 2 current state
Bit 5 = Slot 2 changed status
Bit 6 = 0b
Bit 7 = 0b

In short, and if the reader has only one slot, you will receive 0x50 0x03 when a card is removed and 0x50 0x02 when a card is inserted.

libusb

libusb-0.1

The use of an interrupt end point is already supported in libusb-0.1 but I had many issues when using this feature. The main issue is that libusb-0.1 calls are synchronous and it is not possible to (cleanly) interrupt a usb_interrupt_read call. It is then impossible to cleanly stop the driver when pcscd exits.

One hack I used is to make the usb_interrupt_read call timeout after 2 seconds. But it is still a kind of polling, even if the period is now 2 seconds instead of 200 ms.

libusb-1.0

libusb-1.0 has a new API and, in particular, an asynchronous API. Using the asynchronous API it is possible to cancel an ongoing call. This is exactly what is done when TAG_IFD_STOP_POLLING_THREAD is requested by pcscd to the driver.

But libusb-1.0 is relatively new and has bugs. The latest stable version 1.0.8 is not yet bug free and I found some bugs in particular cases. Bugs have been reported to the libusb project and most are already corrected.

Conclusion

pcscd when used with my CCID driver is now a good citizen regarding the computer CPU use. All the internal active polling loops have been removed and pcsc-lite is now completely event managed.