1049 Commits
Author SHA1 Message Date
iceman1001 2e2598bca9 style 2026-09-27 21:15:18 +02:00
Iceman 2630310336 Merge pull request #3650 from wiillk3/wireless-device-flashing
BWM: add ability to flash over wifi
2026-09-27 19:35:05 +07:00
Iceman 2dea00f183 Merge pull request #3670 from 0x6r1an0y/20260926-felica-raw
Add FeliCa system-specific polling
2026-09-27 19:32:25 +07:00
Philippe Teuwen 12296f4afb CEP: change to SKIP_CEP=1 and clean a bit the doc 2026-09-26 21:16:19 +02:00
Tom HarknessandClaude Sonnet 5 16024ed4a1 Make WITH_CEP default-on for PM5, add SKIP_CEP to opt out
doegox asked on PR #3668 whether CEP really needs to be guarded by a
compile flag, suggesting it ship on by default with a SKIP_CEP opt-out
instead - mirrors the existing NO_LOWBATT_SHUTDOWN/NO_LOWBATT_BEEP
opt-out pattern in common_arm/Makefile.hal. WITH_CEP is now baked into
PM5's base PLATFORM_DEFS; PLATFORM_EXTRAS=SKIP_CEP filters it back out.

No change to armsrc/Makefile (already keys off the WITH_CEP define, not
the old extras token) or to the CEP transport logic itself. Updated the
PM5-FLIPPER-USAGE doc, the CHANGELOG entry, and one stale comment in
include/pm3_cmd.h that referenced the old opt-in token.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 19:55:50 +02:00
歐歪andCodex a991b20a51 hf felica: handle system polling in ARM select
Pass the requested system code to firmware selection so default and system-specific reader modes share one polling path. Keep the RF field active across retries for the system-specific mode.

Co-Authored-By: Codex (GPT-6) <noreply@openai.com>
2026-09-27 01:27:38 +08:00
WillandCursor 8150c2af77 BWM: add ability to flash over wifi
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-26 12:23:47 -04:00
Iceman cbadbf4bfe Merge branch 'master' into pm5-idle-lowpower
Signed-off-by: Iceman <iceman@iuse.se>
2026-09-26 21:51:29 +07:00
Iceman 9ba8b13da6 Merge pull request #3653 from 0x6r1an0y/20260917-15magic-fix
Improve `hf 15 csetuid` command
2026-09-26 21:48:47 +07:00
Tom HarknessandClaude Sonnet 5 2b5e3e51eb Add PM5 CEP transport for Flipper Zero (WITH_CEP)
Wire up the previously-dead Flipper Zero handshake/SPI code from
at32_unit_test.c into a real WITH_CEP platform extra, independent of
BWM (new g_reply_via_cep flag, not reusing BWM's g_reply_via_fpc, so
both transports can run concurrently).

Fixes a real reconnect bug found during hardware bring-up: the
handshake listener was gated on a CC-controller attach edge that
didn't reliably fire on every FAP relaunch, requiring a physical
cable replug to reconnect. Now watches for a fresh incoming byte any
time the link reports attached, with a bounded receive timeout so a
stray byte can never hang the main loop.

RF/FPGA-dependent functionality (hf/lf reads) is out of scope here -
tracked separately. Closes #3667.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 09:45:51 -04:00
MsprgandClaude Fable 5.1 39bbf20cce pm5: hw bwm ble, the module's BLE settings incl. on/off and pairing
The module ships with BLE open: anyone in range can connect and run
commands, and there was no way to turn the radio off or to require
pairing from the PM5, although the module already implements bonding
with a static passkey (LE Secure Connections + MITM, SPP characteristic
encrypted) behind commands nothing exposed.

New CMD_PM5_BWM_BLE (0x0183): one action byte, then a full status
snapshot back (bwm_ble_status_t: switch, state, bonding, passkey, TX
power, address, name, bonded devices). Client menu `hw bwm ble`:
  status              everything above, with a warning while open
  on | off            persisted radio switch (needs the companion
                      Proxmark5_BWM_esp32 PR; off =
                      nothing can connect, USB/WiFi only)
  pairing on|off [-k] require the 6-digit passkey, set the passkey; a
                      change of on/off restarts the stack (drops a
                      connected client), the factory key 123456 is
                      flagged
  forget -i N | --all remove bonded devices
  txpower -a/-c dBm   advertising / connection power, -24..18 and 20

