From 5ed6eaa2034b5a52b7a60d01aefbdc112a3f38a9 Mon Sep 17 00:00:00 2001 From: Tau Date: Sat, 19 Oct 2019 15:51:10 -0400 Subject: [PATCH] Overhaul card reader emulation --- aimeio/aimeio.c | 218 ++++++++++++++++++++++++------- aimeio/aimeio.def | 5 +- aimeio/aimeio.h | 6 +- board/meson.build | 3 + board/sg-nfc-cmd.h | 57 ++++++-- board/sg-nfc.c | 319 +++++++++++++++++++++++++++++---------------- board/sg-nfc.h | 16 ++- board/sg-reader.c | 25 ++-- 8 files changed, 451 insertions(+), 198 deletions(-) diff --git a/aimeio/aimeio.c b/aimeio/aimeio.c index 240b0d8..7dd0807 100644 --- a/aimeio/aimeio.c +++ b/aimeio/aimeio.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -11,13 +12,35 @@ #include "util/crc.h" #include "util/dprintf.h" +enum { + AIME_IO_TOUCH_MSEC = 1000, +}; + struct aime_io_config { - wchar_t id_path[MAX_PATH]; + wchar_t aime_path[MAX_PATH]; + wchar_t felica_path[MAX_PATH]; uint8_t vk_scan; }; static struct aime_io_config aime_io_cfg; -static uint8_t aime_io_luid[10]; +static uint8_t aime_io_aime_id[10]; +static uint8_t aime_io_felica_id[8]; +static uint32_t aime_io_touch_t; +static bool aime_io_aime_id_present; +static bool aime_io_felica_id_present; +static bool aime_io_latch; + +static void aime_io_config_read( + struct aime_io_config *cfg, + const wchar_t *filename); + +static HRESULT aime_io_read_id_file( + const wchar_t *path, + uint8_t *bytes, + size_t nbytes); + +static HRESULT aime_io_nfc_poll_rise(void); +static void aime_io_nfc_poll_fall(void); static void aime_io_config_read( struct aime_io_config *cfg, @@ -28,10 +51,18 @@ static void aime_io_config_read( GetPrivateProfileStringW( L"aime", - L"cardPath", + L"aimePath", L"DEVICE\\aime.txt", - cfg->id_path, - _countof(cfg->id_path), + cfg->aime_path, + _countof(cfg->aime_path), + filename); + + GetPrivateProfileStringW( + L"aime", + L"felicaPath", + L"DEVICE\\felica.txt", + cfg->felica_path, + _countof(cfg->felica_path), filename); cfg->vk_scan = GetPrivateProfileIntW( @@ -39,7 +70,51 @@ static void aime_io_config_read( L"scan", VK_RETURN, filename); +} +static HRESULT aime_io_read_id_file( + const wchar_t *path, + uint8_t *bytes, + size_t nbytes) +{ + HRESULT hr; + FILE *f; + size_t i; + int byte; + int r; + + f = _wfopen(path, L"r"); + + if (f == NULL) { + return S_FALSE; + } + + memset(bytes, 0, nbytes); + + for (i = 0 ; i < nbytes ; i++) { + r = fscanf(f, "%02x ", &byte); + + if (r != 1) { + hr = E_FAIL; + dprintf("AimeIO DLL: %S: fscanf[%i] failed: %i\n", + path, + (int) i, + r); + + goto end; + } + + bytes[i] = byte; + } + + hr = S_OK; + +end: + if (f != NULL) { + fclose(f); + } + + return hr; } HRESULT aime_io_init(void) @@ -53,72 +128,119 @@ void aime_io_fini(void) { } -HRESULT aime_io_mifare_poll(uint8_t unit_no, uint32_t *uid) +HRESULT aime_io_nfc_poll(uint8_t unit_no) { + uint32_t dt; + uint32_t t; + bool level; HRESULT hr; - FILE *f; - size_t i; - int byte; - int r; if (unit_no != 0) { return S_FALSE; } - hr = S_FALSE; - f = NULL; + t = GetTickCount(); + level = GetAsyncKeyState(aime_io_cfg.vk_scan) & 0x8000; - if (!(GetAsyncKeyState(aime_io_cfg.vk_scan) & 0x8000)) { - goto end; + /* 1. Linger a card for AIME_IO_TOUCH_MSEC after vk_scan has been released. + 2. Detect rising and falling edges and call the relevant worker fns. */ + + if (level) { + aime_io_touch_t = t; } - f = _wfopen(aime_io_cfg.id_path, L"r"); + if (aime_io_latch) { + dt = aime_io_touch_t - t; - if (f == NULL) { - dprintf("Aime DLL: Failed to open %S\n", aime_io_cfg.id_path); - - goto end; - } - - for (i = 0 ; i < sizeof(aime_io_luid) ; i++) { - r = fscanf(f, "%02x ", &byte); - - if (r != 1) { - dprintf("Aime DLL: fscanf[%i] failed: %i\n", (int) i, r); - - goto end; + if (dt < AIME_IO_TOUCH_MSEC) { + hr = S_OK; + } else { + aime_io_nfc_poll_fall(); + aime_io_latch = false; + hr = S_FALSE; + } + } else { + if (level) { + hr = aime_io_nfc_poll_rise(); + aime_io_latch = true; + } else { + hr = S_FALSE; } - - aime_io_luid[i] = byte; - } - - /* NOTE: We are just arbitrarily using the CRC32 of the LUID here, real - cards do not work like this! However, neither the application code nor - the network protocol care what the UID is, it just has to be a stable - unique identifier for over-the-air NFC communications. */ - - *uid = crc32(aime_io_luid, sizeof(aime_io_luid), 0); - - hr = S_OK; - -end: - if (f != NULL) { - fclose(f); } return hr; } -HRESULT aime_io_mifare_read_luid( +static HRESULT aime_io_nfc_poll_rise(void) +{ + HRESULT hr; + + hr = aime_io_read_id_file( + aime_io_cfg.aime_path, + aime_io_aime_id, + sizeof(aime_io_aime_id)); + + if (SUCCEEDED(hr) && hr != S_FALSE) { + aime_io_aime_id_present = true; + + return hr; + } + + hr = aime_io_read_id_file( + aime_io_cfg.felica_path, + aime_io_felica_id, + sizeof(aime_io_felica_id)); + + if (SUCCEEDED(hr) && hr != S_FALSE) { + aime_io_felica_id_present = true; + + return hr; + } + + return S_FALSE; +} + +static void aime_io_nfc_poll_fall(void) +{ + aime_io_aime_id_present = false; + aime_io_felica_id_present = false; +} + +HRESULT aime_io_nfc_get_aime_id( uint8_t unit_no, - uint32_t uid, uint8_t *luid, size_t luid_size) { assert(luid != NULL); - assert(luid_size == sizeof(aime_io_luid)); + assert(luid_size == sizeof(aime_io_aime_id)); - memcpy(luid, aime_io_luid, luid_size); + if (unit_no != 0 || !aime_io_aime_id_present) { + return S_FALSE; + } + + memcpy(luid, aime_io_aime_id, luid_size); + + return S_OK; +} + +HRESULT aime_io_nfc_get_felica_id(uint8_t unit_no, uint64_t *IDm) +{ + uint64_t val; + size_t i; + + assert(IDm != NULL); + + if (unit_no != 0 || !aime_io_felica_id_present) { + return S_FALSE; + } + + val = 0; + + for (i = 0 ; i < 8 ; i++) { + val = (val << 8) | aime_io_felica_id[i]; + } + + *IDm = val; return S_OK; } diff --git a/aimeio/aimeio.def b/aimeio/aimeio.def index a52560d..6192298 100644 --- a/aimeio/aimeio.def +++ b/aimeio/aimeio.def @@ -4,5 +4,6 @@ EXPORTS aime_io_fini aime_io_init aime_io_led_set_color - aime_io_mifare_poll - aime_io_mifare_read_luid + aime_io_nfc_poll + aime_io_nfc_get_aime_id + aime_io_nfc_get_felica_id diff --git a/aimeio/aimeio.h b/aimeio/aimeio.h index 89247ac..884d110 100644 --- a/aimeio/aimeio.h +++ b/aimeio/aimeio.h @@ -7,10 +7,10 @@ HRESULT aime_io_init(void); void aime_io_fini(void); -HRESULT aime_io_mifare_poll(uint8_t unit_no, uint32_t *uid); -HRESULT aime_io_mifare_read_luid( +HRESULT aime_io_nfc_poll(uint8_t unit_no); +HRESULT aime_io_nfc_get_aime_id( uint8_t unit_no, - uint32_t uid, uint8_t *luid, size_t luid_size); +HRESULT aime_io_nfc_get_felica_id(uint8_t unit_no, uint64_t *IDm); void aime_io_led_set_color(uint8_t unit_no, uint8_t r, uint8_t g, uint8_t b); diff --git a/board/meson.build b/board/meson.build index 83a8cff..eb2caa7 100644 --- a/board/meson.build +++ b/board/meson.build @@ -6,6 +6,9 @@ board_lib = static_library( dependencies : [ capnhook.get_variable('hook_dep'), ], + link_with : [ + iccard_lib, + ], sources : [ 'config.c', 'config.h', diff --git a/board/sg-nfc-cmd.h b/board/sg-nfc-cmd.h index 70a4f51..aeab127 100644 --- a/board/sg-nfc-cmd.h +++ b/board/sg-nfc-cmd.h @@ -2,18 +2,21 @@ #include +#pragma pack(push, 1) + enum { SG_NFC_CMD_GET_FW_VERSION = 0x30, SG_NFC_CMD_GET_HW_VERSION = 0x32, - SG_NFC_CMD_40_POLL = 0x40, - SG_NFC_CMD_41_POLL = 0x41, - SG_NFC_CMD_MIFARE_POLL = 0x42, + SG_NFC_CMD_RADIO_ON = 0x40, + SG_NFC_CMD_RADIO_OFF = 0x41, + SG_NFC_CMD_POLL = 0x42, SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43, - SG_NFC_CMD_MIFARE_50 = 0x50, + SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x50, SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, - SG_NFC_CMD_MIFARE_SET_KEY = 0x54, - SG_NFC_CMD_MIFARE_55 = 0x55, + SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x54, + SG_NFC_CMD_MIFARE_AUTHENTICATE = 0x55, /* guess based on time sent */ SG_NFC_CMD_RESET = 0x62, + SG_NFC_CMD_FELICA_ENCAP = 0x71, }; struct sg_nfc_resp_get_fw_version { @@ -41,23 +44,34 @@ struct sg_nfc_req_poll_40 { uint8_t payload; }; -struct sg_nfc_resp_mifare_poll { +struct sg_nfc_poll_mifare { + uint8_t type; + uint8_t id_len; + uint32_t uid; +}; + +struct sg_nfc_poll_felica { + uint8_t type; + uint8_t id_len; + uint64_t IDm; + uint64_t PMm; +}; + +struct sg_nfc_resp_poll { struct sg_resp_header resp; - union { - uint8_t none; - uint8_t some[7]; - } payload; + uint8_t count; + uint8_t payload[250]; }; struct sg_nfc_req_mifare_select_tag { struct sg_resp_header resp; - uint8_t uid[4]; + uint32_t uid; }; struct sg_nfc_req_mifare_read_block { struct sg_req_header req; struct { - uint8_t uid[4]; + uint32_t uid; uint8_t block_no; } payload; }; @@ -67,6 +81,17 @@ struct sg_nfc_resp_mifare_read_block { uint8_t block[16]; }; +struct sg_nfc_req_felica_encap { + struct sg_req_header req; + uint64_t IDm; + uint8_t payload[243]; +}; + +struct sg_nfc_resp_felica_encap { + struct sg_resp_header resp; + uint8_t payload[250]; +}; + union sg_nfc_req_any { uint8_t bytes[256]; struct sg_req_header simple; @@ -74,6 +99,7 @@ union sg_nfc_req_any { struct sg_nfc_req_mifare_read_block mifare_read_block; struct sg_nfc_req_mifare_50 mifare_50; struct sg_nfc_req_poll_40 poll_40; + struct sg_nfc_req_felica_encap felica_encap; }; union sg_nfc_resp_any { @@ -81,6 +107,9 @@ union sg_nfc_resp_any { struct sg_resp_header simple; struct sg_nfc_resp_get_fw_version get_fw_version; struct sg_nfc_resp_get_hw_version get_hw_version; - struct sg_nfc_resp_mifare_poll mifare_poll; + struct sg_nfc_resp_poll poll; struct sg_nfc_resp_mifare_read_block mifare_read_block; + struct sg_nfc_resp_felica_encap felica_encap; }; + +#pragma pack(pop) diff --git a/board/sg-nfc.c b/board/sg-nfc.c index a9bacbc..2409b6d 100644 --- a/board/sg-nfc.c +++ b/board/sg-nfc.c @@ -4,13 +4,18 @@ #include #include #include +#include #include #include "board/sg-cmd.h" #include "board/sg-nfc.h" #include "board/sg-nfc-cmd.h" +#include "iccard/aime.h" +#include "iccard/felica.h" + #include "util/dprintf.h" +#include "util/dump.h" static HRESULT sg_nfc_dispatch( void *ctx, @@ -18,50 +23,48 @@ static HRESULT sg_nfc_dispatch( void *v_resp); static HRESULT sg_nfc_cmd_reset( - const struct sg_nfc *nfc, + struct sg_nfc *nfc, const struct sg_req_header *req, struct sg_resp_header *resp); static HRESULT sg_nfc_cmd_get_fw_version( - const struct sg_nfc *nfc, + struct sg_nfc *nfc, const struct sg_req_header *req, struct sg_nfc_resp_get_fw_version *resp); static HRESULT sg_nfc_cmd_get_hw_version( - const struct sg_nfc *nfc, + struct sg_nfc *nfc, const struct sg_req_header *req, struct sg_nfc_resp_get_hw_version *resp); -static HRESULT sg_nfc_cmd_mifare_poll( - const struct sg_nfc *nfc, +static HRESULT sg_nfc_cmd_poll( + struct sg_nfc *nfc, const struct sg_req_header *req, - struct sg_nfc_resp_mifare_poll *resp); + struct sg_nfc_resp_poll *resp); + +static HRESULT sg_nfc_poll_aime( + struct sg_nfc *nfc, + struct sg_nfc_poll_mifare *mifare); + +static HRESULT sg_nfc_poll_felica( + struct sg_nfc *nfc, + struct sg_nfc_poll_felica *felica); static HRESULT sg_nfc_cmd_mifare_read_block( - const struct sg_nfc *nfc, + struct sg_nfc *nfc, const struct sg_nfc_req_mifare_read_block *req, struct sg_nfc_resp_mifare_read_block *resp); -static HRESULT sg_nfc_mifare_read_block_1( - const struct sg_nfc *nfc, - uint32_t uid, - uint8_t *block); - -static HRESULT sg_nfc_mifare_read_block_2( - const struct sg_nfc *nfc, - uint32_t uid, - uint8_t *block); +static HRESULT sg_nfc_cmd_felica_encap( + struct sg_nfc *nfc, + const struct sg_nfc_req_felica_encap *req, + struct sg_nfc_resp_felica_encap *resp); static HRESULT sg_nfc_cmd_dummy( - const struct sg_nfc *nfc, + struct sg_nfc *nfc, const struct sg_req_header *req, struct sg_resp_header *resp); -static const uint8_t sg_nfc_block_1[] = { - 'S', 'B', 'D', 'T', 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0xC6, 0x22, -}; - void sg_nfc_init( struct sg_nfc *nfc, uint8_t addr, @@ -120,7 +123,7 @@ static HRESULT sg_nfc_dispatch( const void *v_req, void *v_resp) { - const struct sg_nfc *nfc; + struct sg_nfc *nfc; const union sg_nfc_req_any *req; union sg_nfc_resp_any *resp; @@ -149,11 +152,11 @@ static HRESULT sg_nfc_dispatch( &req->simple, &resp->get_hw_version); - case SG_NFC_CMD_MIFARE_POLL: - return sg_nfc_cmd_mifare_poll( + case SG_NFC_CMD_POLL: + return sg_nfc_cmd_poll( nfc, &req->simple, - &resp->mifare_poll); + &resp->poll); case SG_NFC_CMD_MIFARE_READ_BLOCK: return sg_nfc_cmd_mifare_read_block( @@ -161,12 +164,18 @@ static HRESULT sg_nfc_dispatch( &req->mifare_read_block, &resp->mifare_read_block); - case SG_NFC_CMD_40_POLL: - case SG_NFC_CMD_41_POLL: - case SG_NFC_CMD_MIFARE_SET_KEY: + case SG_NFC_CMD_FELICA_ENCAP: + return sg_nfc_cmd_felica_encap( + nfc, + &req->felica_encap, + &resp->felica_encap); + + case SG_NFC_CMD_MIFARE_AUTHENTICATE: case SG_NFC_CMD_MIFARE_SELECT_TAG: - case SG_NFC_CMD_MIFARE_50: - case SG_NFC_CMD_MIFARE_55: + case SG_NFC_CMD_MIFARE_SET_KEY_AIME: + case SG_NFC_CMD_MIFARE_SET_KEY_BANA: + case SG_NFC_CMD_RADIO_ON: + case SG_NFC_CMD_RADIO_OFF: return sg_nfc_cmd_dummy(nfc, &req->simple, &resp->simple); default: @@ -177,7 +186,7 @@ static HRESULT sg_nfc_dispatch( } static HRESULT sg_nfc_cmd_reset( - const struct sg_nfc *nfc, + struct sg_nfc *nfc, const struct sg_req_header *req, struct sg_resp_header *resp) { @@ -189,7 +198,7 @@ static HRESULT sg_nfc_cmd_reset( } static HRESULT sg_nfc_cmd_get_fw_version( - const struct sg_nfc *nfc, + struct sg_nfc *nfc, const struct sg_req_header *req, struct sg_nfc_resp_get_fw_version *resp) { @@ -201,7 +210,7 @@ static HRESULT sg_nfc_cmd_get_fw_version( } static HRESULT sg_nfc_cmd_get_hw_version( - const struct sg_nfc *nfc, + struct sg_nfc *nfc, const struct sg_req_header *req, struct sg_nfc_resp_get_hw_version *resp) { @@ -212,54 +221,124 @@ static HRESULT sg_nfc_cmd_get_hw_version( return S_OK; } -static HRESULT sg_nfc_cmd_mifare_poll( - const struct sg_nfc *nfc, +static HRESULT sg_nfc_cmd_poll( + struct sg_nfc *nfc, const struct sg_req_header *req, - struct sg_nfc_resp_mifare_poll *resp) + struct sg_nfc_resp_poll *resp) { - uint32_t uid; + struct sg_nfc_poll_mifare mifare; + struct sg_nfc_poll_felica felica; HRESULT hr; - uid = 0; - hr = nfc->ops->mifare_poll(nfc->ops_ctx, &uid); - - if (hr == S_OK) { - if (uid == 0 || uid == -1) { - sg_nfc_dprintf(nfc, "nfc->ops->mifare_poll returned bad uid\n"); - - return E_UNEXPECTED; - } - - sg_nfc_dprintf(nfc, "Mifare card is present\n"); - - sg_resp_init(&resp->resp, req, sizeof(resp->payload.some)); - resp->payload.some[0] = 0x01; /* Chunk size? */ - resp->payload.some[1] = 0x10; /* Unknown */ - resp->payload.some[2] = 0x04; /* Chunk size? */ - resp->payload.some[3] = uid >> 24; /* UID byte 0 */ - resp->payload.some[4] = uid >> 16; /* UID byte 1 */ - resp->payload.some[5] = uid >> 8; /* UID byte 2 */ - resp->payload.some[6] = uid ; /* UID byte 3 */ - - return S_OK; - } else if (hr == S_FALSE) { - sg_resp_init(&resp->resp, req, sizeof(resp->payload.none)); - resp->payload.none = 0x00; - - return S_OK; - } else if (FAILED(hr)) { - sg_nfc_dprintf(nfc, "nfc->ops->mifare_poll error: %x\n", (int) hr); + hr = nfc->ops->poll(nfc->ops_ctx); + if (FAILED(hr)) { return hr; - } else { - sg_nfc_dprintf(nfc, "nfc->ops->mifare_poll bad return: %x\n", (int) hr); - - return E_UNEXPECTED; } + + hr = sg_nfc_poll_felica(nfc, &felica); + + if (SUCCEEDED(hr) && hr != S_FALSE) { + sg_resp_init(&resp->resp, req, 1 + sizeof(felica)); + memcpy(resp->payload, &felica, sizeof(felica)); + resp->count = 1; + + return S_OK; + } + + hr = sg_nfc_poll_aime(nfc, &mifare); + + if (SUCCEEDED(hr) && hr != S_FALSE) { + sg_resp_init(&resp->resp, req, 1 + sizeof(mifare)); + memcpy(resp->payload, &mifare, sizeof(mifare)); + resp->count = 1; + + return S_OK; + } + + sg_resp_init(&resp->resp, req, 1); + resp->count = 0; + + return S_OK; +} + +static HRESULT sg_nfc_poll_aime( + struct sg_nfc *nfc, + struct sg_nfc_poll_mifare *mifare) +{ + uint8_t luid[10]; + HRESULT hr; + + /* Call backend */ + + if (nfc->ops->get_aime_id != NULL) { + hr = nfc->ops->get_aime_id(nfc->ops_ctx, luid, sizeof(luid)); + } else { + hr = S_FALSE; + } + + if (FAILED(hr) || hr == S_FALSE) { + return hr; + } + + sg_nfc_dprintf(nfc, "AiMe card is present\n"); + + /* Construct response (use an arbitrary UID) */ + + mifare->type = 0x10; + mifare->id_len = sizeof(mifare->uid); + mifare->uid = _byteswap_ulong(0x01020304); + + /* Initialize MIFARE IC emulator */ + + hr = aime_card_populate(&nfc->mifare, luid, sizeof(luid)); + + if (FAILED(hr)) { + return hr; + } + + return S_OK; +} + +static HRESULT sg_nfc_poll_felica( + struct sg_nfc *nfc, + struct sg_nfc_poll_felica *felica) +{ + uint64_t IDm; + HRESULT hr; + + /* Call backend */ + + if (nfc->ops->get_felica_id != NULL) { + hr = nfc->ops->get_felica_id(nfc->ops_ctx, &IDm); + } else { + hr = S_FALSE; + } + + if (FAILED(hr) || hr == S_FALSE) { + return hr; + } + + sg_nfc_dprintf(nfc, "FeliCa card is present\n"); + + /* Construct poll response */ + + felica->type = 0x20; + felica->id_len = sizeof(felica->IDm) + sizeof(felica->PMm); + felica->IDm = _byteswap_uint64(IDm); + felica->PMm = _byteswap_uint64(felica_get_generic_PMm()); + + /* Initialize FeliCa IC emulator */ + + nfc->felica.IDm = IDm; + nfc->felica.PMm = felica_get_generic_PMm(); + nfc->felica.system_code = 0x0000; + + return S_OK; } static HRESULT sg_nfc_cmd_mifare_read_block( - const struct sg_nfc *nfc, + struct sg_nfc *nfc, const struct sg_nfc_req_mifare_read_block *req, struct sg_nfc_resp_mifare_read_block *resp) { @@ -271,71 +350,81 @@ static HRESULT sg_nfc_cmd_mifare_read_block( return E_FAIL; } - uid = (req->payload.uid[0] << 24) | - (req->payload.uid[1] << 16) | - (req->payload.uid[2] << 8) | - (req->payload.uid[3] ) ; + uid = _byteswap_ulong(req->payload.uid); sg_nfc_dprintf(nfc, "Read uid %08x block %i\n", uid, req->payload.block_no); + if (req->payload.block_no > 3) { + sg_nfc_dprintf(nfc, "MIFARE block number out of range\n"); + + return E_FAIL; + } + sg_resp_init(&resp->resp, &req->req, sizeof(resp->block)); - switch (req->payload.block_no) { - case 1: - return sg_nfc_mifare_read_block_1(nfc, uid, resp->block); - - case 2: - return sg_nfc_mifare_read_block_2(nfc, uid, resp->block); - - case 0: - case 3: - sg_nfc_dprintf( - nfc, - "Block %i access not implemented\n", - req->payload.block_no); - - return E_NOTIMPL; - - default: - sg_nfc_dprintf( - nfc, - "Read from invalid mifare block nr %i\n", - req->payload.block_no); - - return E_INVALIDARG; - } -} - -static HRESULT sg_nfc_mifare_read_block_1( - const struct sg_nfc *nfc, - uint32_t uid, - uint8_t *block) -{ - memcpy(block, sg_nfc_block_1, sizeof(sg_nfc_block_1)); + memcpy( resp->block, + nfc->mifare.sectors[0].blocks[req->payload.block_no].bytes, + sizeof(resp->block)); return S_OK; } -static HRESULT sg_nfc_mifare_read_block_2( - const struct sg_nfc *nfc, - uint32_t uid, - uint8_t *block) +static HRESULT sg_nfc_cmd_felica_encap( + struct sg_nfc *nfc, + const struct sg_nfc_req_felica_encap *req, + struct sg_nfc_resp_felica_encap *resp) { + struct const_iobuf f_req; + struct iobuf f_res; HRESULT hr; - hr = nfc->ops->mifare_read_luid(nfc->ops_ctx, uid, &block[6], 10); + /* First byte of encapsulated request and response is a length byte + (inclusive of itself). The FeliCa emulator expects its caller to handle + that length byte on its behalf (we adopt the convention that the length + byte is part of the FeliCa protocol's framing layer). */ + + if (req->req.payload_len != 8 + req->payload[0]) { + sg_nfc_dprintf( + nfc, + "FeliCa encap payload length mismatch: sg %i != felica %i + 8", + req->req.payload_len, + req->payload[0]); + + return E_FAIL; + } + + f_req.bytes = req->payload; + f_req.nbytes = req->payload[0]; + f_req.pos = 1; + + f_res.bytes = resp->payload; + f_res.nbytes = sizeof(resp->payload); + f_res.pos = 1; + +#if 0 + dprintf("FELICA OUTBOUND:\n"); + dump_const_iobuf(&f_req); +#endif + + hr = felica_transact(&nfc->felica, &f_req, &f_res); if (FAILED(hr)) { return hr; } - memset(block, 0, 6); + sg_resp_init(&resp->resp, &req->req, f_res.pos); + resp->payload[0] = f_res.pos; + +#if 0 + dprintf("FELICA INBOUND:\n"); + dump_iobuf(&f_res); +#endif return S_OK; } static HRESULT sg_nfc_cmd_dummy( - const struct sg_nfc *nfc, + struct sg_nfc *nfc, const struct sg_req_header *req, struct sg_resp_header *resp) { diff --git a/board/sg-nfc.h b/board/sg-nfc.h index e3307b2..b88b222 100644 --- a/board/sg-nfc.h +++ b/board/sg-nfc.h @@ -7,19 +7,23 @@ #include "hook/iobuf.h" +#include "iccard/felica.h" +#include "iccard/mifare.h" + struct sg_nfc_ops { - HRESULT (*mifare_poll)(void *ctx, uint32_t *uid); - HRESULT (*mifare_read_luid)( - void *ctx, - uint32_t uid, - uint8_t *luid, - size_t nbytes); + HRESULT (*poll)(void *ctx); + HRESULT (*get_aime_id)(void *ctx, uint8_t *luid, size_t nbytes); + HRESULT (*get_felica_id)(void *ctx, uint64_t *IDm); + + // TODO Banapass, AmuseIC }; struct sg_nfc { const struct sg_nfc_ops *ops; void *ops_ctx; uint8_t addr; + struct felica felica; + struct mifare mifare; }; void sg_nfc_init( diff --git a/board/sg-reader.c b/board/sg-reader.c index 55f0647..8274e26 100644 --- a/board/sg-reader.c +++ b/board/sg-reader.c @@ -20,17 +20,18 @@ static HRESULT sg_reader_handle_irp(struct irp *irp); static HRESULT sg_reader_handle_irp_locked(struct irp *irp); -static HRESULT sg_reader_mifare_poll(void *ctx, uint32_t *uid); -static HRESULT sg_reader_mifare_read_luid( +static HRESULT sg_reader_nfc_poll(void *ctx); +static HRESULT sg_reader_nfc_get_aime_id( void *ctx, - uint32_t uid, uint8_t *luid, size_t luid_size); +static HRESULT sg_reader_nfc_get_felica_id(void *ctx, uint64_t *IDm); static void sg_reader_led_set_color(void *ctx, uint8_t r, uint8_t g, uint8_t b); static const struct sg_nfc_ops sg_reader_nfc_ops = { - .mifare_poll = sg_reader_mifare_poll, - .mifare_read_luid = sg_reader_mifare_read_luid, + .poll = sg_reader_nfc_poll, + .get_aime_id = sg_reader_nfc_get_aime_id, + .get_felica_id = sg_reader_nfc_get_felica_id, }; static const struct sg_led_ops sg_reader_led_ops = { @@ -134,18 +135,22 @@ static HRESULT sg_reader_handle_irp_locked(struct irp *irp) return hr; } -static HRESULT sg_reader_mifare_poll(void *ctx, uint32_t *uid) +static HRESULT sg_reader_nfc_poll(void *ctx) { - return aime_io_mifare_poll(0, uid); + return aime_io_nfc_poll(0); } -static HRESULT sg_reader_mifare_read_luid( +static HRESULT sg_reader_nfc_get_aime_id( void *ctx, - uint32_t uid, uint8_t *luid, size_t luid_size) { - return aime_io_mifare_read_luid(0, uid, luid, luid_size); + return aime_io_nfc_get_aime_id(0, luid, luid_size); +} + +static HRESULT sg_reader_nfc_get_felica_id(void *ctx, uint64_t *IDm) +{ + return aime_io_nfc_get_felica_id(0, IDm); } static void sg_reader_led_set_color(void *ctx, uint8_t r, uint8_t g, uint8_t b)