libnfc  1.7.1
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 [-q] -o FILE\n", progname);
76  fprintf(stderr, "\nOptions:\n");
77  fprintf(stderr, " -o FILE Extract NDEF message if available in FILE\n");
78  fprintf(stderr, " -o - Extract NDEF message if available to stdout\n");
79  fprintf(stderr, " -q Be quiet, don't display Attribute Block parsing info\n");
80 }
81 
82 static void stop_select(int sig)
83 {
84  (void) sig;
85  if (pnd != NULL) {
86  nfc_abort_command(pnd);
87  } else {
88  nfc_exit(context);
89  exit(EXIT_FAILURE);
90  }
91 }
92 
93 static void
94 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)
95 {
96  frame[0] = 1 + 1 + 8 + payload_len;
97  *frame_len = frame[0];
98  frame[1] = command;
99  memcpy(frame + 2, nfi.abtId, 8);
100  memcpy(frame + 10, payload, payload_len);
101 }
102 
103 #define CHECK 0x06
104 static int
105 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)
106 {
107  uint8_t payload[1024] = {
108  1, // Services
109  0x0B, 0x00, // NFC Forum Tag Type 3's Service code
110  block_count,
111  0x80, block, // block 0
112  };
113 
114  size_t payload_len = 1 + 2 + 1;
115  for (uint8_t b = 0; b < block_count; b++) {
116  if (block < 0x100) {
117  payload[payload_len++] = 0x80;
118  payload[payload_len++] = block + b;
119  } else {
120  payload[payload_len++] = 0x00;
121  payload[payload_len++] = (block + b) >> 8;
122  payload[payload_len++] = (block + b) & 0xff;
123  }
124  }
125 
126  uint8_t frame[1024];
127  size_t frame_len = sizeof(frame);
128  build_felica_frame(nt->nti.nfi, CHECK, payload, payload_len, frame, &frame_len);
129 
130  uint8_t rx[1024];
131  int res;
132  if ((res = nfc_initiator_transceive_bytes(dev, frame, frame_len, rx, sizeof(rx), 0)) < 0) {
133  return res;
134  }
135 
136  const int res_overhead = 1 + 1 + 8 + 2; // 1+1+8+2: LEN + CMD + NFCID2 + STATUS
137  if (res < res_overhead) {
138  // Not enough data
139  return -1;
140  }
141  uint8_t felica_res_len = rx[0];
142  if (res != felica_res_len) {
143  // Error while receiving felica frame
144  return -1;
145  }
146  if ((CHECK + 1) != rx[1]) {
147  // Command return does not match
148  return -1;
149  }
150  if (0 != memcmp(&rx[2], nt->nti.nfi.abtId, 8)) {
151  // NFCID2 does not match
152  return -1;
153  }
154  const uint8_t status_flag1 = rx[10];
155  const uint8_t status_flag2 = rx[11];
156  if ((status_flag1) || (status_flag2)) {
157  // Felica card's error
158  fprintf(stderr, "Status bytes: %02x, %02x\n", status_flag1, status_flag2);
159  return -1;
160  }
161  // const uint8_t res_block_count = res[12];
162  *data_len = res - res_overhead + 1; // +1 => block count is stored on 1 byte
163  memcpy(data, &rx[res_overhead + 1], *data_len);
164  return *data_len;
165 }
166 
167 int
168 main(int argc, char *argv[])
169 {
170  (void)argc;
171  (void)argv;
172 
173  int ch;
174  bool quiet = false;
175  char *ndef_output = NULL;
176  while ((ch = getopt(argc, argv, "hqo:")) != -1) {
177  switch (ch) {
178  case 'h':
179  print_usage(argv[0]);
180  exit(EXIT_SUCCESS);
181  break;
182  case 'q':
183  quiet = true;
184  break;
185  case 'o':
186  ndef_output = optarg;
187  break;
188  default:
189  print_usage(argv[0]);
190  exit(EXIT_FAILURE);
191  }
192  }
193 
194  if (ndef_output == NULL) {
195  print_usage(argv[0]);
196  exit(EXIT_FAILURE);
197  }
198  FILE *message_stream = NULL;
199  FILE *ndef_stream = NULL;
200 
201  if ((strlen(ndef_output) == 1) && (ndef_output[0] == '-')) {
202  message_stream = stderr;
203  ndef_stream = stdout;
204  } else {
205  message_stream = stdout;
206  ndef_stream = fopen(ndef_output, "wb");
207  if (!ndef_stream) {
208  fprintf(stderr, "Could not open file %s.\n", ndef_output);
209  exit(EXIT_FAILURE);
210  }
211  }
212 
213  nfc_init(&context);
214  if (context == NULL) {
215  ERR("Unable to init libnfc (malloc)\n");
216  exit(EXIT_FAILURE);
217  }
218 
219  pnd = nfc_open(context, NULL);
220 
221  if (pnd == NULL) {
222  ERR("Unable to open NFC device");
223  fclose(ndef_stream);
224  nfc_exit(context);
225  exit(EXIT_FAILURE);
226  }
227 
228  if (!quiet) {
229  fprintf(message_stream, "NFC device: %s opened\n", nfc_device_get_name(pnd));
230  }
231 
232  nfc_modulation nm = {
233  .nmt = NMT_FELICA,
234  .nbr = NBR_212,
235  };
236 
237  signal(SIGINT, stop_select);
238 
239  nfc_target nt;
240 
241  if (nfc_initiator_init(pnd) < 0) {
242  nfc_perror(pnd, "nfc_initiator_init");
243  fclose(ndef_stream);
244  nfc_close(pnd);
245  nfc_exit(context);
246  exit(EXIT_FAILURE);
247  }
248 
249  if (!quiet) {
250  fprintf(message_stream, "Place your NFC Forum Tag Type 3 in the field...\n");
251  }
252 
253  // Polling payload (SENSF_REQ) must be present (see NFC Digital Protol)
254  const uint8_t *pbtSensfReq = (uint8_t *)"\x00\xff\xff\x01\x00";
255  if (nfc_initiator_select_passive_target(pnd, nm, pbtSensfReq, 5, &nt) <= 0) {
256  nfc_perror(pnd, "nfc_initiator_select_passive_target");
257  fclose(ndef_stream);
258  nfc_close(pnd);
259  nfc_exit(context);
260  exit(EXIT_FAILURE);
261  }
262 
263  // Check if System Code equals 0x12fc
264  const uint8_t abtNfcForumSysCode[] = { 0x12, 0xfc };
265  if (0 != memcmp(nt.nti.nfi.abtSysCode, abtNfcForumSysCode, 2)) {
266  // Retry with special polling
267  const uint8_t *pbtSensfReqNfcForum = (uint8_t *)"\x00\x12\xfc\x01\x00";
268  if (nfc_initiator_select_passive_target(pnd, nm, pbtSensfReqNfcForum, 5, &nt) <= 0) {
269  nfc_perror(pnd, "nfc_initiator_select_passive_target");
270  fclose(ndef_stream);
271  nfc_close(pnd);
272  nfc_exit(context);
273  exit(EXIT_FAILURE);
274  }
275  // Check again if System Code equals 0x12fc
276  if (0 != memcmp(nt.nti.nfi.abtSysCode, abtNfcForumSysCode, 2)) {
277  fprintf(stderr, "Tag is not NFC Forum Tag Type 3 compliant.\n");
278  fclose(ndef_stream);
279  nfc_close(pnd);
280  nfc_exit(context);
281  exit(EXIT_FAILURE);
282  }
283  }
284 
285  //print_nfc_felica_info(nt.nti.nfi, true);
286 
288  nfc_perror(pnd, "nfc_device_set_property_bool");
289  fclose(ndef_stream);
290  nfc_close(pnd);
291  nfc_exit(context);
292  exit(EXIT_FAILURE);
293  }
294 
295  uint8_t data[1024];
296  size_t data_len = sizeof(data);
297 
298  if (nfc_forum_tag_type3_check(pnd, &nt, 0, 1, data, &data_len) <= 0) {
299  nfc_perror(pnd, "nfc_forum_tag_type3_check");
300  fclose(ndef_stream);
301  nfc_close(pnd);
302  nfc_exit(context);
303  exit(EXIT_FAILURE);
304  }
305 
306  const int ndef_major_version = (data[0] & 0xf0) >> 4;
307  const int ndef_minor_version = (data[0] & 0x0f);
308  const int ndef_nbr = data[1];
309  const int ndef_nbw = data[2];
310  const int ndef_nmaxb = (data[3] << 8) + data[4];
311  const int ndef_writeflag = data[9];
312  const int ndef_rwflag = data[10];
313  uint32_t ndef_data_len = (data[11] << 16) + (data[12] << 8) + data[13];
314  uint16_t ndef_calculated_checksum = 0;
315  for (size_t n = 0; n < 14; n++)
316  ndef_calculated_checksum += data[n];
317  const uint16_t ndef_checksum = (data[14] << 8) + data[15];
318 
319  if (!quiet) {
320  fprintf(message_stream, "NDEF Attribute Block:\n");
321  fprintf(message_stream, "* Mapping version: %d.%d\n", ndef_major_version, ndef_minor_version);
322  fprintf(message_stream, "* Maximum nr of blocks to read by Check Command: %3d block%s\n", ndef_nbr, ndef_nbr > 1 ? "s" : "");
323  fprintf(message_stream, "* Maximum nr of blocks to write by Update Command: %3d block%s\n", ndef_nbw, ndef_nbw > 1 ? "s" : "");
324  fprintf(message_stream, "* Maximum nr of blocks available for NDEF data: %3d block%s (%d bytes)\n", ndef_nmaxb, ndef_nmaxb > 1 ? "s" : "", ndef_nmaxb * 16);
325  fprintf(message_stream, "* NDEF writing state: ");
326  switch (ndef_writeflag) {
327  case 0x00:
328  fprintf(message_stream, "finished (0x00)\n");
329  break;
330  case 0x0f:
331  fprintf(message_stream, "in progress (0x0F)\n");
332  break;
333  default:
334  fprintf(message_stream, "invalid (0x%02X)\n", ndef_writeflag);
335  break;
336  }
337  fprintf(message_stream, "* NDEF Access Attribute: ");
338  switch (ndef_rwflag) {
339  case 0x00:
340  fprintf(message_stream, "Read only (0x00)\n");
341  break;
342  case 0x01:
343  fprintf(message_stream, "Read/Write (0x01)\n");
344  break;
345  default:
346  fprintf(message_stream, "invalid (0x%02X)\n", ndef_rwflag);
347  break;
348  }
349  fprintf(message_stream, "* NDEF message length: %d bytes\n", ndef_data_len);
350  if (ndef_calculated_checksum != ndef_checksum) {
351  fprintf(message_stream, "* Checksum: fail (0x%04X != 0x%04X)\n", ndef_calculated_checksum, ndef_checksum);
352  } else {
353  fprintf(message_stream, "* Checksum: ok (0x%04X)\n", ndef_checksum);
354  }
355  }
356 
357  if (ndef_calculated_checksum != ndef_checksum) {
358  fprintf(stderr, "Error: Checksum failed! Exiting now.\n");
359  fclose(ndef_stream);
360  nfc_close(pnd);
361  nfc_exit(context);
362  exit(EXIT_FAILURE);
363  }
364 
365  if (!ndef_data_len) {
366  fprintf(stderr, "Error: empty NFC Forum Tag Type 3, nothing to read!\n");
367  fclose(ndef_stream);
368  nfc_close(pnd);
369  nfc_exit(context);
370  exit(EXIT_FAILURE);
371  }
372 
373  const uint8_t block_max_per_check = data[1];
374  const uint16_t block_count_to_check = (ndef_data_len / 16) + 1;
375 
376  data_len = 0;
377  for (uint16_t b = 0; b < ((block_count_to_check - 1) / block_max_per_check + 1); b += block_max_per_check) {
378  size_t size = sizeof(data) - data_len;
379  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)) {
380  nfc_perror(pnd, "nfc_forum_tag_type3_check");
381  fclose(ndef_stream);
382  nfc_close(pnd);
383  nfc_exit(context);
384  exit(EXIT_FAILURE);
385  }
386  data_len += size;
387  }
388 
389  if (fwrite(data, 1, ndef_data_len, ndef_stream) != ndef_data_len) {
390  fprintf(stderr, "Error: could not write to file.\n");
391  fclose(ndef_stream);
392  nfc_close(pnd);
393  nfc_exit(context);
394  exit(EXIT_FAILURE);
395  } else {
396  if (!quiet) {
397  fprintf(stderr, "%i bytes written to %s\n", ndef_data_len, ndef_output);
398  }
399  }
400 
401  fclose(ndef_stream);
402  nfc_close(pnd);
403  nfc_exit(context);
404  exit(EXIT_SUCCESS);
405 }
nfc_initiator_init
int nfc_initiator_init(nfc_device *pnd)
Initialize NFC device as initiator (reader)
Definition: nfc.c:452
nfc_init
void nfc_init(nfc_context **context)
Initialize libnfc. This function must be called before calling any other libnfc function.
Definition: nfc.c:192
nfc_context
NFC library context Struct which contains internal options, references, pointers, etc....
Definition: nfc-internal.h:175
nfc_device
NFC device information.
Definition: nfc-internal.h:190
NP_INFINITE_SELECT
@ NP_INFINITE_SELECT
Definition: nfc-types.h:114
nfc_exit
void nfc_exit(nfc_context *context)
Deinitialize libnfc. Should be called after closing all open devices and before your application term...
Definition: nfc.c:209
nfc_target
NFC target structure.
Definition: nfc-types.h:328
nfc_initiator_transceive_bytes
int nfc_initiator_transceive_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout)
Send data to target then retrieve data from target.
Definition: nfc.c:764
nfc_modulation
NFC modulation structure.
Definition: nfc-types.h:319
nfc_device_get_name
const char * nfc_device_get_name(nfc_device *pnd)
Returns the device name.
Definition: nfc.c:1164
nfc_open
nfc_device * nfc_open(nfc_context *context, const nfc_connstring connstring)
Open a NFC device.
Definition: nfc.c:238
nfc_initiator_select_passive_target
int nfc_initiator_select_passive_target(nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt)
Select a passive or emulated tag.
Definition: nfc.c:521
nfc_perror
void nfc_perror(const nfc_device *pnd, const char *pcString)
Display the last error occured on a nfc_device.
Definition: nfc.c:1138
ERR
#define ERR(...)
Print a error message.
Definition: nfc-utils.h:85
nfc_felica_info
NFC FeLiCa tag information.
Definition: nfc-types.h:198
nfc_abort_command
int nfc_abort_command(nfc_device *pnd)
Abort current running command.
Definition: nfc.c:991
nfc_close
void nfc_close(nfc_device *pnd)
Close from a NFC device.
Definition: nfc.c:300
NP_EASY_FRAMING
@ NP_EASY_FRAMING
Definition: nfc-types.h:135
nfc-utils.h
Provide some examples shared functions like print, parity calculation, options parsing.
nfc_device_set_property_bool
int nfc_device_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable)
Set a device's boolean-property value.
Definition: nfc.c:426
nfc.h
libnfc interface