The firmware replies before restarting the stack so the reply survives
when the command itself arrived over BLE. Fields a module without the
switch cannot answer read 0xFF and print as unknown. A module that does
not answer at all ends the status snapshot after its first query instead
of running into the client's timeout.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 10:33:47 +02:00
MsprgandClaude Fable 5.1 0cd1fada0e pm5: auto power-off: idle timeout, unplug switch, stored on the BWM
The USB-unplug power-off left two ways to drain the battery: a PM5
woken by the button and forgotten, and one left idle after the phone
disconnected.

Idle trigger (opt-in, PM5_AUTOOFF_IDLE_MS 0 by default so out of the box
only the unplug trigger exists, as before): on battery the board powers
off after the idle timeout with no interaction and no wireless client.
Interaction is a received command over any transport, any button press,
or a client connecting or leaving; a standalone mode or a long-running
command holds the main loop, so neither can be cut short. The BWM
reports its clients with the LINK_STATE broadcast (8092, companion
Proxmark5_BWM_esp32 PR) which bwm_forward.c tracks; at boot the BLE
half is seeded with a status query since the module only reports
changes. When the timer is due but a client is still tracked, the module
is asked for its BLE state (at most every 10 s), so a lost "client left"
broadcast cannot pin the board on. And right before going off the module
is asked once more: older module firmware never sends the broadcast and
a "connected" one can get lost, and neither may power the board off
under a silent BLE client. No answer means off.

--unplug off: the unplug trigger always won, so "survive the unplug, go
off after N idle seconds" was not reachable. It is its own setting
(default on = unchanged). With it off an unplug only restarts the idle
clock - from the unplug, not from the last command, or a board that sat
idle on USB for an hour would still die with the cable. Unplug detection
is edge-based (VUSB present at the previous poll, absent at this one)
instead of "absent and seen since boot", which would fire on every poll
after a tolerated unplug. VUSB is followed while the feature is switched
off too, so switching it on again on battery is not taken for an unplug.

Stored on the BWM: runtime-only settings reset at every boot, which is
exactly when the idle trigger matters. The PM5 has no settings store, so
the switch, the idle timeout and the unplug switch live in the module's
host value slots (APP_CMD_SET/GET_SYS_HOST_VALUE 1021/1022, companion
PR; slot 0 switch, 1 idle seconds, 2 unplug), loaded at the first
auto-off poll and saved by CMD_PM5_BWM_AUTOOFF with 1 s per write, so a
silent or older module still leaves the reply inside the client's 5 s
wait. Without a module, or with an older one, the defaults apply and the
status says "not stored".

hw bwm autooff [on|off] [--idle <sec>] [--unplug <on|off>]; no argument
shows the state, one fact per line: switch, idle timeout, unplug
power-off, stored on module, USB power, USB seen since boot, unplug
trigger armed, tracked client, the module's BLE state, idle time.
Payload [action][enabled][idle_s u32][unplug, optional] with keep
sentinels; both actions are non-zero so an old firmware, which reads
byte 0 as the enable flag, can only be left enabled. hw status prints
the module's live BLE state and the auto power-off setting; at debug
level also the tracked client, which should agree with the live state.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 10:33:46 +02:00
MsprgandClaude Fable 5.1 5e1b04def1 pm5: hw bwm wifipower, WiFi off or the modem power-save type
New `hw bwm wifipower [off|none|min|max]`. `off` turns the BWM's WiFi
fully off (BLE-only, persisted; the same path as `hw bwm wifi stop`,
and the module's default state). The other three set the ESP's persisted
WiFi modem power-save type (CMD_PM5_BWM_WIFI_PS 0x0182, module commands
2052/2053, esp_wifi_set_ps()) used while WiFi is up: min (the ESP-IDF
default, the modem sleeps between DTIM beacons), max (sleeps for the
whole listen interval, lowest current, slower to react), none (modem
always on, lowest latency). With no argument it reports whether WiFi is
up at all and the stored type. Independent of `hw bwm powersave`.

The link helper's "cmd failed" diagnostic is now printed only at debug
level: a status query while WiFi is off fails by design and was
cluttering every call.

Verified on hardware: default reads min with WiFi off; none, max and
min each set and read back; off tears WiFi down; an unknown value is
rejected; max survives a module reboot. Not measured with WiFi
associated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 10:33:46 +02:00
MsprgandClaude Fable 5.1 552276c75f pm5: hw bwm powersave
New `hw bwm powersave [on|off]` (CMD_PM5_BWM_POWERSAVE 0x0181) shows or
sets the ESP's persisted power-save switch (companion Proxmark5_BWM_esp32
PR: DFS, light sleep and slow advertising after a 30 s fast phase, or
the stock always-on behaviour), so the two can be A/B measured and the
saving turned off when chasing a link problem. `hw status` prints the
state next to the BWM firmware version.

