libnfc  1.4.2
acr122.c
Go to the documentation of this file.
1 /*-
2  * Public platform independent Near Field Communication (NFC) library
3  *
4  * Copyright (C) 2009, Roel Verdult
5  *
6  * This program is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>
18  */
19 
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif // HAVE_CONFIG_H
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <string.h>
33 
34 #include "acr122.h"
35 #include "../drivers.h"
36 
37 // Bus
38 #include <winscard.h>
39 
40 // XXX: Some review from users cross-compiling is welcome!
41 #if defined (_WIN32)
42 # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(3500)
43 #elif defined(__APPLE__)
44 # include <wintypes.h>
45 # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2))
46 #elif defined (__FreeBSD__) || defined (__OpenBSD__)
47 # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2))
48 #elif defined (__linux__)
49 # include <reader.h>
50 // Escape IOCTL tested successfully:
51 # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(1)
52 #else
53 # error "Can't determine serial string for your system"
54 #endif
55 
56 #include <nfc/nfc.h>
57 #include <nfc/nfc-messages.h>
58 
59 #define SCARD_OPERATION_SUCCESS 0x61
60 #define SCARD_OPERATION_ERROR 0x63
61 
62 #ifndef SCARD_PROTOCOL_UNDEFINED
63 # define SCARD_PROTOCOL_UNDEFINED SCARD_PROTOCOL_UNSET
64 #endif
65 
66 #define FIRMWARE_TEXT "ACR122U" // Tested on: ACR122U101(ACS), ACR122U102(Tikitag), ACR122U203(ACS)
67 
68 #define ACR122_WRAP_LEN 5
69 #define ACR122_COMMAND_LEN 266
70 #define ACR122_RESPONSE_LEN 268
71 
72 const char *supported_devices[] = {
73  "ACS ACR122", // ACR122U & Touchatag, last version
74  "ACS ACR 38U-CCID", // Touchatag, early version
75  "ACS ACR38U-CCID", // Touchatag, early version, under MacOSX
76  " CCID USB", // ??
77  "ACS AET65 00 00",
78  NULL
79 };
80 
81 typedef struct {
82  SCARDHANDLE hCard;
83  SCARD_IO_REQUEST ioCard;
84 } acr122_spec_t;
85 
86 static SCARDCONTEXT _SCardContext;
87 static int _iSCardContextRefCount = 0;
88 
89 SCARDCONTEXT *
90 acr122_get_scardcontext (void)
91 {
92  if (_iSCardContextRefCount == 0) {
93  if (SCardEstablishContext (SCARD_SCOPE_USER, NULL, NULL, &_SCardContext) != SCARD_S_SUCCESS)
94  return NULL;
95  }
96  _iSCardContextRefCount++;
97 
98  return &_SCardContext;
99 }
100 
101 void
102 acr122_free_scardcontext (void)
103 {
104  if (_iSCardContextRefCount) {
105  _iSCardContextRefCount--;
106  if (!_iSCardContextRefCount) {
107  SCardReleaseContext (_SCardContext);
108  }
109  }
110 }
111 
112 
114 acr122_pick_device (void)
115 {
116  nfc_device_desc_t *pndd;
117 
118  if ((pndd = malloc (sizeof (*pndd)))) {
119  size_t szN;
120 
121  if (!acr122_list_devices (pndd, 1, &szN)) {
122  DBG ("%s", "acr122_list_devices failed");
123  free (pndd);
124  return NULL;
125  }
126 
127  if (szN == 0) {
128  DBG ("%s", "No device found");
129  free (pndd);
130  return NULL;
131  }
132  }
133 
134  return pndd;
135 }
136 
147 bool
148 acr122_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound)
149 {
150  size_t szPos = 0;
151  char acDeviceNames[256 + 64 * DRIVERS_MAX_DEVICES];
152  size_t szDeviceNamesLen = sizeof (acDeviceNames);
153  uint32_t uiBusIndex = 0;
154  SCARDCONTEXT *pscc;
155  bool bSupported;
156  int i;
157 
158  // Clear the reader list
159  memset (acDeviceNames, '\0', szDeviceNamesLen);
160 
161  *pszDeviceFound = 0;
162 
163  // Test if context succeeded
164  if (!(pscc = acr122_get_scardcontext ())) {
165  DBG ("%s", "PCSC context not found");
166  return false;
167  }
168  // Retrieve the string array of all available pcsc readers
169  if (SCardListReaders (*pscc, NULL, acDeviceNames, (void *) &szDeviceNamesLen) != SCARD_S_SUCCESS)
170  return false;
171 
172  // DBG("%s", "PCSC reports following device(s):");
173 
174  while ((acDeviceNames[szPos] != '\0') && ((*pszDeviceFound) < szDevices)) {
175  uiBusIndex++;
176 
177  // DBG("- %s (pos=%ld)", acDeviceNames + szPos, (unsigned long) szPos);
178 
179  bSupported = false;
180  for (i = 0; supported_devices[i] && !bSupported; i++) {
181  int l = strlen (supported_devices[i]);
182  bSupported = 0 == strncmp (supported_devices[i], acDeviceNames + szPos, l);
183  }
184 
185  if (bSupported) {
186  // Supported ACR122 device found
187  strncpy (pnddDevices[*pszDeviceFound].acDevice, acDeviceNames + szPos, DEVICE_NAME_LENGTH - 1);
188  pnddDevices[*pszDeviceFound].acDevice[DEVICE_NAME_LENGTH - 1] = '\0';
189  pnddDevices[*pszDeviceFound].pcDriver = ACR122_DRIVER_NAME;
190  pnddDevices[*pszDeviceFound].uiBusIndex = uiBusIndex;
191  (*pszDeviceFound)++;
192  } else {
193  DBG ("PCSC device [%s] is not NFC capable or not supported by libnfc.", acDeviceNames + szPos);
194  }
195 
196  // Find next device name position
197  while (acDeviceNames[szPos++] != '\0');
198  }
199  acr122_free_scardcontext ();
200 
201  if (*pszDeviceFound)
202  return true;
203  return false;
204 }
205 
206 nfc_device_t *
207 acr122_connect (const nfc_device_desc_t * pndd)
208 {
209  nfc_device_t *pnd = NULL;
210  acr122_spec_t as;
211  acr122_spec_t *pas;
212  char *pcFirmware;
213 
214  SCARDCONTEXT *pscc;
215 
216  DBG ("Attempt to connect to %s", pndd->acDevice);
217  // Test if context succeeded
218  if (!(pscc = acr122_get_scardcontext ()))
219  return NULL;
220  // Test if we were able to connect to the "emulator" card
221  if (SCardConnect (*pscc, pndd->acDevice, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &(as.hCard), (void *) &(as.ioCard.dwProtocol)) != SCARD_S_SUCCESS) {
222  // Connect to ACR122 firmware version >2.0
223  if (SCardConnect (*pscc, pndd->acDevice, SCARD_SHARE_DIRECT, 0, &(as.hCard), (void *) &(as.ioCard.dwProtocol)) != SCARD_S_SUCCESS) {
224  // We can not connect to this device.
225  DBG ("%s", "PCSC connect failed");
226  return NULL;
227  }
228  }
229  // Configure I/O settings for card communication
230  as.ioCard.cbPciLength = sizeof (SCARD_IO_REQUEST);
231 
232  // Retrieve the current firmware version
233  pcFirmware = acr122_firmware ((nfc_device_t *) & as);
234  if (strstr (pcFirmware, FIRMWARE_TEXT) != NULL) {
235  // Allocate memory and store the device specification
236  pas = malloc (sizeof (acr122_spec_t));
237  *pas = as;
238 
239  // Done, we found the reader we are looking for
240  pnd = malloc (sizeof (nfc_device_t));
241  strcpy (pnd->acName, pndd->acDevice);
242  strcpy (pnd->acName + strlen (pnd->acName), " / ");
243  strcpy (pnd->acName + strlen (pnd->acName), pcFirmware);
244  pnd->nc = NC_PN532;
245  pnd->nds = (nfc_device_spec_t) pas;
246  pnd->bActive = true;
247 
248  return pnd;
249  }
250 
251  return NULL;
252 }
253 
254 void
255 acr122_disconnect (nfc_device_t * pnd)
256 {
257  acr122_spec_t *pas = (acr122_spec_t *) pnd->nds;
258  SCardDisconnect (pas->hCard, SCARD_LEAVE_CARD);
259  acr122_free_scardcontext ();
260  free (pas);
261  free (pnd);
262 }
263 
264 bool
265 acr122_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, byte_t * pbtRx, size_t * pszRx)
266 {
267  byte_t abtRxCmd[5] = { 0xFF, 0xC0, 0x00, 0x00 };
268  size_t szRxCmdLen = sizeof (abtRxCmd);
269  byte_t abtRxBuf[ACR122_RESPONSE_LEN];
270  size_t szRxBufLen;
271  byte_t abtTxBuf[ACR122_WRAP_LEN + ACR122_COMMAND_LEN] = { 0xFF, 0x00, 0x00, 0x00 };
272  acr122_spec_t *pas = (acr122_spec_t *) pnd->nds;
273 
274  // FIXME: Should be handled by the library.
275  // Make sure the command does not overflow the send buffer
276  if (szTx > ACR122_COMMAND_LEN) {
277  pnd->iLastError = DEIO;
278  return false;
279  }
280  // Store the length of the command we are going to send
281  abtTxBuf[4] = szTx;
282 
283  // Prepare and transmit the send buffer
284  memcpy (abtTxBuf + 5, pbtTx, szTx);
285  szRxBufLen = sizeof (abtRxBuf);
286 #ifdef DEBUG
287  PRINT_HEX ("TX", abtTxBuf, szTx + 5);
288 #endif
289 
290  if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED) {
291  if (SCardControl
292  (pas->hCard, IOCTL_CCID_ESCAPE_SCARD_CTL_CODE, abtTxBuf, szTx + 5, abtRxBuf, szRxBufLen,
293  (void *) &szRxBufLen) != SCARD_S_SUCCESS) {
294  pnd->iLastError = DEIO;
295  return false;
296  }
297  } else {
298  if (SCardTransmit (pas->hCard, &(pas->ioCard), abtTxBuf, szTx + 5, NULL, abtRxBuf, (void *) &szRxBufLen) !=
299  SCARD_S_SUCCESS) {
300  pnd->iLastError = DEIO;
301  return false;
302  }
303  }
304 
305  if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_T0) {
306  // Make sure we received the byte-count we expected
307  if (szRxBufLen != 2) {
308  pnd->iLastError = DEIO;
309  return false;
310  }
311  // Check if the operation was successful, so an answer is available
312  if (*abtRxBuf == SCARD_OPERATION_ERROR) {
313  pnd->iLastError = DEISERRFRAME;
314  return false;
315  }
316  // Retrieve the response bytes
317  abtRxCmd[4] = abtRxBuf[1];
318  szRxBufLen = sizeof (abtRxBuf);
319  if (SCardTransmit (pas->hCard, &(pas->ioCard), abtRxCmd, szRxCmdLen, NULL, abtRxBuf, (void *) &szRxBufLen) !=
320  SCARD_S_SUCCESS) {
321  pnd->iLastError = DEIO;
322  return false;
323  }
324  }
325 #ifdef DEBUG
326  PRINT_HEX ("RX", abtRxBuf, szRxBufLen);
327 #endif
328 
329  // When the answer should be ignored, just return a succesful result
330  if (pbtRx == NULL || pszRx == NULL)
331  return true;
332 
333  // Make sure we have an emulated answer that fits the return buffer
334  if (szRxBufLen < 4 || (szRxBufLen - 4) > *pszRx) {
335  pnd->iLastError = DEIO;
336  return false;
337  }
338  // Wipe out the 4 APDU emulation bytes: D5 4B .. .. .. 90 00
339  *pszRx = ((size_t) szRxBufLen) - 4;
340  memcpy (pbtRx, abtRxBuf + 2, *pszRx);
341 
342  // Transmission went successful
343  return true;
344 }
345 
346 char *
347 acr122_firmware (const nfc_device_spec_t nds)
348 {
349  byte_t abtGetFw[5] = { 0xFF, 0x00, 0x48, 0x00, 0x00 };
350  uint32_t uiResult;
351 
352  acr122_spec_t *pas = (acr122_spec_t *) nds;
353  static char abtFw[11];
354  size_t szFwLen = sizeof (abtFw);
355  memset (abtFw, 0x00, szFwLen);
356  if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED) {
357  uiResult = SCardControl (pas->hCard, IOCTL_CCID_ESCAPE_SCARD_CTL_CODE, abtGetFw, sizeof (abtGetFw), abtFw, szFwLen-1, (void *) &szFwLen);
358  } else {
359  uiResult = SCardTransmit (pas->hCard, &(pas->ioCard), abtGetFw, sizeof (abtGetFw), NULL, (byte_t *) abtFw, (void *) &szFwLen);
360  }
361 
362  if (uiResult != SCARD_S_SUCCESS) {
363  ERR ("No ACR122 firmware received, Error: %08x", uiResult);
364  }
365 
366  return abtFw;
367 }
368 
369 bool
370 acr122_led_red (const nfc_device_spec_t nds, bool bOn)
371 {
372  byte_t abtLed[9] = { 0xFF, 0x00, 0x40, 0x05, 0x04, 0x00, 0x00, 0x00, 0x00 };
373  acr122_spec_t *pas = (acr122_spec_t *) nds;
374  byte_t abtBuf[2];
375  size_t szBufLen = sizeof (abtBuf);
376  (void) bOn;
377  if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED) {
378  return (SCardControl
379  (pas->hCard, IOCTL_CCID_ESCAPE_SCARD_CTL_CODE, abtLed, sizeof (abtLed), abtBuf, szBufLen,
380  (void *) &szBufLen) == SCARD_S_SUCCESS);
381  } else {
382  return (SCardTransmit
383  (pas->hCard, &(pas->ioCard), abtLed, sizeof (abtLed), NULL, (byte_t *) abtBuf,
384  (void *) &szBufLen) == SCARD_S_SUCCESS);
385  }
386 }