libnfc  1.7.0
nfc-read-forum-tag3.c
Go to the documentation of this file.
1 /*-
2  * Free/Libre Near Field Communication (NFC) library
3  *
4  * Libnfc historical contributors:
5  * Copyright (C) 2009 Roel Verdult
6  * Copyright (C) 2009-2013 Romuald Conty
7  * Copyright (C) 2010-2012 Romain Tartière
8  * Copyright (C) 2010-2013 Philippe Teuwen
9  * Copyright (C) 2012-2013 Ludovic Rousseau
10  * See AUTHORS file for a more comprehensive list of contributors.
11  * Additional contributors of this file:
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions are met:
15  * 1) Redistributions of source code must retain the above copyright notice,
16  * this list of conditions and the following disclaimer.
17  * 2 )Redistributions in binary form must reproduce the above copyright
18  * notice, this list of conditions and the following disclaimer in the
19  * documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Note that this license only applies on the examples, NFC library itself is under LGPL
34  *
35  */
36 
43 /*
44  * This implementation was written based on information provided by the
45  * following documents:
46  *
47  * NFC Forum Type 3 Tag Operation Specification
48  * Technical Specification
49  * NFCForum-TS-Type-3-Tag_1.1 - 2011-06-28
50  */
51 
52 #ifdef HAVE_CONFIG_H
53 # include "config.h"
54 #endif // HAVE_CONFIG_H
55 
56 #include <errno.h>
57 #include <signal.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 
61 #include <nfc/nfc.h>
62 
63 #include "nfc-utils.h"
64 
65 #if defined(WIN32) && defined(__GNUC__) /* mingw compiler */
66 #include <getopt.h>
67 #endif
68 
69 static nfc_device *pnd;
70 static nfc_context *context;
71 
72 static void
73 print_usage(char *progname)
74 {
75  fprintf(stderr, "usage: %s -o FILE\n", progname);
76  fprintf(stderr, "\nOptions:\n");
77  fprintf(stderr, " -o Extract NDEF message if available in FILE\n");
78 }
79 
80 static void stop_select(int sig)
81 {
82  (void) sig;
83  if (pnd != NULL) {
84  nfc_abort_command(pnd);
85  } else {
86  nfc_exit(context);
87  exit(EXIT_FAILURE);
88  }
89 }
90 
91 static void
92 build_felica_frame(const nfc_felica_info nfi, const uint8_t command, const uint8_t *payload, const size_t payload_len, uint8_t *frame, size_t *frame_len)
93 {
94  frame[0] = 1 + 1 + 8 + payload_len;
95  *frame_len = frame[0];
96  frame[1] = command;
97  memcpy(frame + 2, nfi.abtId, 8);
98  memcpy(frame + 10, payload, payload_len);
99 }
100 
101 #define CHECK 0x06
102 static int
103 nfc_forum_tag_type3_check(nfc_device *dev, const nfc_target nt, const uint16_t block, const uint8_t block_count, uint8_t *data, size_t *data_len)
104 {
105  uint8_t payload[1024] = {
106  1, // Services
107  0x0B, 0x00, // NFC Forum Tag Type 3's Service code
108  block_count,
109  0x80, block, // block 0
110  };
111 
112  size_t payload_len = 1 + 2 + 1;
113  for (uint8_t b = 0; b < block_count; b++) {
114  if (block < 0x100) {
115  payload[payload_len++] = 0x80;
116  payload[payload_len++] = block + b;
117  } else {
118  payload[payload_len++] = 0x00;
119  payload[payload_len++] = (block + b) >> 8;
120  payload[payload_len++] = (block + b) & 0xff;
121  }
122  }
123 
124  uint8_t frame[1024];
125  size_t frame_len = sizeof(frame);
126  build_felica_frame(nt.nti.nfi, CHECK, payload, payload_len, frame, &frame_len);
127 
128  uint8_t rx[1024];
129  int res;
130  if ((res = nfc_initiator_transceive_bytes(dev, frame, frame_len, rx, sizeof(rx), 0)) < 0) {
131  return res;
132  }
133  const int res_overhead = 1 + 1 + 8 + 2; // 1+1+8+2: LEN + CMD + NFCID2 + STATUS
134  if (res < res_overhead) {
135  // Not enough data
136  return -1;
137  }
138  uint8_t felica_res_len = rx[0];
139  if (res != felica_res_len) {
140  // Error while receiving felica frame
141  return -1;
142  }
143  if ((CHECK + 1) != rx[1]) {
144  // Command return does not match
145  return -1;
146  }
147  if (0 != memcmp(&rx[2], nt.nti.nfi.abtId, 8)) {
148  // NFCID2 does not match
149  return -1;
150  }
151  const uint8_t status_flag1 = rx[10];
152  const uint8_t status_flag2 = rx[11];
153  if ((status_flag1) || (status_flag2)) {
154  // Felica card's error
155  fprintf(stderr, "Status bytes: %02x, %02x\n", status_flag1, status_flag2);
156  return -1;
157  }
158  // const uint8_t res_block_count = res[12];
159  *data_len = res - res_overhead + 1; // +1 => block count is stored on 1 byte
160  memcpy(data, &rx[res_overhead + 1], *data_len);
161  return *data_len;
162 }
163 
164 int
165 main(int argc, char *argv[])
166 {
167  (void)argc;
168  (void)argv;
169 
170  int ch;
171  char *ndef_output = NULL;
172  while ((ch = getopt(argc, argv, "ho:")) != -1) {
173  switch (ch) {
174  case 'h':
175  print_usage(argv[0]);
176  exit(EXIT_SUCCESS);
177  break;
178  case 'o':
179  ndef_output = optarg;
180  break;
181  case '?':
182  if (optopt == 'o')
183  fprintf(stderr, "Option -%c requires an argument.\n", optopt);
184  default:
185  print_usage(argv[0]);
186  exit(EXIT_FAILURE);
187  }
188  }
189 
190  if (ndef_output == NULL) {
191  print_usage(argv[0]);
192  exit(EXIT_FAILURE);
193  }
194  FILE *message_stream = NULL;
195  FILE *ndef_stream = NULL;
196 
197  if ((strlen(ndef_output) == 1) && (ndef_output[0] == '-')) {
198  message_stream = stderr;
199  ndef_stream = stdout;
200  } else {
201  message_stream = stdout;
202  ndef_stream = fopen(ndef_output, "wb");
203  if (!ndef_stream) {
204  fprintf(stderr, "Could not open file %s.\n", ndef_output);
205  exit(EXIT_FAILURE);
206  }
207  }
208 
209  nfc_init(&context);
210  if (context == NULL) {
211  ERR("Unable to init libnfc (malloc)\n");
212  exit(EXIT_FAILURE);
213  }
214 
215  pnd = nfc_open(context, NULL);
216 
217  if (pnd == NULL) {
218  ERR("Unable to open NFC device");
219  fclose(ndef_stream);
220  nfc_exit(context);
221  exit(EXIT_FAILURE);
222  }
223 
224  fprintf(message_stream, "NFC device: %s opened\n", nfc_device_get_name(pnd));
225 
226  nfc_modulation nm = {
227  .nmt = NMT_FELICA,
228  .nbr = NBR_212,
229  };
230 
231  signal(SIGINT, stop_select);
232 
233  nfc_target nt;
234 
235  if (nfc_initiator_init(pnd) < 0) {
236  nfc_perror(pnd, "nfc_initiator_init");
237  fclose(ndef_stream);
238  nfc_close(pnd);
239  nfc_exit(context);
240  exit(EXIT_FAILURE);
241  }
242  fprintf(message_stream, "Place your NFC Forum Tag Type 3 in the field...\n");
243 
244  // Polling payload (SENSF_REQ) must be present (see NFC Digital Protol)
245  const uint8_t *pbtSensfReq = (uint8_t *)"\x00\xff\xff\x01\x00";
246  if (nfc_initiator_select_passive_target(pnd, nm, pbtSensfReq, 5, &nt) <= 0) {
247  nfc_perror(pnd, "nfc_initiator_select_passive_target");
248  fclose(ndef_stream);
249  nfc_close(pnd);
250  nfc_exit(context);
251  exit(EXIT_FAILURE);
252  }
253 
254  // Check if System Code equals 0x12fc
255  const uint8_t abtNfcForumSysCode[] = { 0x12, 0xfc };
256  if (0 != memcmp(nt.nti.nfi.abtSysCode, abtNfcForumSysCode, 2)) {
257  // Retry with special polling
258  const uint8_t *pbtSensfReqNfcForum = (uint8_t *)"\x00\x12\xfc\x01\x00";
259  if (nfc_initiator_select_passive_target(pnd, nm, pbtSensfReqNfcForum, 5, &nt) <= 0) {
260  nfc_perror(pnd, "nfc_initiator_select_passive_target");
261  fclose(ndef_stream);
262  nfc_close(pnd);
263  nfc_exit(context);
264  exit(EXIT_FAILURE);
265  }
266  // Check again if System Code equals 0x12fc
267  if (0 != memcmp(nt.nti.nfi.abtSysCode, abtNfcForumSysCode, 2)) {
268  fprintf(stderr, "Tag is not NFC Forum Tag Type 3 compliant.\n");
269  fclose(ndef_stream);
270  nfc_close(pnd);
271  nfc_exit(context);
272  exit(EXIT_FAILURE);
273  }
274  }
275 
276  //print_nfc_felica_info(nt.nti.nfi, true);
277 
279  nfc_perror(pnd, "nfc_device_set_property_bool");
280  fclose(ndef_stream);
281  nfc_close(pnd);
282  nfc_exit(context);
283  exit(EXIT_FAILURE);
284  }
285 
286  uint8_t data[1024];
287  size_t data_len = sizeof(data);
288 
289  if (nfc_forum_tag_type3_check(pnd, nt, 0, 1, data, &data_len) <= 0) {
290  nfc_perror(pnd, "nfc_forum_tag_type3_check");
291  fclose(ndef_stream);
292  nfc_close(pnd);
293  nfc_exit(context);
294  exit(EXIT_FAILURE);
295  }
296 
297  const int ndef_major_version = (data[0] & 0xf0) >> 4;
298  const int ndef_minor_version = (data[0] & 0x0f);
299  fprintf(message_stream, "NDEF Mapping version: %d.%d\n", ndef_major_version, ndef_minor_version);
300 
301  const int available_block_count = (data[3] << 8) + data[4];
302  fprintf(message_stream, "NFC Forum Tag Type 3 capacity: %d bytes\n", available_block_count * 16);
303 
304  uint32_t ndef_data_len = (data[11] << 16) + (data[12] << 8) + data[13];
305  fprintf(message_stream, "NDEF data length: %d bytes\n", ndef_data_len);
306 
307  uint16_t ndef_calculated_checksum = 0;
308  for (size_t n = 0; n < 14; n++)
309  ndef_calculated_checksum += data[n];
310 
311  const uint16_t ndef_checksum = (data[14] << 8) + data[15];
312  if (ndef_calculated_checksum != ndef_checksum) {
313  fprintf(stderr, "NDEF CRC does not match with calculated one\n");
314  fclose(ndef_stream);
315  nfc_close(pnd);
316  nfc_exit(context);
317  exit(EXIT_FAILURE);
318  }
319 
320  if (!ndef_data_len) {
321  fprintf(stderr, "Empty NFC Forum Tag Type 3\n");
322  fclose(ndef_stream);
323  nfc_close(pnd);
324  nfc_exit(context);
325  exit(EXIT_FAILURE);
326  }
327 
328  const uint8_t block_max_per_check = data[1];
329  const uint16_t block_count_to_check = (ndef_data_len / 16) + 1;
330 
331  data_len = 0;
332  for (uint16_t b = 0; b < (block_count_to_check / block_max_per_check); b += block_max_per_check) {
333  size_t size = sizeof(data) - data_len;
334  if (!nfc_forum_tag_type3_check(pnd, nt, 1 + b, MIN(block_max_per_check, (block_count_to_check - (b * block_max_per_check))), data + data_len, &size)) {
335  nfc_perror(pnd, "nfc_forum_tag_type3_check");
336  fclose(ndef_stream);
337  nfc_close(pnd);
338  nfc_exit(context);
339  exit(EXIT_FAILURE);
340  }
341  data_len += size;
342  }
343  if (fwrite(data, 1, data_len, ndef_stream) != data_len) {
344  fprintf(stderr, "Could not write to file.\n");
345  fclose(ndef_stream);
346  nfc_close(pnd);
347  nfc_exit(context);
348  exit(EXIT_FAILURE);
349  }
350 
351  fclose(ndef_stream);
352  nfc_close(pnd);
353  nfc_exit(context);
354  exit(EXIT_SUCCESS);
355 }