Introduce experimental FeliCa Lite API.
This commit is contained in:
parent
4016405214
commit
6049acaf5a
15 changed files with 726 additions and 21 deletions
|
|
@ -1,7 +1,9 @@
|
|||
AM_CFLAGS = -I. -I$(top_srcdir)/libfreefare @LIBNFC_CFLAGS@
|
||||
AM_LDFLAGS = @LIBNFC_LIBS@
|
||||
|
||||
bin_PROGRAMS = mifare-classic-format \
|
||||
bin_PROGRAMS = felica-lite-dump \
|
||||
felica-read-ndef \
|
||||
mifare-classic-format \
|
||||
mifare-classic-write-ndef \
|
||||
mifare-classic-read-ndef \
|
||||
mifare-desfire-access \
|
||||
|
|
@ -15,6 +17,12 @@ bin_PROGRAMS = mifare-classic-format \
|
|||
mifare-desfire-write-ndef \
|
||||
mifare-ultralight-info
|
||||
|
||||
felica_lite_dump_SOURCES = felica-lite-dump.c
|
||||
felica_lite_dump_LDADD = $(top_builddir)/libfreefare/libfreefare.la
|
||||
|
||||
felica_read_ndef_SOURCES = felica-read-ndef.c
|
||||
felica_read_ndef_LDADD = $(top_builddir)/libfreefare/libfreefare.la
|
||||
|
||||
mifare_classic_format_SOURCES = mifare-classic-format.c
|
||||
mifare_classic_format_LDADD = $(top_builddir)/libfreefare/libfreefare.la
|
||||
|
||||
|
|
|
|||
104
examples/felica-lite-dump.c
Normal file
104
examples/felica-lite-dump.c
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*-
|
||||
* Copyright (C) 2015, Romain Tartiere.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include <freefare.h>
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
nfc_device *device = NULL;
|
||||
FreefareTag *tags = NULL;
|
||||
nfc_connstring devices[8];
|
||||
|
||||
nfc_context *context;
|
||||
nfc_init (&context);
|
||||
if (context == NULL)
|
||||
errx (EXIT_FAILURE, "Unable to init libnfc (malloc)");
|
||||
|
||||
size_t device_count = nfc_list_devices (context, devices, 8);
|
||||
if (device_count <= 0)
|
||||
errx (EXIT_FAILURE, "No NFC device found.");
|
||||
|
||||
for (size_t d = 0; d < device_count; d++) {
|
||||
device = nfc_open (context, devices[d]);
|
||||
if (!device) {
|
||||
errx (EXIT_FAILURE, "nfc_open() failed.");
|
||||
}
|
||||
|
||||
tags = freefare_get_tags (device);
|
||||
if (!tags) {
|
||||
nfc_close (device);
|
||||
errx (EXIT_FAILURE, "Error listing FeliCa tag.");
|
||||
}
|
||||
|
||||
for (int i = 0; tags[i]; i++) {
|
||||
int r = felica_connect (tags[i]);
|
||||
if (r < 0)
|
||||
errx (EXIT_FAILURE, "Cannot connect to FeliCa target");
|
||||
|
||||
printf ("Dumping %s tag %s\n", freefare_get_tag_friendly_name (tags[i]), freefare_get_tag_uid (tags[i]));
|
||||
printf ("Number\tName\tData\n");
|
||||
|
||||
for (int block = 0x00; block < 0x0f; block++) {
|
||||
uint8_t buffer[16];
|
||||
|
||||
if (felica_read (tags[i], FELICA_SC_RO, block, buffer, sizeof (buffer)) < 0)
|
||||
errx (EXIT_FAILURE, "Error reading block %d", block);
|
||||
|
||||
if (block < 0x0e)
|
||||
printf ("0x%02x\tS_PAD%d\t", block, block);
|
||||
else
|
||||
printf ("0x%02x\tREG\t", block);
|
||||
for (int j = 0; j < 16; j++) {
|
||||
printf ("%02x ", buffer[j]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
char *block_names[] = {
|
||||
"RC", "MAC", "ID", "D_ID", "SER_C", "SYS_C", "CKV", "CK", "MC",
|
||||
};
|
||||
int valid_bytes[] = {
|
||||
16, 8, 16, 16, 2, 2, 2, 16, 5
|
||||
};
|
||||
for (int block = 0x80; block < 0x89; block++) {
|
||||
uint8_t buffer[16];
|
||||
|
||||
if (felica_read (tags[i], FELICA_SC_RO, block, buffer, sizeof (buffer)) < 0)
|
||||
errx (EXIT_FAILURE, "Error reading block %d", block);
|
||||
|
||||
printf ("0x%02x\t%s\t", block, block_names[block - 0x80]);
|
||||
for (int j = 0; j < valid_bytes[block - 0x80]; j++) {
|
||||
printf ("%02x ", buffer[j]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
felica_disconnect (tags[i]);
|
||||
}
|
||||
|
||||
freefare_free_tags (tags);
|
||||
nfc_close (device);
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
164
examples/felica-read-ndef.c
Normal file
164
examples/felica-read-ndef.c
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*-
|
||||
* Copyright (C) 2015, Romain Tartiere.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined(HAVE_SYS_ENDIAN_H)
|
||||
# include <sys/endian.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_ENDIAN_H)
|
||||
# include <endian.h>
|
||||
#endif
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include <freefare.h>
|
||||
|
||||
#define NDEF_BUFFER_SIZE 512
|
||||
|
||||
void
|
||||
usage (char *progname)
|
||||
{
|
||||
fprintf (stderr, "usage: %s [options]\n", progname);
|
||||
fprintf (stderr, "\nAvailable options:\n");
|
||||
fprintf (stderr, " -o FILE Write NDEF message to FILE\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int error = EXIT_SUCCESS;
|
||||
nfc_device *device = NULL;
|
||||
FreefareTag *tags = NULL;
|
||||
|
||||
int ch;
|
||||
char *ndef_file = NULL;
|
||||
while ((ch = getopt (argc, argv, "o:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'o':
|
||||
ndef_file = optarg;
|
||||
case '?':
|
||||
usage (argv[0]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
nfc_connstring devices[8];
|
||||
|
||||
size_t device_count;
|
||||
|
||||
nfc_context *context;
|
||||
nfc_init (&context);
|
||||
if (context == NULL)
|
||||
errx (EXIT_FAILURE, "Unable to init libnfc (malloc)");
|
||||
|
||||
device_count = nfc_list_devices (context, devices, 8);
|
||||
if (device_count <= 0)
|
||||
errx (EXIT_FAILURE, "No NFC device found.");
|
||||
|
||||
for (size_t d = 0; d < device_count; d++) {
|
||||
device = nfc_open (context, devices[d]);
|
||||
if (!device) {
|
||||
warnx ("nfc_open() failed.");
|
||||
error = EXIT_FAILURE;
|
||||
continue;
|
||||
}
|
||||
|
||||
tags = freefare_get_tags (device);
|
||||
if (!tags) {
|
||||
nfc_close (device);
|
||||
errx (EXIT_FAILURE, "Error listing FeliCa tag.");
|
||||
}
|
||||
|
||||
for (int i = 0; (!error) && tags[i]; i++) {
|
||||
int r = felica_connect (tags[i]);
|
||||
if (r < 0)
|
||||
errx (EXIT_FAILURE, "Cannot connect to FeliCa target");
|
||||
|
||||
int block = 1;
|
||||
uint8_t ndef_message[NDEF_BUFFER_SIZE];
|
||||
int ndef_space_left = NDEF_BUFFER_SIZE;
|
||||
uint8_t *p = ndef_message;
|
||||
ssize_t s;
|
||||
|
||||
// FIXME Instead of reading as much as we can, we should read until end of NDEF record (if any is found).
|
||||
while ((ndef_space_left >= 16) && (s = felica_read (tags[i], FELICA_SC_RO, block++, p, 16)) > 0) {
|
||||
p += s;
|
||||
ndef_space_left -= s;
|
||||
}
|
||||
|
||||
size_t ndef_message_length = 0;
|
||||
|
||||
if ((ndef_message[0] & 0x80) == 0x80) {
|
||||
uint8_t *ndef_record;
|
||||
do {
|
||||
ndef_record = ndef_message + ndef_message_length;
|
||||
|
||||
size_t ndef_record_length = 1 + 1 + ndef_record[1];
|
||||
size_t payload_length;
|
||||
size_t payload_length_length;
|
||||
|
||||
if (ndef_record[0] & 0x10) {
|
||||
/* Short record */
|
||||
payload_length = ndef_record[2];
|
||||
payload_length_length = 1;
|
||||
} else {
|
||||
payload_length = be32toh ((uint32_t) ndef_record + 2);
|
||||
payload_length_length = 4;
|
||||
}
|
||||
ndef_record_length += payload_length_length;
|
||||
ndef_record_length += payload_length;
|
||||
|
||||
if (ndef_record[0] & 0x08) {
|
||||
ndef_record_length += 2;
|
||||
}
|
||||
|
||||
ndef_message_length += ndef_record_length;
|
||||
if (ndef_message_length > NDEF_BUFFER_SIZE)
|
||||
errx (EXIT_FAILURE, "NDEF message truncated");
|
||||
|
||||
} while ((ndef_record[0] & 0x40) != 0x40);
|
||||
}
|
||||
|
||||
if (ndef_message_length == 0)
|
||||
errx (EXIT_FAILURE, "No NDEF message found");
|
||||
|
||||
FILE *f;
|
||||
if (ndef_file)
|
||||
f = fopen (ndef_file, "w");
|
||||
else
|
||||
f = stdout;
|
||||
|
||||
if (fwrite (ndef_message, ndef_message_length, 1, f) != 1)
|
||||
err (EXIT_FAILURE, "Can't write NDEF message");
|
||||
|
||||
fclose (f);
|
||||
|
||||
felica_disconnect (tags[i]);
|
||||
}
|
||||
|
||||
freefare_free_tags (tags);
|
||||
nfc_close (device);
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue