From dc842a844c6a706415bbd4aac5533dd33607ba94 Mon Sep 17 00:00:00 2001 From: Romuald Conty Date: Mon, 10 Oct 2011 00:40:34 +0000 Subject: [PATCH] examples/nfc-read-forum-tag3: add new example to read a NFC Forum Tag Type 3 --- ChangeLog | 2 + debian/changelog | 8 + debian/libnfc-bin.install | 6 + debian/libnfc-examples.install | 5 - libnfc/drivers/pn53x_usb.c | 1 + utils/Makefile.am | 13 +- utils/nfc-read-forum-tag3.c | 316 +++++++++++++++++++++++++++++++++ utils/nfc-utils.c | 2 + 8 files changed, 344 insertions(+), 9 deletions(-) create mode 100644 utils/nfc-read-forum-tag3.c diff --git a/ChangeLog b/ChangeLog index 2880dc6..1247e5d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,6 +23,7 @@ Improvements: - libnfc: list_targets support for ASK CTS512B (no anticol support yet) - libnfc: nfc_disconnect() now switches NFC device into idle before disconnecting - libnfc: nfc_initiator_poll_target() is now available for all devices + - libnfc: implement software polling for non-PN532 equipped device - chips/pn53x: add pn53x_data_new() function to alloc and init pn53x_data structure - chips/pn53x: add some SFR registers description - chips/pn53x: implement WriteBack cache @@ -50,6 +51,7 @@ Improvements: - examples/nfc-emulate-forum-tag4: this example now fails with ENOTSUPP when used with a non-PN532 chip. - examples/nfc-mfclassic: write special Mifare 1K cards, including Block 0 / UID - examples/nfc-mfsetuid: add a new example to set UID of special Mifare 1K cards + - examples/nfc-read-forum-tag3: add new example to read a NFC Forum Tag Type 3 - examples/pn53x-tamashell-scripts: minor enhancements - tests/test-dep: add a threaded DEP test to check DEP communication between two local devices - debian: enable all drivers at compile time diff --git a/debian/changelog b/debian/changelog index 30122b8..b94b163 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +libnfc (1.5.1-0) unstable; urgency=low + + * Move nfc-emulate-nfcforum-tag2, nfc-emulate-nfcforum-tag4 and + nfc-relay-picc from libnfc-examples to libnfc-bin package. + * Add nfc-read-forum-tag3 to libnfc-bin package. + + -- Romuald Conty Mon, 10 Oct 2011 02:42:42 +0100 + libnfc (1.5.0pre1.4-0) unstable; urgency=low * All drivers are now enabled under Debian; diff --git a/debian/libnfc-bin.install b/debian/libnfc-bin.install index 22af3d0..a9bb4ff 100644 --- a/debian/libnfc-bin.install +++ b/debian/libnfc-bin.install @@ -1,6 +1,12 @@ +debian/tmp/usr/bin/nfc-emulate-forum-tag2 +debian/tmp/usr/bin/nfc-emulate-forum-tag4 debian/tmp/usr/bin/nfc-list debian/tmp/usr/bin/nfc-mfclassic debian/tmp/usr/bin/nfc-mfultralight +debian/tmp/usr/bin/nfc-relay-picc +debian/tmp/usr/bin/nfc-read-forum-tag3 +debian/tmp/usr/share/man/man1/nfc-emulate-forum-tag4.1 debian/tmp/usr/share/man/man1/nfc-list.1 debian/tmp/usr/share/man/man1/nfc-mfclassic.1 debian/tmp/usr/share/man/man1/nfc-mfultralight.1 +debian/tmp/usr/share/man/man1/nfc-relay-picc.1 diff --git a/debian/libnfc-examples.install b/debian/libnfc-examples.install index 8584aa6..fb616bd 100644 --- a/debian/libnfc-examples.install +++ b/debian/libnfc-examples.install @@ -1,21 +1,16 @@ debian/tmp/usr/bin/nfc-anticol debian/tmp/usr/bin/nfc-dep-initiator debian/tmp/usr/bin/nfc-dep-target -debian/tmp/usr/bin/nfc-emulate-forum-tag2 -debian/tmp/usr/bin/nfc-emulate-forum-tag4 debian/tmp/usr/bin/nfc-emulate-tag debian/tmp/usr/bin/nfc-emulate-uid debian/tmp/usr/bin/nfc-mfsetuid debian/tmp/usr/bin/nfc-poll debian/tmp/usr/bin/nfc-relay -debian/tmp/usr/bin/nfc-relay-picc debian/tmp/usr/share/man/man1/nfc-anticol.1 debian/tmp/usr/share/man/man1/nfc-dep-initiator.1 debian/tmp/usr/share/man/man1/nfc-dep-target.1 -debian/tmp/usr/share/man/man1/nfc-emulate-forum-tag4.1 debian/tmp/usr/share/man/man1/nfc-emulate-tag.1 debian/tmp/usr/share/man/man1/nfc-emulate-uid.1 debian/tmp/usr/share/man/man1/nfc-mfsetuid.1 debian/tmp/usr/share/man/man1/nfc-poll.1 -debian/tmp/usr/share/man/man1/nfc-relay-picc.1 debian/tmp/usr/share/man/man1/nfc-relay.1 diff --git a/libnfc/drivers/pn53x_usb.c b/libnfc/drivers/pn53x_usb.c index 664e080..f4f3e81 100644 --- a/libnfc/drivers/pn53x_usb.c +++ b/libnfc/drivers/pn53x_usb.c @@ -477,6 +477,7 @@ pn53x_usb_send (nfc_device_t * pnd, const byte_t * pbtData, const size_t szData, // response packet. With this hack, the nextly executed function (ie. // pn53x_usb_receive()) will be able to retreive the correct response // packet. + // FIXME Sony reader is also affected by this bug but NACK is not supported int res = pn53x_usb_bulk_write (DRIVER_DATA (pnd), (byte_t *)pn53x_nack_frame, sizeof(pn53x_nack_frame), timeout); if (res < 0) { pnd->iLastError = ECOMIO; diff --git a/utils/Makefile.am b/utils/Makefile.am index 226a73b..b4b1c3e 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -5,6 +5,7 @@ bin_PROGRAMS = \ nfc-mfclassic \ nfc-mfsetuid \ nfc-mfultralight \ + nfc-read-forum-tag3 \ nfc-relay-picc # set the include path found by configure @@ -29,9 +30,6 @@ nfc_list_SOURCES = nfc-list.c nfc_list_LDADD = $(top_builddir)/libnfc/libnfc.la \ libnfcutils.la -nfc_mfultralight_SOURCES = nfc-mfultralight.c mifare.c mifare.h -nfc_mfultralight_LDADD = $(top_builddir)/libnfc/libnfc.la - nfc_mfclassic_SOURCES = nfc-mfclassic.c mifare.c mifare.h nfc_mfclassic_LDADD = $(top_builddir)/libnfc/libnfc.la \ libnfcutils.la @@ -40,9 +38,16 @@ nfc_mfsetuid_SOURCES = nfc-mfsetuid.c nfc_mfsetuid_LDADD = $(top_builddir)/libnfc/libnfc.la \ libnfcutils.la +nfc_mfultralight_SOURCES = nfc-mfultralight.c mifare.c mifare.h +nfc_mfultralight_LDADD = $(top_builddir)/libnfc/libnfc.la + +nfc_read_forum_tag3_SOURCES = nfc-read-forum-tag3.c +nfc_read_forum_tag3_LDADD = $(top_builddir)/libnfc/libnfc.la \ + libnfcutils.la + nfc_relay_picc_SOURCES = nfc-relay-picc.c nfc_relay_picc_LDADD = $(top_builddir)/libnfc/libnfc.la \ - libnfcutils.la + libnfcutils.la dist_man_MANS = \ nfc-emulate-forum-tag4.1 \ diff --git a/utils/nfc-read-forum-tag3.c b/utils/nfc-read-forum-tag3.c new file mode 100644 index 0000000..cf68e23 --- /dev/null +++ b/utils/nfc-read-forum-tag3.c @@ -0,0 +1,316 @@ +/*- + * Public platform independent Near Field Communication (NFC) library examples + * + * Copyright (C) 2011, Romuald Conty + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1) Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 )Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Note that this license only applies on the examples, NFC library itself is under LGPL + * + */ + +/** + * @file nfc-read-forum-tag3.c + * @brief Extract NDEF Message from a NFC Forum Tag Type 3 + * This utility extract (if available) the NDEF Message contained in an NFC Forum Tag Type 3. + */ + +/* + * This implementation was written based on information provided by the + * following documents: + * + * NFC Forum Type 3 Tag Operation Specification + * Technical Specification + * NFCForum-TS-Type-3-Tag_1.1 - 2011-06-28 + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif // HAVE_CONFIG_H + +#include +#include +#include +#include +#include + +#include +#include + +#include "nfc-utils.h" + +static nfc_device_t *pnd; + +void +print_usage(char *progname) +{ + fprintf (stderr, "usage: %s -o FILE\n", progname); + fprintf (stderr, "\nOptions:\n"); + fprintf (stderr, " -o Extract NDEF message if available in FILE\n"); +} + +void stop_select (int sig) +{ + (void) sig; + if (pnd) + nfc_abort_command (pnd); + else + exit (EXIT_FAILURE); +} + +void +build_felica_frame(const nfc_felica_info_t nfi, const byte_t command, const byte_t* payload, const size_t payload_len, byte_t * frame, size_t * frame_len) +{ + frame[0] = 1 + 1 + 8 + payload_len; + *frame_len = frame[0]; + frame[1] = command; + memcpy (frame + 2, nfi.abtId, 8); + memcpy (frame + 10, payload, payload_len); +} + +#define CHECK 0x06 +int +nfc_forum_tag_type3_check (nfc_device_t *pnd, const nfc_target_t nt, const uint16_t block, const uint8_t block_count, byte_t * data, size_t * data_len) +{ + byte_t payload[1024] = { + 1, // Services + 0x0B, 0x00, // NFC Forum Tag Type 3's Service code + block_count, + 0x80, block, // block 0 + }; + + size_t payload_len = 1 + 2 + 1; + for (uint8_t b=0; b> 8; + payload[payload_len++] = (block + b) & 0xff; + } + } + + byte_t frame[1024]; + size_t frame_len = sizeof(frame); + build_felica_frame (nt.nti.nfi, CHECK, payload, payload_len, frame, &frame_len); + + byte_t res[1024]; + + size_t res_len; + if (!nfc_initiator_transceive_bytes (pnd, frame, frame_len, res, &res_len, NULL)) { + return -1; + } + const size_t res_overhead = 1 + 1 + 8 + 2; // 1+1+8+2: LEN + CMD + NFCID2 + STATUS + if (res_len block count is stored on 1 byte + memcpy (data, &res[res_overhead+1], *data_len); + return *data_len; +} + +int +main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + int ch; + char *ndef_output = NULL; + while ((ch = getopt (argc, argv, "ho:")) != -1) { + switch (ch) { + case 'h': + print_usage(argv[0]); + exit (EXIT_SUCCESS); + break; + case 'o': + ndef_output = optarg; + break; + case '?': + if (optopt == 'o') + fprintf (stderr, "Option -%c requires an argument.\n", optopt); + default: + print_usage (argv[0]); + exit (EXIT_FAILURE); + } + } + + if (ndef_output == NULL) { + print_usage (argv[0]); + exit (EXIT_FAILURE); + } + FILE* message_stream = NULL; + FILE* ndef_stream = NULL; + + if ((strlen (ndef_output) == 1) && (ndef_output[0] == '-')) { + message_stream = stderr; + ndef_stream = stdout; + } else { + message_stream = stdout; + ndef_stream = fopen(ndef_output, "wb"); + if (!ndef_stream) { + fprintf (stderr, "Could not open file %s.\n", ndef_output); + exit (EXIT_FAILURE); + } + } + + pnd = nfc_connect (NULL); + + if (pnd == NULL) { + ERR("Unable to connect to NFC device"); + exit (EXIT_FAILURE); + } + + fprintf (message_stream, "Connected to NFC device: %s\n", pnd->acName); + + nfc_modulation_t nm = { + .nmt = NMT_FELICA, + .nbr = NBR_212, + }; + + signal (SIGINT, stop_select); + + nfc_target_t nt; + + nfc_initiator_init(pnd); + fprintf (message_stream, "Place your NFC Forum Tag Type 3 in the field...\n"); + + int error = EXIT_SUCCESS; + // Polling payload (SENSF_REQ) must be present (see NFC Digital Protol) + const byte_t *pbtSensfReq = (byte_t*)"\x00\xff\xff\x01\x00"; + if (!nfc_initiator_select_passive_target(pnd, nm, pbtSensfReq, 5, &nt)) { + nfc_perror (pnd, "nfc_initiator_select_passive_target"); + error = EXIT_FAILURE; + goto error; + } + + // Check if System Code equals 0x12fc + const byte_t abtNfcForumSysCode[] = { 0x12, 0xfc }; + if (0 != memcmp (nt.nti.nfi.abtSysCode, abtNfcForumSysCode, 2)) { + // Retry with special polling + const byte_t *pbtSensfReqNfcForum = (byte_t*)"\x00\x12\xfc\x01\x00"; + if (!nfc_initiator_select_passive_target(pnd, nm, pbtSensfReqNfcForum, 5, &nt)) { + nfc_perror (pnd, "nfc_initiator_select_passive_target"); + error = EXIT_FAILURE; + goto error; + } + // Check again if System Code equals 0x12fc + if (0 != memcmp (nt.nti.nfi.abtSysCode, abtNfcForumSysCode, 2)) { + fprintf (stderr, "Tag is not NFC Forum Tag Type 3 compiliant.\n"); + error = EXIT_FAILURE; + goto error; + } + } + + //print_nfc_felica_info(nt.nti.nfi, true); + + if (!nfc_configure (pnd, NDO_EASY_FRAMING, false) || !nfc_configure (pnd, NDO_INFINITE_SELECT, false)) { + nfc_perror (pnd, "nfc_configure"); + error = EXIT_FAILURE; + goto error; + } + + byte_t data[1024]; + size_t data_len = sizeof(data); + int len; + + if (0 >= (len = nfc_forum_tag_type3_check (pnd, nt, 0, 1, data, &data_len))) { + nfc_perror (pnd, "nfc_forum_tag_type3_check"); + error = EXIT_FAILURE; + goto error; + } + + const int ndef_major_version = (data[0] & 0xf0) >> 4; + const int ndef_minor_version = (data[0] & 0x0f); + fprintf (message_stream, "NDEF Mapping version: %d.%d\n", ndef_major_version, ndef_minor_version); + + const int available_block_count = (data[3] << 8) + data[4]; + fprintf (message_stream, "NFC Forum Tag Type 3 capacity: %d bytes\n", available_block_count * 16); + + uint32_t ndef_data_len = (data[11] << 16) + (data[12] << 8) + data[13]; + fprintf (message_stream, "NDEF data lenght: %d bytes\n", ndef_data_len); + + uint16_t ndef_calculated_checksum = 0; + for (size_t n=0; n<14; n++) + ndef_calculated_checksum += data[n]; + + const uint16_t ndef_checksum = (data[14] << 8) + data[15]; + if (ndef_calculated_checksum != ndef_checksum) { + fprintf (stderr, "NDEF CRC does not match with calculated one\n"); + error = EXIT_FAILURE; + goto error; + } + + if (!ndef_data_len) { + fprintf (stderr, "Empty NFC Forum Tag Type 3\n"); + error = EXIT_FAILURE; + goto error; + } + + const uint8_t block_max_per_check = data[1]; + const uint16_t block_count_to_check = (ndef_data_len / 16) + 1; + + data_len = 0; + for (uint16_t b=0; b<(block_count_to_check/block_max_per_check); b+=block_max_per_check) { + size_t len = sizeof(data) - data_len; + 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, &len)) { + nfc_perror (pnd, "nfc_forum_tag_type3_check"); + error = EXIT_FAILURE; + goto error; + } + data_len += len; + } + if (fwrite (data, 1, data_len, ndef_stream) != data_len) { + fprintf (stderr, "Could not write to file.\n"); + error = EXIT_FAILURE; + goto error; + } + +error: + fclose (ndef_stream); + if (pnd) { + nfc_disconnect (pnd); + } + exit (error); +} diff --git a/utils/nfc-utils.c b/utils/nfc-utils.c index 7dfd7d0..a3416e4 100644 --- a/utils/nfc-utils.c +++ b/utils/nfc-utils.c @@ -537,6 +537,8 @@ print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose) print_hex (nfi.abtId, 8); printf (" Parameter (PAD): "); print_hex (nfi.abtPad, 8); + printf (" System Code (SC): "); + print_hex (nfi.abtSysCode, 2); } void