libnfc  1.4.2
nfc-relay.c
Go to the documentation of this file.
1 /*-
2  * Public platform independent Near Field Communication (NFC) library examples
3  *
4  * Copyright (C) 2009, Roel Verdult
5  * Copyright (C) 2010, Romuald Conty
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  * 1) Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  * 2 )Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  *
27  * Note that this license only applies on the examples, NFC library itself is under LGPL
28  *
29  */
30 
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif /* HAVE_CONFIG_H */
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <stdint.h>
43 #include <string.h>
44 #include <signal.h>
45 
46 #include <nfc/nfc.h>
47 
48 #include <nfc/nfc-messages.h>
49 #include "nfc-utils.h"
50 
51 #define MAX_FRAME_LEN 264
52 #define MAX_DEVICE_COUNT 2
53 
54 static byte_t abtReaderRx[MAX_FRAME_LEN];
55 static byte_t abtReaderRxPar[MAX_FRAME_LEN];
56 static size_t szReaderRxBits;
57 static byte_t abtTagRx[MAX_FRAME_LEN];
58 static byte_t abtTagRxPar[MAX_FRAME_LEN];
59 static size_t szTagRxBits;
60 static nfc_device_t *pndReader;
61 static nfc_device_t *pndTag;
62 static bool quitting = false;
63 
64 void
65 intr_hdlr (void)
66 {
67  printf ("\nQuitting...\n");
68  quitting = true;
69  return;
70 }
71 
72 void
73 print_usage (char *argv[])
74 {
75  printf ("Usage: %s [OPTIONS]\n", argv[0]);
76  printf ("Options:\n");
77  printf ("\t-h\tHelp. Print this message.\n");
78  printf ("\t-q\tQuiet mode. Suppress output of READER and EMULATOR data (improves timing).\n");
79 }
80 
81 int
82 main (int argc, char *argv[])
83 {
84  int arg;
85  bool quiet_output = false;
86  size_t szFound;
87  nfc_device_desc_t *pnddDevices;
88  const char *acLibnfcVersion = nfc_version ();
89 
90  // Get commandline options
91  for (arg = 1; arg < argc; arg++) {
92  if (0 == strcmp (argv[arg], "-h")) {
93  print_usage (argv);
94  return EXIT_SUCCESS;
95  } else if (0 == strcmp (argv[arg], "-q")) {
96  quiet_output = true;
97  } else {
98  ERR ("%s is not supported option.", argv[arg]);
99  print_usage (argv);
100  return EXIT_FAILURE;
101  }
102  }
103 
104  // Display libnfc version
105  printf ("%s use libnfc %s\n", argv[0], acLibnfcVersion);
106 
107 #ifdef WIN32
108  signal (SIGINT, (void (__cdecl *) (int)) intr_hdlr);
109 #else
110  signal (SIGINT, (void (*)()) intr_hdlr);
111 #endif
112 
113  // Allocate memory to put the result of available devices listing
114  if (!(pnddDevices = malloc (MAX_DEVICE_COUNT * sizeof (*pnddDevices)))) {
115  fprintf (stderr, "malloc() failed\n");
116  return EXIT_FAILURE;
117  }
118  // List available devices
119  nfc_list_devices (pnddDevices, MAX_DEVICE_COUNT, &szFound);
120 
121  if (szFound < 2) {
122  ERR ("%zd device found but two connected devices are needed to relay NFC.", szFound);
123  return EXIT_FAILURE;
124  }
125  // Try to open the NFC emulator device
126  pndTag = nfc_connect (&(pnddDevices[0]));
127  if (pndTag == NULL) {
128  printf ("Error connecting NFC emulator device\n");
129  return EXIT_FAILURE;
130  }
131 
132  printf ("Hint: tag <---> initiator (relay) <---> target (relay) <---> original reader\n\n");
133 
134  printf ("Connected to the NFC emulator device: %s\n", pndTag->acName);
135  printf ("[+] Try to break out the auto-emulation, this requires a second reader!\n");
136  printf ("[+] To do this, please send any command after the anti-collision\n");
137  printf ("[+] For example, send a RATS command or use the \"nfc-anticol\" tool\n");
138 
139  nfc_target_t nt = {
140  .nm.nmt = NMT_ISO14443A,
141  .nm.nbr = NBR_UNDEFINED,
142  .nti.nai.abtAtqa = { 0x04, 0x00 },
143  .nti.nai.abtUid = { 0xde, 0xad, 0xbe, 0xef },
144  .nti.nai.btSak = 0x20,
145  .nti.nai.szUidLen = 4,
146  .nti.nai.szAtsLen = 0,
147  };
148 
149  if (!nfc_target_init (pndTag, &nt, abtReaderRx, &szReaderRxBits)) {
150  ERR ("%s", "Initialization of NFC emulator failed");
151  nfc_disconnect (pndTag);
152  return EXIT_FAILURE;
153  }
154  printf ("%s", "Configuring emulator settings...");
155  if (!nfc_configure (pndTag, NDO_HANDLE_CRC, false) ||
156  !nfc_configure (pndTag, NDO_HANDLE_PARITY, false) || !nfc_configure (pndTag, NDO_ACCEPT_INVALID_FRAMES, true)) {
157  nfc_perror (pndTag, "nfc_configure");
158  exit (EXIT_FAILURE);
159  }
160  printf ("%s", "Done, emulated tag is initialized");
161 
162  // Try to open the NFC reader
163  pndReader = nfc_connect (&(pnddDevices[1]));
164 
165  printf ("Connected to the NFC reader device: %s", pndReader->acName);
166  printf ("%s", "Configuring NFC reader settings...");
167  nfc_initiator_init (pndReader);
168  if (!nfc_configure (pndReader, NDO_HANDLE_CRC, false) ||
169  !nfc_configure (pndReader, NDO_HANDLE_PARITY, false) ||
170  !nfc_configure (pndReader, NDO_ACCEPT_INVALID_FRAMES, true)) {
171  nfc_perror (pndReader, "nfc_configure");
172  exit (EXIT_FAILURE);
173  }
174  printf ("%s", "Done, relaying frames now!");
175 
176  while (!quitting) {
177  // Test if we received a frame from the reader
178  if (nfc_target_receive_bits (pndTag, abtReaderRx, &szReaderRxBits, abtReaderRxPar)) {
179  // Drop down the field before sending a REQA command and start a new session
180  if (szReaderRxBits == 7 && abtReaderRx[0] == 0x26) {
181  // Drop down field for a very short time (original tag will reboot)
182  if (!nfc_configure (pndReader, NDO_ACTIVATE_FIELD, false)) {
183  nfc_perror (pndReader, "nfc_configure");
184  exit (EXIT_FAILURE);
185  }
186  if (!quiet_output)
187  printf ("\n");
188  if (!nfc_configure (pndReader, NDO_ACTIVATE_FIELD, true)) {
189  nfc_perror (pndReader, "nfc_configure");
190  exit (EXIT_FAILURE);
191  }
192  }
193  // Print the reader frame to the screen
194  if (!quiet_output) {
195  printf ("R: ");
196  print_hex_par (abtReaderRx, szReaderRxBits, abtReaderRxPar);
197  }
198  // Forward the frame to the original tag
200  (pndReader, abtReaderRx, szReaderRxBits, abtReaderRxPar, abtTagRx, &szTagRxBits, abtTagRxPar)) {
201  // Redirect the answer back to the reader
202  if (!nfc_target_send_bits (pndTag, abtTagRx, szTagRxBits, abtTagRxPar)) {
203  nfc_perror (pndTag, "nfc_target_send_bits");
204  exit (EXIT_FAILURE);
205  }
206  // Print the tag frame to the screen
207  if (!quiet_output) {
208  printf ("T: ");
209  print_hex_par (abtTagRx, szTagRxBits, abtTagRxPar);
210  }
211  }
212  }
213  }
214 
215  nfc_disconnect (pndTag);
216  nfc_disconnect (pndReader);
217  exit (EXIT_SUCCESS);
218 }