forked from Dniel97/segatools
Overhaul card reader emulation
This commit is contained in:
parent
225a889b34
commit
5ed6eaa203
218
aimeio/aimeio.c
218
aimeio/aimeio.c
@ -1,6 +1,7 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -6,6 +6,9 @@ board_lib = static_library(
|
||||
dependencies : [
|
||||
capnhook.get_variable('hook_dep'),
|
||||
],
|
||||
link_with : [
|
||||
iccard_lib,
|
||||
],
|
||||
sources : [
|
||||
'config.c',
|
||||
'config.h',
|
||||
|
@ -2,18 +2,21 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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)
|
||||
|
319
board/sg-nfc.c
319
board/sg-nfc.c
@ -4,13 +4,18 @@
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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)
|
||||
{
|
||||
|
@ -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(
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user