From 2721b1379235c4cf9198fdf3ede91a0e6bb4d5e7 Mon Sep 17 00:00:00 2001 From: kormax <3392860+kormax@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:45:05 +0200 Subject: [PATCH] hf felica dump: vastly improve speed; fix traces being empty after command execution --- armsrc/felica.c | 65 ++++++++++++++++++++++++---------------- client/src/cmdhffelica.c | 63 +++++++++++++++++++++++++++++--------- 2 files changed, 88 insertions(+), 40 deletions(-) diff --git a/armsrc/felica.c b/armsrc/felica.c index c47fc3450..7fb1c6053 100644 --- a/armsrc/felica.c +++ b/armsrc/felica.c @@ -47,6 +47,7 @@ static uint32_t felica_timeout; static uint32_t felica_nexttransfertime; static uint32_t felica_lasttime_prox2air_start; +static bool felica_field_active; static void iso18092_setup(uint8_t fpga_minor_mode); static uint8_t felica_select_card(felica_card_select_t *card); @@ -62,16 +63,13 @@ static uint32_t iso18092_get_timeout(void) { } #ifndef FELICA_MAX_FRAME_SIZE +// 255 base length (max 254 data + 1 len byte) + 2 sync + 2 crc + 1 extra for safety #define FELICA_MAX_FRAME_SIZE 260 #endif - - - - //structure to hold outgoing NFC frame -static uint8_t frameSpace[FELICA_MAX_FRAME_SIZE + 4]; +static uint8_t frameSpace[FELICA_MAX_FRAME_SIZE]; //structure to hold incoming NFC frame, used for ISO/IEC 18092-compatible frames static struct { @@ -494,10 +492,6 @@ static void iso18092_setup(uint8_t fpga_minor_mode) { #endif // allocate command receive buffer BigBuf_free(); - BigBuf_Clear_ext(false); - - // Initialize Demod and Uart structs - // DemodInit(BigBuf_calloc(MAX_FRAME_SIZE)); FelicaFrameinit(BigBuf_calloc(FELICA_MAX_FRAME_SIZE)); felica_nexttransfertime = 2 * DELAY_ARM2AIR_AS_READER; // 418 @@ -525,10 +519,12 @@ static void iso18092_setup(uint8_t fpga_minor_mode) { StartCountSspClk(); LED_D_ON(); + felica_field_active = true; } static void felica_reset_frame_mode(void) { switch_off(); + felica_field_active = false; //Resetting Frame mode (First set in fpgaloader.c) AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); } @@ -545,35 +541,47 @@ void felica_sendraw(const PacketCommandNG *c) { felica_command_t param = c->oldarg[0]; size_t len = c->oldarg[1] & 0xffff; uint32_t arg0; + bool do_connect = ((param & FELICA_CONNECT) == FELICA_CONNECT); + bool no_disconnect = ((param & FELICA_NO_DISCONNECT) == FELICA_NO_DISCONNECT); - if ((param & FELICA_CONNECT) == FELICA_CONNECT) { + if (do_connect) { clear_trace(); } + set_tracing(true); - iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); + // Preserve compatibility with existing commands that do not send CONNECT: + // set up reader path when starting from field-off state. + if (do_connect || !felica_field_active) { + iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); + } - if ((param & FELICA_CONNECT) == FELICA_CONNECT) { + if (do_connect && ((param & FELICA_NO_SELECT) != FELICA_NO_SELECT)) { // notify client selecting status. - // if failed selecting, turn off antenna and quite. - if ((param & FELICA_NO_SELECT) != FELICA_NO_SELECT) { - - felica_card_select_t card; - arg0 = felica_select_card(&card); - reply_mix(CMD_ACK, arg0, sizeof(card.uid), 0, &card, sizeof(felica_card_select_t)); - if (arg0) { - felica_reset_frame_mode(); - return; - } + // if failed selecting, turn off antenna and quit. + felica_card_select_t card; + arg0 = felica_select_card(&card); + reply_mix(CMD_ACK, arg0, sizeof(card.uid), 0, &card, sizeof(felica_card_select_t)); + if (arg0) { + felica_reset_frame_mode(); + return; } - } if ((param & FELICA_RAW) == FELICA_RAW) { + if (len > FELICA_MAX_FRAME_SIZE) { + Dbprintf("FeliCa raw payload too long: %u (max %u)", len, FELICA_MAX_FRAME_SIZE); + reply_mix(CMD_ACK, 0, PM3_ELENGTH, 0, NULL, 0); + if (!no_disconnect) { + felica_reset_frame_mode(); + } + return; + } + + uint8_t buf[FELICA_MAX_FRAME_SIZE]; + memset(buf, 0, sizeof(buf)); - // 2 sync, 1 len, 2 crc == 5 - uint8_t *buf = BigBuf_calloc(len + 5); // add sync bits buf[0] = 0xb2; buf[1] = 0x4d; @@ -614,7 +622,7 @@ void felica_sendraw(const PacketCommandNG *c) { } } - if ((param & FELICA_NO_DISCONNECT) == FELICA_NO_DISCONNECT) { + if (no_disconnect) { return; } @@ -695,6 +703,7 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) { } } switch_off(); + felica_field_active = false; //reset framing AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); @@ -733,6 +742,7 @@ void felica_sim_lite(const uint8_t *uid) { AddCrc(&resp_poll1[2], resp_poll1[2]); AddCrc(&resp_readblk[2], resp_readblk[2]); + clear_trace(); iso18092_setup(FPGA_HF_ISO18092_FLAG_NOMOD); int retval = PM3_SUCCESS; @@ -840,6 +850,7 @@ void felica_sim_lite(const uint8_t *uid) { } switch_off(); + felica_field_active = false; // reset framing AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); @@ -856,6 +867,7 @@ void felica_dump_lite_s(void) { uint16_t liteblks[28] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x90, 0x91, 0x92, 0xa0}; // setup device. + clear_trace(); iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); uint8_t blknum; @@ -917,6 +929,7 @@ void felica_dump_lite_s(void) { } } switch_off(); + felica_field_active = false; // Resetting Frame mode (First set in fpgaloader.c) AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); diff --git a/client/src/cmdhffelica.c b/client/src/cmdhffelica.c index bb5d1247b..08ddc5df4 100644 --- a/client/src/cmdhffelica.c +++ b/client/src/cmdhffelica.c @@ -1717,8 +1717,11 @@ static int CmdHFFelicaDump(const char *Cmd) { return PM3_EINVARG; } - uint8_t flags = FELICA_APPEND_CRC | FELICA_RAW; + // Set up field once and keep it up for the entire dump sequence. + // First command connects (with NO_SELECT since we already have IDm). + uint8_t flags = FELICA_CONNECT | FELICA_NO_SELECT | FELICA_NO_DISCONNECT | FELICA_APPEND_CRC | FELICA_RAW; + int ret = PM3_SUCCESS; uint16_t cursor = 0x0000; felica_service_dump_response_t resp; @@ -1731,14 +1734,20 @@ static int CmdHFFelicaDump(const char *Cmd) { if (send_dump_sv_plain(flags, service_datalen, data_service_dump, 0, &resp, false) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "No response at cursor 0x%04X", cursor); - return PM3_ERFTRANS; + ret = PM3_ERFTRANS; + break; } + + // After first command, drop CONNECT flag — field is already up + flags = FELICA_NO_DISCONNECT | FELICA_APPEND_CRC | FELICA_RAW; + if (resp.frame_response.cmd_code[0] != 0x0B) { PrintAndLogEx(FAILED, "Bad response cmd 0x%02X @ 0x%04X.", resp.frame_response.cmd_code[0], cursor); PrintAndLogEx(INFO, "This is a normal signal issue. Please try again."); PrintAndLogEx(INFO, "If the issue persists, move the card around and check signal strength. FeliCa can be hard to keep in field."); - return PM3_ERFTRANS; + ret = PM3_ERFTRANS; + break; } uint8_t len = resp.frame_response.length[0]; uint16_t node_code = resp.payload[0] | (resp.payload[1] << 8); @@ -1811,14 +1820,20 @@ static int CmdHFFelicaDump(const char *Cmd) { default: PrintAndLogEx(FAILED, "Unexpected length 0x%02X @ 0x%04X", len, cursor); - return PM3_ERFTRANS; + ret = PM3_ERFTRANS; + break; } + if (ret != PM3_SUCCESS) break; cursor++; if (cursor == 0) break; } - PrintAndLogEx(SUCCESS, "Unauth service dump complete."); - return PM3_SUCCESS; + DropField(); + + if (ret == PM3_SUCCESS) + PrintAndLogEx(SUCCESS, "Unauth service dump complete."); + + return ret; } @@ -1956,11 +1971,15 @@ static int CmdHFFelicaDumpServiceArea(const char *Cmd) { PrintAndLogEx(HINT, "Area and service codes are printed in network order."); PrintAndLogEx(INFO, "┌───────────────────────────────────────────────"); - uint8_t flags = FELICA_APPEND_CRC | FELICA_RAW; + // Set up field once and keep it up for the entire traversal. + // First command connects (with NO_SELECT since we already have IDm). + uint8_t flags = FELICA_CONNECT | FELICA_NO_SELECT | FELICA_NO_DISCONNECT | FELICA_APPEND_CRC | FELICA_RAW; + + int ret = PM3_SUCCESS; /* -- traversal state ------------------------------------------ */ uint16_t cursor = 0x0000; - uint16_t area_end_stack[8] = {0xFFFF}; /* root “end” = 0xFFFF */ + uint16_t area_end_stack[8] = {0xFFFF}; /* root "end" = 0xFFFF */ int depth = 0; /* current stack depth */ felica_service_dump_response_t resp; @@ -1974,14 +1993,20 @@ static int CmdHFFelicaDumpServiceArea(const char *Cmd) { if (send_dump_sv_plain(flags, datalen, data, 0, &resp, false) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "No response at cursor 0x%04X", cursor); - return PM3_ERFTRANS; + ret = PM3_ERFTRANS; + break; } + + // After first command, drop CONNECT flag — field is already up + flags = FELICA_NO_DISCONNECT | FELICA_APPEND_CRC | FELICA_RAW; + if (resp.frame_response.cmd_code[0] != 0x0B) { PrintAndLogEx(FAILED, "Bad response cmd 0x%02X @ 0x%04X.", resp.frame_response.cmd_code[0], cursor); PrintAndLogEx(INFO, "This is a normal signal issue. Please try again."); PrintAndLogEx(INFO, "If the issue persists, move the card around and check signal strength. FeliCa can be hard to keep in field."); - return PM3_ERFTRANS; + ret = PM3_ERFTRANS; + break; } uint8_t len = resp.frame_response.length[0]; @@ -2021,12 +2046,15 @@ static int CmdHFFelicaDumpServiceArea(const char *Cmd) { } else { PrintAndLogEx(FAILED, "Unexpected length 0x%02X @ 0x%04X", len, cursor); - return PM3_ERFTRANS; + ret = PM3_ERFTRANS; + break; } cursor++; if (cursor == 0) break; /* overflow safety */ } + DropField(); + /* draw closing bar └─┴─... based on final depth */ char bar[128]; /* large enough for depth ≤ 7 */ size_t pos = 0; @@ -2043,9 +2071,10 @@ static int CmdHFFelicaDumpServiceArea(const char *Cmd) { PrintAndLogEx(INFO, "%s", bar); + if (ret == PM3_SUCCESS) + PrintAndLogEx(SUCCESS, "Service code and area dump complete."); - PrintAndLogEx(SUCCESS, "Service code and area dump complete."); - return PM3_SUCCESS; + return ret; } static int CmdHFFelicaSniff(const char *Cmd) { @@ -3107,7 +3136,13 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) { flags |= FELICA_RAW; } - // Max buffer is PM3_CMD_DATA_SIZE + // FeliCa length byte includes itself, so raw payload must be <= 254 bytes. + if (datalen > 254) { + PrintAndLogEx(FAILED, "FeliCa raw payload too long (%d). Max is 254 bytes.", datalen); + return PM3_EINVARG; + } + + // Max transport buffer is PM3_CMD_DATA_SIZE datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; clearCommandBuffer();