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

132 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 `#define`s 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)
```bash
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).
```