libnfc  1.4.2
nfc-relay-picc.c
Go to the documentation of this file.
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