Commit 90970ca
RTL8814AU: pcapng-fidelity USB diff + replay tooling (#55)
## Summary
Adds a binary-fidelity USB diff toolchain to compare kernel
`aircrack-ng/88XXau` TX vs devourer's on RTL8814AU, plus three env-gated
diagnostic switches in `WiFiDriverTxDemo` and one library change to
close a concrete kernel-vs-devourer wire-level divergence.
The existing `tools/usbmon_diff.py` (#53, text-format) is bulk-OUT only
and cannot represent EP0 control transfers — the carrier for ~5000 init
register pokes per chip cold-init. Without those axes, "the wire
matches" diff conclusions are not load-bearing. The new tool was the
difference between "the gate is somewhere in path-A RF table
application" (the previous narrowing, indirect) and a concrete URB-level
diff against a real kernel-side capture (this PR, direct).
### Tooling
- `tools/usbmon_pcap_diff.py` — pcapng-aware diff (Linux usbmon binary,
`LINKTYPE_USB_LINUX_MMAPPED = 220`). Surfaces setup packet, full payload
+ SHA-256, URB flags, status, timestamps, and IN URBs as first-class
records. Modes: default position-aligned diff w/ lookahead resync,
`--offload-probe`, `--phase-split`, `--aggregate`. Real-capture caveat
handled: modern kernels write `flag_setup=0` (not `' '/0x20` as the old
docs say) for valid setup packets — parser decodes setup unconditionally
on CTRL submits.
- `tools/pcapng_to_urbscript.py` — pcapng → binary URB script emitter.
- `tools/usbmon_replay.c` → `build/usbmon_replay` — `USBDEVFS_SUBMITURB`
verbatim replay. `--dry-run`, `--disconnect`, capped inter-URB gaps,
bulk-OUT default `URB_ZERO_PACKET` matching
`RtlUsbAdapter::send_packet`.
- Unit + roundtrip tests (synthetic pcaps, no hardware) —
`tests/test_usbmon_pcap_diff.py`, `tests/test_urbscript_roundtrip.py`.
- `tools/usbmon_diff.py` — banner update pointing forward.
### Diagnostic gates in `WiFiDriverTxDemo` (all OFF by default)
- `DEVOURER_USB_SENTINEL=1` — 0xDEAD/0xBEEF writes to `REG_DUMMY
(0x04FC)` bracketing init, so `--phase-split` can use sentinels instead
of the gap heuristic.
- `DEVOURER_DRAIN_BULK_IN=1` — background bulk-IN drainer on EP 0x81
(kernel pre-arms 8×32KB; devourer in TX-only mode never had any IN URBs
in flight). With this gate the chip starts pushing 176–390 B C2H/status
messages back. Empirically necessary but not sufficient — does NOT alone
unblock on-air TX.
- `DEVOURER_POLL_INTR_IN=1` — EP 0x85 interrupt-IN poller. Confirmed
empirically the chip does NOT push on EP 0x85 during devourer init;
upstream's `CONFIG_USB_INTERRUPT_IN_PIPE` codepath is not load-bearing
for the TX gate. Kept as a diagnostic.
### Library change
`RtlUsbAdapter::ReadEFuseByte`: mirror the kernel's per-byte-read
`REG_EFUSE_TEST (0x0034) = 0x0000` (16-bit RD-then-WR), 312 times per
init. Removes a known concrete divergence flagged by the new diff.
Empirically harmless on its own (does NOT close the TX-on-air gate) but
matches upstream wire shape — useful as bisection ground truth.
### Real-capture findings (first watertight kernel-vs-devourer diff on
8814AU)
Kernel cold-init capture taken inside `devourer-testrig` VM (host kernel
6.18 cannot build `aircrack-ng/88XXau`); devourer-side on the host with
chip then handed back.
| Axis | Kernel | Devourer | Δ |
|---|---|---|---|
| Realtek ctrl writes | 6146 | 5399 | +747 |
| Realtek ctrl reads | 2337 | 1651 | +686 |
| Bulk-IN URBs (EP 0x81) | 8 × 32 KB | 0 | +8 |
| Reg 0x1998 (BB cal loop) | 1029 | 781 | **+248** ← biggest single-reg
|
| Reg 0x0034 (`REG_EFUSE_TEST`) | 312 | 0 → 312 (after patch) | closed |
| Path-A/B/C/D LSSI | 370 / 296 / 296 / 296 | 354 / 282 / 282 / 282 |
+14 each |
Hypotheses tested & falsified this session: FW-offload of path-A RF
table; EP 0x85 interrupt-IN polling; REG_CR missing MAC enables;
EFUSE_TEST 0x0034 missing writes; bulk-IN drainage as sufficient cause.
Strongest remaining open candidate: register 0x1998 (248-write deficit)
at `hal/phydm/rtl8814a/Hal8814_PhyTables.c:3607+` — a BB calibration
loop whose phydm conditional evaluates a different branch between kernel
and devourer.
## Test plan
- [x] `cmake --build build -j` clean
- [x] `python3 tests/test_usbmon_pcap_diff.py` — 8 cases pass
- [x] `python3 tests/test_urbscript_roundtrip.py` — pcap → urbs → replay
--dry-run pass
- [x] `WiFiDriverTxDemo` with `DEVOURER_USB_SENTINEL=1` runs init+TX
with 2 visible sentinel writes
- [x] Real pcapng captured via `tshark -i usbmon4 -s 0` parses cleanly;
phase-split lands on sentinel boundary deterministically
- [x] Kernel-side cold-init capture inside `devourer-testrig` VM, diff
against host devourer-side cold-init produces concrete divergence
numbers (table above)
- [ ] Followup PR: investigate and address the 0x1998 248-write deficit
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent be3c7cf commit 90970ca
9 files changed
Lines changed: 1764 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
212 | 212 | | |
213 | 213 | | |
214 | 214 | | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
215 | 228 | | |
216 | 229 | | |
217 | 230 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
0 commit comments