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