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 #ifdef __APPLE__
00041 #  include <wintypes.h>
00042 #endif
00043 
00044 #include <nfc/nfc.h>
00045 #include <nfc/nfc-messages.h>
00046 
00047 // WINDOWS: #define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(3500)
00048 #define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2))
00049 #define SCARD_OPERATION_SUCCESS 0x61
00050 #define SCARD_OPERATION_ERROR 0x63
00051 
00052 #ifndef SCARD_PROTOCOL_UNDEFINED
00053 #  define SCARD_PROTOCOL_UNDEFINED SCARD_PROTOCOL_UNSET
00054 #endif
00055 
00056 #define FIRMWARE_TEXT "ACR122U" // Tested on: ACR122U101(ACS), ACR122U102(Tikitag), ACR122U203(ACS)
00057 
00058 #define ACR122_WRAP_LEN 5
00059 #define ACR122_COMMAND_LEN 266
00060 #define ACR122_RESPONSE_LEN 268
00061 
00062 const char *supported_devices[] = {
00063   "ACS ACR122",
00064   "ACS ACR 38U-CCID",
00065   "    CCID USB",
00066   NULL
00067 };
00068 
00069 typedef struct {
00070   SCARDHANDLE hCard;
00071   SCARD_IO_REQUEST ioCard;
00072 } acr122_spec_t;
00073 
00074 static SCARDCONTEXT _SCardContext;
00075 static int _iSCardContextRefCount = 0;
00076 
00077 SCARDCONTEXT *
00078 acr122_get_scardcontext (void)
00079 {
00080   if (_iSCardContextRefCount == 0) {
00081     if (SCardEstablishContext (SCARD_SCOPE_USER, NULL, NULL, &_SCardContext) != SCARD_S_SUCCESS)
00082       return NULL;
00083   }
00084   _iSCardContextRefCount++;
00085 
00086   return &_SCardContext;
00087 }
00088 
00089 void
00090 acr122_free_scardcontext (void)
00091 {
00092   if (_iSCardContextRefCount) {
00093     _iSCardContextRefCount--;
00094     if (!_iSCardContextRefCount) {
00095       SCardReleaseContext (_SCardContext);
00096     }
00097   }
00098 }
00099 
00100 
00101 nfc_device_desc_t *
00102 acr122_pick_device (void)
00103 {
00104   nfc_device_desc_t *pndd;
00105 
00106   if ((pndd = malloc (sizeof (*pndd)))) {
00107     size_t  szN;
00108 
00109     if (!acr122_list_devices (pndd, 1, &szN)) {
00110       DBG ("%s", "acr122_list_devices failed");
00111       return NULL;
00112     }
00113 
00114     if (szN == 0) {
00115       DBG ("%s", "No device found");
00116       return NULL;
00117     }
00118   }
00119 
00120   return pndd;
00121 }
00122 
00133 bool
00134 acr122_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound)
00135 {
00136   size_t  szPos = 0;
00137   char    acDeviceNames[256 + 64 * DRIVERS_MAX_DEVICES];
00138   size_t  szDeviceNamesLen = sizeof (acDeviceNames);
00139   uint32_t uiBusIndex = 0;
00140   SCARDCONTEXT *pscc;
00141   bool    bSupported;
00142   int     i;
00143 
00144   // Clear the reader list
00145   memset (acDeviceNames, '\0', szDeviceNamesLen);
00146 
00147   *pszDeviceFound = 0;
00148 
00149   // Test if context succeeded
00150   if (!(pscc = acr122_get_scardcontext ())) {
00151     DBG ("%s", "PCSC context not found");
00152     return false;
00153   }
00154   // Retrieve the string array of all available pcsc readers
00155   if (SCardListReaders (*pscc, NULL, acDeviceNames, (void *) &szDeviceNamesLen) != SCARD_S_SUCCESS)
00156     return false;
00157 
00158   // DBG("%s", "PCSC reports following device(s):");
00159 
00160   while ((acDeviceNames[szPos] != '\0') && ((*pszDeviceFound) < szDevices)) {
00161     uiBusIndex++;
00162 
00163     // DBG("- %s (pos=%ld)", acDeviceNames + szPos, (unsigned long) szPos);
00164 
00165     bSupported = false;
00166     for (i = 0; supported_devices[i] && !bSupported; i++) {
00167       int     l = strlen (supported_devices[i]);
00168       bSupported = 0 == strncmp (supported_devices[i], acDeviceNames + szPos, l);
00169     }
00170 
00171     if (bSupported) {
00172       // Supported ACR122 device found
00173       strncpy (pnddDevices[*pszDeviceFound].acDevice, acDeviceNames + szPos, DEVICE_NAME_LENGTH - 1);
00174       pnddDevices[*pszDeviceFound].acDevice[DEVICE_NAME_LENGTH - 1] = '\0';
00175       pnddDevices[*pszDeviceFound].pcDriver = ACR122_DRIVER_NAME;
00176       pnddDevices[*pszDeviceFound].uiBusIndex = uiBusIndex;
00177       (*pszDeviceFound)++;
00178     } else {
00179       DBG ("PCSC device [%s] is not NFC capable or not supported by libnfc.", acDeviceNames + szPos);
00180     }
00181 
00182     // Find next device name position
00183     while (acDeviceNames[szPos++] != '\0');
00184   }
00185   acr122_free_scardcontext ();
00186 
00187   if (*pszDeviceFound)
00188     return true;
00189   return false;
00190 }
00191 
00192 nfc_device_t *
00193 acr122_connect (const nfc_device_desc_t * pndd)
00194 {
00195   nfc_device_t *pnd = NULL;
00196   acr122_spec_t as;
00197   acr122_spec_t *pas;
00198   char   *pcFirmware;
00199 
00200   SCARDCONTEXT *pscc;
00201 
00202   DBG ("Attempt to connect to %s", pndd->acDevice);
00203   // Test if context succeeded
00204   if (!(pscc = acr122_get_scardcontext ()))
00205     return NULL;
00206   // Test if we were able to connect to the "emulator" card
00207   if (SCardConnect
00208       (*pscc, pndd->acDevice, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &(as.hCard),
00209        (void *) &(as.ioCard.dwProtocol)) != SCARD_S_SUCCESS) {
00210     // Connect to ACR122 firmware version >2.0
00211     if (SCardConnect (*pscc, pndd->acDevice, SCARD_SHARE_DIRECT, 0, &(as.hCard), (void *) &(as.ioCard.dwProtocol)) !=
00212         SCARD_S_SUCCESS) {
00213       // We can not connect to this device.
00214       DBG ("%s", "PCSC connect failed");
00215       return NULL;
00216     }
00217   }
00218   // Configure I/O settings for card communication
00219   as.ioCard.cbPciLength = sizeof (SCARD_IO_REQUEST);
00220 
00221   // Retrieve the current firmware version
00222   pcFirmware = acr122_firmware ((nfc_device_t *) & as);
00223   if (strstr (pcFirmware, FIRMWARE_TEXT) != NULL) {
00224     // Allocate memory and store the device specification
00225     pas = malloc (sizeof (acr122_spec_t));
00226     *pas = as;
00227 
00228     // Done, we found the reader we are looking for
00229     pnd = malloc (sizeof (nfc_device_t));
00230     strcpy (pnd->acName, pndd->acDevice);
00231     strcpy (pnd->acName + strlen (pnd->acName), " / ");
00232     strcpy (pnd->acName + strlen (pnd->acName), pcFirmware);
00233     pnd->nc = NC_PN532;
00234     pnd->nds = (nfc_device_spec_t) pas;
00235     pnd->bActive = true;
00236     pnd->bCrc = true;
00237     pnd->bPar = true;
00238     pnd->ui8TxBits = 0;
00239     return pnd;
00240   }
00241 
00242   return NULL;
00243 }
00244 
00245 void
00246 acr122_disconnect (nfc_device_t * pnd)
00247 {
00248   acr122_spec_t *pas = (acr122_spec_t *) pnd->nds;
00249   SCardDisconnect (pas->hCard, SCARD_LEAVE_CARD);
00250   acr122_free_scardcontext ();
00251   free (pas);
00252   free (pnd);
00253 }
00254 
00255 bool
00256 acr122_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTxLen, byte_t * pbtRx, size_t * pszRxLen)
00257 {
00258   byte_t  abtRxCmd[5] = { 0xFF, 0xC0, 0x00, 0x00 };
00259   size_t  szRxCmdLen = sizeof (abtRxCmd);
00260   byte_t  abtRxBuf[ACR122_RESPONSE_LEN];
00261   size_t  szRxBufLen;
00262   byte_t  abtTxBuf[ACR122_WRAP_LEN + ACR122_COMMAND_LEN] = { 0xFF, 0x00, 0x00, 0x00 };
00263   acr122_spec_t *pas = (acr122_spec_t *) pnd->nds;
00264 
00265   // FIXME: Should be handled by the library.
00266   // Make sure the command does not overflow the send buffer
00267   if (szTxLen > ACR122_COMMAND_LEN) {
00268     pnd->iLastError = DEIO;
00269     return false;
00270   }
00271   // Store the length of the command we are going to send
00272   abtTxBuf[4] = szTxLen;
00273 
00274   // Prepare and transmit the send buffer
00275   memcpy (abtTxBuf + 5, pbtTx, szTxLen);
00276   szRxBufLen = sizeof (abtRxBuf);
00277 #ifdef DEBUG
00278   PRINT_HEX ("TX", abtTxBuf, szTxLen + 5);
00279 #endif
00280 
00281   if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED) {
00282     if (SCardControl
00283         (pas->hCard, IOCTL_CCID_ESCAPE_SCARD_CTL_CODE, abtTxBuf, szTxLen + 5, abtRxBuf, szRxBufLen,
00284          (void *) &szRxBufLen) != SCARD_S_SUCCESS) {
00285       pnd->iLastError = DEIO;
00286       return false;
00287     }
00288   } else {
00289     if (SCardTransmit (pas->hCard, &(pas->ioCard), abtTxBuf, szTxLen + 5, NULL, abtRxBuf, (void *) &szRxBufLen) !=
00290         SCARD_S_SUCCESS) {
00291       pnd->iLastError = DEIO;
00292       return false;
00293     }
00294   }
00295 
00296   if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_T0) {
00297     // Make sure we received the byte-count we expected
00298     if (szRxBufLen != 2) {
00299       pnd->iLastError = DEIO;
00300       return false;
00301     }
00302     // Check if the operation was successful, so an answer is available
00303     if (*abtRxBuf == SCARD_OPERATION_ERROR) {
00304       pnd->iLastError = DEISERRFRAME;
00305       return false;
00306     }
00307     // Retrieve the response bytes
00308     abtRxCmd[4] = abtRxBuf[1];
00309     szRxBufLen = sizeof (abtRxBuf);
00310     if (SCardTransmit (pas->hCard, &(pas->ioCard), abtRxCmd, szRxCmdLen, NULL, abtRxBuf, (void *) &szRxBufLen) !=
00311         SCARD_S_SUCCESS) {
00312       pnd->iLastError = DEIO;
00313       return false;
00314     }
00315   }
00316 #ifdef DEBUG
00317   PRINT_HEX ("RX", abtRxBuf, szRxBufLen);
00318 #endif
00319 
00320   // When the answer should be ignored, just return a succesful result
00321   if (pbtRx == NULL || pszRxLen == NULL)
00322     return true;
00323 
00324   // Make sure we have an emulated answer that fits the return buffer
00325   if (szRxBufLen < 4 || (szRxBufLen - 4) > *pszRxLen) {
00326     pnd->iLastError = DEIO;
00327     return false;
00328   }
00329   // Wipe out the 4 APDU emulation bytes: D5 4B .. .. .. 90 00
00330   *pszRxLen = ((size_t) szRxBufLen) - 4;
00331   memcpy (pbtRx, abtRxBuf + 2, *pszRxLen);
00332 
00333   // Transmission went successful
00334   return true;
00335 }
00336 
00337 char   *
00338 acr122_firmware (const nfc_device_spec_t nds)
00339 {
00340   byte_t  abtGetFw[5] = { 0xFF, 0x00, 0x48, 0x00, 0x00 };
00341   uint32_t uiResult;
00342 
00343   acr122_spec_t *pas = (acr122_spec_t *) nds;
00344   static char abtFw[11];
00345   size_t  szFwLen = sizeof (abtFw);
00346   memset (abtFw, 0x00, szFwLen);
00347   if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED) {
00348     uiResult =
00349       SCardControl (pas->hCard, IOCTL_CCID_ESCAPE_SCARD_CTL_CODE, abtGetFw, sizeof (abtGetFw), abtFw, szFwLen,
00350                     (void *) &szFwLen);
00351   } else {
00352     uiResult =
00353       SCardTransmit (pas->hCard, &(pas->ioCard), abtGetFw, sizeof (abtGetFw), NULL, (byte_t *) abtFw,
00354                      (void *) &szFwLen);
00355   }
00356 
00357 #ifdef DEBUG
00358   if (uiResult != SCARD_S_SUCCESS) {
00359     printf ("No ACR122 firmware received, Error: %08x\n", uiResult);
00360   }
00361 #endif
00362 
00363   return abtFw;
00364 }
00365 
00366 bool
00367 acr122_led_red (const nfc_device_spec_t nds, bool bOn)
00368 {
00369   byte_t  abtLed[9] = { 0xFF, 0x00, 0x40, 0x05, 0x04, 0x00, 0x00, 0x00, 0x00 };
00370   acr122_spec_t *pas = (acr122_spec_t *) nds;
00371   byte_t  abtBuf[2];
00372   size_t  szBufLen = sizeof (abtBuf);
00373   (void) bOn;
00374   if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED) {
00375     return (SCardControl
00376             (pas->hCard, IOCTL_CCID_ESCAPE_SCARD_CTL_CODE, abtLed, sizeof (abtLed), abtBuf, szBufLen,
00377              (void *) &szBufLen) == SCARD_S_SUCCESS);
00378   } else {
00379     return (SCardTransmit
00380             (pas->hCard, &(pas->ioCard), abtLed, sizeof (abtLed), NULL, (byte_t *) abtBuf,
00381              (void *) &szBufLen) == SCARD_S_SUCCESS);
00382   }
00383 }