Overhaul card reader emulation

This commit is contained in:
Tau 2019-10-19 15:51:10 -04:00
parent 225a889b34
commit 5ed6eaa203
8 changed files with 451 additions and 198 deletions

View File

@ -1,6 +1,7 @@
#include <windows.h> #include <windows.h>
#include <assert.h> #include <assert.h>
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -11,13 +12,35 @@
#include "util/crc.h" #include "util/crc.h"
#include "util/dprintf.h" #include "util/dprintf.h"
enum {
AIME_IO_TOUCH_MSEC = 1000,
};
struct aime_io_config { 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; uint8_t vk_scan;
}; };
static struct aime_io_config aime_io_cfg; 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( static void aime_io_config_read(
struct aime_io_config *cfg, struct aime_io_config *cfg,
@ -28,10 +51,18 @@ static void aime_io_config_read(
GetPrivateProfileStringW( GetPrivateProfileStringW(
L"aime", L"aime",
L"cardPath", L"aimePath",
L"DEVICE\\aime.txt", L"DEVICE\\aime.txt",
cfg->id_path, cfg->aime_path,
_countof(cfg->id_path), _countof(cfg->aime_path),
filename);
GetPrivateProfileStringW(
L"aime",
L"felicaPath",
L"DEVICE\\felica.txt",
cfg->felica_path,
_countof(cfg->felica_path),
filename); filename);
cfg->vk_scan = GetPrivateProfileIntW( cfg->vk_scan = GetPrivateProfileIntW(
@ -39,7 +70,51 @@ static void aime_io_config_read(
L"scan", L"scan",
VK_RETURN, VK_RETURN,
filename); 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) 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; HRESULT hr;
FILE *f;
size_t i;
int byte;
int r;
if (unit_no != 0) { if (unit_no != 0) {
return S_FALSE; return S_FALSE;
} }
hr = S_FALSE; t = GetTickCount();
f = NULL; level = GetAsyncKeyState(aime_io_cfg.vk_scan) & 0x8000;
if (!(GetAsyncKeyState(aime_io_cfg.vk_scan) & 0x8000)) { /* 1. Linger a card for AIME_IO_TOUCH_MSEC after vk_scan has been released.
goto end; 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;
}
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);
if (dt < AIME_IO_TOUCH_MSEC) {
hr = S_OK; hr = S_OK;
} else {
end: aime_io_nfc_poll_fall();
if (f != NULL) { aime_io_latch = false;
fclose(f); hr = S_FALSE;
}
} else {
if (level) {
hr = aime_io_nfc_poll_rise();
aime_io_latch = true;
} else {
hr = S_FALSE;
}
} }
return hr; 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, uint8_t unit_no,
uint32_t uid,
uint8_t *luid, uint8_t *luid,
size_t luid_size) size_t luid_size)
{ {
assert(luid != NULL); 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; return S_OK;
} }

View File

@ -4,5 +4,6 @@ EXPORTS
aime_io_fini aime_io_fini
aime_io_init aime_io_init
aime_io_led_set_color aime_io_led_set_color
aime_io_mifare_poll aime_io_nfc_poll
aime_io_mifare_read_luid aime_io_nfc_get_aime_id
aime_io_nfc_get_felica_id

View File

@ -7,10 +7,10 @@
HRESULT aime_io_init(void); HRESULT aime_io_init(void);
void aime_io_fini(void); 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);
HRESULT aime_io_mifare_read_luid( HRESULT aime_io_nfc_get_aime_id(
uint8_t unit_no, uint8_t unit_no,
uint32_t uid,
uint8_t *luid, uint8_t *luid,
size_t luid_size); 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); void aime_io_led_set_color(uint8_t unit_no, uint8_t r, uint8_t g, uint8_t b);

View File

@ -6,6 +6,9 @@ board_lib = static_library(
dependencies : [ dependencies : [
capnhook.get_variable('hook_dep'), capnhook.get_variable('hook_dep'),
], ],
link_with : [
iccard_lib,
],
sources : [ sources : [
'config.c', 'config.c',
'config.h', 'config.h',

View File

@ -2,18 +2,21 @@
#include <stdint.h> #include <stdint.h>
#pragma pack(push, 1)
enum { enum {
SG_NFC_CMD_GET_FW_VERSION = 0x30, SG_NFC_CMD_GET_FW_VERSION = 0x30,
SG_NFC_CMD_GET_HW_VERSION = 0x32, SG_NFC_CMD_GET_HW_VERSION = 0x32,
SG_NFC_CMD_40_POLL = 0x40, SG_NFC_CMD_RADIO_ON = 0x40,
SG_NFC_CMD_41_POLL = 0x41, SG_NFC_CMD_RADIO_OFF = 0x41,
SG_NFC_CMD_MIFARE_POLL = 0x42, SG_NFC_CMD_POLL = 0x42,
SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43, 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_READ_BLOCK = 0x52,
SG_NFC_CMD_MIFARE_SET_KEY = 0x54, SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x54,
SG_NFC_CMD_MIFARE_55 = 0x55, SG_NFC_CMD_MIFARE_AUTHENTICATE = 0x55, /* guess based on time sent */
SG_NFC_CMD_RESET = 0x62, SG_NFC_CMD_RESET = 0x62,
SG_NFC_CMD_FELICA_ENCAP = 0x71,
}; };
struct sg_nfc_resp_get_fw_version { struct sg_nfc_resp_get_fw_version {
@ -41,23 +44,34 @@ struct sg_nfc_req_poll_40 {
uint8_t payload; 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; struct sg_resp_header resp;
union { uint8_t count;
uint8_t none; uint8_t payload[250];
uint8_t some[7];
} payload;
}; };
struct sg_nfc_req_mifare_select_tag { struct sg_nfc_req_mifare_select_tag {
struct sg_resp_header resp; struct sg_resp_header resp;
uint8_t uid[4]; uint32_t uid;
}; };
struct sg_nfc_req_mifare_read_block { struct sg_nfc_req_mifare_read_block {
struct sg_req_header req; struct sg_req_header req;
struct { struct {
uint8_t uid[4]; uint32_t uid;
uint8_t block_no; uint8_t block_no;
} payload; } payload;
}; };
@ -67,6 +81,17 @@ struct sg_nfc_resp_mifare_read_block {
uint8_t block[16]; 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 { union sg_nfc_req_any {
uint8_t bytes[256]; uint8_t bytes[256];
struct sg_req_header simple; 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_read_block mifare_read_block;
struct sg_nfc_req_mifare_50 mifare_50; struct sg_nfc_req_mifare_50 mifare_50;
struct sg_nfc_req_poll_40 poll_40; struct sg_nfc_req_poll_40 poll_40;
struct sg_nfc_req_felica_encap felica_encap;
}; };
union sg_nfc_resp_any { union sg_nfc_resp_any {
@ -81,6 +107,9 @@ union sg_nfc_resp_any {
struct sg_resp_header simple; struct sg_resp_header simple;
struct sg_nfc_resp_get_fw_version get_fw_version; struct sg_nfc_resp_get_fw_version get_fw_version;
struct sg_nfc_resp_get_hw_version get_hw_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_mifare_read_block mifare_read_block;
struct sg_nfc_resp_felica_encap felica_encap;
}; };
#pragma pack(pop)

View File

@ -4,13 +4,18 @@
#include <stdarg.h> #include <stdarg.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "board/sg-cmd.h" #include "board/sg-cmd.h"
#include "board/sg-nfc.h" #include "board/sg-nfc.h"
#include "board/sg-nfc-cmd.h" #include "board/sg-nfc-cmd.h"
#include "iccard/aime.h"
#include "iccard/felica.h"
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/dump.h"
static HRESULT sg_nfc_dispatch( static HRESULT sg_nfc_dispatch(
void *ctx, void *ctx,
@ -18,50 +23,48 @@ static HRESULT sg_nfc_dispatch(
void *v_resp); void *v_resp);
static HRESULT sg_nfc_cmd_reset( static HRESULT sg_nfc_cmd_reset(
const struct sg_nfc *nfc, struct sg_nfc *nfc,
const struct sg_req_header *req, const struct sg_req_header *req,
struct sg_resp_header *resp); struct sg_resp_header *resp);
static HRESULT sg_nfc_cmd_get_fw_version( static HRESULT sg_nfc_cmd_get_fw_version(
const struct sg_nfc *nfc, struct sg_nfc *nfc,
const struct sg_req_header *req, const struct sg_req_header *req,
struct sg_nfc_resp_get_fw_version *resp); struct sg_nfc_resp_get_fw_version *resp);
static HRESULT sg_nfc_cmd_get_hw_version( static HRESULT sg_nfc_cmd_get_hw_version(
const struct sg_nfc *nfc, struct sg_nfc *nfc,
const struct sg_req_header *req, const struct sg_req_header *req,
struct sg_nfc_resp_get_hw_version *resp); struct sg_nfc_resp_get_hw_version *resp);
static HRESULT sg_nfc_cmd_mifare_poll( static HRESULT sg_nfc_cmd_poll(
const struct sg_nfc *nfc, struct sg_nfc *nfc,
const struct sg_req_header *req, 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( 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, const struct sg_nfc_req_mifare_read_block *req,
struct sg_nfc_resp_mifare_read_block *resp); struct sg_nfc_resp_mifare_read_block *resp);
static HRESULT sg_nfc_mifare_read_block_1( static HRESULT sg_nfc_cmd_felica_encap(
const struct sg_nfc *nfc, struct sg_nfc *nfc,
uint32_t uid, const struct sg_nfc_req_felica_encap *req,
uint8_t *block); struct sg_nfc_resp_felica_encap *resp);
static HRESULT sg_nfc_mifare_read_block_2(
const struct sg_nfc *nfc,
uint32_t uid,
uint8_t *block);
static HRESULT sg_nfc_cmd_dummy( static HRESULT sg_nfc_cmd_dummy(
const struct sg_nfc *nfc, struct sg_nfc *nfc,
const struct sg_req_header *req, const struct sg_req_header *req,
struct sg_resp_header *resp); 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( void sg_nfc_init(
struct sg_nfc *nfc, struct sg_nfc *nfc,
uint8_t addr, uint8_t addr,
@ -120,7 +123,7 @@ static HRESULT sg_nfc_dispatch(
const void *v_req, const void *v_req,
void *v_resp) void *v_resp)
{ {
const struct sg_nfc *nfc; struct sg_nfc *nfc;
const union sg_nfc_req_any *req; const union sg_nfc_req_any *req;
union sg_nfc_resp_any *resp; union sg_nfc_resp_any *resp;
@ -149,11 +152,11 @@ static HRESULT sg_nfc_dispatch(
&req->simple, &req->simple,
&resp->get_hw_version); &resp->get_hw_version);
case SG_NFC_CMD_MIFARE_POLL: case SG_NFC_CMD_POLL:
return sg_nfc_cmd_mifare_poll( return sg_nfc_cmd_poll(
nfc, nfc,
&req->simple, &req->simple,
&resp->mifare_poll); &resp->poll);
case SG_NFC_CMD_MIFARE_READ_BLOCK: case SG_NFC_CMD_MIFARE_READ_BLOCK:
return 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, &req->mifare_read_block,
&resp->mifare_read_block); &resp->mifare_read_block);
case SG_NFC_CMD_40_POLL: case SG_NFC_CMD_FELICA_ENCAP:
case SG_NFC_CMD_41_POLL: return sg_nfc_cmd_felica_encap(
case SG_NFC_CMD_MIFARE_SET_KEY: 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_SELECT_TAG:
case SG_NFC_CMD_MIFARE_50: case SG_NFC_CMD_MIFARE_SET_KEY_AIME:
case SG_NFC_CMD_MIFARE_55: 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); return sg_nfc_cmd_dummy(nfc, &req->simple, &resp->simple);
default: default:
@ -177,7 +186,7 @@ static HRESULT sg_nfc_dispatch(
} }
static HRESULT sg_nfc_cmd_reset( static HRESULT sg_nfc_cmd_reset(
const struct sg_nfc *nfc, struct sg_nfc *nfc,
const struct sg_req_header *req, const struct sg_req_header *req,
struct sg_resp_header *resp) struct sg_resp_header *resp)
{ {
@ -189,7 +198,7 @@ static HRESULT sg_nfc_cmd_reset(
} }
static HRESULT sg_nfc_cmd_get_fw_version( static HRESULT sg_nfc_cmd_get_fw_version(
const struct sg_nfc *nfc, struct sg_nfc *nfc,
const struct sg_req_header *req, const struct sg_req_header *req,
struct sg_nfc_resp_get_fw_version *resp) 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( static HRESULT sg_nfc_cmd_get_hw_version(
const struct sg_nfc *nfc, struct sg_nfc *nfc,
const struct sg_req_header *req, const struct sg_req_header *req,
struct sg_nfc_resp_get_hw_version *resp) struct sg_nfc_resp_get_hw_version *resp)
{ {
@ -212,54 +221,124 @@ static HRESULT sg_nfc_cmd_get_hw_version(
return S_OK; return S_OK;
} }
static HRESULT sg_nfc_cmd_mifare_poll( static HRESULT sg_nfc_cmd_poll(
const struct sg_nfc *nfc, struct sg_nfc *nfc,
const struct sg_req_header *req, 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; HRESULT hr;
uid = 0; hr = nfc->ops->poll(nfc->ops_ctx);
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);
if (FAILED(hr)) {
return 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( 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, const struct sg_nfc_req_mifare_read_block *req,
struct sg_nfc_resp_mifare_read_block *resp) struct sg_nfc_resp_mifare_read_block *resp)
{ {
@ -271,71 +350,81 @@ static HRESULT sg_nfc_cmd_mifare_read_block(
return E_FAIL; return E_FAIL;
} }
uid = (req->payload.uid[0] << 24) | uid = _byteswap_ulong(req->payload.uid);
(req->payload.uid[1] << 16) |
(req->payload.uid[2] << 8) |
(req->payload.uid[3] ) ;
sg_nfc_dprintf(nfc, "Read uid %08x block %i\n", uid, req->payload.block_no); 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)); sg_resp_init(&resp->resp, &req->req, sizeof(resp->block));
switch (req->payload.block_no) { memcpy( resp->block,
case 1: nfc->mifare.sectors[0].blocks[req->payload.block_no].bytes,
return sg_nfc_mifare_read_block_1(nfc, uid, resp->block); sizeof(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));
return S_OK; return S_OK;
} }
static HRESULT sg_nfc_mifare_read_block_2( static HRESULT sg_nfc_cmd_felica_encap(
const struct sg_nfc *nfc, struct sg_nfc *nfc,
uint32_t uid, const struct sg_nfc_req_felica_encap *req,
uint8_t *block) struct sg_nfc_resp_felica_encap *resp)
{ {
struct const_iobuf f_req;
struct iobuf f_res;
HRESULT hr; 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)) { if (FAILED(hr)) {
return 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; return S_OK;
} }
static HRESULT sg_nfc_cmd_dummy( static HRESULT sg_nfc_cmd_dummy(
const struct sg_nfc *nfc, struct sg_nfc *nfc,
const struct sg_req_header *req, const struct sg_req_header *req,
struct sg_resp_header *resp) struct sg_resp_header *resp)
{ {

View File

@ -7,19 +7,23 @@
#include "hook/iobuf.h" #include "hook/iobuf.h"
#include "iccard/felica.h"
#include "iccard/mifare.h"
struct sg_nfc_ops { struct sg_nfc_ops {
HRESULT (*mifare_poll)(void *ctx, uint32_t *uid); HRESULT (*poll)(void *ctx);
HRESULT (*mifare_read_luid)( HRESULT (*get_aime_id)(void *ctx, uint8_t *luid, size_t nbytes);
void *ctx, HRESULT (*get_felica_id)(void *ctx, uint64_t *IDm);
uint32_t uid,
uint8_t *luid, // TODO Banapass, AmuseIC
size_t nbytes);
}; };
struct sg_nfc { struct sg_nfc {
const struct sg_nfc_ops *ops; const struct sg_nfc_ops *ops;
void *ops_ctx; void *ops_ctx;
uint8_t addr; uint8_t addr;
struct felica felica;
struct mifare mifare;
}; };
void sg_nfc_init( void sg_nfc_init(

View File

@ -20,17 +20,18 @@
static HRESULT sg_reader_handle_irp(struct irp *irp); static HRESULT sg_reader_handle_irp(struct irp *irp);
static HRESULT sg_reader_handle_irp_locked(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_nfc_poll(void *ctx);
static HRESULT sg_reader_mifare_read_luid( static HRESULT sg_reader_nfc_get_aime_id(
void *ctx, void *ctx,
uint32_t uid,
uint8_t *luid, uint8_t *luid,
size_t luid_size); 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 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 = { static const struct sg_nfc_ops sg_reader_nfc_ops = {
.mifare_poll = sg_reader_mifare_poll, .poll = sg_reader_nfc_poll,
.mifare_read_luid = sg_reader_mifare_read_luid, .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 = { 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; 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, void *ctx,
uint32_t uid,
uint8_t *luid, uint8_t *luid,
size_t luid_size) 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) static void sg_reader_led_set_color(void *ctx, uint8_t r, uint8_t g, uint8_t b)