Both module queries in `hw status` are time-bounded (version 2 x 800 ms,
power save 300 ms): a module that is silent, or a firmware without the
command, cannot push the report past the client's timeout.

Verified on hardware: state read/set/persist across an ESP reboot,
`hw status` after 4, 15 and 40 s idle in power-save mode and after 6 s
idle with it off.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 10:33:46 +02:00
4f4acedbdd pm5: reduce idle power (core clock scaling + WFI idle)
Port the "reduce idle power" feature from the Fantasi firmware
(soeinova/Fantasi @ 9671309, plus its later ACC-SOF fix) to the PM5
(AT32F435) target.

Problem
-------
The PM5 firmware ran the ARM core at 288 MHz with a 1.3 V LDO and a
main loop that busy-polled at full speed even when the device was idle.
The 288 MHz PLL and the 1.3 V LDO dominate idle draw, and the busy loop
adds to it. Nothing scaled back when there was no work.

Change
------
New armsrc/pm5_power.c drives a refcounted clock/voltage governor:
- Idle (nothing pending, boost count 0, boot grace elapsed, FPGA off):
  take SCLK off the PLL onto HICK-48, power the PLL down, drop the LDO
  to 1.1 V, park the FPGA 24 MHz clock (PA8 low), and halt the core in
  WFI until the next IRQ or the 1 ms SysTick wake.
- Any timing-critical work holds a 288 MHz boost: AppMain wraps
  PacketReceived (which on the PM5 also covers a standalone mode, since
  it is only entered through a command there); the BWM low-batt poll
  and the RGB indicator wrap their I2C. Boost is refcounted and
  IRQ-guarded.
- USB (OS image) moves to the crystal-less HICK-48 clock, ACC-trimmed
  against the SOF, so powering the PLL down never touches USB. The
  bootrom keeps the HEXT/PLL USB path (AS_BOOTROM), so DFU flashing is
  unchanged.
- bwm_uart_clock_update() re-inits UART4 through the SDK usart_init()
  on each clock switch (the divider set at 288 MHz is 6x off at 48 MHz).
- FpgaIsOff() (fpga_core.c, PM5 only) tracks the last conf word so the
  governor never downclocks while a reader field / emulation is running.
- Wake preamble on the BWM link: the companion module firmware
  (Proxmark5_BWM_esp32) light-sleeps 2 s after the last byte on the link
  and its UART wakes on RX edges but loses the bytes that carried them.
  bwm_uart_write() therefore leads with four 0x55 bytes and a 10 ms
  settle on its first write and after 1 s without a write of its own
  (RX is not tracked: the ring can be drained long after the bytes
  came in). The module only starts light-sleeping once it has seen a
  preamble, so the one sent while it was still booting is repeated
  after the boot-time link negotiation. A module firmware without light
  sleep drops the preamble as noise.

New `hw powersave on|off` toggles the governor at runtime (default on);
`hw status` reports the idle-clock and WFI-asleep fractions.

Behaviour change
----------------
- PM5 idles at 48 MHz with the PLL off and the CPU halted; it boosts to
  288 MHz for commands and BWM housekeeping. Command timing and
  throughput are unchanged (intra-command work is always boosted).
- PM5 USB now runs off HICK-48 (ACC-trimmed) instead of the HEXT PLL.
- New command id CMD_PM5_POWERSAVE (0x0180).

Testing
-------
Built warning-free (gcc) for PLATFORM=PM5 (with and without
PLATFORM_EXTRAS=BWM), PM3RDV4 and PM3GENERIC, armsrc and bootrom. Client
built via the default Makefile. Not built with clang or on
Windows/macOS; nothing outside PM5/AT32 guards changes.

