libnfc 1.4.2
|
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 }