/* * This implementation was written based on information provided by the * following documents: * * FeliCa Lite User's Manual * Version 1.2 * No. M624-E01-20 */ #if defined(HAVE_CONFIG_H) # include "config.h" #endif #include #include #include #include #ifdef WITH_DEBUG # include #endif #include #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[0], "===> "); 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; } bool felica_taste(nfc_device *device, nfc_target target) { (void) device; return target.nm.nmt == NMT_FELICA; } FreefareTag felica_tag_new(nfc_device *device, nfc_target target) { FreefareTag tag; if ((tag = malloc(sizeof(struct felica_tag)))) { tag->type = FELICA; tag->free_tag = felica_tag_free; tag->device = device; tag->info = target; tag->active = 0; } return tag; } void felica_tag_free(FreefareTag tag) { free(tag); } ssize_t felica_read_ex(FreefareTag tag, uint16_t service, uint8_t block_count, uint8_t blocks[], uint8_t *data, size_t length) { 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) { 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); }