Introduce experimental FeliCa Lite API.
This commit is contained in:
parent
4016405214
commit
6049acaf5a
15 changed files with 726 additions and 21 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -21,6 +21,8 @@ ltmain.sh
|
||||||
missing
|
missing
|
||||||
stamp-h1
|
stamp-h1
|
||||||
test-driver
|
test-driver
|
||||||
|
examples/felica-lite-dump
|
||||||
|
examples/felica-read-ndef
|
||||||
examples/mifare-classic-format
|
examples/mifare-classic-format
|
||||||
examples/mifare-classic-read-ndef
|
examples/mifare-classic-read-ndef
|
||||||
examples/mifare-classic-write-ndef
|
examples/mifare-classic-write-ndef
|
||||||
|
|
31
README.md
31
README.md
|
@ -8,21 +8,22 @@ If you are new to _libfreefare_ or the _nfc-tools_, you should collect useful in
|
||||||
|
|
||||||
# Feature matrix
|
# Feature matrix
|
||||||
## Tags
|
## Tags
|
||||||
| Tag | Status |
|
| Tag | Status |
|
||||||
|:-------------------|:--------------|
|
|:--------------------|:--------------|
|
||||||
| MIFARE Classic 1k | Supported |
|
| FeliCa Lite | Supported |
|
||||||
| MIFARE Classic 4k | Supported |
|
| MIFARE Classic 1k | Supported |
|
||||||
| MIFARE DESFire 2k | Supported |
|
| MIFARE Classic 4k | Supported |
|
||||||
| MIFARE DESFire 4k | Supported |
|
| MIFARE DESFire 2k | Supported |
|
||||||
| MIFARE DESFire 8k | Supported |
|
| MIFARE DESFire 4k | Supported |
|
||||||
| MIFARE DESFire EV1 | Supported |
|
| MIFARE DESFire 8k | Supported |
|
||||||
| MIFARE Mini | Not supported |
|
| MIFARE DESFire EV1 | Supported |
|
||||||
| MIFARE Plus S 2k | Not supported |
|
| MIFARE Mini | Not supported |
|
||||||
| MIFARE Plus S 4k | Not supported |
|
| MIFARE Plus S 2k | Not supported |
|
||||||
| MIFARE Plus X 2k | Not supported |
|
| MIFARE Plus S 4k | Not supported |
|
||||||
| MIFARE Plus X 4k | Not supported |
|
| MIFARE Plus X 2k | Not supported |
|
||||||
| MIFARE Ultralight | Supported |
|
| MIFARE Plus X 4k | Not supported |
|
||||||
| MIFARE UltralightC | Supported |
|
| MIFARE Ultralight | Supported |
|
||||||
|
| MIFARE Ultralight C | Supported |
|
||||||
|
|
||||||
## Specifications
|
## Specifications
|
||||||
| Specification | Status |
|
| Specification | Status |
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
AM_CFLAGS = -I. -I$(top_srcdir)/libfreefare @LIBNFC_CFLAGS@
|
AM_CFLAGS = -I. -I$(top_srcdir)/libfreefare @LIBNFC_CFLAGS@
|
||||||
AM_LDFLAGS = @LIBNFC_LIBS@
|
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-write-ndef \
|
||||||
mifare-classic-read-ndef \
|
mifare-classic-read-ndef \
|
||||||
mifare-desfire-access \
|
mifare-desfire-access \
|
||||||
|
@ -15,6 +17,12 @@ bin_PROGRAMS = mifare-classic-format \
|
||||||
mifare-desfire-write-ndef \
|
mifare-desfire-write-ndef \
|
||||||
mifare-ultralight-info
|
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_SOURCES = mifare-classic-format.c
|
||||||
mifare_classic_format_LDADD = $(top_builddir)/libfreefare/libfreefare.la
|
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);
|
||||||
|
}
|
|
@ -3,7 +3,8 @@ AM_LDFLAGS = @LIBNFC_LIBS@
|
||||||
|
|
||||||
lib_LTLIBRARIES = libfreefare.la
|
lib_LTLIBRARIES = libfreefare.la
|
||||||
|
|
||||||
libfreefare_la_SOURCES = freefare.c \
|
libfreefare_la_SOURCES = felica.c \
|
||||||
|
freefare.c \
|
||||||
mifare_classic.c \
|
mifare_classic.c \
|
||||||
mifare_ultralight.c \
|
mifare_ultralight.c \
|
||||||
mifare_desfire.c \
|
mifare_desfire.c \
|
||||||
|
|
211
libfreefare/felica.c
Normal file
211
libfreefare/felica.c
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
/*-
|
||||||
|
* 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/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This implementation was written based on information provided by the
|
||||||
|
* following documents:
|
||||||
|
*
|
||||||
|
* FeliCa Lite User's Manual
|
||||||
|
* Version 1.2
|
||||||
|
* No. M624-E01-20
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifdef WITH_DEBUG
|
||||||
|
# include <libutil.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <freefare.h>
|
||||||
|
#include "freefare_internal.h"
|
||||||
|
|
||||||
|
#define MAX_BLOCK_COUNT 8
|
||||||
|
|
||||||
|
inline static
|
||||||
|
ssize_t felica_transceive (FreefareTag tag, uint8_t *data_in, uint8_t *data_out, size_t data_out_length)
|
||||||
|
{
|
||||||
|
DEBUG_XFER (data_in, data_in_length, "===> ");
|
||||||
|
ssize_t res = nfc_initiator_transceive_bytes (tag->device, data_in, data_in[0], data_out, data_out_length, 0);
|
||||||
|
DEBUG_XFER (data_out, res, "<=== ");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
FreefareTag
|
||||||
|
felica_tag_new (void)
|
||||||
|
{
|
||||||
|
return malloc (sizeof (struct felica_tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
felica_tag_free (FreefareTag tag)
|
||||||
|
{
|
||||||
|
free (tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
felica_connect (FreefareTag tag)
|
||||||
|
{
|
||||||
|
ASSERT_INACTIVE (tag);
|
||||||
|
ASSERT_FELICA (tag);
|
||||||
|
|
||||||
|
nfc_target pnti;
|
||||||
|
nfc_modulation modulation = {
|
||||||
|
.nmt = NMT_FELICA,
|
||||||
|
.nbr = NBR_212,
|
||||||
|
};
|
||||||
|
if (nfc_initiator_select_passive_target (tag->device, modulation, tag->info.nti.nfi.abtId, 0, &pnti) >= 0) {
|
||||||
|
tag->active = 1;
|
||||||
|
} else {
|
||||||
|
errno = EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
felica_disconnect (FreefareTag tag)
|
||||||
|
{
|
||||||
|
ASSERT_ACTIVE (tag);
|
||||||
|
ASSERT_FELICA (tag);
|
||||||
|
|
||||||
|
if (nfc_initiator_deselect_target (tag->device) >= 0) {
|
||||||
|
tag->active = 0;
|
||||||
|
} else {
|
||||||
|
errno = EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
felica_read_ex (FreefareTag tag, uint16_t service, uint8_t block_count, uint8_t blocks[], uint8_t *data, size_t length)
|
||||||
|
{
|
||||||
|
ASSERT_ACTIVE (tag);
|
||||||
|
ASSERT_FELICA (tag);
|
||||||
|
|
||||||
|
assert (block_count <= MAX_BLOCK_COUNT);
|
||||||
|
assert (length == 16 * block_count);
|
||||||
|
|
||||||
|
DEBUG_FUNCTION();
|
||||||
|
|
||||||
|
uint8_t cmd[1 + 1 + 8 + 1 + 2 + 1 + 2 * MAX_BLOCK_COUNT] = {
|
||||||
|
0x00, /* Length */
|
||||||
|
0x06,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x01,
|
||||||
|
0x00, 0x00, /* Service */
|
||||||
|
0x00,
|
||||||
|
/* Block ... */
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t res[100];
|
||||||
|
|
||||||
|
cmd[0] = 14 + 2 * block_count;
|
||||||
|
memcpy (cmd + 2, tag->info.nti.nfi.abtId, 8);
|
||||||
|
cmd[11] = service;
|
||||||
|
cmd[12] = service >> 8;
|
||||||
|
cmd[13] = block_count;
|
||||||
|
|
||||||
|
for (int i = 0; i < block_count; i++) {
|
||||||
|
cmd[14 + 2*i] = 0x80;
|
||||||
|
cmd[14 + 2*i + 1] = blocks[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
int cnt = felica_transceive (tag, cmd, res, sizeof (res));
|
||||||
|
if (cnt != 1 + 1 + 8 + 1 + 1 + 1 + 16 * block_count) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size_t len = MIN(res[12] * 16, length);
|
||||||
|
memcpy (data, res + 13, len);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
felica_read (FreefareTag tag, uint16_t service, uint8_t block, uint8_t *data, size_t length)
|
||||||
|
{
|
||||||
|
uint8_t blocks[] = {
|
||||||
|
block
|
||||||
|
};
|
||||||
|
|
||||||
|
return felica_read_ex (tag, service, 1, blocks, data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
felica_write_ex (FreefareTag tag, uint16_t service, uint8_t block_count, uint8_t blocks[], uint8_t *data, size_t length)
|
||||||
|
{
|
||||||
|
ASSERT_ACTIVE (tag);
|
||||||
|
ASSERT_FELICA (tag);
|
||||||
|
|
||||||
|
DEBUG_FUNCTION();
|
||||||
|
|
||||||
|
assert (block_count <= MAX_BLOCK_COUNT);
|
||||||
|
assert (length == 16 * block_count);
|
||||||
|
|
||||||
|
uint8_t cmd[1 + 1 + 8 + 1 + 2 + 1 + 2 + 16 * MAX_BLOCK_COUNT] = {
|
||||||
|
0x00, /* Length */
|
||||||
|
0x08,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x01,
|
||||||
|
0x00, 0x00, /* Service */
|
||||||
|
0x00,
|
||||||
|
/* Block ... */
|
||||||
|
/* n * 16 */
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t res[12];
|
||||||
|
|
||||||
|
cmd[0] = 1 + 1 + 8 + 1 + 2 * 1 + 1 + 2 * 1 + 16 * block_count;
|
||||||
|
memcpy (cmd + 2, tag->info.nti.nfi.abtId, 8);
|
||||||
|
cmd[11] = service;
|
||||||
|
cmd[12] = service >> 8;
|
||||||
|
cmd[13] = block_count;
|
||||||
|
|
||||||
|
for (int i = 0; i < block_count; i++) {
|
||||||
|
cmd[14 + 2*i] = 0x80;
|
||||||
|
cmd[14 + 2*i + 1] = blocks[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (cmd + 14 + 2 * block_count, data, length);
|
||||||
|
|
||||||
|
ssize_t cnt = felica_transceive (tag, cmd, res, sizeof (res));
|
||||||
|
|
||||||
|
if (cnt != sizeof (res))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return res[10] == 0 ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
felica_write (FreefareTag tag, uint16_t service, uint8_t block, uint8_t *data, size_t length)
|
||||||
|
{
|
||||||
|
uint8_t blocks[] = {
|
||||||
|
block
|
||||||
|
};
|
||||||
|
|
||||||
|
return felica_write_ex (tag, service, 1, blocks, data, length);
|
||||||
|
}
|
|
@ -50,6 +50,7 @@ Mifare card manipulation library (libfreefare, \-lfreefare)
|
||||||
.Fn freefare_get_tags "nfc_device_t *device"
|
.Fn freefare_get_tags "nfc_device_t *device"
|
||||||
.Bd -literal
|
.Bd -literal
|
||||||
enum freefare_tag_type {
|
enum freefare_tag_type {
|
||||||
|
FELICA,
|
||||||
MIFARE_CLASSIC_1K,
|
MIFARE_CLASSIC_1K,
|
||||||
MIFARE_CLASSIC_4K,
|
MIFARE_CLASSIC_4K,
|
||||||
MIFARE_DESFIRE,
|
MIFARE_DESFIRE,
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#define NXP_MANUFACTURER_CODE 0x04
|
#define NXP_MANUFACTURER_CODE 0x04
|
||||||
|
|
||||||
struct supported_tag supported_tags[] = {
|
struct supported_tag supported_tags[] = {
|
||||||
|
{ FELICA, "FeliCA", NMT_FELICA, 0x00, 0, 0, { 0x00 }, NULL },
|
||||||
{ MIFARE_CLASSIC_1K, "Mifare Classic 1k", NMT_ISO14443A, 0x08, 0, 0, { 0x00 }, NULL },
|
{ MIFARE_CLASSIC_1K, "Mifare Classic 1k", NMT_ISO14443A, 0x08, 0, 0, { 0x00 }, NULL },
|
||||||
{ MIFARE_CLASSIC_1K, "Mifare Classic 1k (Emulated)", NMT_ISO14443A, 0x28, 0, 0, { 0x00 }, NULL },
|
{ MIFARE_CLASSIC_1K, "Mifare Classic 1k (Emulated)", NMT_ISO14443A, 0x28, 0, 0, { 0x00 }, NULL },
|
||||||
{ MIFARE_CLASSIC_1K, "Mifare Classic 1k (Emulated)", NMT_ISO14443A, 0x68, 0, 0, { 0x00 }, NULL },
|
{ MIFARE_CLASSIC_1K, "Mifare Classic 1k (Emulated)", NMT_ISO14443A, 0x68, 0, 0, { 0x00 }, NULL },
|
||||||
|
@ -55,6 +56,11 @@ freefare_tag_new (nfc_device *device, nfc_target target)
|
||||||
if (target.nm.nmt != supported_tags[i].modulation_type)
|
if (target.nm.nmt != supported_tags[i].modulation_type)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (target.nm.nmt == NMT_FELICA) {
|
||||||
|
tag_info = &(supported_tags[i]);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if ((target.nm.nmt == NMT_ISO14443A) && ((target.nti.nai.szUidLen == 4) || (target.nti.nai.abtUid[0] == NXP_MANUFACTURER_CODE)) &&
|
if ((target.nm.nmt == NMT_ISO14443A) && ((target.nti.nai.szUidLen == 4) || (target.nti.nai.abtUid[0] == NXP_MANUFACTURER_CODE)) &&
|
||||||
(target.nti.nai.btSak == supported_tags[i].SAK) &&
|
(target.nti.nai.btSak == supported_tags[i].SAK) &&
|
||||||
(!supported_tags[i].ATS_min_length || ((target.nti.nai.szAtsLen >= supported_tags[i].ATS_min_length) &&
|
(!supported_tags[i].ATS_min_length || ((target.nti.nai.szAtsLen >= supported_tags[i].ATS_min_length) &&
|
||||||
|
@ -73,6 +79,9 @@ freefare_tag_new (nfc_device *device, nfc_target target)
|
||||||
|
|
||||||
/* Allocate memory for the found MIFARE target */
|
/* Allocate memory for the found MIFARE target */
|
||||||
switch (tag_info->type) {
|
switch (tag_info->type) {
|
||||||
|
case FELICA:
|
||||||
|
tag = felica_tag_new ();
|
||||||
|
break;
|
||||||
case MIFARE_CLASSIC_1K:
|
case MIFARE_CLASSIC_1K:
|
||||||
case MIFARE_CLASSIC_4K:
|
case MIFARE_CLASSIC_4K:
|
||||||
tag = mifare_classic_tag_new ();
|
tag = mifare_classic_tag_new ();
|
||||||
|
@ -162,6 +171,26 @@ freefare_get_tags (nfc_device *device)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Poll for a FELICA tag
|
||||||
|
modulation.nmt = NMT_FELICA;
|
||||||
|
modulation.nbr = NBR_424; // FIXME NBR_212 should also be supported
|
||||||
|
if ((candidates_count = nfc_initiator_list_passive_targets(device, modulation, candidates, MAX_CANDIDATES)) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (int c = 0; c < candidates_count; c++) {
|
||||||
|
FreefareTag t;
|
||||||
|
if ((t = freefare_tag_new(device, candidates[c]))) {
|
||||||
|
/* (Re)Allocate memory for the found FELICA targets array */
|
||||||
|
FreefareTag *p = realloc (tags, (tag_count + 2) * sizeof (FreefareTag));
|
||||||
|
if (p)
|
||||||
|
tags = p;
|
||||||
|
else
|
||||||
|
return tags; // FAIL! Return what has been found so far.
|
||||||
|
tags[tag_count++] = t;
|
||||||
|
tags[tag_count] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,10 +218,27 @@ freefare_get_tag_friendly_name (FreefareTag tag)
|
||||||
char *
|
char *
|
||||||
freefare_get_tag_uid (FreefareTag tag)
|
freefare_get_tag_uid (FreefareTag tag)
|
||||||
{
|
{
|
||||||
char *res;
|
char *res = NULL;
|
||||||
if ((res = malloc (2 * tag->info.nti.nai.szUidLen + 1))) {
|
switch (tag->info.nm.nmt) {
|
||||||
for (size_t i =0; i < tag->info.nti.nai.szUidLen; i++)
|
case NMT_FELICA:
|
||||||
snprintf (res + 2*i, 3, "%02x", tag->info.nti.nai.abtUid[i]);
|
if ((res = malloc (16))) {
|
||||||
|
for (size_t i = 0; i < 8; i++)
|
||||||
|
snprintf (res + 2*i, 3, "%02x", tag->info.nti.nfi.abtId[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NMT_ISO14443A:
|
||||||
|
if ((res = malloc (2 * tag->info.nti.nai.szUidLen + 1))) {
|
||||||
|
for (size_t i = 0; i < tag->info.nti.nai.szUidLen; i++)
|
||||||
|
snprintf (res + 2*i, 3, "%02x", tag->info.nti.nai.abtUid[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NMT_DEP:
|
||||||
|
case NMT_ISO14443B2CT:
|
||||||
|
case NMT_ISO14443B2SR:
|
||||||
|
case NMT_ISO14443B:
|
||||||
|
case NMT_ISO14443BI:
|
||||||
|
case NMT_JEWEL:
|
||||||
|
res = strdup ("UNKNOWN");
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -213,6 +259,9 @@ freefare_free_tag (FreefareTag tag)
|
||||||
{
|
{
|
||||||
if (tag) {
|
if (tag) {
|
||||||
switch (tag->tag_info->type) {
|
switch (tag->tag_info->type) {
|
||||||
|
case FELICA:
|
||||||
|
felica_tag_free (tag);
|
||||||
|
break;
|
||||||
case MIFARE_CLASSIC_1K:
|
case MIFARE_CLASSIC_1K:
|
||||||
case MIFARE_CLASSIC_4K:
|
case MIFARE_CLASSIC_4K:
|
||||||
mifare_classic_tag_free (tag);
|
mifare_classic_tag_free (tag);
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
enum freefare_tag_type {
|
enum freefare_tag_type {
|
||||||
|
FELICA,
|
||||||
// MIFARE_MINI,
|
// MIFARE_MINI,
|
||||||
MIFARE_CLASSIC_1K,
|
MIFARE_CLASSIC_1K,
|
||||||
MIFARE_CLASSIC_4K,
|
MIFARE_CLASSIC_4K,
|
||||||
|
@ -66,6 +67,17 @@ const char *freefare_strerror (FreefareTag tag);
|
||||||
int freefare_strerror_r (FreefareTag tag, char *buffer, size_t len);
|
int freefare_strerror_r (FreefareTag tag, char *buffer, size_t len);
|
||||||
void freefare_perror (FreefareTag tag, const char *string);
|
void freefare_perror (FreefareTag tag, const char *string);
|
||||||
|
|
||||||
|
#define FELICA_SC_RW 0x0009
|
||||||
|
#define FELICA_SC_RO 0x000b
|
||||||
|
|
||||||
|
int felica_connect (FreefareTag tag);
|
||||||
|
int felica_disconnect (FreefareTag tag);
|
||||||
|
|
||||||
|
ssize_t felica_read (FreefareTag tag, uint16_t service, uint8_t block, uint8_t *data, size_t length);
|
||||||
|
ssize_t felica_read_ex (FreefareTag tag, uint16_t service, uint8_t block_count, uint8_t blocks[], uint8_t *data, size_t length);
|
||||||
|
ssize_t felica_write (FreefareTag tag, uint16_t service, uint8_t block, uint8_t *data, size_t length);
|
||||||
|
ssize_t felica_write_ex (FreefareTag tag, uint16_t service, uint8_t block_count, uint8_t blocks[], uint8_t *data, size_t length);
|
||||||
|
|
||||||
int mifare_ultralight_connect (FreefareTag tag);
|
int mifare_ultralight_connect (FreefareTag tag);
|
||||||
int mifare_ultralight_disconnect (FreefareTag tag);
|
int mifare_ultralight_disconnect (FreefareTag tag);
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,8 @@ struct mad_sector_0x00;
|
||||||
struct mad_sector_0x10;
|
struct mad_sector_0x10;
|
||||||
|
|
||||||
void nxp_crc (uint8_t *crc, const uint8_t value);
|
void nxp_crc (uint8_t *crc, const uint8_t value);
|
||||||
|
FreefareTag felica_tag_new (void);
|
||||||
|
void felica_tag_free (FreefareTag tag);
|
||||||
FreefareTag mifare_classic_tag_new (void);
|
FreefareTag mifare_classic_tag_new (void);
|
||||||
void mifare_classic_tag_free (FreefareTag tag);
|
void mifare_classic_tag_free (FreefareTag tag);
|
||||||
FreefareTag mifare_desfire_tag_new (void);
|
FreefareTag mifare_desfire_tag_new (void);
|
||||||
|
@ -189,6 +191,10 @@ struct freefare_tag {
|
||||||
int active;
|
int active;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct felica_tag {
|
||||||
|
struct freefare_tag __tag;
|
||||||
|
};
|
||||||
|
|
||||||
struct mifare_classic_tag {
|
struct mifare_classic_tag {
|
||||||
struct freefare_tag __tag;
|
struct freefare_tag __tag;
|
||||||
|
|
||||||
|
@ -262,6 +268,7 @@ struct mifare_ultralight_tag {
|
||||||
#define ASSERT_ACTIVE(tag) do { if (!tag->active) return errno = ENXIO, -1; } while (0)
|
#define ASSERT_ACTIVE(tag) do { if (!tag->active) return errno = ENXIO, -1; } while (0)
|
||||||
#define ASSERT_INACTIVE(tag) do { if (tag->active) return errno = ENXIO, -1; } while (0)
|
#define ASSERT_INACTIVE(tag) do { if (tag->active) return errno = ENXIO, -1; } while (0)
|
||||||
|
|
||||||
|
#define ASSERT_FELICA(tag) do { if (tag->tag_info->type != FELICA) return errno = ENODEV, -1; } while (0)
|
||||||
#define ASSERT_MIFARE_CLASSIC(tag) do { if ((tag->tag_info->type != MIFARE_CLASSIC_1K) && (tag->tag_info->type != MIFARE_CLASSIC_4K)) return errno = ENODEV, -1; } while (0)
|
#define ASSERT_MIFARE_CLASSIC(tag) do { if ((tag->tag_info->type != MIFARE_CLASSIC_1K) && (tag->tag_info->type != MIFARE_CLASSIC_4K)) return errno = ENODEV, -1; } while (0)
|
||||||
#define ASSERT_MIFARE_DESFIRE(tag) do { if (tag->tag_info->type != MIFARE_DESFIRE) return errno = ENODEV, -1; } while (0)
|
#define ASSERT_MIFARE_DESFIRE(tag) do { if (tag->tag_info->type != MIFARE_DESFIRE) return errno = ENODEV, -1; } while (0)
|
||||||
#define IS_MIFARE_ULTRALIGHT_C(tag) (tag->tag_info->type == MIFARE_ULTRALIGHT_C)
|
#define IS_MIFARE_ULTRALIGHT_C(tag) (tag->tag_info->type == MIFARE_ULTRALIGHT_C)
|
||||||
|
@ -274,6 +281,7 @@ struct mifare_ultralight_tag {
|
||||||
* This macros are intended to provide a convenient way to cast abstract
|
* This macros are intended to provide a convenient way to cast abstract
|
||||||
* FreefareTag structures to concrete Tags (e.g. MIFARE Classic tag).
|
* FreefareTag structures to concrete Tags (e.g. MIFARE Classic tag).
|
||||||
*/
|
*/
|
||||||
|
#define FELICA(tag) ((struct felica_tag *) tag)
|
||||||
#define MIFARE_CLASSIC(tag) ((struct mifare_classic_tag *) tag)
|
#define MIFARE_CLASSIC(tag) ((struct mifare_classic_tag *) tag)
|
||||||
#define MIFARE_DESFIRE(tag) ((struct mifare_desfire_tag *) tag)
|
#define MIFARE_DESFIRE(tag) ((struct mifare_desfire_tag *) tag)
|
||||||
#define MIFARE_ULTRALIGHT(tag) ((struct mifare_ultralight_tag *) tag)
|
#define MIFARE_ULTRALIGHT(tag) ((struct mifare_ultralight_tag *) tag)
|
||||||
|
|
|
@ -11,6 +11,7 @@ TESTS = run-test.sh
|
||||||
TESTS_ENVIRONMENT = NO_MAKE=yes CUTTER="$(CUTTER)"
|
TESTS_ENVIRONMENT = NO_MAKE=yes CUTTER="$(CUTTER)"
|
||||||
|
|
||||||
cutter_unit_test_libs = \
|
cutter_unit_test_libs = \
|
||||||
|
test_felica.la \
|
||||||
test_mad.la \
|
test_mad.la \
|
||||||
test_mifare_application.la \
|
test_mifare_application.la \
|
||||||
test_mifare_classic.la \
|
test_mifare_classic.la \
|
||||||
|
@ -33,6 +34,11 @@ endif
|
||||||
|
|
||||||
AM_LDFLAGS = -module -rpath $(libdir) -avoid-version -no-undefined
|
AM_LDFLAGS = -module -rpath $(libdir) -avoid-version -no-undefined
|
||||||
|
|
||||||
|
test_felica_la_SOURCES = test_felica.c \
|
||||||
|
felica_fixture.c \
|
||||||
|
felica_fixture.h
|
||||||
|
test_felica_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la
|
||||||
|
|
||||||
test_mad_la_SOURCES = test_mad.c
|
test_mad_la_SOURCES = test_mad.c
|
||||||
test_mad_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la
|
test_mad_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la
|
||||||
|
|
||||||
|
|
82
test/felica_fixture.c
Normal file
82
test/felica_fixture.c
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*-
|
||||||
|
* 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 <cutter.h>
|
||||||
|
#include <freefare.h>
|
||||||
|
|
||||||
|
#include "felica_fixture.h"
|
||||||
|
|
||||||
|
static nfc_context *context;
|
||||||
|
static nfc_device *device = NULL;
|
||||||
|
static FreefareTag *tags = NULL;
|
||||||
|
FreefareTag tag = NULL;
|
||||||
|
|
||||||
|
void
|
||||||
|
cut_setup (void)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
nfc_connstring devices[8];
|
||||||
|
size_t device_count;
|
||||||
|
|
||||||
|
nfc_init (&context);
|
||||||
|
cut_assert_not_null (context, cut_message ("Unable to init libnfc (malloc)"));
|
||||||
|
|
||||||
|
device_count = nfc_list_devices (context, devices, 8);
|
||||||
|
if (device_count <= 0)
|
||||||
|
cut_omit ("No device found");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < device_count; i++) {
|
||||||
|
device = nfc_open (context, devices[i]);
|
||||||
|
if (!device)
|
||||||
|
cut_omit ("nfc_open() failed.");
|
||||||
|
|
||||||
|
tags = freefare_get_tags (device);
|
||||||
|
cut_assert_not_null (tags, cut_message ("freefare_get_tags() failed"));
|
||||||
|
|
||||||
|
tag = NULL;
|
||||||
|
for (int i=0; tags[i]; i++) {
|
||||||
|
if (freefare_get_tag_type(tags[i]) == FELICA) {
|
||||||
|
tag = tags[i];
|
||||||
|
res = felica_connect (tag);
|
||||||
|
cut_assert_equal_int (0, res, cut_message ("felica_connect() failed"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nfc_close (device);
|
||||||
|
device = NULL;
|
||||||
|
freefare_free_tags (tags);
|
||||||
|
tags = NULL;
|
||||||
|
}
|
||||||
|
cut_omit ("No FeliCa tag on NFC device");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cut_teardown (void)
|
||||||
|
{
|
||||||
|
if (tag)
|
||||||
|
mifare_classic_disconnect (tag);
|
||||||
|
|
||||||
|
if (tags) {
|
||||||
|
freefare_free_tags (tags);
|
||||||
|
tags = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device)
|
||||||
|
nfc_close (device);
|
||||||
|
|
||||||
|
nfc_exit (context);
|
||||||
|
}
|
18
test/felica_fixture.h
Normal file
18
test/felica_fixture.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*-
|
||||||
|
* 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/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern FreefareTag tag;
|
38
test/test_felica.c
Normal file
38
test/test_felica.c
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#include <cutter.h>
|
||||||
|
|
||||||
|
#include <freefare.h>
|
||||||
|
|
||||||
|
#include "felica_fixture.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
test_felica_read_without_encryption (void)
|
||||||
|
{
|
||||||
|
uint8_t buffer[64];
|
||||||
|
|
||||||
|
int res = felica_read (tag, FELICA_SC_RO, 0x00, buffer, 16);
|
||||||
|
cut_assert_equal_int (16, res);
|
||||||
|
|
||||||
|
uint8_t blocks[] = {
|
||||||
|
0x02,
|
||||||
|
0x03,
|
||||||
|
0x04,
|
||||||
|
};
|
||||||
|
|
||||||
|
res = felica_read_ex (tag, FELICA_SC_RO, 3, blocks, buffer, 3 * 16);
|
||||||
|
cut_assert_equal_int (3 * 16, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_felica_write_without_encryption (void)
|
||||||
|
{
|
||||||
|
uint8_t buffer[16] = {
|
||||||
|
0x00, 0x01, 0x02, 0x03,
|
||||||
|
0x03, 0x04, 0x05, 0x06,
|
||||||
|
0x07, 0x08, 0x09, 0x0a,
|
||||||
|
0x0b, 0x0c, 0x0d, 0x0e,
|
||||||
|
};
|
||||||
|
|
||||||
|
int res = felica_write (tag, FELICA_SC_RW, 0x0a, buffer, sizeof (buffer));
|
||||||
|
|
||||||
|
cut_assert_equal_int (0, res);
|
||||||
|
}
|
Loading…
Reference in a new issue