From 5ea5922dcc7b19180fb94939614ad3d181f1a91c Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 18 Sep 2026 19:03:01 -0400 Subject: [PATCH] move code from segatools --- aimeio/aimeio.c | 221 +++++++++++++++++++--- aimeio/aimeio.h | 188 ++++++++++++++++++- board/aime-dll.c | 49 ++++- board/aime-dll.h | 47 +++++ board/sg-nfc-cmd.h | 30 +-- board/sg-nfc.c | 445 ++++++++++++++++++++++++++++++++++++++++++--- board/sg-nfc.h | 39 ++++ board/sg-reader.c | 200 +++++++++++++++++++- board/sg-reader.h | 6 +- iccard/felica.c | 42 ++--- iccard/felica.h | 5 +- util/env.c | 10 + util/env.h | 4 + util/meson.build | 4 + util/slurp.c | 67 +++++++ util/slurp.h | 12 ++ 16 files changed, 1263 insertions(+), 106 deletions(-) create mode 100644 util/env.c create mode 100644 util/env.h create mode 100644 util/slurp.c create mode 100644 util/slurp.h diff --git a/aimeio/aimeio.c b/aimeio/aimeio.c index 3b3d92b..d3b2593 100644 --- a/aimeio/aimeio.c +++ b/aimeio/aimeio.c @@ -12,6 +12,7 @@ #include "util/crc.h" #include "util/dprintf.h" +#include "util/env.h" struct aime_io_config { wchar_t aime_path[MAX_PATH]; @@ -26,6 +27,8 @@ static uint8_t aime_io_aime_id[10]; static uint8_t aime_io_felica_id[8]; static bool aime_io_aime_id_present; static bool aime_io_felica_id_present; +static bool aime_io_radio_on = true; +static bool aime_io_update_mode; static void aime_io_config_read( struct aime_io_config *cfg, @@ -217,12 +220,12 @@ static HRESULT aime_io_generate_aime( uint16_t aime_io_get_api_version(void) { - return 0x0100; + return 0x0101; } HRESULT aime_io_init(void) { - aime_io_config_read(&aime_io_cfg, L".\\bananatools.ini"); + aime_io_config_read(&aime_io_cfg, get_config_path()); return S_OK; } @@ -232,10 +235,6 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no) bool sense; HRESULT hr; - if (unit_no != 0) { - return S_OK; - } - /* Reset presence flags */ aime_io_aime_id_present = false; @@ -243,6 +242,10 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no) /* Don't do anything more if the scan key is not held */ + if (!aime_io_radio_on) { + return S_OK; + } + sense = GetAsyncKeyState(aime_io_cfg.vk_scan) & 0x8000; if (!sense) { @@ -262,6 +265,20 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no) return S_OK; } + /* Try FeliCa IC */ + + 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 S_OK; + } + + // 2026-08-24 Hay1tsme: Skipping Generating aime before checking for felica was incredibly annoying. /* Try generating AiMe IC (if enabled) */ if (aime_io_cfg.aime_gen) { @@ -278,19 +295,6 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no) return S_OK; } - /* Try FeliCa IC */ - - 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 S_OK; - } - /* Try generating FeliCa IC (if enabled) */ if (aime_io_cfg.felica_gen) { @@ -317,7 +321,7 @@ HRESULT aime_io_nfc_get_aime_id( assert(luid != NULL); assert(luid_size == sizeof(aime_io_aime_id)); - if (unit_no != 0 || !aime_io_aime_id_present) { + if (!aime_io_aime_id_present) { return S_FALSE; } @@ -333,7 +337,7 @@ HRESULT aime_io_nfc_get_felica_id(uint8_t unit_no, uint64_t *IDm) assert(IDm != NULL); - if (unit_no != 0 || !aime_io_felica_id_present) { + if (!aime_io_felica_id_present) { return S_FALSE; } @@ -348,5 +352,180 @@ HRESULT aime_io_nfc_get_felica_id(uint8_t unit_no, uint64_t *IDm) return S_OK; } +HRESULT aime_io_nfc_get_mifare_uid( + uint8_t unit_no, + uint8_t *uid, + size_t uid_size) +{ + (void) uid; + (void) uid_size; + + if (unit_no != 0 || !aime_io_aime_id_present) { + return S_FALSE; + } + + return S_FALSE; +} + +HRESULT aime_io_nfc_mifare_select( + uint8_t unit_no, + const uint8_t *uid, + size_t uid_size) +{ + (void) uid; + (void) uid_size; + + if (unit_no != 0) { + return S_FALSE; + } + + return S_FALSE; +} + +HRESULT aime_io_nfc_mifare_set_key( + uint8_t unit_no, + uint8_t key_type, + const uint8_t *key, + size_t key_size) +{ + (void) key_type; + (void) key; + (void) key_size; + + if (unit_no != 0) { + return S_FALSE; + } + + return S_FALSE; +} + +HRESULT aime_io_nfc_mifare_authenticate( + uint8_t unit_no, + uint8_t key_type, + const uint8_t *payload, + size_t payload_size) +{ + (void) key_type; + (void) payload; + (void) payload_size; + + if (unit_no != 0) { + return S_FALSE; + } + + return S_FALSE; +} + +HRESULT aime_io_nfc_mifare_read_block( + uint8_t unit_no, + const uint8_t *uid, + size_t uid_size, + uint8_t block_no, + uint8_t *block, + size_t block_size) +{ + (void) uid; + (void) uid_size; + (void) block_no; + (void) block; + (void) block_size; + + if (unit_no != 0) { + return S_FALSE; + } + + return S_FALSE; +} + +HRESULT aime_io_nfc_felica_transact( + uint8_t unit_no, + const uint8_t *req, + size_t req_size, + uint8_t *res, + size_t res_size, + size_t *res_size_written) +{ + (void) req; + (void) req_size; + (void) res; + (void) res_size; + (void) res_size_written; + + if (unit_no != 0) { + return S_FALSE; + } + + return S_FALSE; +} + +HRESULT aime_io_nfc_radio_on(uint8_t unit_no) +{ + if (unit_no != 0) { + return S_FALSE; + } + + aime_io_radio_on = true; + aime_io_update_mode = false; + + return S_OK; +} + +HRESULT aime_io_nfc_radio_off(uint8_t unit_no) +{ + if (unit_no != 0) { + return S_FALSE; + } + + aime_io_radio_on = false; + + return S_OK; +} + +HRESULT aime_io_nfc_to_update_mode(uint8_t unit_no) +{ + if (unit_no != 0) { + return S_FALSE; + } + + aime_io_update_mode = true; + + return S_OK; +} + +HRESULT aime_io_nfc_send_hex_data( + uint8_t unit_no, + const uint8_t *payload, + size_t payload_size, + uint8_t *status_out) +{ + (void) payload; + (void) payload_size; + + if (unit_no != 0) { + return S_FALSE; + } + + if (status_out != NULL) { + *status_out = (payload_size == 0x2b) ? 0x20 : 0x00; + } + + return S_OK; +} + void aime_io_led_set_color(uint8_t unit_no, uint8_t r, uint8_t g, uint8_t b) {} + +void aime_io_vfd_set_text( + const uint8_t *text, + size_t text_len, + const struct aime_io_vfd_state *state) +{ + (void) text; + (void) text_len; + (void) state; +} + +void aime_io_vfd_set_state(const struct aime_io_vfd_state *state) +{ + (void) state; +} diff --git a/aimeio/aimeio.h b/aimeio/aimeio.h index 221f8e0..3c15dcf 100644 --- a/aimeio/aimeio.h +++ b/aimeio/aimeio.h @@ -11,7 +11,7 @@ version and the low byte is the minor version (as defined by the Semantic Versioning standard). - The latest API version as of this writing is 0x0100. + The latest API version as of this writing is 0x0101. */ uint16_t aime_io_get_api_version(void); @@ -27,7 +27,7 @@ HRESULT aime_io_init(void); /* Poll for IC cards in the vicinity. - - unit_no: Always 0 as of the current API version + - unit_no: 0 on the primary Aime reader (most games), may be 1 on Sangokushi Taisen for the queue reader Minimum API version: 0x0100 */ @@ -36,7 +36,7 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no); /* Attempt to read out a classic Aime card ID - - unit_no: Always 0 as of the current API version + - unit_no: 0 on the primary Aime reader (most games), may be 1 on Sangokushi Taisen for the queue reader - luid: Pointer to a ten-byte buffer that will receive the ID - luid_size: Size of the buffer at *luid. Always 10. @@ -63,7 +63,7 @@ HRESULT aime_io_nfc_get_aime_id( Parameters: - - unit_no: Always 0 as of the current API version + - unit_no: 0 on the primary Aime reader (most games), may be 1 on Sangokushi Taisen for the queue reader - IDm: Output parameter that will receive the card ID Returns: @@ -77,11 +77,189 @@ HRESULT aime_io_nfc_get_aime_id( HRESULT aime_io_nfc_get_felica_id(uint8_t unit_no, uint64_t *IDm); /* - Change the color and brightness of the card reader's RGB lighting + MIFARE key selector values used by the set key/authenticate functions. + + Minimum API version: 0x0101 +*/ +enum { + AIME_IO_MIFARE_KEY_AIME = 0, + AIME_IO_MIFARE_KEY_BANA = 1, +}; + +/* + Attempt to read the 4-byte MIFARE UID of the currently present card. + + Parameters: - unit_no: Always 0 as of the current API version + - uid: Pointer to a four-byte buffer that will receive the UID + - uid_size: Size of the buffer at *uid. Always 4. + + Returns: + + - S_OK if a MIFARE card is present and the UID was read successfully + - S_FALSE if no MIFARE card is present (*uid will be ignored) + - Any HRESULT error if an error occured. + + Minimum API version: 0x0101 +*/ +HRESULT aime_io_nfc_get_mifare_uid( + uint8_t unit_no, + uint8_t *uid, + size_t uid_size); + +/* + Select a MIFARE card by UID (optional for real readers). + + Minimum API version: 0x0101 +*/ +HRESULT aime_io_nfc_mifare_select( + uint8_t unit_no, + const uint8_t *uid, + size_t uid_size); + +/* + Supply a MIFARE authentication key to the reader. + + Minimum API version: 0x0101 +*/ +HRESULT aime_io_nfc_mifare_set_key( + uint8_t unit_no, + uint8_t key_type, + const uint8_t *key, + size_t key_size); + +/* + Perform a MIFARE authentication sequence. + + Minimum API version: 0x0101 +*/ +HRESULT aime_io_nfc_mifare_authenticate( + uint8_t unit_no, + uint8_t key_type, + const uint8_t *payload, + size_t payload_size); + +/* + Read a 16-byte MIFARE block from the card. + + Minimum API version: 0x0101 +*/ +HRESULT aime_io_nfc_mifare_read_block( + uint8_t unit_no, + const uint8_t *uid, + size_t uid_size, + uint8_t block_no, + uint8_t *block, + size_t block_size); + +/* + Forward a raw FeliCa request to a real reader. + + Parameters: + + - req: FeliCa request buffer, including the length byte + - res: FeliCa response buffer, including the length byte + - res_size_written: Output size of the response (bytes written to *res) + + Minimum API version: 0x0101 +*/ +HRESULT aime_io_nfc_felica_transact( + uint8_t unit_no, + const uint8_t *req, + size_t req_size, + uint8_t *res, + size_t res_size, + size_t *res_size_written); + +/* + Enable the reader's RF field. + + Minimum API version: 0x0101 +*/ +HRESULT aime_io_nfc_radio_on(uint8_t unit_no); + +/* + Disable the reader's RF field. + + Minimum API version: 0x0101 +*/ +HRESULT aime_io_nfc_radio_off(uint8_t unit_no); + +/* + Put the reader into firmware update mode. + + Minimum API version: 0x0101 +*/ +HRESULT aime_io_nfc_to_update_mode(uint8_t unit_no); + +/* + Forward a raw hex-data command to the reader. + + Parameters: + + - payload: Command payload bytes + - payload_size: Size of the payload + - status_out: Optional pointer to receive the SG status byte + + Minimum API version: 0x0101 +*/ +HRESULT aime_io_nfc_send_hex_data( + uint8_t unit_no, + const uint8_t *payload, + size_t payload_size, + uint8_t *status_out); + +/* + Change the color and brightness of the card reader's RGB lighting + + - unit_no: 0 on the primary Aime reader (most games), may be 1 on Sangokushi Taisen for the queue reader - r, g, b: Primary color intensity, from 0 to 255 inclusive. Minimum API version: 0x0100 */ void aime_io_led_set_color(uint8_t unit_no, uint8_t r, uint8_t g, uint8_t b); + +/* + VFD text forwarding. This is intended to pass through the text payload + plus the most recent VFD state so external handlers can emulate scrolling + or layout if desired. + + - text: Pointer to raw text bytes (not null-terminated) + - text_len: Length of the text buffer + - state: Current VFD state at the time of rendering + + The encoding field uses VFD encoding values (0=GB2312, 1=Big5, + 2=Shift-JIS, 3=KSC5601). + + Minimum API version: 0x0101 +*/ +struct aime_io_vfd_state { + uint8_t encoding; + uint8_t text_speed; + uint8_t scroll_enabled; + uint16_t h_scroll; + uint16_t cursor_x; + uint8_t cursor_y; + uint16_t wnd_x0; + uint8_t wnd_y0; + uint16_t wnd_x1; + uint8_t wnd_y1; + uint8_t rotate; + uint8_t brightness; + uint8_t screen_on; + uint32_t clear_seq; +}; + +void aime_io_vfd_set_text( + const uint8_t *text, + size_t text_len, + const struct aime_io_vfd_state *state); + +/* + VFD state change notification. Called when the VFD state changes even + when no text is written. + + Minimum API version: 0x0101 +*/ +void aime_io_vfd_set_state(const struct aime_io_vfd_state *state); diff --git a/board/aime-dll.c b/board/aime-dll.c index 465fcfd..94b380c 100644 --- a/board/aime-dll.c +++ b/board/aime-dll.c @@ -8,6 +8,11 @@ #include "util/dll-bind.h" #include "util/dprintf.h" +enum { + AIME_DLL_SYM_COUNT_V100 = 5, + AIME_DLL_SYM_COUNT_V101 = 17, +}; + const struct dll_bind_sym aime_dll_syms[] = { { .sym = "aime_io_init", @@ -24,7 +29,43 @@ const struct dll_bind_sym aime_dll_syms[] = { }, { .sym = "aime_io_led_set_color", .off = offsetof(struct aime_dll, led_set_color), - } + }, { + .sym = "aime_io_vfd_set_text", + .off = offsetof(struct aime_dll, vfd_set_text), + }, { + .sym = "aime_io_vfd_set_state", + .off = offsetof(struct aime_dll, vfd_set_state), + }, { + .sym = "aime_io_nfc_get_mifare_uid", + .off = offsetof(struct aime_dll, nfc_get_mifare_uid), + }, { + .sym = "aime_io_nfc_mifare_select", + .off = offsetof(struct aime_dll, nfc_mifare_select), + }, { + .sym = "aime_io_nfc_mifare_set_key", + .off = offsetof(struct aime_dll, nfc_mifare_set_key), + }, { + .sym = "aime_io_nfc_mifare_authenticate", + .off = offsetof(struct aime_dll, nfc_mifare_authenticate), + }, { + .sym = "aime_io_nfc_mifare_read_block", + .off = offsetof(struct aime_dll, nfc_mifare_read_block), + }, { + .sym = "aime_io_nfc_felica_transact", + .off = offsetof(struct aime_dll, nfc_felica_transact), + }, { + .sym = "aime_io_nfc_radio_on", + .off = offsetof(struct aime_dll, nfc_radio_on), + }, { + .sym = "aime_io_nfc_radio_off", + .off = offsetof(struct aime_dll, nfc_radio_off), + }, { + .sym = "aime_io_nfc_to_update_mode", + .off = offsetof(struct aime_dll, nfc_to_update_mode), + }, { + .sym = "aime_io_nfc_send_hex_data", + .off = offsetof(struct aime_dll, nfc_send_hex_data), + }, }; struct aime_dll aime_dll; @@ -42,6 +83,7 @@ HRESULT aime_dll_init(const struct aime_dll_config *cfg, HINSTANCE self) HINSTANCE owned; HINSTANCE src; HRESULT hr; + size_t sym_count; assert(cfg != NULL); assert(self != NULL); @@ -86,7 +128,10 @@ HRESULT aime_dll_init(const struct aime_dll_config *cfg, HINSTANCE self) } sym = aime_dll_syms; - hr = dll_bind(&aime_dll, src, &sym, _countof(aime_dll_syms)); + sym_count = (aime_dll.api_version < 0x0101) + ? AIME_DLL_SYM_COUNT_V100 + : AIME_DLL_SYM_COUNT_V101; + hr = dll_bind(&aime_dll, src, &sym, sym_count); if (FAILED(hr)) { if (src != self) { diff --git a/board/aime-dll.h b/board/aime-dll.h index 354516b..00a5368 100644 --- a/board/aime-dll.h +++ b/board/aime-dll.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "aimeio/aimeio.h" @@ -13,11 +14,57 @@ struct aime_dll { uint8_t *luid, size_t luid_size); HRESULT (*nfc_get_felica_id)(uint8_t unit_no, uint64_t *IDm); + HRESULT (*nfc_get_mifare_uid)( + uint8_t unit_no, + uint8_t *uid, + size_t uid_size); + HRESULT (*nfc_mifare_select)( + uint8_t unit_no, + const uint8_t *uid, + size_t uid_size); + HRESULT (*nfc_mifare_set_key)( + uint8_t unit_no, + uint8_t key_type, + const uint8_t *key, + size_t key_size); + HRESULT (*nfc_mifare_authenticate)( + uint8_t unit_no, + uint8_t key_type, + const uint8_t *payload, + size_t payload_size); + HRESULT (*nfc_mifare_read_block)( + uint8_t unit_no, + const uint8_t *uid, + size_t uid_size, + uint8_t block_no, + uint8_t *block, + size_t block_size); + HRESULT (*nfc_felica_transact)( + uint8_t unit_no, + const uint8_t *req, + size_t req_size, + uint8_t *res, + size_t res_size, + size_t *res_size_written); + HRESULT (*nfc_radio_on)(uint8_t unit_no); + HRESULT (*nfc_radio_off)(uint8_t unit_no); + HRESULT (*nfc_to_update_mode)(uint8_t unit_no); + HRESULT (*nfc_send_hex_data)( + uint8_t unit_no, + const uint8_t *payload, + size_t payload_size, + uint8_t *status_out); void (*led_set_color)(uint8_t unit_no, uint8_t r, uint8_t g, uint8_t b); + void (*vfd_set_text)( + const uint8_t *text, + size_t text_len, + const struct aime_io_vfd_state *state); + void (*vfd_set_state)(const struct aime_io_vfd_state *state); }; struct aime_dll_config { wchar_t path[MAX_PATH]; + bool path64; }; extern struct aime_dll aime_dll; diff --git a/board/sg-nfc-cmd.h b/board/sg-nfc-cmd.h index 08923fd..e54e0a7 100644 --- a/board/sg-nfc-cmd.h +++ b/board/sg-nfc-cmd.h @@ -5,21 +5,21 @@ #pragma pack(push, 1) enum { - SG_NFC_CMD_GET_FW_VERSION = 0x30, - SG_NFC_CMD_GET_HW_VERSION = 0x32, - 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_SET_KEY_AIME = 0x50, - SG_NFC_CMD_MIFARE_AUTHENTICATE_A = 0x51, - SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, - SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x54, - SG_NFC_CMD_MIFARE_AUTHENTICATE_B = 0x55, - SG_NFC_CMD_TO_UPDATE_MODE = 0x60, - SG_NFC_CMD_SEND_HEX_DATA = 0x61, - SG_NFC_CMD_RESET = 0x62, - SG_NFC_CMD_FELICA_ENCAP = 0x71, + SG_NFC_CMD_GET_FW_VERSION = 0x30, + SG_NFC_CMD_GET_HW_VERSION = 0x32, + 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_SET_KEY_AIME = 0x50, + SG_NFC_CMD_MIFARE_AUTHENTICATE_AIME = 0x51, + SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, + SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x54, + SG_NFC_CMD_MIFARE_AUTHENTICATE_BANA = 0x55, + SG_NFC_CMD_TO_UPDATE_MODE = 0x60, + SG_NFC_CMD_SEND_HEX_DATA = 0x61, + SG_NFC_CMD_RESET = 0x62, + SG_NFC_CMD_FELICA_ENCAP = 0x71, }; struct sg_nfc_res_get_fw_version { diff --git a/board/sg-nfc.c b/board/sg-nfc.c index de99115..cb51d66 100644 --- a/board/sg-nfc.c +++ b/board/sg-nfc.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -11,11 +12,14 @@ #include "board/sg-nfc.h" #include "board/sg-nfc-cmd.h" +#include "aimeio/aimeio.h" + #include "iccard/aime.h" #include "iccard/felica.h" #include "util/dprintf.h" #include "util/dump.h" +#include "util/slurp.h" static HRESULT sg_nfc_dispatch( void *ctx, @@ -55,6 +59,38 @@ static HRESULT sg_nfc_cmd_mifare_read_block( const struct sg_nfc_req_mifare_read_block *req, struct sg_nfc_res_mifare_read_block *res); +static HRESULT sg_nfc_cmd_mifare_select( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res); + +static HRESULT sg_nfc_cmd_mifare_set_key( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res, + uint8_t key_type); + +static HRESULT sg_nfc_cmd_mifare_authenticate( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res, + uint8_t key_type); + +static HRESULT sg_nfc_cmd_radio_on( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res); + +static HRESULT sg_nfc_cmd_radio_off( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res); + +static HRESULT sg_nfc_cmd_to_update_mode( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res); + static HRESULT sg_nfc_cmd_felica_encap( struct sg_nfc *nfc, const struct sg_nfc_req_felica_encap *req, @@ -87,6 +123,9 @@ void sg_nfc_init( uint8_t addr, const struct sg_nfc_ops *ops, unsigned int gen, + unsigned int proxy_flag, + const wchar_t* authdata_path, + bool mobile_felica, void *ops_ctx) { assert(nfc != NULL); @@ -96,6 +135,9 @@ void sg_nfc_init( nfc->ops_ctx = ops_ctx; nfc->addr = addr; nfc->gen = gen; + nfc->proxy_flag = proxy_flag; + nfc->authdata_path = authdata_path; + nfc->felica.is_mobile = mobile_felica; } #ifdef NDEBUG @@ -189,19 +231,49 @@ static HRESULT sg_nfc_dispatch( &req->felica_encap, &res->felica_encap); - case SG_NFC_CMD_MIFARE_AUTHENTICATE_A: - case SG_NFC_CMD_MIFARE_AUTHENTICATE_B: + case SG_NFC_CMD_MIFARE_SELECT_TAG: + return sg_nfc_cmd_mifare_select(nfc, &req->simple, &res->simple); + + case SG_NFC_CMD_MIFARE_SET_KEY_AIME: + return sg_nfc_cmd_mifare_set_key( + nfc, + &req->simple, + &res->simple, + AIME_IO_MIFARE_KEY_AIME); + + case SG_NFC_CMD_MIFARE_SET_KEY_BANA: + return sg_nfc_cmd_mifare_set_key( + nfc, + &req->simple, + &res->simple, + AIME_IO_MIFARE_KEY_BANA); + + case SG_NFC_CMD_MIFARE_AUTHENTICATE_AIME: + return sg_nfc_cmd_mifare_authenticate( + nfc, + &req->simple, + &res->simple, + AIME_IO_MIFARE_KEY_AIME); + + case SG_NFC_CMD_MIFARE_AUTHENTICATE_BANA: + return sg_nfc_cmd_mifare_authenticate( + nfc, + &req->simple, + &res->simple, + AIME_IO_MIFARE_KEY_BANA); + + case SG_NFC_CMD_RADIO_ON: + return sg_nfc_cmd_radio_on(nfc, &req->simple, &res->simple); + + case SG_NFC_CMD_RADIO_OFF: + return sg_nfc_cmd_radio_off(nfc, &req->simple, &res->simple); + + case SG_NFC_CMD_TO_UPDATE_MODE: + return sg_nfc_cmd_to_update_mode(nfc, &req->simple, &res->simple); + case SG_NFC_CMD_SEND_HEX_DATA: return sg_nfc_cmd_send_hex_data(nfc, &req->simple, &res->simple); - case SG_NFC_CMD_MIFARE_SELECT_TAG: - 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: - case SG_NFC_CMD_TO_UPDATE_MODE: - return sg_nfc_cmd_dummy(nfc, &req->simple, &res->simple); - default: sg_nfc_dprintf(nfc, "Unimpl command %02x\n", req->simple.hdr.cmd); @@ -294,7 +366,9 @@ static HRESULT sg_nfc_poll_aime( struct sg_nfc *nfc, struct sg_nfc_poll_mifare *mifare) { + bool has_uid; uint8_t luid[10]; + uint8_t uid[4]; HRESULT hr; /* Call backend */ @@ -311,11 +385,30 @@ static HRESULT sg_nfc_poll_aime( sg_nfc_dprintf(nfc, "AiMe card is present\n"); - /* Construct response (use an arbitrary UID) */ + has_uid = false; + + if (nfc->ops->get_mifare_uid != NULL) { + hr = nfc->ops->get_mifare_uid(nfc->ops_ctx, uid, sizeof(uid)); + + if (FAILED(hr)) { + return hr; + } + + if (hr == S_OK) { + has_uid = true; + } + } + + /* Construct response */ mifare->type = 0x10; mifare->id_len = sizeof(mifare->uid); - mifare->uid = _byteswap_ulong(0x01020304); + if (has_uid) { + memcpy(&mifare->uid, uid, sizeof(uid)); + } else { + // mifare->uid = _byteswap_ulong(0x8FBECBFF); + mifare->uid = _byteswap_ulong(0x01020304); + } /* Initialize MIFARE IC emulator */ @@ -354,22 +447,193 @@ static HRESULT sg_nfc_poll_felica( felica->type = 0x20; felica->id_len = sizeof(felica->IDm) + sizeof(felica->PMm); felica->IDm = _byteswap_uint64(IDm); - felica->PMm = _byteswap_uint64(felica_get_amusement_ic_PMm()); + felica->PMm = _byteswap_uint64(felica_get_amusement_ic_PMm(nfc->felica.is_mobile)); /* Initialize FeliCa IC emulator */ nfc->felica.IDm = IDm; - nfc->felica.PMm = felica_get_amusement_ic_PMm(); + nfc->felica.PMm = felica_get_amusement_ic_PMm(nfc->felica.is_mobile); nfc->felica.system_code = 0x88b4; return S_OK; } +static HRESULT sg_nfc_cmd_mifare_select( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res) +{ + const uint8_t *payload; + HRESULT hr; + + if (req->payload_len != sizeof(uint32_t)) { + sg_nfc_dprintf(nfc, "%s: Payload size is incorrect\n", __func__); + + return E_FAIL; + } + + payload = (const uint8_t *) req + sizeof(*req); + + if (nfc->ops->mifare_select != NULL) { + hr = nfc->ops->mifare_select(nfc->ops_ctx, payload, req->payload_len); + + if (FAILED(hr)) { + return hr; + } + } + + sg_res_init(res, req, 0); + + return S_OK; +} + +static HRESULT sg_nfc_cmd_mifare_set_key( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res, + uint8_t key_type) +{ + const uint8_t *payload; + HRESULT hr; + + payload = (const uint8_t *) req + sizeof(*req); + + if (nfc->ops->mifare_set_key != NULL) { + hr = nfc->ops->mifare_set_key( + nfc->ops_ctx, + key_type, + payload, + req->payload_len); + + if (FAILED(hr)) { + return hr; + } + } + + sg_res_init(res, req, 0); + + return S_OK; +} + +static HRESULT sg_nfc_cmd_mifare_authenticate( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res, + uint8_t key_type) +{ + const uint8_t *payload; + HRESULT hr; + + payload = (const uint8_t *) req + sizeof(*req); + + if (nfc->ops->mifare_authenticate != NULL) { + hr = nfc->ops->mifare_authenticate( + nfc->ops_ctx, + key_type, + payload, + req->payload_len); + + if (FAILED(hr)) { + return hr; + } + } + + sg_res_init(res, req, 0); + + return S_OK; +} + +static HRESULT sg_nfc_cmd_radio_on( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res) +{ + HRESULT hr; + + if (nfc->ops->radio_on == NULL) { + sg_res_init(res, req, 0); + return S_OK; + } + + hr = nfc->ops->radio_on(nfc->ops_ctx); + + if (FAILED(hr)) { + return hr; + } + + if (hr == S_FALSE) { + sg_res_init(res, req, 0); + return S_OK; + } + + sg_res_init(res, req, 0); + + return S_OK; +} + +static HRESULT sg_nfc_cmd_radio_off( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res) +{ + HRESULT hr; + + if (nfc->ops->radio_off == NULL) { + sg_res_init(res, req, 0); + return S_OK; + } + + hr = nfc->ops->radio_off(nfc->ops_ctx); + + if (FAILED(hr)) { + return hr; + } + + if (hr == S_FALSE) { + sg_res_init(res, req, 0); + return S_OK; + } + + sg_res_init(res, req, 0); + + return S_OK; +} + +static HRESULT sg_nfc_cmd_to_update_mode( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res) +{ + HRESULT hr; + + if (nfc->ops->to_update_mode == NULL) { + sg_res_init(res, req, 0); + return S_OK; + } + + hr = nfc->ops->to_update_mode(nfc->ops_ctx); + + if (FAILED(hr)) { + return hr; + } + + if (hr == S_FALSE) { + sg_res_init(res, req, 0); + return S_OK; + } + + sg_res_init(res, req, 0); + + return S_OK; +} + static HRESULT sg_nfc_cmd_mifare_read_block( struct sg_nfc *nfc, const struct sg_nfc_req_mifare_read_block *req, struct sg_nfc_res_mifare_read_block *res) { + const uint8_t *uid_bytes; + HRESULT hr; uint32_t uid; if (req->req.payload_len != sizeof(req->payload)) { @@ -378,22 +642,86 @@ static HRESULT sg_nfc_cmd_mifare_read_block( return E_FAIL; } + uid_bytes = (const uint8_t *) &req->payload.uid; 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) { + if (nfc->ops->mifare_read_block != NULL) { + hr = nfc->ops->mifare_read_block( + nfc->ops_ctx, + uid_bytes, + sizeof(req->payload.uid), + req->payload.block_no, + res->block, + sizeof(res->block)); + + if (FAILED(hr)) { + return hr; + } + + if (hr == S_OK) { + sg_res_init(&res->res, &req->req, sizeof(res->block)); + return S_OK; + } + } + + if (req->payload.block_no > 14) { sg_nfc_dprintf(nfc, "MIFARE block number out of range\n"); return E_FAIL; + } else if (req->payload.block_no >= 5){ // emoney auth encrypted + + sg_res_init(&res->res, &req->req, sizeof(res->block)); + + char* auth; + long size = wslurp(nfc->authdata_path, &auth, false); + if (size < 0){ + sg_nfc_dprintf(nfc, "Failed to read %ls: %lx!\n", nfc->authdata_path, GetLastError()); + return E_FAIL; + } + + int offset = 0; + if (req->payload.block_no == 6){ + offset = 16; + } else if (req->payload.block_no == 8){ + offset = 32; + } else if (req->payload.block_no == 9){ + offset = 48; + } else if (req->payload.block_no == 10){ + offset = 64; + } else if (req->payload.block_no == 12){ + offset = 82; + } else if (req->payload.block_no == 13){ + offset = 98; + } else if (req->payload.block_no == 14){ + offset = 114; + } + + for (int i = 0; i < 16 && offset + i < size; i++){ + res->block[i] = auth[offset + i]; + } + + free(auth); + + } else if (req->payload.block_no == 4){ // emoney auth plain + + sg_res_init(&res->res, &req->req, sizeof(res->block)); + + res->block[0] = 0x54; // header + res->block[1] = 0x43; + res->block[2] = nfc->proxy_flag; // 2 or 3 depending on game (useProxy in env.json) + res->block[3] = 0x01; // unknown flag + + } else { // read all other blocks normally + + sg_res_init(&res->res, &req->req, sizeof(res->block)); + + memcpy( res->block, + nfc->mifare.sectors[0].blocks[req->payload.block_no].bytes, + sizeof(res->block)); } - sg_res_init(&res->res, &req->req, sizeof(res->block)); - - memcpy( res->block, - nfc->mifare.sectors[0].blocks[req->payload.block_no].bytes, - sizeof(res->block)); - return S_OK; } @@ -404,6 +732,7 @@ static HRESULT sg_nfc_cmd_felica_encap( { struct const_iobuf f_req; struct iobuf f_res; + size_t res_size_written; HRESULT hr; /* First byte of encapsulated request and response is a length byte @@ -421,6 +750,32 @@ static HRESULT sg_nfc_cmd_felica_encap( return E_FAIL; } + if (nfc->ops->felica_transact != NULL) { + res_size_written = 0; + hr = nfc->ops->felica_transact( + nfc->ops_ctx, + req->payload, + req->payload[0], + res->payload, + sizeof(res->payload), + &res_size_written); + + if (FAILED(hr)) { + return hr; + } + + if (hr == S_OK) { + if (res_size_written == 0 || + res_size_written > sizeof(res->payload)) { + return E_FAIL; + } + + sg_res_init(&res->res, &req->req, res_size_written); + + return S_OK; + } + } + f_req.bytes = req->payload; f_req.nbytes = req->payload[0]; f_req.pos = 1; @@ -429,7 +784,7 @@ static HRESULT sg_nfc_cmd_felica_encap( f_res.nbytes = sizeof(res->payload); f_res.pos = 1; -#if 0 +#if defined(LOG_NFC) dprintf("FELICA OUTBOUND:\n"); dump_const_iobuf(&f_req); #endif @@ -443,7 +798,7 @@ static HRESULT sg_nfc_cmd_felica_encap( sg_res_init(&res->res, &req->req, f_res.pos); res->payload[0] = f_res.pos; -#if 0 +#if defined(LOG_NFC) dprintf("FELICA INBOUND:\n"); dump_iobuf(&f_res); #endif @@ -456,14 +811,48 @@ static HRESULT sg_nfc_cmd_send_hex_data( const struct sg_req_header *req, struct sg_res_header *res) { - sg_res_init(res, req, 0); + const uint8_t *payload; + HRESULT hr; + uint8_t status; - /* Firmware checksum length? */ - if (req->payload_len == 0x2b) { - /* The firmware is identical flag? */ - res->status = 0x20; + if (nfc->ops->send_hex_data == NULL) { + sg_res_init(res, req, 0); + + /* Firmware checksum length? */ + if (req->payload_len == 0x2b) { + /* The firmware is identical flag? */ + res->status = 0x20; + } + + return S_OK; } + payload = (const uint8_t *) req + sizeof(*req); + status = 0; + + hr = nfc->ops->send_hex_data( + nfc->ops_ctx, + payload, + req->payload_len, + &status); + + if (FAILED(hr)) { + return hr; + } + + if (hr == S_FALSE) { + sg_res_init(res, req, 0); + + if (req->payload_len == 0x2b) { + res->status = 0x20; + } + + return S_OK; + } + + sg_res_init(res, req, 0); + res->status = status; + return S_OK; } diff --git a/board/sg-nfc.h b/board/sg-nfc.h index 3c8eb49..a3465c8 100644 --- a/board/sg-nfc.h +++ b/board/sg-nfc.h @@ -14,6 +14,40 @@ struct sg_nfc_ops { 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); + HRESULT (*get_mifare_uid)(void *ctx, uint8_t *uid, size_t nbytes); + HRESULT (*mifare_select)(void *ctx, const uint8_t *uid, size_t nbytes); + HRESULT (*mifare_set_key)( + void *ctx, + uint8_t key_type, + const uint8_t *key, + size_t nbytes); + HRESULT (*mifare_authenticate)( + void *ctx, + uint8_t key_type, + const uint8_t *payload, + size_t nbytes); + HRESULT (*mifare_read_block)( + void *ctx, + const uint8_t *uid, + size_t uid_size, + uint8_t block_no, + uint8_t *block, + size_t block_size); + HRESULT (*felica_transact)( + void *ctx, + const uint8_t *req, + size_t req_size, + uint8_t *res, + size_t res_size, + size_t *res_size_written); + HRESULT (*radio_on)(void *ctx); + HRESULT (*radio_off)(void *ctx); + HRESULT (*to_update_mode)(void *ctx); + HRESULT (*send_hex_data)( + void *ctx, + const uint8_t *payload, + size_t payload_size, + uint8_t *status_out); // TODO Banapass, AmuseIC }; @@ -23,8 +57,10 @@ struct sg_nfc { void *ops_ctx; uint8_t addr; unsigned int gen; + unsigned int proxy_flag; struct felica felica; struct mifare mifare; + const wchar_t* authdata_path; }; void sg_nfc_init( @@ -32,6 +68,9 @@ void sg_nfc_init( uint8_t addr, const struct sg_nfc_ops *ops, unsigned int gen, + unsigned int proxy_flag, + const wchar_t* authdata_path, + bool mobile_felica, void *ops_ctx); void sg_nfc_transact( diff --git a/board/sg-reader.c b/board/sg-reader.c index 24df4df..ffa12a2 100644 --- a/board/sg-reader.c +++ b/board/sg-reader.c @@ -24,12 +24,62 @@ static HRESULT sg_reader_nfc_get_aime_id( uint8_t *luid, size_t luid_size); static HRESULT sg_reader_nfc_get_felica_id(void *ctx, uint64_t *IDm); +static HRESULT sg_reader_nfc_get_mifare_uid( + void *ctx, + uint8_t *uid, + size_t uid_size); +static HRESULT sg_reader_nfc_mifare_select( + void *ctx, + const uint8_t *uid, + size_t uid_size); +static HRESULT sg_reader_nfc_mifare_set_key( + void *ctx, + uint8_t key_type, + const uint8_t *key, + size_t key_size); +static HRESULT sg_reader_nfc_mifare_authenticate( + void *ctx, + uint8_t key_type, + const uint8_t *payload, + size_t payload_size); +static HRESULT sg_reader_nfc_mifare_read_block( + void *ctx, + const uint8_t *uid, + size_t uid_size, + uint8_t block_no, + uint8_t *block, + size_t block_size); +static HRESULT sg_reader_nfc_felica_transact( + void *ctx, + const uint8_t *req, + size_t req_size, + uint8_t *res, + size_t res_size, + size_t *res_size_written); +static HRESULT sg_reader_nfc_radio_on(void *ctx); +static HRESULT sg_reader_nfc_radio_off(void *ctx); +static HRESULT sg_reader_nfc_to_update_mode(void *ctx); +static HRESULT sg_reader_nfc_send_hex_data( + void *ctx, + const uint8_t *payload, + size_t payload_size, + uint8_t *status_out); 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 = { .poll = sg_reader_nfc_poll, .get_aime_id = sg_reader_nfc_get_aime_id, .get_felica_id = sg_reader_nfc_get_felica_id, + .get_mifare_uid = sg_reader_nfc_get_mifare_uid, + .mifare_select = sg_reader_nfc_mifare_select, + .mifare_set_key = sg_reader_nfc_mifare_set_key, + .mifare_authenticate = sg_reader_nfc_mifare_authenticate, + .mifare_read_block = sg_reader_nfc_mifare_read_block, + .felica_transact = sg_reader_nfc_felica_transact, + .radio_on = sg_reader_nfc_radio_on, + .radio_off = sg_reader_nfc_radio_off, + .to_update_mode = sg_reader_nfc_to_update_mode, + .send_hex_data = sg_reader_nfc_send_hex_data, }; static const struct sg_led_ops sg_reader_led_ops = { @@ -47,7 +97,7 @@ static struct sg_led sg_reader_led; HRESULT sg_reader_hook_init( const struct aime_config *cfg, - unsigned int port_no, + unsigned int default_port_no, unsigned int gen, HINSTANCE self) { @@ -66,6 +116,11 @@ HRESULT sg_reader_hook_init( return hr; } + unsigned int port_no = cfg->port_no; + if (port_no == 0){ + port_no = default_port_no; + } + if (cfg->gen != 0) { gen = cfg->gen; } @@ -76,7 +131,7 @@ HRESULT sg_reader_hook_init( return E_INVALIDARG; } - sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, gen, NULL); + sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, gen, cfg->proxy_flag, cfg->authdata_path, cfg->mobile_felica, NULL); sg_led_init(&sg_reader_led, 0x08, &sg_reader_led_ops, gen, NULL); InitializeCriticalSection(&sg_reader_lock); @@ -85,6 +140,7 @@ HRESULT sg_reader_hook_init( sg_reader_uart.baud.BaudRate = 38400; } + dprintf("NFC Assembly: enabling (port=%d)\n", port_no); uart_init(&sg_reader_uart, port_no); sg_reader_uart.written.bytes = sg_reader_written_bytes; sg_reader_uart.written.nbytes = sizeof(sg_reader_written_bytes); @@ -115,14 +171,14 @@ static HRESULT sg_reader_handle_irp_locked(struct irp *irp) { HRESULT hr; -#if 0 +#if defined(LOG_NFC) if (irp->op == IRP_OP_WRITE) { dprintf("WRITE:\n"); dump_const_iobuf(&irp->write); } #endif -#if 0 +#if defined(LOG_NFC) if (irp->op == IRP_OP_READ) { dprintf("READ:\n"); dump_iobuf(&sg_reader_uart.readable); @@ -195,6 +251,142 @@ static HRESULT sg_reader_nfc_get_felica_id(void *ctx, uint64_t *IDm) return aime_dll.nfc_get_felica_id(0, IDm); } +static HRESULT sg_reader_nfc_get_mifare_uid( + void *ctx, + uint8_t *uid, + size_t uid_size) +{ + if (aime_dll.nfc_get_mifare_uid == NULL) { + return S_FALSE; + } + + return aime_dll.nfc_get_mifare_uid(0, uid, uid_size); +} + +static HRESULT sg_reader_nfc_mifare_select( + void *ctx, + const uint8_t *uid, + size_t uid_size) +{ + if (aime_dll.nfc_mifare_select == NULL) { + return S_FALSE; + } + + return aime_dll.nfc_mifare_select(0, uid, uid_size); +} + +static HRESULT sg_reader_nfc_mifare_set_key( + void *ctx, + uint8_t key_type, + const uint8_t *key, + size_t key_size) +{ + if (aime_dll.nfc_mifare_set_key == NULL) { + return S_FALSE; + } + + return aime_dll.nfc_mifare_set_key(0, key_type, key, key_size); +} + +static HRESULT sg_reader_nfc_mifare_authenticate( + void *ctx, + uint8_t key_type, + const uint8_t *payload, + size_t payload_size) +{ + if (aime_dll.nfc_mifare_authenticate == NULL) { + return S_FALSE; + } + + return aime_dll.nfc_mifare_authenticate( + 0, + key_type, + payload, + payload_size); +} + +static HRESULT sg_reader_nfc_mifare_read_block( + void *ctx, + const uint8_t *uid, + size_t uid_size, + uint8_t block_no, + uint8_t *block, + size_t block_size) +{ + if (aime_dll.nfc_mifare_read_block == NULL) { + return S_FALSE; + } + + return aime_dll.nfc_mifare_read_block( + 0, + uid, + uid_size, + block_no, + block, + block_size); +} + +static HRESULT sg_reader_nfc_felica_transact( + void *ctx, + const uint8_t *req, + size_t req_size, + uint8_t *res, + size_t res_size, + size_t *res_size_written) +{ + if (aime_dll.nfc_felica_transact == NULL) { + return S_FALSE; + } + + return aime_dll.nfc_felica_transact( + 0, + req, + req_size, + res, + res_size, + res_size_written); +} + +static HRESULT sg_reader_nfc_radio_on(void *ctx) +{ + if (aime_dll.nfc_radio_on == NULL) { + return S_FALSE; + } + + return aime_dll.nfc_radio_on(0); +} + +static HRESULT sg_reader_nfc_radio_off(void *ctx) +{ + if (aime_dll.nfc_radio_off == NULL) { + return S_FALSE; + } + + return aime_dll.nfc_radio_off(0); +} + +static HRESULT sg_reader_nfc_to_update_mode(void *ctx) +{ + if (aime_dll.nfc_to_update_mode == NULL) { + return S_FALSE; + } + + return aime_dll.nfc_to_update_mode(0); +} + +static HRESULT sg_reader_nfc_send_hex_data( + void *ctx, + const uint8_t *payload, + size_t payload_size, + uint8_t *status_out) +{ + if (aime_dll.nfc_send_hex_data == NULL) { + return S_FALSE; + } + + return aime_dll.nfc_send_hex_data(0, payload, payload_size, status_out); +} + static void sg_reader_led_set_color(void *ctx, uint8_t r, uint8_t g, uint8_t b) { aime_dll.led_set_color(0, r, g, b); diff --git a/board/sg-reader.h b/board/sg-reader.h index 01eb0b3..137fceb 100644 --- a/board/sg-reader.h +++ b/board/sg-reader.h @@ -9,12 +9,16 @@ struct aime_config { struct aime_dll_config dll; bool enable; + unsigned int port_no; bool high_baudrate; unsigned int gen; + unsigned int proxy_flag; + wchar_t authdata_path[MAX_PATH]; + bool mobile_felica; }; HRESULT sg_reader_hook_init( const struct aime_config *cfg, - unsigned int port_no, + unsigned int default_port_no, unsigned int gen, HINSTANCE self); diff --git a/iccard/felica.c b/iccard/felica.c index 85c8aea..8f20e2a 100644 --- a/iccard/felica.c +++ b/iccard/felica.c @@ -1,9 +1,9 @@ #include -#include #include #include #include +#include #include "hook/iobuf.h" @@ -37,28 +37,14 @@ static HRESULT felica_cmd_write_without_encryption( struct const_iobuf* req, struct iobuf* res); -uint64_t felica_get_generic_PMm(void) -{ - /* A FeliCa PMm contains low-level protocol timing information for - communicating with a particular IC card. The exact values are not - particularly important for our purposes, so we'll just return a hard- - coded PMm. This current value has been taken from an iPhone, emulating - a Suica pass via Apple Wallet, which seems to be one of the few - universally accepted FeliCa types for these games. Certain older - Suica passes and other payment and transportation cards - do not seem to be supported anymore. */ - - return 0x01168B868FBECBFFULL; -} - -uint64_t felica_get_amusement_ic_PMm(void) +uint64_t felica_get_amusement_ic_PMm(bool is_mobile) { /* * AIC Card PMm, if this is returned from the card, * the aimelib will access the actual blocks for authentication. */ - return 0x00F1000000014300; + return is_mobile ? 0x0018000000014300 : 0x00F1000000014300; } HRESULT felica_transact( @@ -211,17 +197,6 @@ static HRESULT felica_cmd_get_system_code( return S_OK; } -static HRESULT felica_cmd_active( - struct felica *f, - struct const_iobuf *req, - struct iobuf *res) -{ - /* The specification for this command is probably only available under NDA. - Returning what the driver seems to want. */ - - return iobuf_write_8(res, 0); -} - static HRESULT felica_cmd_read_without_encryption( struct felica *f, struct const_iobuf *req, @@ -345,3 +320,14 @@ static HRESULT felica_cmd_write_without_encryption( { return iobuf_write_be16(res, 0); } + +static HRESULT felica_cmd_active( + struct felica *f, + struct const_iobuf *req, + struct iobuf *res) +{ + /* The specification for this command is probably only available under NDA. + Returning what the driver seems to want. */ + + return iobuf_write_8(res, 0); +} diff --git a/iccard/felica.h b/iccard/felica.h index be4f4e1..f6b1410 100644 --- a/iccard/felica.h +++ b/iccard/felica.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -19,6 +20,7 @@ struct felica { uint64_t IDm; uint64_t PMm; uint16_t system_code; + bool is_mobile; }; HRESULT felica_transact( @@ -26,5 +28,4 @@ HRESULT felica_transact( struct const_iobuf *req, struct iobuf *res); -uint64_t felica_get_generic_PMm(void); -uint64_t felica_get_amusement_ic_PMm(void); +uint64_t felica_get_amusement_ic_PMm(bool is_mobile); diff --git a/util/env.c b/util/env.c new file mode 100644 index 0000000..dd52528 --- /dev/null +++ b/util/env.c @@ -0,0 +1,10 @@ +#include "env.h" + +const wchar_t* get_config_path() { + static wchar_t path[MAX_PATH]; + if (!GetEnvironmentVariableW(L"BANANATOOLS_CONFIG_PATH", path, MAX_PATH)) { + return L".\\bananatools.ini"; + } + + return path; +} diff --git a/util/env.h b/util/env.h new file mode 100644 index 0000000..c62194a --- /dev/null +++ b/util/env.h @@ -0,0 +1,4 @@ +#pragma once +#include + +const wchar_t* get_config_path(); diff --git a/util/meson.build b/util/meson.build index 95f08b2..8ea9f38 100644 --- a/util/meson.build +++ b/util/meson.build @@ -10,6 +10,8 @@ util_lib = static_library( 'async.h', 'crc.c', 'crc.h', + 'env.c', + 'env.h', 'dll-bind.c', 'dll-bind.h', 'dprintf.c', @@ -20,6 +22,8 @@ util_lib = static_library( 'lib.h', 'str.c', 'str.h', + 'slurp.c', + 'slurp.h', 'hexstr.c', 'hexstr.h', ], diff --git a/util/slurp.c b/util/slurp.c new file mode 100644 index 0000000..1af73a4 --- /dev/null +++ b/util/slurp.c @@ -0,0 +1,67 @@ +#include +#include +#include +/* + * 'slurp' reads the file identified by 'path' into a character buffer + * pointed at by 'buf', optionally adding a terminating NUL if + * 'add_nul' is true. On success, the size of the file is returned; on + * failure, -1 is returned and ERRNO is set by the underlying system + * or library call that failed. + * + * WARNING: 'slurp' malloc()s memory to '*buf' which must be freed by + * the caller. + */ +long wslurp(const wchar_t* path, char **buf, bool add_nul) +{ + FILE *fp; + size_t fsz; + long off_end; + int rc; + + /* Open the file */ + fp = _wfopen(path, L"rb"); + if( NULL == fp ) { + return -1L; + } + + /* Seek to the end of the file */ + rc = fseek(fp, 0L, SEEK_END); + if( 0 != rc ) { + return -1L; + } + + /* Byte offset to the end of the file (size) */ + if( 0 > (off_end = ftell(fp)) ) { + return -1L; + } + fsz = (size_t)off_end; + + /* Allocate a buffer to hold the whole file */ + *buf = malloc( fsz+(int)add_nul ); + if( NULL == *buf ) { + return -1L; + } + + /* Rewind file pointer to start of file */ + rewind(fp); + + /* Slurp file into buffer */ + if( fsz != fread(*buf, 1, fsz, fp) ) { + free(*buf); + return -1L; + } + + /* Close the file */ + if( EOF == fclose(fp) ) { + free(*buf); + return -1L; + } + + if( add_nul ) { + /* Make sure the buffer is NUL-terminated, just in case */ + buf[fsz] = '\0'; + } + + /* Return the file size */ + return (long)fsz; +} \ No newline at end of file diff --git a/util/slurp.h b/util/slurp.h new file mode 100644 index 0000000..407a2d8 --- /dev/null +++ b/util/slurp.h @@ -0,0 +1,12 @@ +#include +/* + * 'slurp' reads the file identified by 'path' into a character buffer + * pointed at by 'buf', optionally adding a terminating NUL if + * 'add_nul' is true. On success, the size of the file is returned; on + * failure, -1 is returned and ERRNO is set by the underlying system + * or library call that failed. + * + * WARNING: 'slurp' malloc()s memory to '*buf' which must be freed by + * the caller. + */ +long wslurp(const wchar_t* path, char **buf, bool add_nul); \ No newline at end of file