hf felica dump: vastly improve speed; fix traces being empty after command execution

This commit is contained in:
kormax
2026-02-14 15:36:28 +02:00
parent 7c4758f40b
commit 2721b13792
2 changed files with 88 additions and 40 deletions
+39 -26
View File
@@ -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);
+49 -14
View File
@@ -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();