libnfc 1.4.2

acr122.c

Go to the documentation of this file.
00001 /*-
00002  * Public platform independent Near Field Communication (NFC) library
00003  * 
00004  * Copyright (C) 2009, Roel Verdult
00005  * 
00006  * This program is free software: you can redistribute it and/or modify it
00007  * under the terms of the GNU Lesser General Public License as published by the
00008  * Free Software Foundation, either version 3 of the License, or (at your
00009  * option) any later version.
00010  * 
00011  * This program is distributed in the hope that it will be useful, but WITHOUT
00012  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00013  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00014  * more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 
00025 #ifdef HAVE_CONFIG_H
00026 #  include "config.h"
00027 #endif // HAVE_CONFIG_H
00028 
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <stddef.h>
00032 #include <string.h>
00033 
00034 #include "acr122.h"
00035 #include "../drivers.h"
00036 
00037 // Bus
00038 #include <winscard.h>
00039 
00040 // XXX: Some review from users cross-compiling is welcome!
00041 #if defined (_WIN32)
00042 #  define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(3500)
00043 #elif defined(__APPLE__)
00044 #  include <wintypes.h>
00045 #  define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2))
00046 #elif defined (__FreeBSD__) || defined (__OpenBSD__)
00047 #  define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2))
00048 #elif defined (__linux__)
00049 #  include <reader.h>
00050 // Escape IOCTL tested successfully:
00051 #  define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(1)
00052 #else
00053 #    error "Can't determine serial string for your system"
00054 #endif
00055 
00056 #include <nfc/nfc.h>
00057 #include <nfc/nfc-messages.h>
00058 
00059 #define SCARD_OPERATION_SUCCESS 0x61
00060 #define SCARD_OPERATION_ERROR 0x63
00061 
00062 #ifndef SCARD_PROTOCOL_UNDEFINED
00063 #  define SCARD_PROTOCOL_UNDEFINED SCARD_PROTOCOL_UNSET
00064 #endif
00065 
00066 #define FIRMWARE_TEXT "ACR122U" // Tested on: ACR122U101(ACS), ACR122U102(Tikitag), ACR122U203(ACS)
00067 
00068 #define ACR122_WRAP_LEN 5
00069 #define ACR122_COMMAND_LEN 266
00070 #define ACR122_RESPONSE_LEN 268
00071 
00072 const char *supported_devices[] = {
00073   "ACS ACR122",         // ACR122U & Touchatag, last version
00074   "ACS ACR 38U-CCID",   // Touchatag, early version
00075   "ACS ACR38U-CCID",    // Touchatag, early version, under MacOSX
00076   "    CCID USB",       // ??
00077   NULL
00078 };
00079 
00080 typedef struct {
00081   SCARDHANDLE hCard;
00082   SCARD_IO_REQUEST ioCard;
00083 } acr122_spec_t;
00084 
00085 static SCARDCONTEXT _SCardContext;
00086 static int _iSCardContextRefCount = 0;
00087 
00088 SCARDCONTEXT *
00089 acr122_get_scardcontext (void)
00090 {
00091   if (_iSCardContextRefCount == 0) {
00092     if (SCardEstablishContext (SCARD_SCOPE_USER, NULL, NULL, &_SCardContext) != SCARD_S_SUCCESS)
00093       return NULL;
00094   }
00095   _iSCardContextRefCount++;
00096 
00097   return &_SCardContext;
00098 }
00099 
00100 void
00101 acr122_free_scardcontext (void)
00102 {
00103   if (_iSCardContextRefCount) {
00104     _iSCardContextRefCount--;
00105     if (!_iSCardContextRefCount) {
00106       SCardReleaseContext (_SCardContext);
00107     }
00108   }
00109 }
00110 
00111 
00112 nfc_device_desc_t *
00113 acr122_pick_device (void)
00114 {
00115   nfc_device_desc_t *pndd;
00116 
00117   if ((pndd = malloc (sizeof (*pndd)))) {
00118     size_t  szN;
00119 
00120     if (!acr122_list_devices (pndd, 1, &szN)) {
00121       DBG ("%s", "acr122_list_devices failed");
00122       free (pndd);
00123       return NULL;
00124     }
00125 
00126     if (szN == 0) {
00127       DBG ("%s", "No device found");
00128       free (pndd);
00129       return NULL;
00130     }
00131   }
00132 
00133   return pndd;
00134 }
00135 
00146 bool
00147 acr122_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound)
00148 {
00149   size_t  szPos = 0;
00150   char    acDeviceNames[256 + 64 * DRIVERS_MAX_DEVICES];
00151   size_t  szDeviceNamesLen = sizeof (acDeviceNames);
00152   uint32_t uiBusIndex = 0;
00153   SCARDCONTEXT *pscc;
00154   bool    bSupported;
00155   int     i;
00156 
00157   // Clear the reader list
00158   memset (acDeviceNames, '\0', szDeviceNamesLen);
00159 
00160   *pszDeviceFound = 0;
00161 
00162   // Test if context succeeded
00163   if (!(pscc = acr122_get_scardcontext ())) {
00164     DBG ("%s", "PCSC context not found");
00165     return false;
00166   }
00167   // Retrieve the string array of all available pcsc readers
00168   if (SCardListReaders (*pscc, NULL, acDeviceNames, (void *) &szDeviceNamesLen) != SCARD_S_SUCCESS)
00169     return false;
00170 
00171   // DBG("%s", "PCSC reports following device(s):");
00172 
00173   while ((acDeviceNames[szPos] != '\0') && ((*pszDeviceFound) < szDevices)) {
00174     uiBusIndex++;
00175 
00176     // DBG("- %s (pos=%ld)", acDeviceNames + szPos, (unsigned long) szPos);
00177 
00178     bSupported = false;
00179     for (i = 0; supported_devices[i] && !bSupported; i++) {
00180       int     l = strlen (supported_devices[i]);
00181       bSupported = 0 == strncmp (supported_devices[i], acDeviceNames + szPos, l);
00182     }
00183 
00184     if (bSupported) {
00185       // Supported ACR122 device found
00186       strncpy (pnddDevices[*pszDeviceFound].acDevice, acDeviceNames + szPos, DEVICE_NAME_LENGTH - 1);
00187       pnddDevices[*pszDeviceFound].acDevice[DEVICE_NAME_LENGTH - 1] = '\0';
00188       pnddDevices[*pszDeviceFound].pcDriver = ACR122_DRIVER_NAME;
00189       pnddDevices[*pszDeviceFound].uiBusIndex = uiBusIndex;
00190       (*pszDeviceFound)++;
00191     } else {
00192       DBG ("PCSC device [%s] is not NFC capable or not supported by libnfc.", acDeviceNames + szPos);
00193     }
00194 
00195     // Find next device name position
00196     while (acDeviceNames[szPos++] != '\0');
00197   }
00198   acr122_free_scardcontext ();
00199 
00200   if (*pszDeviceFound)
00201     return true;
00202   return false;
00203 }
00204 
00205 nfc_device_t *
00206 acr122_connect (const nfc_device_desc_t * pndd)
00207 {
00208   nfc_device_t *pnd = NULL;
00209   acr122_spec_t as;
00210   acr122_spec_t *pas;
00211   char   *pcFirmware;
00212 
00213   SCARDCONTEXT *pscc;
00214 
00215   DBG ("Attempt to connect to %s", pndd->acDevice);
00216   // Test if context succeeded
00217   if (!(pscc = acr122_get_scardcontext ()))
00218     return NULL;
00219   // Test if we were able to connect to the "emulator" card
00220   if (SCardConnect (*pscc, pndd->acDevice, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &(as.hCard), (void *) &(as.ioCard.dwProtocol)) != SCARD_S_SUCCESS) {
00221     // Connect to ACR122 firmware version >2.0
00222     if (SCardConnect (*pscc, pndd->acDevice, SCARD_SHARE_DIRECT, 0, &(as.hCard), (void *) &(as.ioCard.dwProtocol)) != SCARD_S_SUCCESS) {
00223       // We can not connect to this device.
00224       DBG ("%s", "PCSC connect failed");
00225       return NULL;
00226     }
00227   }
00228   // Configure I/O settings for card communication
00229   as.ioCard.cbPciLength = sizeof (SCARD_IO_REQUEST);
00230 
00231   // Retrieve the current firmware version
00232   pcFirmware = acr122_firmware ((nfc_device_t *) & as);
00233   if (strstr (pcFirmware, FIRMWARE_TEXT) != NULL) {
00234     // Allocate memory and store the device specification
00235     pas = malloc (sizeof (acr122_spec_t));
00236     *pas = as;
00237 
00238     // Done, we found the reader we are looking for
00239     pnd = malloc (sizeof (nfc_device_t));
00240     strcpy (pnd->acName, pndd->acDevice);
00241     strcpy (pnd->acName + strlen (pnd->acName), " / ");
00242     strcpy (pnd->acName + strlen (pnd->acName), pcFirmware);
00243     pnd->nc = NC_PN532;
00244     pnd->nds = (nfc_device_spec_t) pas;
00245     pnd->bActive = true;
00246 
00247     return pnd;
00248   }
00249 
00250   return NULL;
00251 }
00252 
00253 void
00254 acr122_disconnect (nfc_device_t * pnd)
00255 {
00256   acr122_spec_t *pas = (acr122_spec_t *) pnd->nds;
00257   SCardDisconnect (pas->hCard, SCARD_LEAVE_CARD);
00258   acr122_free_scardcontext ();
00259   free (pas);
00260   free (pnd);
00261 }
00262 
00263 bool
00264 acr122_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, byte_t * pbtRx, size_t * pszRx)
00265 {
00266   byte_t  abtRxCmd[5] = { 0xFF, 0xC0, 0x00, 0x00 };
00267   size_t  szRxCmdLen = sizeof (abtRxCmd);
00268   byte_t  abtRxBuf[ACR122_RESPONSE_LEN];
00269   size_t  szRxBufLen;
00270   byte_t  abtTxBuf[ACR122_WRAP_LEN + ACR122_COMMAND_LEN] = { 0xFF, 0x00, 0x00, 0x00 };
00271   acr122_spec_t *pas = (acr122_spec_t *) pnd->nds;
00272 
00273   // FIXME: Should be handled by the library.
00274   // Make sure the command does not overflow the send buffer
00275   if (szTx > ACR122_COMMAND_LEN) {
00276     pnd->iLastError = DEIO;
00277     return false;
00278   }
00279   // Store the length of the command we are going to send
00280   abtTxBuf[4] = szTx;
00281 
00282   // Prepare and transmit the send buffer
00283   memcpy (abtTxBuf + 5, pbtTx, szTx);
00284   szRxBufLen = sizeof (abtRxBuf);
00285 #ifdef DEBUG
00286   PRINT_HEX ("TX", abtTxBuf, szTx + 5);
00287 #endif
00288 
00289   if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED) {
00290     if (SCardControl
00291         (pas->hCard, IOCTL_CCID_ESCAPE_SCARD_CTL_CODE, abtTxBuf, szTx + 5, abtRxBuf, szRxBufLen,
00292          (void *) &szRxBufLen) != SCARD_S_SUCCESS) {
00293       pnd->iLastError = DEIO;
00294       return false;
00295     }
00296   } else {
00297     if (SCardTransmit (pas->hCard, &(pas->ioCard), abtTxBuf, szTx + 5, NULL, abtRxBuf, (void *) &szRxBufLen) !=
00298         SCARD_S_SUCCESS) {
00299       pnd->iLastError = DEIO;
00300       return false;
00301     }
00302   }
00303 
00304   if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_T0) {
00305     // Make sure we received the byte-count we expected
00306     if (szRxBufLen != 2) {
00307       pnd->iLastError = DEIO;
00308       return false;
00309     }
00310     // Check if the operation was successful, so an answer is available
00311     if (*abtRxBuf == SCARD_OPERATION_ERROR) {
00312       pnd->iLastError = DEISERRFRAME;
00313       return false;
00314     }
00315     // Retrieve the response bytes
00316     abtRxCmd[4] = abtRxBuf[1];
00317     szRxBufLen = sizeof (abtRxBuf);
00318     if (SCardTransmit (pas->hCard, &(pas->ioCard), abtRxCmd, szRxCmdLen, NULL, abtRxBuf, (void *) &szRxBufLen) !=
00319         SCARD_S_SUCCESS) {
00320       pnd->iLastError = DEIO;
00321       return false;
00322     }
00323   }
00324 #ifdef DEBUG
00325   PRINT_HEX ("RX", abtRxBuf, szRxBufLen);
00326 #endif
00327 
00328   // When the answer should be ignored, just return a succesful result
00329   if (pbtRx == NULL || pszRx == NULL)
00330     return true;
00331 
00332   // Make sure we have an emulated answer that fits the return buffer
00333   if (szRxBufLen < 4 || (szRxBufLen - 4) > *pszRx) {
00334     pnd->iLastError = DEIO;
00335     return false;
00336   }
00337   // Wipe out the 4 APDU emulation bytes: D5 4B .. .. .. 90 00
00338   *pszRx = ((size_t) szRxBufLen) - 4;
00339   memcpy (pbtRx, abtRxBuf + 2, *pszRx);
00340 
00341   // Transmission went successful
00342   return true;
00343 }
00344 
00345 char   *
00346 acr122_firmware (const nfc_device_spec_t nds)
00347 {
00348   byte_t  abtGetFw[5] = { 0xFF, 0x00, 0x48, 0x00, 0x00 };
00349   uint32_t uiResult;
00350 
00351   acr122_spec_t *pas = (acr122_spec_t *) nds;
00352   static char abtFw[11];
00353   size_t  szFwLen = sizeof (abtFw);
00354   memset (abtFw, 0x00, szFwLen);
00355   if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED) {
00356     uiResult = SCardControl (pas->hCard, IOCTL_CCID_ESCAPE_SCARD_CTL_CODE, abtGetFw, sizeof (abtGetFw), abtFw, szFwLen-1, (void *) &szFwLen);
00357   } else {
00358     uiResult = SCardTransmit (pas->hCard, &(pas->ioCard), abtGetFw, sizeof (abtGetFw), NULL, (byte_t *) abtFw, (void *) &szFwLen);
00359   }
00360 
00361   if (uiResult != SCARD_S_SUCCESS) {
00362     ERR ("No ACR122 firmware received, Error: %08x", uiResult);
00363   }
00364 
00365   return abtFw;
00366 }
00367 
00368 bool
00369 acr122_led_red (const nfc_device_spec_t nds, bool bOn)
00370 {
00371   byte_t  abtLed[9] = { 0xFF, 0x00, 0x40, 0x05, 0x04, 0x00, 0x00, 0x00, 0x00 };
00372   acr122_spec_t *pas = (acr122_spec_t *) nds;
00373   byte_t  abtBuf[2];
00374   size_t  szBufLen = sizeof (abtBuf);
00375   (void) bOn;
00376   if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED) {
00377     return (SCardControl
00378             (pas->hCard, IOCTL_CCID_ESCAPE_SCARD_CTL_CODE, abtLed, sizeof (abtLed), abtBuf, szBufLen,
00379              (void *) &szBufLen) == SCARD_S_SUCCESS);
00380   } else {
00381     return (SCardTransmit
00382             (pas->hCard, &(pas->ioCard), abtLed, sizeof (abtLed), NULL, (byte_t *) abtBuf,
00383              (void *) &szBufLen) == SCARD_S_SUCCESS);
00384   }
00385 }