libnfc
1.4.2
|
00001 /*- 00002 * Public platform independent Near Field Communication (NFC) library examples 00003 * 00004 * Copyright (C) 2010, Romuald Conty 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions are met: 00008 * 1) Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions and the following disclaimer. 00010 * 2 )Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 00014 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00015 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00016 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00017 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00018 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00019 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00020 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00021 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00022 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00023 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00024 * POSSIBILITY OF SUCH DAMAGE. 00025 * 00026 * Note that this license only applies on the examples, NFC library itself is under LGPL 00027 * 00028 */ 00029 00035 // Notes & differences with nfc-relay: 00036 // - This example only works with PN532 because it relies on 00037 // its internal handling of ISO14443-4 specificities. 00038 // - Thanks to this internal handling & injection of WTX frames, 00039 // this example works on readers very strict on timing 00040 00041 #ifdef HAVE_CONFIG_H 00042 # include "config.h" 00043 #endif /* HAVE_CONFIG_H */ 00044 00045 #include <stdio.h> 00046 #include <stdlib.h> 00047 #include <stdint.h> 00048 #include <string.h> 00049 #include <signal.h> 00050 //#include <stddef.h> 00051 00052 #include <nfc/nfc.h> 00053 00054 #include <nfc/nfc-messages.h> 00055 #include "nfc-utils.h" 00056 00057 #ifndef _WIN32 00058 // Needed by sleep() under Unix 00059 # include <unistd.h> 00060 # define sleep sleep 00061 # define SUSP_TIME 1 // secs. 00062 #else 00063 // Needed by Sleep() under Windows 00064 # include "../contrib/windows.h" 00065 # include <winbase.h> 00066 # define sleep Sleep 00067 # define SUSP_TIME 1000 // msecs. 00068 #endif 00069 00070 #define MAX_FRAME_LEN 264 00071 #define MAX_DEVICE_COUNT 2 00072 00073 static byte_t abtCapdu[MAX_FRAME_LEN]; 00074 static size_t szCapduLen; 00075 static byte_t abtRapdu[MAX_FRAME_LEN]; 00076 static size_t szRapduLen; 00077 static nfc_device_t *pndInitiator; 00078 static nfc_device_t *pndTarget; 00079 static bool quitting = false; 00080 static bool quiet_output = false; 00081 static bool initiator_only_mode = false; 00082 static bool target_only_mode = false; 00083 static int waiting_time = 0; 00084 FILE * fd3; 00085 FILE * fd4; 00086 00087 void 00088 intr_hdlr (void) 00089 { 00090 printf ("\nQuitting...\n"); 00091 printf ("Please send a last command to the emulator to quit properly.\n"); 00092 quitting = true; 00093 return; 00094 } 00095 00096 void 00097 print_usage (char *argv[]) 00098 { 00099 printf ("Usage: %s [OPTIONS]\n", argv[0]); 00100 printf ("Options:\n"); 00101 printf ("\t-h\tHelp. Print this message.\n"); 00102 printf ("\t-q\tQuiet mode. Suppress printing of relayed data (improves timing).\n"); 00103 printf ("\t-t\tTarget mode only (the one on reader side). Data expected from FD3 to FD4.\n"); 00104 printf ("\t-i\tInitiator mode only (the one on tag side). Data expected from FD3 to FD4.\n"); 00105 printf ("\t-n N\tAdds a waiting time of N seconds (integer) in the relay to mimic long distance.\n"); 00106 } 00107 00108 bool print_hex_fd4 (const byte_t * pbtData, const size_t szBytes, const char * pchPrefix) 00109 { 00110 size_t szPos; 00111 if (szBytes > MAX_FRAME_LEN) { 00112 return EXIT_FAILURE; 00113 } 00114 if (fprintf (fd4, "#%s %04zx: ", pchPrefix, szBytes)<0) { 00115 return EXIT_FAILURE; 00116 } 00117 00118 for (szPos = 0; szPos < szBytes; szPos++) { 00119 if (fprintf (fd4, "%02x ", pbtData[szPos])<0) { 00120 return EXIT_FAILURE; 00121 } 00122 } 00123 if (fprintf (fd4, "\n")<0) { 00124 return EXIT_FAILURE; 00125 } 00126 fflush(fd4); 00127 return EXIT_SUCCESS; 00128 } 00129 00130 bool scan_hex_fd3 (byte_t *pbtData, size_t *pszBytes, const char * pchPrefix) 00131 { 00132 size_t szPos; 00133 unsigned int uiBytes; 00134 unsigned int uiData; 00135 char pchScan[256]; 00136 int c; 00137 // Look for our next sync marker 00138 while ( (c=fgetc(fd3)) != '#') { 00139 if (c == EOF) { 00140 return EXIT_FAILURE; 00141 } 00142 } 00143 strncpy(pchScan, pchPrefix, 250); 00144 strcat(pchScan, " %04x:"); 00145 if (fscanf (fd3, pchScan, &uiBytes)<1) { 00146 return EXIT_FAILURE; 00147 } 00148 *pszBytes=uiBytes; 00149 if (*pszBytes > MAX_FRAME_LEN) { 00150 return EXIT_FAILURE; 00151 } 00152 for (szPos = 0; szPos < *pszBytes; szPos++) { 00153 if (fscanf (fd3, "%02x", &uiData)<1) { 00154 return EXIT_FAILURE; 00155 } 00156 pbtData[szPos]=uiData; 00157 } 00158 return EXIT_SUCCESS; 00159 } 00160 00161 int 00162 main (int argc, char *argv[]) 00163 { 00164 int arg; 00165 size_t szFound; 00166 nfc_device_desc_t *pnddDevices; 00167 const char *acLibnfcVersion = nfc_version (); 00168 nfc_target_t ntRealTarget; 00169 00170 // Get commandline options 00171 for (arg = 1; arg < argc; arg++) { 00172 if (0 == strcmp (argv[arg], "-h")) { 00173 print_usage (argv); 00174 return EXIT_SUCCESS; 00175 } else if (0 == strcmp (argv[arg], "-q")) { 00176 quiet_output = true; 00177 } else if (0 == strcmp (argv[arg], "-t")) { 00178 printf ("INFO: %s\n", "Target mode only."); 00179 initiator_only_mode = false; 00180 target_only_mode = true; 00181 } else if (0 == strcmp (argv[arg], "-i")) { 00182 printf ("INFO: %s\n", "Initiator mode only."); 00183 initiator_only_mode = true; 00184 target_only_mode = false; 00185 } else if (0 == strcmp (argv[arg], "-n")) { 00186 if (++arg==argc || (sscanf(argv[arg], "%i", &waiting_time)<1)) { 00187 ERR ("Missing or wrong waiting time value: %s.", argv[arg]); 00188 print_usage (argv); 00189 return EXIT_FAILURE; 00190 } 00191 printf ("Waiting time: %i secs.\n", waiting_time); 00192 } else { 00193 ERR ("%s is not supported option.", argv[arg]); 00194 print_usage (argv); 00195 return EXIT_FAILURE; 00196 } 00197 } 00198 00199 // Display libnfc version 00200 printf ("%s use libnfc %s\n", argv[0], acLibnfcVersion); 00201 00202 #ifdef WIN32 00203 signal (SIGINT, (void (__cdecl *) (int)) intr_hdlr); 00204 #else 00205 signal (SIGINT, (void (*)()) intr_hdlr); 00206 #endif 00207 00208 // Allocate memory to put the result of available devices listing 00209 if (!(pnddDevices = malloc (MAX_DEVICE_COUNT * sizeof (*pnddDevices)))) { 00210 fprintf (stderr, "malloc() failed\n"); 00211 return EXIT_FAILURE; 00212 } 00213 // List available devices 00214 nfc_list_devices (pnddDevices, MAX_DEVICE_COUNT, &szFound); 00215 00216 if (initiator_only_mode || target_only_mode) { 00217 if (szFound < 1) { 00218 ERR ("No device found"); 00219 return EXIT_FAILURE; 00220 } 00221 fd3 = fdopen(3, "r"); 00222 fd4 = fdopen(4, "w"); 00223 } 00224 else { 00225 if (szFound < 2) { 00226 ERR ("%zd device found but two connected devices are needed to relay NFC.", szFound); 00227 return EXIT_FAILURE; 00228 } 00229 } 00230 00231 if (!target_only_mode) { 00232 // Try to open the NFC reader used as initiator 00233 // Little hack to allow using initiator no matter if 00234 // there is already a target used locally or not on the same machine: 00235 // if there is more than one readers connected we connect to the second reader 00236 // (we hope they're always detected in the same order) 00237 if (szFound == 1) { 00238 pndInitiator = nfc_connect (&(pnddDevices[0])); 00239 } else { 00240 pndInitiator = nfc_connect (&(pnddDevices[1])); 00241 } 00242 00243 if (!pndInitiator) { 00244 printf ("Error connecting NFC reader\n"); 00245 exit(EXIT_FAILURE); 00246 } 00247 00248 printf ("Connected to the NFC reader device: %s\n", pndInitiator->acName); 00249 00250 // Try to find a ISO 14443-4A tag 00251 nfc_modulation_t nm = { 00252 .nmt = NMT_ISO14443A, 00253 .nbr = NBR_106, 00254 }; 00255 if (!nfc_initiator_select_passive_target (pndInitiator, nm, NULL, 0, &ntRealTarget)) { 00256 printf ("Error: no tag was found\n"); 00257 nfc_disconnect (pndInitiator); 00258 exit (EXIT_FAILURE); 00259 } 00260 00261 printf("Found tag:\n"); 00262 print_nfc_iso14443a_info (ntRealTarget.nti.nai, false); 00263 if (initiator_only_mode) { 00264 if (print_hex_fd4(ntRealTarget.nti.nai.abtUid, ntRealTarget.nti.nai.szUidLen, "UID") != EXIT_SUCCESS) { 00265 fprintf (stderr, "Error while printing UID to FD4\n"); 00266 nfc_disconnect (pndInitiator); 00267 exit(EXIT_FAILURE); 00268 } 00269 if (print_hex_fd4(ntRealTarget.nti.nai.abtAtqa, 2, "ATQA") != EXIT_SUCCESS) { 00270 fprintf (stderr, "Error while printing ATQA to FD4\n"); 00271 nfc_disconnect (pndInitiator); 00272 exit(EXIT_FAILURE); 00273 } 00274 if (print_hex_fd4(&(ntRealTarget.nti.nai.btSak), 1, "SAK") != EXIT_SUCCESS) { 00275 fprintf (stderr, "Error while printing SAK to FD4\n"); 00276 nfc_disconnect (pndInitiator); 00277 exit(EXIT_FAILURE); 00278 } 00279 if (print_hex_fd4(ntRealTarget.nti.nai.abtAts, ntRealTarget.nti.nai.szAtsLen, "ATS") != EXIT_SUCCESS) { 00280 fprintf (stderr, "Error while printing ATS to FD4\n"); 00281 nfc_disconnect (pndInitiator); 00282 exit(EXIT_FAILURE); 00283 } 00284 } 00285 } 00286 if (initiator_only_mode) { 00287 printf ("Hint: tag <---> *INITIATOR* (relay) <-FD3/FD4-> target (relay) <---> original reader\n\n"); 00288 } else if (target_only_mode) { 00289 printf ("Hint: tag <---> initiator (relay) <-FD3/FD4-> *TARGET* (relay) <---> original reader\n\n"); 00290 } else { 00291 printf ("Hint: tag <---> initiator (relay) <---> target (relay) <---> original reader\n\n"); 00292 } 00293 if (!initiator_only_mode) { 00294 nfc_target_t ntEmulatedTarget = { 00295 .nm.nmt = NMT_ISO14443A, 00296 .nm.nbr = NBR_106, 00297 }; 00298 if (target_only_mode) { 00299 size_t foo; 00300 if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtUid, &(ntEmulatedTarget.nti.nai.szUidLen), "UID") != EXIT_SUCCESS) { 00301 fprintf (stderr, "Error while scanning UID from FD3\n"); 00302 nfc_disconnect (pndInitiator); 00303 exit(EXIT_FAILURE); 00304 } 00305 if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtAtqa, &foo, "ATQA") != EXIT_SUCCESS) { 00306 fprintf (stderr, "Error while scanning ATQA from FD3\n"); 00307 nfc_disconnect (pndInitiator); 00308 exit(EXIT_FAILURE); 00309 } 00310 if (scan_hex_fd3(&(ntEmulatedTarget.nti.nai.btSak), &foo, "SAK") != EXIT_SUCCESS) { 00311 fprintf (stderr, "Error while scanning SAK from FD3\n"); 00312 nfc_disconnect (pndInitiator); 00313 exit(EXIT_FAILURE); 00314 } 00315 if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtAts, &(ntEmulatedTarget.nti.nai.szAtsLen), "ATS") != EXIT_SUCCESS) { 00316 fprintf (stderr, "Error while scanning ATS from FD3\n"); 00317 nfc_disconnect (pndInitiator); 00318 exit(EXIT_FAILURE); 00319 } 00320 } else { 00321 ntEmulatedTarget.nti = ntRealTarget.nti; 00322 } 00323 // We can only emulate a short UID, so fix length & ATQA bit: 00324 ntEmulatedTarget.nti.nai.szUidLen = 4; 00325 ntEmulatedTarget.nti.nai.abtAtqa[1] &= (0xFF-0x40); 00326 // First byte of UID is always automatically replaced by 0x08 in this mode anyway 00327 ntEmulatedTarget.nti.nai.abtUid[0] = 0x08; 00328 // ATS is always automatically replaced by PN532, we've no control on it: 00329 // ATS = (05) 75 33 92 03 00330 // (TL) T0 TA TB TC 00331 // | | | +-- CID supported, NAD supported 00332 // | | +----- FWI=9 SFGI=2 => FWT=154ms, SFGT=1.21ms 00333 // | +-------- DR=2,4 DS=2,4 => supports 106, 212 & 424bps in both directions 00334 // +----------- TA,TB,TC, FSCI=5 => FSC=64 00335 // It seems hazardous to tell we support NAD if the tag doesn't support NAD but I don't know how to disable it 00336 // PC/SC pseudo-ATR = 3B 80 80 01 01 if there is no historical bytes 00337 00338 // Creates ATS and copy max 48 bytes of Tk: 00339 byte_t * pbtTk; 00340 size_t szTk; 00341 pbtTk = iso14443a_locate_historical_bytes (ntEmulatedTarget.nti.nai.abtAts, ntEmulatedTarget.nti.nai.szAtsLen, &szTk); 00342 szTk = (szTk > 48) ? 48 : szTk; 00343 byte_t pbtTkt[48]; 00344 memcpy(pbtTkt, pbtTk, szTk); 00345 ntEmulatedTarget.nti.nai.abtAts[0] = 0x75; 00346 ntEmulatedTarget.nti.nai.abtAts[1] = 0x33; 00347 ntEmulatedTarget.nti.nai.abtAts[2] = 0x92; 00348 ntEmulatedTarget.nti.nai.abtAts[3] = 0x03; 00349 ntEmulatedTarget.nti.nai.szAtsLen = 4 + szTk; 00350 memcpy(&(ntEmulatedTarget.nti.nai.abtAts[4]), pbtTkt, szTk); 00351 00352 printf("We will emulate:\n"); 00353 print_nfc_iso14443a_info (ntEmulatedTarget.nti.nai, false); 00354 00355 // Try to open the NFC emulator device 00356 pndTarget = nfc_connect (&(pnddDevices[0])); 00357 if (pndTarget == NULL) { 00358 printf ("Error connecting NFC emulator device\n"); 00359 if (!target_only_mode) { 00360 nfc_disconnect (pndInitiator); 00361 } 00362 return EXIT_FAILURE; 00363 } 00364 00365 printf ("Connected to the NFC emulator device: %s\n", pndTarget->acName); 00366 00367 if (!nfc_target_init (pndTarget, &ntEmulatedTarget, abtCapdu, &szCapduLen)) { 00368 ERR ("%s", "Initialization of NFC emulator failed"); 00369 if (!target_only_mode) { 00370 nfc_disconnect (pndInitiator); 00371 } 00372 nfc_disconnect (pndTarget); 00373 exit(EXIT_FAILURE); 00374 } 00375 printf ("%s\n", "Done, relaying frames now!"); 00376 } 00377 00378 00379 while (!quitting) { 00380 bool ret; 00381 if (!initiator_only_mode) { 00382 // Receive external reader command through target 00383 if (!nfc_target_receive_bytes(pndTarget,abtCapdu,&szCapduLen)) { 00384 nfc_perror (pndTarget, "nfc_target_receive_bytes"); 00385 if (!target_only_mode) { 00386 nfc_disconnect (pndInitiator); 00387 } 00388 nfc_disconnect (pndTarget); 00389 exit(EXIT_FAILURE); 00390 } 00391 if (target_only_mode) { 00392 if (print_hex_fd4(abtCapdu, szCapduLen, "C-APDU") != EXIT_SUCCESS) { 00393 fprintf (stderr, "Error while printing C-APDU to FD4\n"); 00394 nfc_disconnect (pndTarget); 00395 exit(EXIT_FAILURE); 00396 } 00397 } 00398 } else { 00399 if (scan_hex_fd3(abtCapdu, &szCapduLen, "C-APDU") != EXIT_SUCCESS) { 00400 fprintf (stderr, "Error while scanning C-APDU from FD3\n"); 00401 nfc_disconnect (pndInitiator); 00402 exit(EXIT_FAILURE); 00403 } 00404 } 00405 // Show transmitted response 00406 if (!quiet_output) { 00407 printf ("Forwarding C-APDU: "); 00408 print_hex (abtCapdu, szCapduLen); 00409 } 00410 00411 if (!target_only_mode) { 00412 // Forward the frame to the original tag 00413 ret = nfc_initiator_transceive_bytes 00414 (pndInitiator, abtCapdu, szCapduLen, abtRapdu, &szRapduLen); 00415 } else { 00416 if (scan_hex_fd3(abtRapdu, &szRapduLen, "R-APDU") != EXIT_SUCCESS) { 00417 fprintf (stderr, "Error while scanning R-APDU from FD3\n"); 00418 nfc_disconnect (pndTarget); 00419 exit(EXIT_FAILURE); 00420 } 00421 ret = true; 00422 } 00423 if (ret) { 00424 // Redirect the answer back to the external reader 00425 if (waiting_time > 0) { 00426 if (!quiet_output) { 00427 printf ("Waiting %is to simulate longer relay...\n", waiting_time); 00428 } 00429 sleep(waiting_time * SUSP_TIME); 00430 } 00431 // Show transmitted response 00432 if (!quiet_output) { 00433 printf ("Forwarding R-APDU: "); 00434 print_hex (abtRapdu, szRapduLen); 00435 } 00436 if (!initiator_only_mode) { 00437 // Transmit the response bytes 00438 if (!nfc_target_send_bytes(pndTarget, abtRapdu, szRapduLen)) { 00439 nfc_perror (pndTarget, "nfc_target_send_bytes"); 00440 if (!target_only_mode) { 00441 nfc_disconnect (pndInitiator); 00442 } 00443 if (!initiator_only_mode) { 00444 nfc_disconnect (pndTarget); 00445 } 00446 exit(EXIT_FAILURE); 00447 } 00448 } else { 00449 if (print_hex_fd4(abtRapdu, szRapduLen, "R-APDU") != EXIT_SUCCESS) { 00450 fprintf (stderr, "Error while printing R-APDU to FD4\n"); 00451 nfc_disconnect (pndInitiator); 00452 exit(EXIT_FAILURE); 00453 } 00454 } 00455 } 00456 } 00457 00458 if (!target_only_mode) { 00459 nfc_disconnect (pndInitiator); 00460 } 00461 if (!initiator_only_mode) { 00462 nfc_disconnect (pndTarget); 00463 } 00464 exit (EXIT_SUCCESS); 00465 } 00466