Flashed to a PM5 and exercised against a MIFARE Classic 4K card:
hw version/status/ping (4000 & 512 B), hw tune, hf search, hf 14a
info/reader (x12 across idle gaps), hf mf info/chk/rdbl, lf search/read,
hw powersave off/on, held-field (raw -sk) correctly blocks the downclock,
hw reset + re-enumerate. All pass; USB stays up across downclocks. Idle
reaches ~80-95% at 48 MHz and ~90%+ WFI-halted after a few seconds idle.
Measured at the USB port: idle draw 283 mA -> 207 mA with the stock
BWM firmware.

Co-authored-by: Soei Nova <soeinova@proton.me>
Co-authored-by: noproto <noproto@zeroday.engineering>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 10:33:46 +02:00
Niel Nielsen 2c8df402f8 Update CAPABILITIES_VERSION to 12
Signed-off-by: Niel Nielsen <nieldk@gmail.com>
2026-09-23 13:44:57 +02:00
歐歪andClaude Opus 5 f0a502b279 refactor: move ISO15693 magic tag handling to the device side
Identification, writing and failure handling for magic Gen1 and V3 tags
now runs in a single field session on the device, which reports
PM3_SUCCESS only when the UID reads back as requested.

armsrc/iso15693.c:
- SetTag15693Uid() probes 0x38/0x39/0x3E/0x3F and refuses to write when
  any of them answers with data, verifies the UID afterwards and blanks
  the four blocks again when it did not change.
- SetTag15693Uid_v3() and FinalizeTag15693_v3() are new, both check the
  0x14/0x15 configuration signature before writing and verify after.

client/src/cmdhf15.c:
- csetuid and cfinalize now only select a command and print the status.
  The V3 block helpers and constants move to armsrc, which restores the
  original read helper with its CALLOC message and the
  ISO15_ERROR_HANDLING_* macros.

Behaviour change: hf 15 cfinalize without -y no longer energizes the tag
and no longer reports configuration mode before asking for confirmation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 07:04:16 +08:00
Mistial DeveloperandClaude Fable 5.1 e588085c10 hf mfdes sim: host driven test hook with injectable randomness
The DESFire simulation could only be reached over the air. A conformance
suite that has recorded a genuine card's session needs to replay it byte
for byte, which takes two things the simulation did not have: a way in
over USB, and control of the card's random draws.

CMD_HF_DESFIRE_SIM_TEST carries one operation per packet into the same
state machine the RF loop drives: BEGIN, SCAN, APDU, RANDOM, FIELDOFF,
STATE, END. SCAN runs the RF-reset path (init, reset, random id, FSD) and
APDU goes through desfire_sim_apdu(), so native and ISO 7816 wrapped
commands answer exactly as they do on air. No FPGA involvement.

Randomness goes through a small host-fed byte queue: RndB and the random
id draw from it first and fall back to the existing fixed value or tick
counter when it is short, raising a sticky underflow flag. With nothing
queued the RF simulation is byte-identical to before; SimulateDesfireTag()
clears the queue so a host session cannot leak into a reader session.

Co-Authored-By: Claude Fable 5.1 (claude-fable-5-1) <noreply@anthropic.com>
2026-09-16 22:04:01 +02:00
iceman1001andClaude Opus 5 4d4dd32354 hf mfdes sim: SetConfiguration
The simulation answers SetConfiguration. The option byte travels in the clear
and the data behind it is enciphered with a CRC32, the same shape ChangeKey uses,
and card level master key authentication is required (M134034 9.4.9).

Option 0x00, the configuration byte, is kept in the card image header. Both bits
it defines are one way on a card -- the spec says "cannot be reset" of each --
so they are only ever set, never cleared, and a reader that sends a zero byte
afterwards gets an OK and no change, which is what the silicon does.

  bit 0 disables FormatPICC, and that command now refuses from then on.

  bit 1 switches anticollision to a random id: a 4 byte id whose first byte is
  the 0x08 random tag and whose other three are the random number, with a single
  cascade level (M134034 6.5). The real UID is then only reachable through
  GetCardUID, which is the reason that command exists. A card draws the number
  at RF reset; the nearest thing here is the start of a simulation, since that is
  when the anticollision answers are built, so it is stable across activations
  within one run and different across runs -- measured 08 01 9A C9 four times in
  a row, then 08 01 BB 96 and 08 01 DC 26 and 08 01 FC 8E on three restarts.

  Simulating that needed the 4 byte case adding to the UID length the simulation
  accepts, which previously took only 7 and 10 and refused to start otherwise.

Option 0x02 replaces the ATS. It lands in the image, so it takes effect the next
time the simulation starts rather than mid-run, because the ATS is one of the
answers precompiled before the reader is listened to.

