mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-10-23 04:22:51 +00:00
Merge pull request #3670 from 0x6r1an0y/20260926-felica-raw
Add FeliCa system-specific polling
This commit is contained in:
4 files changed
+85
-14
No files matched your search
+21
-9
@@ -29,7 +29,7 @@
|
||||
#include "iso18.h"
|
||||
|
||||
#define AddCrc(data, len) compute_crc(CRC_FELICA, (data), (len), (data)+(len)+1, (data)+(len))
|
||||
static uint8_t felica_select_card(felica_card_select_t *card);
|
||||
static uint8_t felica_select_card(felica_card_select_t *card, uint16_t system_code, uint8_t request_code);
|
||||
|
||||
//structure to hold outgoing NFC frame
|
||||
static uint8_t frameSpace[FELICA_MAX_RF_FRAME_SIZE];
|
||||
@@ -244,15 +244,15 @@ void Process18092Byte(felica_frame_t *f, uint8_t bt, uint32_t byte_start_time) {
|
||||
* It expects 0-1 cards in the device's range.
|
||||
* return 0 if selection was successful
|
||||
*/
|
||||
static uint8_t felica_select_card(felica_card_select_t *card) {
|
||||
static uint8_t felica_select_card(felica_card_select_t *card, uint16_t system_code, uint8_t request_code) {
|
||||
|
||||
// POLL command
|
||||
// 0xB2 0x4B = sync code
|
||||
// 0x06 = len
|
||||
// 0x00 = rfu
|
||||
// 0xff = system code service
|
||||
// 0xff = system code service
|
||||
// 0x00 = request code
|
||||
// system code service (high byte)
|
||||
// system code service (low byte)
|
||||
// request code
|
||||
// b7 = automatic switching of data rate
|
||||
// b6-b2 = reserved
|
||||
// b1 = fc/32 (414kbps)
|
||||
@@ -260,6 +260,9 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
||||
// 0x00 = timeslot
|
||||
// 0x09 0x21 = crc
|
||||
uint8_t poll[10] = {0xb2, 0x4d, 0x06, FELICA_POLLING_REQ, 0xFF, 0xFF, 0x00, 0x00, 0x09, 0x21};
|
||||
poll[4] = (uint8_t)(system_code >> 8);
|
||||
poll[5] = (uint8_t)system_code;
|
||||
poll[6] = request_code;
|
||||
|
||||
// Number of time slots offered to the card(s), the FeliCa polling TSN field.
|
||||
// Slot 0 only is what a single card wants, but when several cards share the
|
||||
@@ -692,8 +695,14 @@ void felica_sendraw(const PacketCommandNG *c) {
|
||||
|
||||
bool do_connect = ((param & FELICA_CONNECT) == FELICA_CONNECT);
|
||||
bool no_disconnect = ((param & FELICA_NO_DISCONNECT) == FELICA_NO_DISCONNECT);
|
||||
bool system_select = ((param & FELICA_SYSTEM_SELECT) == FELICA_SYSTEM_SELECT);
|
||||
bool replied = false;
|
||||
|
||||
if (system_select && (len != 2 || !do_connect || (param & (FELICA_RAW | FELICA_NO_SELECT)))) {
|
||||
reply_ng(CMD_HF_FELICA_COMMAND, PM3_EINVARG, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Signal probe. The FPGA hands us envelope peak-to-peak per 8 bit periods
|
||||
// instead of demodulated bits, so nothing will decode while this is on.
|
||||
// It is how you tell "tag out of range" apart from "demodulator not
|
||||
@@ -708,16 +717,17 @@ void felica_sendraw(const PacketCommandNG *c) {
|
||||
|
||||
// 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_is_active() == false) {
|
||||
if (!felica_field_is_active() || (do_connect && !system_select)) {
|
||||
iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||
}
|
||||
|
||||
if (do_connect && ((param & FELICA_NO_SELECT) != FELICA_NO_SELECT)) {
|
||||
|
||||
// notify client selecting status.
|
||||
// if failed selecting, turn off antenna and quit.
|
||||
// on failed selection, retain the field only for system-specific polling.
|
||||
felica_card_select_t card = {0};
|
||||
uint8_t select_result = felica_select_card(&card);
|
||||
uint16_t system_code = system_select ? ((uint16_t)payload[0] << 8) | payload[1] : 0xFFFF;
|
||||
uint8_t select_result = felica_select_card(&card, system_code, system_select ? 0x01 : 0x00);
|
||||
|
||||
int select_status = PM3_SUCCESS;
|
||||
switch (select_result) {
|
||||
@@ -744,7 +754,9 @@ void felica_sendraw(const PacketCommandNG *c) {
|
||||
reply_ng(CMD_HF_FELICA_COMMAND, select_status, (uint8_t *)&card, sizeof(felica_card_select_t));
|
||||
replied = true;
|
||||
if (select_status != PM3_SUCCESS) {
|
||||
felica_reset_frame_mode();
|
||||
if (!system_select || !no_disconnect) {
|
||||
felica_reset_frame_mode();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
#define FELICA_OPTIONAL_CMD_RETRIES 3U
|
||||
// Per FeliCa spec, Polling max response at 16 timeslots is ~25ms; keep extra margin.
|
||||
#define FELICA_POLLING_TIMEOUT_MS 100U
|
||||
#define FELICA_READER_SYSTEM_POLL_TIMEOUT_MS 2500U
|
||||
#define FELICA_READER_SYSTEM_POLL_ATTEMPTS 4U
|
||||
#define FELICA_SEAC_POLL_TIMEOUT_MS 200U
|
||||
#define FELICA_SEAC_POLL_RETRY_COUNT 5U
|
||||
#define FELICA_SEAC_POLL_FRAME_LEN 6U
|
||||
@@ -466,6 +468,7 @@ typedef enum {
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
static void clear_and_send_command(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose);
|
||||
static void clear_and_send_command_ex(uint8_t flags, uint16_t datalen, uint8_t *data, uint16_t numbits, bool verbose, bool normalize_frame);
|
||||
static int send_felica_payload_with_retries(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose,
|
||||
int expected_response_cmd, uint32_t timeout_ms, uint32_t retries, uint32_t backoff_ms, bool logging,
|
||||
PacketResponseNG *resp, const char *request_name);
|
||||
@@ -2685,27 +2688,79 @@ int read_felica_uid(bool loop, bool verbose) {
|
||||
return res;
|
||||
}
|
||||
|
||||
static int read_felica_system(uint16_t system_code, bool loop, bool verbose) {
|
||||
uint8_t system_bytes[2];
|
||||
felica_system_code_to_bytes(system_code, system_bytes);
|
||||
const uint8_t flags = FELICA_CONNECT | FELICA_CLEARTRACE | FELICA_NO_DISCONNECT | FELICA_SYSTEM_SELECT;
|
||||
int res = PM3_ETIMEOUT;
|
||||
|
||||
for (uint32_t attempt = 0; loop || attempt < FELICA_READER_SYSTEM_POLL_ATTEMPTS; attempt++) {
|
||||
clear_and_send_command_ex(flags, sizeof(system_bytes), system_bytes, 0, false, false);
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_HF_FELICA_COMMAND, &resp, FELICA_READER_SYSTEM_POLL_TIMEOUT_MS) &&
|
||||
resp.status == PM3_SUCCESS && resp.length >= sizeof(felica_card_select_t)) {
|
||||
felica_card_select_t card;
|
||||
memcpy(&card, resp.data.asBytes, sizeof(card));
|
||||
set_last_known_card(card);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(SUCCESS, "IDm: " _GREEN_("%s"), sprint_hex_inrow(card.IDm, sizeof(card.IDm)));
|
||||
}
|
||||
res = PM3_SUCCESS;
|
||||
if (loop == false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (kbd_enter_pressed()) {
|
||||
if (res != PM3_SUCCESS) {
|
||||
res = PM3_EOPABORTED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdHFFelicaReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf felica reader",
|
||||
"Act as a ISO 18092 / FeliCa reader. Look for FeliCa tags until Enter or the pm3 button is pressed",
|
||||
"hf felica reader -@ -> Continuous mode");
|
||||
"hf felica reader -@\n"
|
||||
"hf felica reader --sys 0003 -@ -> Continuous polling for system 0003");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("s", "silent", "silent (no messages)"),
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_str0(NULL, "sys", "<hex>", "poll a specific 2-byte system code (4 attempts, or continuous with -@)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool verbose = (arg_get_lit(ctx, 1) == false);
|
||||
bool cm = arg_get_lit(ctx, 2);
|
||||
struct arg_str *system_arg = arg_get_str(ctx, 3);
|
||||
bool has_system = system_arg->count > 0;
|
||||
uint8_t system_bytes[2] = {0};
|
||||
int system_len = 0;
|
||||
int parse_status = has_system ? CLIParamHexToBuf(system_arg, system_bytes, sizeof(system_bytes), &system_len) : PM3_SUCCESS;
|
||||
bool invalid_system = parse_status != PM3_SUCCESS ||
|
||||
(has_system && (strlen(system_arg->sval[0]) != 4 || system_len != 2));
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (invalid_system) {
|
||||
PrintAndLogEx(ERR, "System code must be exactly 4 hex digits");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
if (has_system) {
|
||||
uint16_t system_code = felica_system_code_from_bytes(system_bytes);
|
||||
return read_felica_system(system_code, cm, verbose);
|
||||
}
|
||||
return read_felica_uid(cm, verbose);
|
||||
}
|
||||
|
||||
|
||||
+6
-4
@@ -3208,15 +3208,17 @@
|
||||
"command": "hf felica reader",
|
||||
"description": "Act as a ISO 18092 / FeliCa reader. Look for FeliCa tags until Enter or the pm3 button is pressed",
|
||||
"notes": [
|
||||
"hf felica reader -@ -> Continuous mode"
|
||||
"hf felica reader -@",
|
||||
"hf felica reader --sys 0003 -@ -> Continuous polling for system 0003"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-s, --silent silent (no messages)",
|
||||
"-@ optional - continuous reader mode"
|
||||
"-@ optional - continuous reader mode",
|
||||
"--sys <hex> poll a specific 2-byte system code (4 attempts, or continuous with -@)"
|
||||
],
|
||||
"usage": "hf felica reader [-hs@]"
|
||||
"usage": "hf felica reader [-hs@] [--sys <hex>]"
|
||||
},
|
||||
"hf felica resetmode": {
|
||||
"command": "hf felica resetmode",
|
||||
@@ -16784,6 +16786,6 @@
|
||||
"metadata": {
|
||||
"commands_extracted": 935,
|
||||
"extracted_by": "PM3Help2JSON v1.00",
|
||||
"extracted_on": "2026-09-24T08:32:19+00:00"
|
||||
"extracted_on": "2026-09-26T16:59:35+00:00"
|
||||
}
|
||||
}
|
||||
@@ -90,6 +90,8 @@ typedef enum FELICA_COMMAND {
|
||||
// so reading distance and coupling can be measured rather than guessed
|
||||
FELICA_PROBE = (1 << 2),
|
||||
FELICA_RAW = (1 << 3),
|
||||
// With CONNECT, raw[] holds the two-byte polling system code.
|
||||
FELICA_SYSTEM_SELECT = (1 << 4),
|
||||
FELICA_APPEND_CRC = (1 << 5),
|
||||
FELICA_NO_SELECT = (1 << 6),
|
||||
FELICA_CLEARTRACE = (1 << 7),
|
||||
|
||||
Reference in new issue
Block a user