libnfc 1.8.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
69static nfc_device *pnd;
70static nfc_context *context;
71
72static void
73print_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
82static void stop_select(int sig)
83{
84 (void) sig;
85 if (pnd != NULL) {
87 } else {
88 nfc_exit(context);
89 exit(EXIT_FAILURE);
90 }
91}
92
93static void
94build_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
104static int
105nfc_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
167int
168main(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 case 'q':
182 quiet = true;
183 break;
184 case 'o':
185 ndef_output = optarg;
186 break;
187 default:
188 print_usage(argv[0]);
189 exit(EXIT_FAILURE);
190 }
191 }
192
193 if (ndef_output == NULL) {
194 print_usage(argv[0]);
195 exit(EXIT_FAILURE);
196 }
197 FILE *message_stream = NULL;
198 FILE *ndef_stream = NULL;
199
200 if ((strlen(ndef_output) == 1) && (ndef_output[0] == '-')) {
201 message_stream = stderr;
202 ndef_stream = stdout;
203 } else {
204 message_stream = stdout;
205 ndef_stream = fopen(ndef_output, "wb");
206 if (!ndef_stream) {
207 fprintf(stderr, "Could not open file %s.\n", ndef_output);
208 exit(EXIT_FAILURE);
209 }
210 }
211
212 nfc_init(&context);
213 if (context == NULL) {
214 ERR("Unable to init libnfc (malloc)\n");
215 exit(EXIT_FAILURE);
216 }
217
218 pnd = nfc_open(context, NULL);
219
220 if (pnd == NULL) {
221 ERR("Unable to open NFC device");
222 fclose(ndef_stream);
223 nfc_exit(context);
224 exit(EXIT_FAILURE);
225 }
226
227 if (!quiet) {
228 fprintf(message_stream, "NFC device: %s opened\n", nfc_device_get_name(pnd));
229 }
230
231 nfc_modulation nm = {
232 .nmt = NMT_FELICA,
233 .nbr = NBR_212,
234 };
235
236 signal(SIGINT, stop_select);
237
238 nfc_target nt;
239
240 if (nfc_initiator_init(pnd) < 0) {
241 nfc_perror(pnd, "nfc_initiator_init");
242 fclose(ndef_stream);
243 nfc_close(pnd);
244 nfc_exit(context);
245 exit(EXIT_FAILURE);
246 }
247
248 if (!quiet) {
249 fprintf(message_stream, "Place your NFC Forum Tag Type 3 in the field...\n");
250 }
251
252 // Polling payload (SENSF_REQ) must be present (see NFC Digital Protol)
253 const uint8_t *pbtSensfReq = (uint8_t *)"\x00\xff\xff\x01\x00";
254 if (nfc_initiator_select_passive_target(pnd, nm, pbtSensfReq, 5, &nt) <= 0) {
255 nfc_perror(pnd, "nfc_initiator_select_passive_target");
256 fclose(ndef_stream);
257 nfc_close(pnd);
258 nfc_exit(context);
259 exit(EXIT_FAILURE);
260 }
261
262 // Check if System Code equals 0x12fc
263 const uint8_t abtNfcForumSysCode[] = { 0x12, 0xfc };
264 if (0 != memcmp(nt.nti.nfi.abtSysCode, abtNfcForumSysCode, 2)) {
265 // Retry with special polling
266 const uint8_t *pbtSensfReqNfcForum = (uint8_t *)"\x00\x12\xfc\x01\x00";
267 if (nfc_initiator_select_passive_target(pnd, nm, pbtSensfReqNfcForum, 5, &nt) <= 0) {
268 nfc_perror(pnd, "nfc_initiator_select_passive_target");
269 fclose(ndef_stream);
270 nfc_close(pnd);
271 nfc_exit(context);
272 exit(EXIT_FAILURE);
273 }
274 // Check again if System Code equals 0x12fc
275 if (0 != memcmp(nt.nti.nfi.abtSysCode, abtNfcForumSysCode, 2)) {
276 fprintf(stderr, "Tag is not NFC Forum Tag Type 3 compliant.\n");
277 fclose(ndef_stream);
278 nfc_close(pnd);
279 nfc_exit(context);
280 exit(EXIT_FAILURE);
281 }
282 }
283
284 //print_nfc_felica_info(nt.nti.nfi, true);
285
287 nfc_perror(pnd, "nfc_device_set_property_bool");
288 fclose(ndef_stream);
289 nfc_close(pnd);
290 nfc_exit(context);
291 exit(EXIT_FAILURE);
292 }
293
294 uint8_t data[1024];
295 size_t data_len = sizeof(data);
296
297 if (nfc_forum_tag_type3_check(pnd, &nt, 0, 1, data, &data_len) <= 0) {
298 nfc_perror(pnd, "nfc_forum_tag_type3_check");
299 fclose(ndef_stream);
300 nfc_close(pnd);
301 nfc_exit(context);
302 exit(EXIT_FAILURE);
303 }
304
305 const int ndef_major_version = (data[0] & 0xf0) >> 4;
306 const int ndef_minor_version = (data[0] & 0x0f);
307 const int ndef_nbr = data[1];
308 const int ndef_nbw = data[2];
309 const int ndef_nmaxb = (data[3] << 8) + data[4];
310 const int ndef_writeflag = data[9];
311 const int ndef_rwflag = data[10];
312 uint32_t ndef_data_len = (data[11] << 16) + (data[12] << 8) + data[13];
313 uint16_t ndef_calculated_checksum = 0;
314 for (size_t n = 0; n < 14; n++)
315 ndef_calculated_checksum += data[n];
316 const uint16_t ndef_checksum = (data[14] << 8) + data[15];
317
318 if (!quiet) {
319 fprintf(message_stream, "NDEF Attribute Block:\n");
320 fprintf(message_stream, "* Mapping version: %d.%d\n", ndef_major_version, ndef_minor_version);
321 fprintf(message_stream, "* Maximum nr of blocks to read by Check Command: %3d block%s\n", ndef_nbr, ndef_nbr > 1 ? "s" : "");
322 fprintf(message_stream, "* Maximum nr of blocks to write by Update Command: %3d block%s\n", ndef_nbw, ndef_nbw > 1 ? "s" : "");
323 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);
324 fprintf(message_stream, "* NDEF writing state: ");
325 switch (ndef_writeflag) {
326 case 0x00:
327 fprintf(message_stream, "finished (0x00)\n");
328 break;
329 case 0x0f:
330 fprintf(message_stream, "in progress (0x0F)\n");
331 break;
332 default:
333 fprintf(message_stream, "invalid (0x%02X)\n", ndef_writeflag);
334 break;
335 }
336 fprintf(message_stream, "* NDEF Access Attribute: ");
337 switch (ndef_rwflag) {
338 case 0x00:
339 fprintf(message_stream, "Read only (0x00)\n");
340 break;
341 case 0x01:
342 fprintf(message_stream, "Read/Write (0x01)\n");
343 break;
344 default:
345 fprintf(message_stream, "invalid (0x%02X)\n", ndef_rwflag);
346 break;
347 }
348 fprintf(message_stream, "* NDEF message length: %d bytes\n", ndef_data_len);
349 if (ndef_calculated_checksum != ndef_checksum) {
350 fprintf(message_stream, "* Checksum: fail (0x%04X != 0x%04X)\n", ndef_calculated_checksum, ndef_checksum);
351 } else {
352 fprintf(message_stream, "* Checksum: ok (0x%04X)\n", ndef_checksum);
353 }
354 }
355
356 if (ndef_calculated_checksum != ndef_checksum) {
357 fprintf(stderr, "Error: Checksum failed! Exiting now.\n");
358 fclose(ndef_stream);
359 nfc_close(pnd);
360 nfc_exit(context);
361 exit(EXIT_FAILURE);
362 }
363
364 if (!ndef_data_len) {
365 fprintf(stderr, "Error: empty NFC Forum Tag Type 3, nothing to read!\n");
366 fclose(ndef_stream);
367 nfc_close(pnd);
368 nfc_exit(context);
369 exit(EXIT_FAILURE);
370 }
371
372 const uint8_t block_max_per_check = data[1];
373 const uint16_t block_count_to_check = (ndef_data_len / 16) + 1;
374
375 data_len = 0;
376 for (uint16_t b = 0; b < ((block_count_to_check - 1) / block_max_per_check + 1); b += block_max_per_check) {
377 size_t size = sizeof(data) - data_len;
378 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)) {
379 nfc_perror(pnd, "nfc_forum_tag_type3_check");
380 fclose(ndef_stream);
381 nfc_close(pnd);
382 nfc_exit(context);
383 exit(EXIT_FAILURE);
384 }
385 data_len += size;
386 }
387
388 if (fwrite(data, 1, ndef_data_len, ndef_stream) != ndef_data_len) {
389 fprintf(stderr, "Error: could not write to file.\n");
390 fclose(ndef_stream);
391 nfc_close(pnd);
392 nfc_exit(context);
393 exit(EXIT_FAILURE);
394 } else {
395 if (!quiet) {
396 fprintf(stderr, "%i bytes written to %s\n", ndef_data_len, ndef_output);
397 }
398 }
399
400 fclose(ndef_stream);
401 nfc_close(pnd);
402 nfc_exit(context);
403 exit(EXIT_SUCCESS);
404}
const char * nfc_device_get_name(nfc_device *pnd)
Returns the device name.
Definition: nfc.c:1209
void nfc_close(nfc_device *pnd)
Close from a NFC device.
Definition: nfc.c:339
nfc_device * nfc_open(nfc_context *context, const nfc_connstring connstring)
Open a NFC device.
Definition: nfc.c:277
int nfc_abort_command(nfc_device *pnd)
Abort current running command.
Definition: nfc.c:1036
void nfc_perror(const nfc_device *pnd, const char *pcString)
Display the last error occured on a nfc_device.
Definition: nfc.c:1183
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:809
int nfc_initiator_init(nfc_device *pnd)
Initialize NFC device as initiator (reader)
Definition: nfc.c:493
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:562
void nfc_exit(nfc_context *context)
Deinitialize libnfc. Should be called after closing all open devices and before your application term...
Definition: nfc.c:248
void nfc_init(nfc_context **context)
Initialize libnfc. This function must be called before calling any other libnfc function.
Definition: nfc.c:231
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:466
@ NP_INFINITE_SELECT
Definition: nfc-types.h:115
@ NP_EASY_FRAMING
Definition: nfc-types.h:136
Provide some examples shared functions like print, parity calculation, options parsing.
#define ERR(...)
Print a error message.
Definition: nfc-utils.h:85
libnfc interface
NFC library context Struct which contains internal options, references, pointers, etc....
Definition: nfc-internal.h:175
NFC device information.
Definition: nfc-internal.h:190
NFC FeLiCa tag information.
Definition: nfc-types.h:199
NFC modulation structure.
Definition: nfc-types.h:342
NFC target structure.
Definition: nfc-types.h:351