Files
pm3py/docs/plans/2026-07-03-firmware-upstream-rebase-plan.md
michael 615d4a6115 docs: roadmap index + custom-14a-command plans + backfill plan docs
- Add docs/plans/README.md as the roadmap index cataloguing all design/plan docs.
- Add the custom ISO14443-A command handling design + plan (L3 NTAG I2C
  SECTOR_SELECT / cross-sector reads + native auth; L4 static APDUs + WTX relay),
  produced from a multi-agent design workflow.
- Backfill previously-uncommitted plan docs (trace-formatter, ndef-trace-decode,
  live-sniff, firmware-upstream-rebase, 14a-live-trace) and NTAG5_SECURITY.md.
- Sync CLAUDE.md package structure with the committed transponder models.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 12:58:48 -07:00

6.0 KiB
Raw Blame History

Firmware Upstream Rebase Plan (2026-07-03)

Rebase the firmware/ submodule (fork dangerous-tac0s/proxmark3-pm3py) onto current RRG upstream/master without losing our sim / sniff / inventory patch. Backed by a non-destructive dry-run (worktree + merge-tree).

Current state (measured)

  • merge-base: c7086c227 (2026-02-20) — where we branched.
  • our patch: 33 commits on top of merge-base (main == 35db99fa5).
  • upstream ahead: 1049 commits (tip 87388b389, 2026-07-03) — ~4.5 months.
  • Firmware is on main; ALM branch already scrapped.

Dry-run findings — the conflict surface is small and concentrated

A squash-then-rebase (all 33 commits applied as one combined diff, per git merge-tree) conflicts in exactly 3 files; everything else auto-merges or is untouched:

File Verdict ours vs upstream (lines)
armsrc/iso15693.c ⚠️ real work — 13 hunks +599/146 vs +523/214
client/src/cmdhf15.c ⚠️ moderate +372/7 vs +544/45
include/pm3_cmd.h trivial (textual re-append) +21/0 vs +94/113
appmain.c, iclass.c, iso15693.h, iso15.h, Makefile auto-merge
sim_table.c/h, sim_crypto.c/h, Standalone/hf_15sniff.c, Standalone/hf_unisniff.c upstream never touched

A sequential rebase (replay 33 commits) is worse: it conflicts on commit #1 and, because 24 of the 33 commits touch iso15693.c, it re-conflicts that file many times. → Squash first, resolve once.

CMD-ID collision check — CLEAR

All six IDs we added are free in upstream (upstream's 0x033x block only reaches CSETUID_V2 0x0333; 0x095x is empty):

0x0336 CMD_HF_ISO15693_SIM_TRACE    0x0950 CMD_SIM_TABLE_UPLOAD
0x0337 CMD_HF_SNIFF_STREAM          0x0951 CMD_SIM_TABLE_CLEAR
0x0338 CMD_HF_SNIFF_STATUS          0x0952 CMD_SIM_TABLE_UPDATE

So pm3_cmd.h is a pure textual re-append (drop our #defines at a clean spot in the churned region), not a semantic collision.

iso15693.c hunk map (13 hunks, 2 functions)

  • 15693 sniff loop (~L15981853): our streaming-sniff feature (ring buffer, button-toggle, idle flush) vs upstream sniff edits. Biggest hunk ~53 lines (our idle/flush block) — mostly keep-ours-add-both.
  • SimTag / sim loop (~L24753372): our sim handler (table lookup, access control, random UID, periodic field report) + the CheckCrc15 4-byte-frame fix vs upstream. ~10 hunks: three large (span 3643, our inserted blocks → take-ours), the rest small (≤16) needing genuine line-level reconciliation — notably our CheckCrc15 vs upstream's CalculateCrc15 at ~L2591 (keep ours; it fixes 4-byte frames).

Effort estimate: ~half a day of focused merge work, dominated by iso15693.c; cmdhf15.c moderate; pm3_cmd.h ~10 min.

Strategy: squash-to-one → rebase (single 3-file resolution) → validate → re-split

Resolve conflicts exactly once (matching the merge-tree preview), validate the build, then restore clean per-file commits for cheap future rebases (the design-doc "atomic single-file commit" model).

Procedure (all in an isolated worktree — real checkout never moves)

FW=/home/work/pm3py/firmware
WT=<scratchpad>/fw-rebase
git -C $FW fetch upstream master
git -C $FW worktree add -b rebase-wip "$WT" 35db99fa5

cd "$WT"
# 1. collapse 33 commits into one diff on our base (no upstream yet → no conflicts)
MB=$(git merge-base HEAD upstream/master)
git reset --soft "$MB"
git commit -m "pm3py sim+sniff+inventory patch (squashed for rebase)"

# 2. rebase the single commit → conflicts in the 3 known files, resolved once
git rebase upstream/master      # resolve iso15693.c, cmdhf15.c, pm3_cmd.h
# ... resolve, git add, git rebase --continue

# 3. re-split into logical per-file commits (soft reset + staged adds)
git reset --soft upstream/master
#   commit A: sim_table.c/h + sim_crypto.c/h        (new modules)
#   commit B: pm3_cmd.h + iso15.h + iso15693.h      (IDs + struct fields)
#   commit C: appmain.c                              (dispatch)
#   commit D: iso15693.c                             (sim + sniff + inventory)
#   commit E: cmdhf15.c                              (client reader/inventory)
#   commit F: Makefile + Standalone/*                (build glue)

Validation (all local per build-workflow — ARM builds here, not the Mac)

  1. make -C "$WT" clean && make -C "$WT" PLATFORM=PM3GENERIC — ARM compiles.
  2. make -C "$WT" client — validates cmdhf15.c.
  3. python -m pytest tests/ in pm3py — sim tests are transport-mocked, so they stay green; confirms no Python-side regression.
  4. Hardware smoke test (user, has PM3): flash, then hf 15 scan + 15693 sim + a phone read (the known-good sim path). This is the only check the dry-run can't cover — upstream may have altered 15693 wire behavior around our insertions.

Landing

  • Show resolved iso15693.c diff for review before anything touches main.
  • Fast-forward firmware main to rebase-wip, bump the submodule pointer in a pm3py commit, force-push the fork (--force-with-lease).
  • Remove the worktree (git worktree remove, no --force).

Risks & rollback

  • Semantic drift in iso15693.c: upstream may have changed shared helpers our sim path calls. Compile catches signature breaks; behavior needs the hardware smoke test.
  • Rollback: old main is preserved. Recovery ref for pre-rebase tip: 35db99fa5. Nothing is force-pushed until build + review pass.
  • Safety Net: branch -D, rm -rf, git clean -f, worktree remove --force are blocked — use -d/plain rm/worktree remove (no force), or hand force-ops to the user.

Go-forward (close the gap that let us drift 1049 commits)

From the earlier maintenance discussion, still unbuilt:

  • pm3py/firmware_compat.py — pin UPSTREAM_TESTED_COMMIT = 87388b389.
  • A real rebase-check CI (the existing firmware/.github/workflows/ rebase.yml is upstream's Changelog Reminder, not ours).