diff --git a/armsrc/appmain.c b/armsrc/appmain.c index e7eb0ac99..db6fa55fd 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -68,6 +68,24 @@ extern uint32_t _stack_start, _stack_end; struct common_area common_area __attribute__((section(".commonarea"))); static int button_status = BUTTON_NO_CLICK; static bool allow_send_wtx = false; +static uint32_t tearoff_delay_us = 0; +static bool tearoff_enabled = false; + +int tearoff_hook(void) { + if (tearoff_enabled) { + if (tearoff_delay_us == 0) { + Dbprintf(_RED_("No tear-off delay configured!")); + return PM3_SUCCESS; // SUCCESS = the hook didn't do anything + } + WaitUS(tearoff_delay_us); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + tearoff_enabled = false; + Dbprintf(_YELLOW_("Tear-off triggered!")); + return PM3_ETEAROFF; + } else { + return PM3_SUCCESS; // SUCCESS = the hook didn't do anything + } +} void send_wtx(uint16_t wtx) { if (allow_send_wtx) { @@ -731,6 +749,24 @@ static void PacketReceived(PacketCommandNG *packet) { reply_ng(CMD_SET_DBGMODE, PM3_SUCCESS, NULL, 0); break; } + case CMD_SET_TEAROFF: { + struct p { + uint32_t delay_us; + bool on; + bool off; + } PACKED; + struct p *payload = (struct p *)packet->data.asBytes; + if (payload->on && payload->off) + reply_ng(CMD_SET_TEAROFF, PM3_EINVARG, NULL, 0); + if (payload->on) + tearoff_enabled = true; + if (payload->off) + tearoff_enabled = false; + if (payload->delay_us > 0) + tearoff_delay_us = payload->delay_us; + reply_ng(CMD_SET_TEAROFF, PM3_SUCCESS, NULL, 0); + break; + } // always available case CMD_HF_DROPFIELD: { hf_field_off(); diff --git a/armsrc/appmain.h b/armsrc/appmain.h index 594723983..092e88d0e 100644 --- a/armsrc/appmain.h +++ b/armsrc/appmain.h @@ -16,6 +16,8 @@ extern int g_rsamples; // = 0; extern uint8_t g_trigger; +int tearoff_hook(void); + // ADC Vref = 3300mV, and an (10M+1M):1M voltage divider on the HF input can measure voltages up to 36300 mV #define MAX_ADC_HF_VOLTAGE 36300 // ADC Vref = 3300mV, (240k-10M):240k voltage divider, 140800 mV diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 146acf962..03e322681 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -2573,15 +2573,20 @@ void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) { SendForward(len); - // Wait 20ms for write to complete? - // No, when write is denied, err preamble comes much sooner - //WaitUS(10820); // tPC+tWEE + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + StopTicks(); + reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_ETEAROFF, NULL, 0); + } else { + // Wait 20ms for write to complete? + // No, when write is denied, err preamble comes much sooner + //WaitUS(10820); // tPC+tWEE - DoPartialAcquisition(0, false, 6000, 1000); + DoPartialAcquisition(0, false, 6000, 1000); - StopTicks(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_SUCCESS, NULL, 0); + StopTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_SUCCESS, NULL, 0); + } LEDsoff(); } @@ -2610,15 +2615,19 @@ void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd) { SendForward(len); - // Wait 20ms for write to complete? - // No, when write is denied, err preamble comes much sooner - //WaitUS(13640); // tPC+tPR + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + StopTicks(); + reply_ng(CMD_LF_EM4X_PROTECTWORD, PM3_ETEAROFF, NULL, 0); + } else { + // Wait 20ms for write to complete? + // No, when write is denied, err preamble comes much sooner + //WaitUS(13640); // tPC+tPR - DoPartialAcquisition(0, false, 6000, 1000); - - StopTicks(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - reply_ng(CMD_LF_EM4X_PROTECTWORD, PM3_SUCCESS, NULL, 0); + DoPartialAcquisition(0, false, 6000, 1000); + StopTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + reply_ng(CMD_LF_EM4X_PROTECTWORD, PM3_SUCCESS, NULL, 0); + } LEDsoff(); } diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c index ac938b7c8..5db860d0a 100644 --- a/client/src/cmdhw.c +++ b/client/src/cmdhw.c @@ -15,6 +15,7 @@ #include #include "cmdparser.h" // command_t +#include "cliparser.h" #include "comms.h" #include "usart_defs.h" #include "ui.h" @@ -515,6 +516,57 @@ static int CmdStatus(const char *Cmd) { return PM3_SUCCESS; } +static int CmdTearoff(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hw tearoff", + "Configure a tear-off hook for the next write command supporting tear-off\n" + "After having been triggered by a write command, the tear-off hook is deactivated", + "hw tearoff --delay 1200 --> define delay of 1200us\n" + "hw tearoff --on --> (re)activate a previously defined delay\n" + "hw tearoff --off --> deactivate a previously activated but not yet triggered hook\n"); + + void *argtable[] = { + arg_param_begin, + arg_int0(NULL, "delay", "", "Delay in us before triggering tear-off, must be > 0"), + arg_lit0(NULL, "on", "Activate tear-off hook"), + arg_lit0(NULL, "off", "Deactivate tear-off hook"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, false); + struct { + uint32_t delay_us; + bool on; + bool off; + } PACKED params; + params.delay_us = arg_get_u32_def(ctx, 1, 0); + params.on = arg_get_lit(ctx, 2); + params.off = arg_get_lit(ctx, 3); + CLIParserFree(ctx); + if (params.on && params.off) { + PrintAndLogEx(WARNING, "You can't set both --on and --off!"); + return PM3_EINVARG; + } + clearCommandBuffer(); + SendCommandNG(CMD_SET_TEAROFF, (uint8_t *)¶ms, sizeof(params)); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_SET_TEAROFF, &resp, 500) == false) { + PrintAndLogEx(WARNING, "Tear-off command timeout."); + return PM3_ETIMEOUT; + } + if (resp.status == PM3_SUCCESS) { + if (params.delay_us > 0) + PrintAndLogEx(INFO, "Tear-off hook configured with delay of %ius.", params.delay_us); + if (params.on) + PrintAndLogEx(INFO, "Tear-off hook enabled."); + if (params.off) + PrintAndLogEx(INFO, "Tear-off hook disabled."); + return PM3_SUCCESS; + } + PrintAndLogEx(WARNING, "Tear-off command failed."); + return resp.status; +} + static int CmdTia(const char *Cmd) { (void)Cmd; // Cmd is not used so far PrintAndLogEx(INFO, "Triggering new Timing Interval Acquisition (TIA)..."); @@ -621,6 +673,7 @@ static command_t CommandTable[] = { {"setmux", CmdSetMux, IfPm3Present, "Set the ADC mux to a specific value"}, {"standalone", CmdStandalone, IfPm3Present, "Jump to the standalone mode"}, {"status", CmdStatus, IfPm3Present, "Show runtime status information about the connected Proxmark3"}, + {"tearoff", CmdTearoff, IfPm3Present, "Program a tearoff hook for the next command supporting tearoff"}, {"tia", CmdTia, IfPm3Present, "Trigger a Timing Interval Acquisition to re-adjust the RealTimeCounter divider"}, {"tune", CmdTune, IfPm3Present, "Measure antenna tuning"}, {"version", CmdVersion, IfPm3Present, "Show version information about the connected Proxmark3"}, diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index e96c58984..267ca2b7f 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -401,6 +401,7 @@ typedef struct { #define CMD_WTX 0x0116 #define CMD_TIA 0x0117 #define CMD_BREAK_LOOP 0x0118 +#define CMD_SET_TEAROFF 0x0119 // RDV40, Flash memory operations #define CMD_FLASHMEM_WRITE 0x0121 @@ -774,8 +775,10 @@ typedef struct { // execute pm3 cmd failed client/pm3: when one of our pm3 cmd tries and fails. opposite from PM3_SUCCESS #define PM3_EFAILED -21 -// partial success client/pm3: when tring to dump a tag and fails on some blocks. Partial dump. +// partial success client/pm3: when trying to dump a tag and fails on some blocks. Partial dump. #define PM3_EPARTIAL -22 +// tearoff occured client/pm3: when a tearoff hook was called and a tearoff actually happened +#define PM3_ETEAROFF -23 // No data pm3: no data available, no host frame available (not really an error) #define PM3_ENODATA -98