Option 0x01, the default key new applications are created with, is refused with
91 9E rather than accepted and ignored. Storing it needs two fields the card
image does not have, and adding them moves every table in it. A reader that sets
a default key and then finds new applications keyed with zeros is worse off than
one told the option is not there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 21:58:57 +02:00
iceman1001andClaude Opus 5 2d70fcb4ff hf mfdes sim: self contained DESFire simulation, and stop bitstream downloads eating emulator memory
The DESFire simulation gets its own ISO 14443-A loop in armsrc/desfiresim.c
rather than hooking into SimulateIso14443aTag(). That function is complicated
enough without a DESFire state machine threaded through it, and the hook had
already got the ATQA wrong once. It still borrows the library helpers from
iso14443a.c -- the precompiled activation answers, the receive call, the send
calls -- so there is no duplicated state machine, and iso14443a.c goes back to
knowing nothing about DESFire. desfiresim.h exports one symbol.

Three fixes were needed to make it actually answer a reader.

1. ISO 7816 wrapping. A reader sends `02 90 60 00 00 00`, not `02 60`. The
   simulation read in[0] as the DESFire command and so saw 0x90, the class
   byte, answering ILLEGAL_COMMAND_CODE to everything -- and in native form
   (status || data) when the reader wanted the wrapped form (data || 91 SW).
   Both framings are handled now, including the Lc/Le distinction: five bytes
   means no data and in[4] is Le, longer means in[4] is Lc with data following.

2. A bitstream download frees and clears BigBuf to get scratch space for the
   decompressor. SimulateIso14443aTagEx() and Mifare1ksim() both guard against
   this by calling FpgaDownloadAndGo_keep_EM() before they allocate anything;
   the new loop did not, so iso14443a_setup() wiped the emulator memory holding
   the card image and the precompiled answers after they had been filled. The
   pointers survive, the bytes do not, and the tag then clocks out zeros.

3. iso14443a_setup() itself used the plain FpgaDownloadAndGo(), which does
   BigBuf_free() and BigBuf_Clear_ext() -- taking the emulator memory with it.
   Every 14a command comes through there, so a card image that `eload` had just
   put in place was destroyed by the next `hf 14a` command whenever the HF
   bitstream was not already resident. Demonstrated before and after:
   `eload` then `hf 14a reader` then `eview` used to report "No DESFire card
   image in emulator memory" and now returns the image intact. This affected
   every emulator memory user, not only DESFire.

Verified against a second Proxmark3 acting as reader, simulating a real
DESFire EV1 8K dump: activation (UID 04268512A25680, ATQA 03 44, SAK 20,
ATS 06 75 77 81 02 80), the three frame GetVersion chain over 0xAF, GetFreeMem,
GetApplicationIDs, SelectApplication, GetKeySettings and GetFileSettings.
`hf mfdes info`, `getaids`, `freemem`, `lsapp` and `lsfiles` all read correctly,
including per application key types (AES, 2TDEA, 3TDEA) and all five EV1 file
types with their real settings -- a value file holding 1000 with limits
[0..10000], a linear record 2/8 of 16 bytes, a cyclic record 1/4 of 24 bytes,
standard files of 256 and 64 bytes, and a backup file of 128 bytes in MAC mode
with keyed rights 1200.

Not implemented yet: GetDFNames (0x6D) and GetISOFileIDs (0x61), so a reader
sees empty ISO IDs and DF names. Everything else answers
ILLEGAL_COMMAND_CODE, which is what a PICC says to a command it does not have.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 14:43:52 +02:00
iceman1001 a7b1276781 phase 1 simulation and desfire fixes... 2026-09-14 21:13:10 +02:00
iceman1001andClaude Opus 5 (1M context) ee2d55fafb hf mfdes: put a DESFire card image in emulator memory
Adds the on-device card image a DESFire simulation will read, the client
side that packs a dump into it, and eload / esave / eview.

The layout is in include/desfire_em.h. Tables grow up from the header,
file data grows down from the end, and an allocation only has to leave
the two frontiers apart -- so a three-file card spends a few hundred
bytes rather than a worst case, and the space between them is what the
card has left. The PICC is application 000000 and uses the same struct
as any other application, so key settings and keys are always stated
against an AID. Delete sets a tombstone rather than compacting, which is
not a shortcut: a real card does not reclaim on delete either, measured
as 2080 bytes free with zero applications before an experiment and 2560
after FormatPICC.

