From 267d36d058c66e9dc46e2d0d2860b984efb56abc Mon Sep 17 00:00:00 2001 From: KIT! Date: Wed, 28 Feb 2024 12:09:06 +0100 Subject: [PATCH] partial : Cleaned code a bit, prepping for reading Mifare tags Added two new options in settings : - One to not error out if a reader is missing - One to force using a reader using it's name. --- src/aimeio.c | 207 ++++++-------------- src/aimeio.h | 16 +- src/aimetest.c | 16 +- src/scard/scard.c | 474 +++++++++++++++++++--------------------------- src/scard/scard.h | 36 ++-- 5 files changed, 301 insertions(+), 448 deletions(-) diff --git a/src/aimeio.c b/src/aimeio.c index 9650816..f759769 100644 --- a/src/aimeio.c +++ b/src/aimeio.c @@ -1,41 +1,12 @@ -#include - -#include -#include -#include -#include -#include -#include -#include - #include "aimeio.h" #include "scard/scard.h" -char module[] = "CardReader"; - // Reader Thread -static bool READER_RUNNER_INITIALIZED = false; static HANDLE READER_POLL_THREAD; static bool READER_POLL_STOP_FLAG; -static bool polling = false; -static bool HasCard = false; -uint8_t UID[8] = {0}; - -struct aime_io_config -{ - bool debug; - wchar_t aime_path[MAX_PATH]; - wchar_t felica_path[MAX_PATH]; - bool felica_gen; - uint8_t vk_scan; -}; - static struct aime_io_config aime_io_cfg; -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 struct card_data card_data; #pragma region CONFIG static void aime_io_config_read(struct aime_io_config *cfg, const wchar_t *filename) @@ -65,10 +36,18 @@ static void aime_io_config_read(struct aime_io_config *cfg, const wchar_t *filen _countof(cfg->felica_path), filename); - cfg->felica_gen = GetPrivateProfileIntW( + GetPrivateProfileStringW( L"aimeio", - L"felicaGen", - 1, + L"readerName", + L"", + cfg->reader_name, + _countof(cfg->reader_name), + filename); + + cfg->reader_optional = GetPrivateProfileIntW( + L"aimeio", + L"readerOptional", + 0, filename); cfg->vk_scan = GetPrivateProfileIntW( @@ -104,7 +83,7 @@ static HRESULT aime_io_read_id_file(const wchar_t *path, uint8_t *bytes, size_t if (c == EOF) { // If the end of the file is reached before the desired line, print an error - printf("%s: %S: Error: Line %d does not exist\n", module, path, LineToRead); + printf("aime_io_read_id_file: %S: Error: Line %d does not exist\n", path, LineToRead); hr = E_FAIL; goto end; } @@ -125,7 +104,7 @@ static HRESULT aime_io_read_id_file(const wchar_t *path, uint8_t *bytes, size_t if (r != 1) { - printf("%s: %S: Error parsing line %d\n", module, path, LineToRead); + printf("aime_io_read_id_file: %S: Error parsing line %d\n", path, LineToRead); hr = E_FAIL; goto end; } @@ -136,7 +115,7 @@ static HRESULT aime_io_read_id_file(const wchar_t *path, uint8_t *bytes, size_t // Check if the line is not nbytes long if (fgetc(f) != '\n' && !feof(f)) { - printf("%s: %S: Error: Line %d is not %zu bytes long\n", module, path, LineToRead, nbytes); + printf("aime_io_read_id_file: %S: Error: Line %d is not %zu bytes long\n", path, LineToRead, nbytes); hr = E_FAIL; goto end; } @@ -151,43 +130,6 @@ end: return hr; } - -static HRESULT aime_io_generate_felica(const wchar_t *path, uint8_t *bytes, size_t nbytes) -{ - size_t i; - FILE *f; - - assert(path != NULL); - assert(bytes != NULL); - assert(nbytes > 0); - - srand(time(NULL)); - - for (i = 0; i < nbytes; i++) - bytes[i] = rand(); - - /* FeliCa IDm values should have a 0 in their high nibble. I think. */ - bytes[0] &= 0x0F; - - f = _wfopen(path, L"w"); - - if (f == NULL) // If we somehow can't create the file, we error out. - { - printf("%s: %S: fopen failed: %i\n", module, path, (int)errno); - return E_FAIL; - } - - for (i = 0; i < nbytes; i++) - fprintf(f, "%02X", bytes[i]); - - fprintf(f, "\n"); - fclose(f); - - printf("%s: Generated random FeliCa ID\n", module); - - return S_OK; -} - #pragma endregion #pragma region READER SPECIFIC @@ -197,20 +139,8 @@ static unsigned int __stdcall reader_poll_thread_proc(void *ctx) printf("DEBUG: reader_poll_thread_proc(). \r\n"); while (!READER_POLL_STOP_FLAG) { - if (!HasCard && polling) - { - uint8_t _UID[8] = {0}; - scard_update(_UID); - - if (_UID[0] > 0) // If a card was read, format it properly and set HasCard to true so the game can insert it on next frame. - { - printf("%s: Read card %02X%02X%02X%02X%02X%02X%02X%02X\n", module, _UID[0], _UID[1], _UID[2], _UID[3], _UID[4], _UID[5], _UID[6], _UID[7]); - for (int i = 0; i < 8; i++) - UID[i] = _UID[i]; - - HasCard = true; - } - } + if (card_data.card_type != 0) // Halting polling once a card is found, waiting for the game to read it's value. + scard_poll(&card_data); } return 0; @@ -233,26 +163,26 @@ HRESULT aime_io_init(void) if (ret != 0) freopen_s(&fp, "CONOUT$", "w", stdout); // only when we allocate a console, we need to redirect stdout + memset(&card_data, 0, sizeof(card_data)); // Init card_data structure + // We then read the segatools config file to get settings. aime_io_config_read(&aime_io_cfg, L".\\segatools.ini"); - if (aime_io_cfg.debug) - printf("DEBUG: aime_io_init(). \r\n"); - // Find and initialize reader(s) - if (!READER_RUNNER_INITIALIZED) + printf("aime_io_init: Initializing SmartCard\n"); + if (!scard_init(aime_io_cfg)) { - READER_RUNNER_INITIALIZED = true; - printf("%s: Initializing SmartCard\n", module); - - if (!scard_init()) - { - printf("%s: Couldn't init SmartCard\n", module); + // If we couldn't init reader, error out. + printf("aime_io_init: Couldn't init SmartCard\n"); + if (!aime_io_cfg.reader_optional) return E_FAIL; - } + + // If however the readerOptional flag is set to 1 in segatools.ini, continue with keyboard only. + printf("aime_io_init: Reader is optional, using keyboard only !\n"); + return S_OK; } - printf("%s: Starting reader thread.\n", module); + printf("aime_io_init: Starting reader thread.\n"); // Start reader thread READER_POLL_STOP_FLAG = false; @@ -275,8 +205,6 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no) if (unit_no != 0) return S_OK; - polling = true; - bool sense; HRESULT hr; @@ -284,8 +212,6 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no) sense = GetAsyncKeyState(aime_io_cfg.vk_scan) & 0x8000; if (!sense) { - aime_io_aime_id_present = false; - aime_io_felica_id_present = false; return S_OK; } @@ -301,48 +227,33 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no) } } - printf("%s: Attempting to read card %d from file. \r\n", module, card); + printf("aime_io_nfc_poll: Attempting to read card %d from file. \r\n", card); // Try AiMe IC hr = aime_io_read_id_file( aime_io_cfg.aime_path, - aime_io_aime_id, - sizeof(aime_io_aime_id), + card_data.card_id, + 10, card); if (SUCCEEDED(hr) && hr != S_FALSE) { - aime_io_aime_id_present = true; + card_data.card_type = Mifare; 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), + card_data.card_id, + 8, card); if (SUCCEEDED(hr) && hr != S_FALSE) { - aime_io_felica_id_present = true; + card_data.card_type = FeliCa; return S_OK; } - - // Try generating FeliCa IC (if enabled) - if (aime_io_cfg.felica_gen) - { - hr = aime_io_generate_felica( - aime_io_cfg.felica_path, - aime_io_felica_id, - sizeof(aime_io_felica_id)); - - if (FAILED(hr)) - return hr; - - aime_io_felica_id_present = true; - } - return S_OK; } @@ -352,18 +263,17 @@ HRESULT aime_io_nfc_get_aime_id(uint8_t unit_no, uint8_t *luid, size_t luid_size printf("DEBUG: aime_io_nfc_get_aime_id(unit_no : %d). \r\n", unit_no); assert(luid != NULL); - assert(luid_size == sizeof(aime_io_aime_id)); + assert(luid_size == 10); if (unit_no != 0) return S_FALSE; - if (aime_io_aime_id_present) + if (card_data.card_type == Mifare) { - memcpy(luid, aime_io_aime_id, luid_size); - printf("%s: Read Aime card from file with uid ", module); - for (int i = 0; i < 10; i++) - printf("%02x ", aime_io_aime_id[i]); - printf("\r\n"); + memcpy(luid, card_data.card_id, luid_size); + printf("aime_io_nfc_get_aime_id: Read Aime card from file with uid %02X%02X %02X%02X %02X%02X %02X%02X %02X%02X\r\n", card_data.card_id[0], card_data.card_id[1], card_data.card_id[2], card_data.card_id[3], card_data.card_id[4], card_data.card_id[5], card_data.card_id[6], card_data.card_id[7], card_data.card_id[8], card_data.card_id[9]); + + memset(&card_data, 0, sizeof(card_data)); // Reset card_data structure return S_OK; } @@ -382,33 +292,34 @@ HRESULT aime_io_nfc_get_felica_id(uint8_t unit_no, uint64_t *IDm) if (unit_no != 0) return S_FALSE; - if (aime_io_felica_id_present) + if (card_data.card_type == FeliCa) { val = 0; for (i = 0; i < 8; i++) - val = (val << 8) | aime_io_felica_id[i]; + val = (val << 8) | card_data.card_id[i]; *IDm = val; - printf("%s: Read FeliCa card from file with uid %llx\r\n", module, val); + printf("aime_io_nfc_get_felica_id: Read FeliCa card from file with uid %02X%02X %02X%02X %02X%02X %02X%02X\r\n", card_data.card_id[0], card_data.card_id[1], card_data.card_id[2], card_data.card_id[3], card_data.card_id[4], card_data.card_id[5], card_data.card_id[6], card_data.card_id[7]); + memset(&card_data, 0, sizeof(card_data)); // Reset card_data structure return S_OK; } - if (HasCard) - { - polling = false; - HasCard = false; + // if (HasCard) + // { + // polling = false; + // HasCard = false; - uint64_t val; - for (int i = 0; i < 8; i++) - { - val = (val << 8) | UID[i]; - } - *IDm = val; - printf("%s: FeliCa card has been scanned ! %llx\r\n", module, val); + // uint64_t val; + // for (int i = 0; i < 8; i++) + // { + // val = (val << 8) | UID[i]; + // } + // *IDm = val; + // printf("aime_io_nfc_get_felica_id: FeliCa card has been scanned ! %llx\r\n", val); - return S_OK; - } + // return S_OK; + // } return S_FALSE; } diff --git a/src/aimeio.h b/src/aimeio.h index 42630b5..7b98da9 100644 --- a/src/aimeio.h +++ b/src/aimeio.h @@ -1,9 +1,23 @@ #pragma once #include - +#include +#include #include #include +#include +#include +#include + +struct aime_io_config +{ + bool debug; + wchar_t aime_path[MAX_PATH]; + wchar_t felica_path[MAX_PATH]; + wchar_t reader_name[MAX_PATH]; + bool reader_optional; + uint8_t vk_scan; +}; /* Get the version of the Aime IO API that this DLL supports. This function diff --git a/src/aimetest.c b/src/aimetest.c index c080c17..c94b8c2 100644 --- a/src/aimetest.c +++ b/src/aimetest.c @@ -14,16 +14,16 @@ int main() switch (aime_io_init()) { case E_FAIL: - printf("aime_io_init() returned E_FAIL. Reader is either missing or incompatible !\r\n"); - break; + printf("AIMETEST: aime_io_init() returned E_FAIL. Reader is either missing or incompatible !\r\n"); + return E_FAIL; case S_OK: - printf("aime_io_init() returned S_OK !\r\n"); + printf("AIMETEST: aime_io_init() returned S_OK !\r\n"); break; default: - printf("aime_io_init() returned an unknown state !\r\n"); - break; + printf("AIMETEST: aime_io_init() returned an unknown state !\r\n"); + return E_FAIL; } // printf("aime_io_led_set_color(red) : "); @@ -40,7 +40,7 @@ int main() // Sleep(2000); // aime_io_led_set_color(0, 0, 0, 0); - printf("Running input loop. Press Ctrl+C to exit.\r\n"); + printf("AIMETEST: Running input loop. Press Ctrl+C to exit.\r\n"); uint8_t luid[10] = {0}; uint64_t IDm = 0; @@ -51,12 +51,12 @@ int main() if (aime_io_nfc_get_felica_id(0, &IDm) == S_OK) { // aime_io_led_set_color(0, 0, 255, 0); - printf("Found FeliCa card with uid %llx\r\n\n", IDm); + printf("AIMETEST: Found FeliCa card with uid %llx\r\n\n", IDm); } if (aime_io_nfc_get_aime_id(0, luid, 10) == S_OK) { // aime_io_led_set_color(0, 0, 0, 255); - printf("Found old card with uid "); + printf("AIMETEST: Found old card with uid "); for (int i = 0; i < 10; i++) { printf("%02x ", luid[i]); diff --git a/src/scard/scard.c b/src/scard/scard.c index eb1ed5f..647410b 100644 --- a/src/scard/scard.c +++ b/src/scard/scard.c @@ -1,33 +1,4 @@ -/** - * MIT-License - * Copyright (c) 2018 by nolm - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Modified version. - */ - #include "scard.h" -// #include -// #include - -extern char module[]; #define MAX_APDU_SIZE 255 int readCooldown = 500; @@ -35,35 +6,168 @@ int readCooldown = 500; // based off acr122u reader, see page 26 in api document. // https://www.acs.com.hk/en/download-manual/419/API-ACR122U-2.04.pdf -#define PICC_OPERATING_PARAMS 0xDFu -BYTE PICC_OPERATING_PARAM_CMD[5] = {0xFFu, 0x00u, 0x51u, PICC_OPERATING_PARAMS, 0x00u}; +#define PARAM_POLLRATE 0xDFu +static const BYTE PARAM_SET_PICC[5] = {0xFFu, 0x00u, 0x51u, PARAM_POLLRATE, 0x00u}; +static const BYTE COMMAND_GET_UID[5] = {0xFFu, 0xCAu, 0x00u, 0x00u, 0x00u}; // return bytes from device #define PICC_SUCCESS 0x90u #define PICC_ERROR 0x63u -static const BYTE UID_CMD[5] = {0xFFu, 0xCAu, 0x00u, 0x00u, 0x00u}; - enum scard_atr_protocol { SCARD_ATR_PROTOCOL_ISO14443_PART3 = 0x03, - SCARD_ATR_PROTOCOL_ISO15693_PART3 = 0x0B, SCARD_ATR_PROTOCOL_FELICA_212K = 0x11, - SCARD_ATR_PROTOCOL_FELICA_424K = 0x12, }; // winscard_config_t WINSCARD_CONFIG; -SCARDCONTEXT hContext = 0; -SCARD_READERSTATE reader_states[2]; -LPTSTR reader_name_slots[2] = {NULL, NULL}; -int reader_count = 0; -LONG lRet = 0; +static SCARDCONTEXT hContext = 0; +static SCARD_READERSTATE reader_state; +static LONG lRet = 0; -void scard_poll(uint8_t *buf, SCARDCONTEXT _hContext, LPCTSTR _readerName, uint8_t unit_no) +bool scard_init(struct aime_io_config config) { - printf("%s: Update on reader : %s\n", module, reader_states[unit_no].szReader); + if ((lRet = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hContext)) != SCARD_S_SUCCESS) + { + // log_warning("scard", "failed to establish SCard context: {}", bin2hex(&lRet, sizeof(LONG))); + return FALSE; + } + + // get list of readers + LPTSTR reader_list = NULL; + auto pcchReaders = SCARD_AUTOALLOCATE; + lRet = SCardListReaders(hContext, NULL, (LPTSTR)&reader_list, &pcchReaders); + + switch (lRet) + { + case SCARD_E_NO_READERS_AVAILABLE: + printf("scard_init: No readers available\n"); + return FALSE; + + case SCARD_S_SUCCESS: + LPTSTR reader_name = NULL; + int readerNameLen = 0; + + // Iterate through the multi-string to get individual reader names + printf("scard_init: listing all readers : "); + while (*reader_list != '\0') + { + printf("%s, ", reader_list); + reader_list += strlen(reader_list) + 1; + } + printf("\r\n", reader_list); + + // if the readerName array is populated, replace the first reader in the list + char ReaderCharArray[sizeof(config.reader_name)]; + wcstombs(ReaderCharArray, config.reader_name, sizeof(ReaderCharArray)); + if (strcmp(ReaderCharArray, "") != 0) + { + size_t newLen = strlen(ReaderCharArray) + 1; + LPSTR newMszReaders = (LPSTR)malloc(newLen); + if (newMszReaders != NULL) + { + // Copy the new selected reader + strcpy(newMszReaders, ReaderCharArray); + + // Update the original pointer to the new modified list + reader_list = newMszReaders; + } + printf("scard_init: Forced using reader : %hs\n", ReaderCharArray); + } + + // Connect to reader and send PICC operating params command + SCARDHANDLE hCard; + DWORD dwActiveProtocol; + lRet = SCardConnect(hContext, reader_list, SCARD_SHARE_DIRECT, 0, &hCard, &dwActiveProtocol); + if (lRet != SCARD_S_SUCCESS) + { + printf("scard_init: Error connecting to the reader: 0x%08X\n", lRet); + return FALSE; + } + printf("scard_init: Connected to reader: %s, sending PICC params\n", reader_list); + + // set the reader params + DWORD cbRecv = MAX_APDU_SIZE; + BYTE pbRecv[MAX_APDU_SIZE]; + lRet = SCardControl(hCard, SCARD_CTL_CODE(3500), PARAM_SET_PICC, sizeof(PARAM_SET_PICC), pbRecv, cbRecv, &cbRecv); + Sleep(100); + if (lRet != SCARD_S_SUCCESS) + { + printf("scard_init: Error setting PICC params : 0x%08X\n", lRet); + return FALSE; + } + + if (cbRecv > 2 && pbRecv[0] != PICC_SUCCESS && pbRecv[1] != PARAM_POLLRATE) + { + printf("scard_init: PICC params not valid 0x%02X != 0x%02X\n", pbRecv[1], PARAM_POLLRATE); + return FALSE; + } + + // Disconnect from reader + if ((lRet = SCardDisconnect(hCard, SCARD_LEAVE_CARD)) != SCARD_S_SUCCESS) + printf("scard_init: Failed SCardDisconnect : 0x%08X\n", lRet); + + // Extract the relevant names from the multi-string. + readerNameLen = lstrlen(reader_list); + reader_name = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(TCHAR) * (readerNameLen + 1)); + memcpy(reader_name, &reader_list, (size_t)(readerNameLen + 1)); + + if (reader_name) + printf("scard_init: Using reader : %s\n", reader_name); + + memset(&reader_state, 0, sizeof(SCARD_READERSTATE)); + reader_state.szReader = reader_name; + return TRUE; + + default: + printf("scard_init: Failed SCardListReaders: 0x%08X\n", lRet); + return FALSE; + } +} + +void scard_poll(struct card_data *card_data) +{ + lRet = SCardGetStatusChange(hContext, readCooldown, &reader_state, 1); + if (lRet == SCARD_E_TIMEOUT) + { + return; + } + else if (lRet != SCARD_S_SUCCESS) + { + printf("scard_poll: Failed SCardGetStatusChange: 0x%08X\n", lRet); + return; + } + + if (!(reader_state.dwEventState & SCARD_STATE_CHANGED)) + return; + + DWORD newState = reader_state.dwEventState ^ SCARD_STATE_CHANGED; + bool wasCardPresent = (reader_state.dwCurrentState & SCARD_STATE_PRESENT) > 0; + if (newState & SCARD_STATE_UNAVAILABLE) + { + printf("scard_poll: New card state: unavailable\n"); + Sleep(readCooldown); + } + else if (newState & SCARD_STATE_EMPTY) + { + printf("scard_poll: New card state: empty\n"); + // scard_clear(unit_no); + } + else if (newState & SCARD_STATE_PRESENT && !wasCardPresent) + { + printf("scard_poll: New card state: present\n"); + scard_update(card_data, hContext, reader_state.szReader); + } + + reader_state.dwCurrentState = reader_state.dwEventState; + + return; +} + +void scard_update(struct card_data *card_data, SCARDCONTEXT _hContext, LPCTSTR _readerName) +{ + printf("scard_update: Update on reader : %s\n", reader_state.szReader); // Connect to the smart card. - LONG lRet = 0; SCARDHANDLE hCard; DWORD dwActiveProtocol; for (int retry = 0; retry < 100; retry++) // retry times has to be increased since poll rate is set to 500ms @@ -76,12 +180,11 @@ void scard_poll(uint8_t *buf, SCARDCONTEXT _hContext, LPCTSTR _readerName, uint8 if (lRet != SCARD_S_SUCCESS) { - printf("%s: Error connecting to the card: 0x%08X\n", module, lRet); + printf("scard_update: Error connecting to the card: 0x%08X\n", lRet); return; } // set the reader params - lRet = 0; LPCSCARD_IO_REQUEST pci = dwActiveProtocol == SCARD_PROTOCOL_T1 ? SCARD_PCI_T1 : SCARD_PCI_T0; DWORD cbRecv = MAX_APDU_SIZE; BYTE pbRecv[MAX_APDU_SIZE]; @@ -94,263 +197,76 @@ void scard_poll(uint8_t *buf, SCARDCONTEXT _hContext, LPCTSTR _readerName, uint8 lRet = SCardStatus(hCard, szReader, &cchReader, NULL, NULL, atr, &cByteAtr); if (lRet != SCARD_S_SUCCESS) { - printf("%s: Error getting card status: 0x%08X\n", module, lRet); + printf("scard_update: Error getting card status: 0x%08X\n", lRet); return; } // Only care about 20-byte ATRs returned by arcade-type smart cards if (cByteAtr != 20) { - printf("%s: Ignoring card with len(%d) = %02X (%08X)\n", module, cByteAtr, atr, cByteAtr); + printf("scard_update: Ignoring card with len(%zu) = %02x (%08X)\n", sizeof(cByteAtr), (unsigned int)atr, cByteAtr); return; } - printf("%s: atr Return: len(%d) = %02X (%08X)\n", module, cByteAtr, atr, cByteAtr); + printf("scard_update: atr Return: len(%zu) = %02x (%08X)\n", sizeof(cByteAtr), (unsigned int)atr, cByteAtr); // Figure out if we should reverse the UID returned by the card based on the ATR protocol BYTE cardProtocol = atr[12]; - BOOL shouldReverseUid = false; - if (cardProtocol == SCARD_ATR_PROTOCOL_ISO15693_PART3) + + if (cardProtocol == SCARD_ATR_PROTOCOL_ISO14443_PART3) { - printf("%s: Card protocol: ISO15693_PART3\n", module); - shouldReverseUid = true; + printf("scard_update: Card protocol: ISO14443_PART3\n"); + card_data->card_type = Mifare; } - else if (cardProtocol == SCARD_ATR_PROTOCOL_ISO14443_PART3) - printf("%s: Card protocol: ISO14443_PART3\n", module); + else if (cardProtocol == SCARD_ATR_PROTOCOL_FELICA_212K) // Handling FeliCa + { + printf("scard_update: Card protocol: FELICA_212K\n"); + card_data->card_type = FeliCa; - else if (cardProtocol == SCARD_ATR_PROTOCOL_FELICA_212K) - printf("%s: Card protocol: FELICA_212K\n", module); + // Read mID + cbRecv = MAX_APDU_SIZE; + if ((lRet = SCardTransmit(hCard, pci, COMMAND_GET_UID, sizeof(COMMAND_GET_UID), NULL, pbRecv, &cbRecv)) != SCARD_S_SUCCESS) + { + printf("scard_update: Error querying card UID: 0x%08X\n", lRet); + return; + } - else if (cardProtocol == SCARD_ATR_PROTOCOL_FELICA_424K) - printf("%s: Card protocol: FELICA_424K\n", module); + if (cbRecv > 1 && pbRecv[0] == PICC_ERROR) + { + printf("scard_update: UID query failed\n"); + return; + } + + if ((lRet = SCardDisconnect(hCard, SCARD_LEAVE_CARD)) != SCARD_S_SUCCESS) + printf("scard_update: Failed SCardDisconnect: 0x%08X\n", lRet); + + if (cbRecv < 8) + { + printf("scard_update: Padding card uid to 8 bytes\n"); + memset(&pbRecv[cbRecv], 0, 8 - cbRecv); + } + else if (cbRecv > 8) + printf("scard_update: taking first 8 bytes of len(uid) = %02X\n", cbRecv); + + card_data->card_id_len = 8; + memcpy(card_data->card_id, pbRecv, 8); + } else { - printf("%s: Unknown NFC Protocol: 0x%02X\n", module, cardProtocol); + printf("scard_update: Unknown NFC Protocol: 0x%02X\n", cardProtocol); return; } - // Read UID - cbRecv = MAX_APDU_SIZE; - if ((lRet = SCardTransmit(hCard, pci, UID_CMD, sizeof(UID_CMD), NULL, pbRecv, &cbRecv)) != SCARD_S_SUCCESS) - { - printf("%s: Error querying card UID: 0x%08X\n", module, lRet); - return; - } - - if (cbRecv > 1 && pbRecv[0] == PICC_ERROR) - { - printf("%s: UID query failed\n", module); - return; - } - - if ((lRet = SCardDisconnect(hCard, SCARD_LEAVE_CARD)) != SCARD_S_SUCCESS) - printf("%s: Failed SCardDisconnect: 0x%08X\n", module, lRet); - - if (cbRecv < 8) - { - printf("%s: Padding card uid to 8 bytes\n", module); - memset(&pbRecv[cbRecv], 0, 8 - cbRecv); - } - else if (cbRecv > 8) - printf("%s: taking first 8 bytes of len(uid) = %02X\n", module, cbRecv); - // Copy UID to struct, reversing if necessary - card_info_t card_info; - if (shouldReverseUid) - for (DWORD i = 0; i < 8; i++) - card_info.uid[i] = pbRecv[7 - i]; - else - memcpy(card_info.uid, pbRecv, 8); + // card_info_t card_info; + // if (shouldReverseUid) + // for (DWORD i = 0; i < 8; i++) + // card_info.uid[i] = pbRecv[7 - i]; + // else + // memcpy(card_info.uid, pbRecv, 8); - for (int i = 0; i < 8; ++i) - buf[i] = card_info.uid[i]; -} - -// void scard_clear(uint8_t unitNo) -// { -// card_info_t empty_cardinfo; -// } - -void scard_update(uint8_t *buf) -{ - if (reader_count < 1) - { - return; - } - - lRet = SCardGetStatusChange(hContext, readCooldown, reader_states, reader_count); - if (lRet == SCARD_E_TIMEOUT) - { - return; - } - else if (lRet != SCARD_S_SUCCESS) - { - printf("%s: Failed SCardGetStatusChange: 0x%08X\n", module, lRet); - return; - } - - for (uint8_t unit_no = 0; unit_no < reader_count; unit_no++) - { - if (!(reader_states[unit_no].dwEventState & SCARD_STATE_CHANGED)) - continue; - - DWORD newState = reader_states[unit_no].dwEventState ^ SCARD_STATE_CHANGED; - bool wasCardPresent = (reader_states[unit_no].dwCurrentState & SCARD_STATE_PRESENT) > 0; - if (newState & SCARD_STATE_UNAVAILABLE) - { - printf("%s: New card state: unavailable\n", module); - Sleep(readCooldown); - } - else if (newState & SCARD_STATE_EMPTY) - { - printf("%s: New card state: empty\n", module); - // scard_clear(unit_no); - } - else if (newState & SCARD_STATE_PRESENT && !wasCardPresent) - { - printf("%s: New card state: present\n", module); - scard_poll(buf, hContext, reader_states[unit_no].szReader, unit_no); - } - - reader_states[unit_no].dwCurrentState = reader_states[unit_no].dwEventState; - } - - return; -} - -bool scard_init() -{ - if ((lRet = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hContext)) != SCARD_S_SUCCESS) - { - // log_warning("scard", "failed to establish SCard context: {}", bin2hex(&lRet, sizeof(LONG))); - return lRet; - } - - LPCTSTR reader = NULL; - - int readerNameLen = 0; - - // get list of readers - LPTSTR reader_list = NULL; - auto pcchReaders = SCARD_AUTOALLOCATE; - lRet = SCardListReaders(hContext, NULL, (LPTSTR)&reader_list, &pcchReaders); - - int slot0_idx = -1; - int slot1_idx = -1; - int readerCount = 0; - switch (lRet) - { - case SCARD_E_NO_READERS_AVAILABLE: - printf("%s: No readers available\n", module); - return FALSE; - - case SCARD_S_SUCCESS: - - // So WinAPI has this terrible "multi-string" concept wherein you have a list - // of null-terminated strings, terminated by a double-null. - for (reader = reader_list; *reader; reader = reader + lstrlen(reader) + 1) - { - printf("%s: Found reader: %s\n", module, reader); - readerCount++; - - // Connect to reader and send PICC operating params command - LONG lRet = 0; - SCARDHANDLE hCard; - DWORD dwActiveProtocol; - lRet = SCardConnect(hContext, reader, SCARD_SHARE_DIRECT, 0, &hCard, &dwActiveProtocol); - if (lRet != SCARD_S_SUCCESS) - { - printf("%s: Error connecting to the reader: 0x%08X\n", module, lRet); - continue; - } - printf("%s: Connected to reader: %s, sending PICC operating params command\n", module, reader); - - // set the reader params - lRet = 0; - DWORD cbRecv = MAX_APDU_SIZE; - BYTE pbRecv[MAX_APDU_SIZE]; - lRet = SCardControl(hCard, SCARD_CTL_CODE(3500), PICC_OPERATING_PARAM_CMD, sizeof(PICC_OPERATING_PARAM_CMD), pbRecv, cbRecv, &cbRecv); - Sleep(100); - if (lRet != SCARD_S_SUCCESS) - { - printf("%s: Error setting PICC params: 0x%08X\n", module, lRet); - return FALSE; - } - - if (cbRecv > 2 && pbRecv[0] != PICC_SUCCESS && pbRecv[1] != PICC_OPERATING_PARAMS) - { - printf("%s: PICC params not valid 0x%02X != 0x%02X\n", module, pbRecv[1], PICC_OPERATING_PARAMS); - return FALSE; - } - - // Disconnect from reader - if ((lRet = SCardDisconnect(hCard, SCARD_LEAVE_CARD)) != SCARD_S_SUCCESS) - { - printf("%s: Failed SCardDisconnect: 0x%08X\n", module, lRet); - } - else - { - printf("%s: Disconnected from reader: %s, this is expected behavior\n", module, reader); - } - } - - // If we have at least two readers, assign readers to slots as necessary. - if (readerCount >= 2) - { - if (slot1_idx != 0) - slot0_idx = 0; - if (slot0_idx != 1) - slot1_idx = 1; - } - - // if the reader count is 1 and no reader was set, set first reader - if (readerCount == 1 && slot0_idx < 0 && slot1_idx < 0) - slot0_idx = 0; - - // If we somehow only found slot 1, promote slot 1 to slot 0. - if (slot0_idx < 0 && slot1_idx >= 0) - { - slot0_idx = slot1_idx; - slot1_idx = -1; - } - - // Extract the relevant names from the multi-string. - int i; - for (i = 0, reader = reader_list; *reader; reader = reader + lstrlen(reader) + 1, i++) - { - if (slot0_idx == i) - { - readerNameLen = lstrlen(reader); - reader_name_slots[0] = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(TCHAR) * (readerNameLen + 1)); - memcpy(reader_name_slots[0], &reader[0], (size_t)(readerNameLen + 1)); - } - if (slot1_idx == i) - { - readerNameLen = lstrlen(reader); - reader_name_slots[1] = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(TCHAR) * (readerNameLen + 1)); - memcpy(reader_name_slots[1], &reader[0], (size_t)(readerNameLen + 1)); - } - } - - if (reader_name_slots[0]) - printf("%s: Using reader slot 0: %s\n", module, reader_name_slots[0]); - - if (reader_name_slots[1]) - printf("%s: Using reader slot 1: %s\n", module, reader_name_slots[1]); - - reader_count = reader_name_slots[1] ? 2 : 1; - - memset(&reader_states[0], 0, sizeof(SCARD_READERSTATE)); - reader_states[0].szReader = reader_name_slots[0]; - - memset(&reader_states[1], 0, sizeof(SCARD_READERSTATE)); - reader_states[1].szReader = reader_name_slots[1]; - return TRUE; - - default: - printf("%s: Failed SCardListReaders: 0x%08X\n", module, lRet); - return FALSE; - } + // for (int i = 0; i < 8; ++i) + // buf[i] = card_info.uid[i]; } \ No newline at end of file diff --git a/src/scard/scard.h b/src/scard/scard.h index 70c05fd..8b80e42 100644 --- a/src/scard/scard.h +++ b/src/scard/scard.h @@ -24,23 +24,35 @@ */ #pragma once -#include -#include -#include #include #include +#include +#include +#include +#include -// cardinfo_t is a description of a card that was presented to a reader -typedef struct card_info +/* card types */ +enum AIME_CARDTYPE { - int card_type; - uint8_t uid[8]; -} card_info_t; + Mifare = 0x01, + FeliCa = 0x02, +}; -void scard_update(uint8_t *buf); +// Structure containing card_type, card_id and card_id_len +struct card_data +{ + /* CARDTYPE */ + uint8_t card_type; -void scard_poll(uint8_t *buf, SCARDCONTEXT _hContext, LPCTSTR _readerName, uint8_t unit_no); + /* Card ID */ + uint8_t card_id[32]; -void scard_clear(uint8_t unitNo); + /* Card ID length */ + uint8_t card_id_len; +}; -bool scard_init(); \ No newline at end of file +bool scard_init(struct aime_io_config config); + +void scard_poll(struct card_data *card_data); + +void scard_update(struct card_data *card_data, SCARDCONTEXT _hContext, LPCTSTR _readerName);