Two size limits, and a reader only ever sees the first. cardsize is what
the emulated card claims to hold, so GetFreeMem answers from that and
CreateFile will refuse with OUT_OF_EEPROM when it runs out. Without it a
card impersonating a 2K part would report 7434 bytes free, which no 2K
part does. The image size is what emulator memory physically holds, is
the harder limit, and is never visible.

cardsize is anchored to the free memory the real card reported when the
dump was taken -- observed free plus what we reserve for the same content
-- so the emulation answers what its original answered. That is also a
check on the reservation rule rather than only a convenience: for the
bench card it computed 576 bytes spent, and 1984 + 576 is 2560, exactly
what that card reports when formatted.

Reservation follows what CommitTransaction covers. Backup data, value and
record files each get a shadow region because writes to them are staged
until commit; a standard data file writes through and does not. Sizes
round to a 32 byte granule, which is the granule a real card allocates in.
It deliberately does not reproduce NXP's allocator -- that is
undocumented and does not fit a simple model, a declared 1024 byte record
file costs 1088 on silicon -- so what matters is that the figure is
self-consistent and shrinks as the reader writes.

No new device command. Emulator memory is one shared region, so
CMD_HF_MIFARE_EML_MEMSET and BIG_BUF_EML already reach it, and both
inherit the bounds checking those paths gained earlier.

Verified with the client only, no simulation yet: packing a dump taken
from a DESFire EV2 and walking it back reproduces every field including
file contents byte for byte, the same round trip through the device via
eload and esave is identical, and an image too large is refused by name
rather than truncated -- 'Out of emulator memory laying out AID 112233
file 00: needs 4066 more bytes'.

Co-Authored-By: Claude Opus 5 (1M context)
2026-09-14 19:48:45 +02:00
Niel Nielsen 259f15e7df Merge branch 'RfidResearchGroup:master' into master 2026-09-14 13:11:49 +02:00
iceman1001 9caa6d6117 minor change we device now reports back EMULATOR memory size to the client. Had to bump capability version number to 11. 2026-09-14 12:16:51 +02:00
Niel Nielsen 78dbf840ea Merge branch 'RfidResearchGroup:master' into master 2026-09-14 11:45:55 +02:00
iceman1001 9b60b1b218 missing define 2026-09-14 09:19:17 +02:00
Niel Nielsen 5624a91f98 Decrease PM3_FPC_MAX_DATA from 4096 to 2048
Reduced maximum data size for FPC communication to prevent buffer overrun.

Signed-off-by: Niel Nielsen <nieldk@gmail.com>
2026-09-14 08:38:37 +02:00
Niel Nielsen 96634fb2bf Increase PM3_FPC_MAX_DATA from 2048 to 4096
Fixes the the disconnects when on BLE connection

Signed-off-by: Niel Nielsen <nieldk@gmail.com>
2026-09-13 20:18:32 +02:00
Niel Nielsen 094df6102e Update pm3_cmd.h
Signed-off-by: Niel Nielsen <nieldk@gmail.com>
2026-09-13 11:22:47 +02:00
iceman1001 baea4014c1 fix cident overflows 2026-09-12 20:35:35 +02:00
iceman1001andClaude Opus 5 (1M context) 4d7d49e089 stop an FPGA bitstream download from eating the emulator memory
FpgaDownloadAndGoEx() with keep_em false does BigBuf_free() plus
BigBuf_Clear_ext(): the emulator memory pointer is nulled and all of BigBuf is
zeroed.  iso14443a_setup() calls that variant, and Mifare1ksim(),
SimulateIso14443aTagEx() and SimulateIso14443aTagAID() build their precompiled
anticollision responses in BigBuf first.  CMD_HF_MIFARE_EML_MEMGET had it the
other way round - it downloaded, then read the memory it had just wiped, so
'hf mf eview' and 'hf mf esave' returned their own zeros after any lf hitag,
hf iclass or hf 15 command.  A download already cached early-returns, so which
image the FPGA held decided whether any of this happened.

All five now call FpgaDownloadAndGo_keep_EM() before any BigBuf allocation.
Free-BigBuf floor at download time goes 16384 -> 20480 (ring plus the 4096 byte
emulator block); BigBuf measures 29084..31420 across all standalone configs on
RDV4 and 40120 on a PM3 Easy.

The sim paths also clear the trace before taking their modulation buffer -
BigBuf_malloc() refuses memory a stale trace holds, and MifareSimInit() ignored
the NULL, leaving prepare_tag_modulation() to memcpy 571 bytes over the vector
table at address 0.

'hf mf eload' now zeroes emulator memory device side: CMD_HF_MIFARE_EML_MEMSET
takes a flags byte, set on the first chunk only, so 'hf mf esetblk' and every
other partial write still touch only their own blocks.  That byte is why
CAPABILITIES_VERSION goes 9 -> 10; mismatched client and firmware refuse to
connect rather than write everything one byte offset.

Reported in #2836, whose USB drop is separately addressed by bc289cf43.

Builds clean for PM3RDV4, PM5 and the client; astyle clean.  Not yet verified on
hardware.

Co-Authored-By: Claude Opus 5 (1M context)
2026-09-12 18:49:24 +02:00
iceman1001 f57da9c85d missing files 2026-09-12 15:10:36 +02:00
Niel Nielsen 945619c2d5 Add BLE name command definitions to pm3_cmd.h
Signed-off-by: Niel Nielsen <nieldk@gmail.com>
2026-09-12 13:27:00 +02:00
iceman1001andClaude Opus 5 (1M context) 6341f40b4c hf mf hardnested: fix the nonce reply length, 9 bytes per pair not 4 per nonce
Thanks @TheArchitect0880 for pointing it out and suggested a first fix.

MifareAcquireEncryptedNonces packs two 4 byte encrypted nonces plus one
byte holding both their encrypted parity nibbles into every entry, but
the reply declared num_nonces * 4 bytes. The client walks that buffer 9
bytes at a time, so on RDV4 it read 612 bytes out of a 544 byte payload
and handed roughly 15 of every 136 nonces to add_nonce() from stale
packet buffer content. Those fake nonces went into the .bin nonce file
too.

Count pairs instead of bytes. num_nonces now reports whole pairs only,
so a button abort or a static nonce bailout part way through a pair
drops the dangling nonce rather than shipping a half built entry whose
parity nibble was never filled in.

MFC_NONCE_PAIR_SIZE and MFC_MAX_NONCE_PAIRS document the layout next to
mf_nonces_resp_t so the 9 vs 4 confusion cannot come back, and the
client now refuses a reply too short for the nonce count it carries.

Both acquisition functions collect straight into the reply buffer rather
than a second PM3_CMD_DATA_SIZE stack array, which halves the stack used
per call. MifareAcquireNonces also returned isOK = 2 on button press,
which is not a PM3_* status; that is PM3_EOPABORTED now.

Co-Authored-By: Claude Opus 5 (1M context)
2026-09-12 10:44:00 +02:00
iceman1001andClaude Opus 5 (1M context) 2cd5285cb2 hf mfdes chk: track found keys per application
foundKeys was indexed [keytype][keyno] with no AID dimension and was
never reset between applications, so a key number recovered on one AID
was skipped without a single auth attempt on every later AID.  On a card
with AES key 00 set on two apps, only the first one was ever reported.

Give every application its own desfire_app_keys_t and hand that to the
checker.  Saving to json now uses a new 'mfdes v2' format keyed by AID,
with a loader that round-trips it; v1 is kept for existing files.

Also in the same path:
 - one auth error below 7 broke out of the key number loop, abandoning
   every remaining key number for the AID.  Only an algo mismatch (4, 50,
   51) skips the key type now; an invalid key number (3) skips just that
   key number, and a transmit error retries after a reselect
 - 3TDEA keys were stored 16 bytes wide and written out as 24
 - -k with a 24 byte key was rejected by the parser, making the 24 byte
   branch unreachable
 - DesfireGetAIDList() wrote unbounded into a 78 byte app_ids buffer

Co-Authored-By: Claude Opus 5 (1M context)
2026-09-11 10:38:57 +02:00
kormaxandmxcdoam 1ecbcb74be Add ISO14443-3 Type A timeslot support to 'hf 14a info' and 'hf 14a reader'
Co-authored-by: mxcdoam <72457810+mxcdoam@users.noreply.github.com>
2026-09-07 22:55:24 +03:00
Iceman 9f641c3ced Merge pull request #3427 from Sanduuz/feature/st25ta_ndef_sim
Added support for emulating ST25TA tag (IKEA Rothult) with custom NDEF response
2026-09-07 15:38:46 +07:00
xilni 342cc37cca docs(bwm): fix stale hw bwm command references 2026-09-07 00:07:07 -04:00
Iceman 2da575ab36 Merge branch 'master' into master
Signed-off-by: Iceman <iceman@iuse.se>
2026-09-06 21:25:31 +07:00
dxl fc355df050 Added IO test capabilities to the factory QC for PM5. 2026-09-05 18:09:46 +02:00
dxl ea5485b4b8 Rename CMD_PM5_QC_TEST to CMD_PM5_QC_TEST_HW
and delete repeated def: CMD_PM5_BWM_SET_CAP
2026-09-05 18:09:46 +02:00
Antiklesys 57a42e3ce9 Stability fix for sc-bigbuf traces 2026-09-05 22:31:52 +08:00
Niel Nielsen eb5b9eb561 Added removed comment again
Added removed comment again

Signed-off-by: Niel Nielsen <nieldk@gmail.com>
2026-09-05 09:12:39 +02:00
Niel Nielsen 96e13303c8 Update PM3_FPC_MAX_DATA to 2048
Increase maximum data size for FPC from 240 to 2048 bytes.

Signed-off-by: Niel Nielsen <nieldk@gmail.com>
2026-09-05 08:33:03 +02:00
Niel Nielsen cf3730e1b4 Merge branch 'RfidResearchGroup:master' into BWM-work 2026-09-04 14:29:26 +02:00
iceman1001 ace5d63ff9 hitag2: fix simulation against genuine readers, add restore, fix info
Simulation now completes the full exchange with a genuine Paxton reader in
password mode, and crypto mode read/write passes Proxmark-to-Proxmark.

Firmware:
- SOF was one bit period short. The lead-in that compensated for the lost
  head half bit was removed and nothing replaced it, so readers rejected
  every answer with a second START_AUTH. Default is now 6.
- The edge-detect threshold was latched before being measured, so the value
  chosen depended on whether the Proxmark was in a field when sim started.
  It is now measured on field entry and re-armed when the reader leaves.
- The percentile walk latched on run-scoped variables, so one attempt made
  outside a field poisoned every later one.
- Field loss was detected from TIMESTAMP, which is free-running MCU time and
  never stalls. Detect it from receive silence instead.
- Frames of a length the protocol does not have no longer reach the state
  machine; our own modulation tail was resetting the session and breaking
  every write.
- A dropped edge merges two or three reader bit periods into one gap. Those
  bits were discarded; they are now recovered by decomposition, which is what
  made crypto mode work (AUTH decode 15% -> 100%).
- Threshold selection is limited to 20 and 32 and settles in under 25 ms.

Client:
- lf hitag info printed a hardcoded 0x06 and reported 'Password mode' for
  every tag. It now reads page 3, takes -k (4 bytes password, 6 bytes
  crypto), and says so when the config cannot be read.
- lf hitag restore: writes a dump back in dependency order - user pages,
  then key material, then config last - validates the config byte, and
  prints the credential the tag will require afterwards.
- lf hitag crack2 now reports why it failed instead of a bare 'fail'.
- trace list: bit count moved to its own column, relative mode shows a
  Frame Delay Time row rather than renaming Start/End, --frame and -r
  rejected together.
2026-09-04 13:20:29 +02:00
Niel Nielsen 9d12204135 Change BWM_OTA_CHUNK_MAX to 240
Updated maximum firmware bytes per WRITE action from 2048 to 240.

Signed-off-by: Niel Nielsen <nieldk@gmail.com>
2026-09-04 09:56:04 +02:00
Niel Nielsen fa7aa4e594 Increase PM3_FPC_MAX_DATA from 2048 to 240
240 seems the best choise

Signed-off-by: Niel Nielsen <nieldk@gmail.com>
2026-09-04 09:17:49 +02:00
Niel Nielsen ef09ab673b Update BWM_OTA_CHUNK_MAX to allow larger firmware writes
Increased the maximum firmware bytes per WRITE action from 196 to 2048.

Signed-off-by: Niel Nielsen <nieldk@gmail.com>
2026-09-04 09:15:11 +02:00
Niel Nielsen c1d47f2be9 Reduce BWM_OTA_CHUNK_MAX from 240 to 196
Signed-off-by: Niel Nielsen <nieldk@gmail.com>
2026-09-04 09:10:45 +02:00