Skip to content

RTL8821AU: trace-derived register-init parity (partial — does not fix RX asymmetry)#37

Merged
josephnef merged 1 commit into
masterfrom
feat/rtl8821au-trace-derived-parity
May 23, 2026
Merged

RTL8821AU: trace-derived register-init parity (partial — does not fix RX asymmetry)#37
josephnef merged 1 commit into
masterfrom
feat/rtl8821au-trace-derived-parity

Conversation

@josephnef
Copy link
Copy Markdown
Collaborator

Status: partial — register-state parity with kernel, but doesn't fix #30's 8812-peer asymmetry

Brings devourer's CHIP_8821 init register-write set into parity with aircrack-ng/88XXau's post-fwdl monitor-mode bring-up, based on a usbmon-trace diff. Adds 13 missing post-fwdl writes, 17 BB/AGC value overrides, MAC-address programming, and corrects an earlier wrong guess at REG_USB_HRPWM.

This does NOT fix the asymmetry (devourer-RX 8821 catches kernel-TX 8814 frames but drops kernel-TX 8812 frames at 0/280) that #34 surfaced. The cheap "what's different at the register level" patches don't cross the threshold. Filing anyway because it's honest progress + brings the chip's baseline state into kernel parity, which the next fix attempt can build on.

What this changes

Where Change
HalModule.cpp::rtl8812au_hal_init REG_USB_HRPWM for CHIP_8821: 0x84 → 0x00 (kernel writes 0; my earlier "leave LPS wake" guess was wrong)
HalModule.cpp::rtl8812au_hal_init CHIP_8821: program MAC address to REG_MACID (0x0610-0x0615). Kernel always does this even in monitor; some chip RX-path logic gates on MACID being non-zero.
HalModule.cpp::rtl8812au_hal_init CHIP_8821: 13 trace-derived post-fwdl writes (REG_AUTO_LLT region, REG_TX_PTCL_CTRL, NAV-related, 8821 BB high-addr block 0x1874-0x187f)
HalModule.cpp::rtl8812au_hal_init CHIP_8821: 17 BB/AGC value overrides (0x0830 PWED_TH, 0x0c20-0x0c44 AGC table, 0x0e90 TX power region) forced to kernel's observed runtime values
tests/inject_beacon.py --rate CLI arg (added during rate-decode hypothesis testing; useful diagnostic knob)

8812AU + 8814AU paths untouched.

Why the RX gap probably remains

Aircrack-ng runs phydm — a runtime feedback loop that continually adjusts AGC / RX-gain based on observed signal quality. This PR sets the chip's static values to match kernel's post-init snapshot, but the chip needs the active loop to maintain them during RX. Without phydm running, the chip drifts back toward defaults that work for higher-SNR peers (8814) but not for 8812.

Three follow-up paths to actually fix the asymmetry:

  1. Port phydm runtime for 8821 (substantial — most of aircrack-ng/hal/phydm/rtl8821a/). Days of work, cleanest fix.
  2. Loop-replay: capture kernel's full register sequence over a 5-second RX window (not just init) and replay periodically from devourer. Hacky but cheap.
  3. Accept devourer-RX 8821 as "works for some peers, not others" until phydm is in. Document the limit in the adapter inventory.

usbmon methodology (for future trace-diff work)

Capture kernel side (in VM with aircrack-ng/88XXau):

# On VM:
sudo modprobe usbmon
sudo bash -c "cat /sys/kernel/debug/usb/usbmon/0u > /tmp/trace_kernel.txt &"
# Then attach DUT via virsh, bring up monitor mode, stop usbmon

Capture devourer side (on host):

sudo bash -c "timeout 20 cat /sys/kernel/debug/usb/usbmon/Nu > /tmp/trace_dvr.txt" &
sudo ./build/WiFiDriverDemo ...

Filter Realtek control writes:

grep -E "S Co:.* 40 05 " trace.txt | awk '{print $8, $13}'

Important encoding gotcha: usbmon shows wire bytes in transmission order (= LE u32's byte sequence). To write the same value via rtw_write32 on a LE host, the u32 value is read-as-LE — so the trace text 82824001 represents u32 0x01408282 (NOT 0x82824001). The first attempt at the post-fwdl writes in this PR used wrong-endian values and naturally had no effect; the fix was to byte-pair-reverse them.

Validation

Single-pair test on the trainer rig (Arch host, Ubuntu 22.04 VM with aircrack-ng/88XXau, channel 100, 10s):

Cell Hits Note
kernel-TX 8812 → kernel-RX 8821 (baseline) 283 ✓ rig sane
devourer-TX 8821 → kernel-RX 8814 4663 ✓ dvr-TX 8821 fine
kernel-TX 8812 → devourer-RX 8821 0 ✗ the asymmetry — unresolved
devourer-TX 8821 → devourer-RX 8812 0 ✗ same

Other chips untouched.

Test plan

  • Builds clean
  • CHIP_8812 + CHIP_8814A paths unchanged
  • CHIP_8821 init now writes the kernel-equivalent register set
  • devourer-TX 8821 still works → kernel-RX 8814 (4663 hits)
  • dvr-RX 8821 ↔ 8812 — known not fixed by this PR
  • phydm runtime ported (follow-up)

Refs #30 (initial 8821 port), #34 (full matrix that surfaced the asymmetry).

🤖 Generated with Claude Code

Brings devourer's CHIP_8821 init register-write set into parity with
aircrack-ng/88XXau's post-fwdl monitor-mode bring-up, based on a
usbmon-trace diff of both drivers running on the same T2U Plus
(2357:0120). Adds 13 missing post-fwdl writes, 17 BB/AGC value
overrides, MAC-address programming, and corrects the earlier
REG_USB_HRPWM=0x84 to 0x00 (the LPS-leave wake was a wrong guess —
kernel writes 0x00 here during init).

WHAT THIS DOES NOT FIX
======================

The 8812-peer-asymmetry symptom reported in #30 / surfaced in #34's
full matrix (devourer-RX 8821 catches kernel-TX 8814 at ~200 hits/cell
but gets 0 hits from kernel-TX 8812 — verified asymmetric across
single-pair retests, same chip, same channel) is **NOT fixed** by this
PR. The "what's different at the register level" patches don't cross
the threshold.

Most likely reason: aircrack-ng's runtime phydm continually adjusts
AGC / RX-gain based on observed signal quality. This PR snapshots
kernel's post-init register values — but the chip needs the ACTIVE
feedback loop to maintain them during RX. Without phydm, the chip
drifts back toward defaults that work for higher-SNR peers (8814)
but not lower-SNR ones (8812).

So this PR is partial. The follow-up paths are:

  1. Port phydm runtime — substantial code import from
     aircrack-ng/hal/phydm/rtl8821a/. Days of work. Cleanest fix.
  2. Loop-replay — capture kernel's full register sequence over a
     5-second RX window (not just init) and replay periodically.
     Hacky but cheap.
  3. Accept devourer-RX 8821 as "works for some peers, not others"
     until phydm is in. Document in adapter matrix.

WHAT THIS DOES
==============

Even though it doesn't fix the RX gap, this PR is worth landing because
it brings the chip's *baseline* register state into kernel parity. That:

- Removes 1 register's worth of wrong guesses (REG_USB_HRPWM)
- Adds programmed MAC address (kernel always does this; some chip
  RX-path logic gates on MACID being non-zero even in monitor mode)
- Adds REG_AUTO_LLT / REG_TX_PTCL_CTRL / NAV-related / BB-high-addr
  writes the kernel does — these are not optional from the chip's
  point of view, just under-tested in devourer until now
- Forces 17 BB/AGC values to kernel's observed runtime state, which
  may help future phydm-runtime work start from a sane baseline
- Folds in `--rate` arg for tests/inject_beacon.py (added during
  rate-decode hypothesis testing — useful diagnostic knob to keep)

USBMON METHODOLOGY (for future trace-diff work)
================================================

Capture kernel side (in VM with aircrack-ng/88XXau):

    # On VM:
    sudo modprobe usbmon
    sudo bash -c "cat /sys/kernel/debug/usb/usbmon/0u > /tmp/trace_kernel.txt &"
    # Then attach DUT via virsh, bring up monitor mode, stop usbmon

Capture devourer side (on host):

    sudo bash -c "timeout 20 cat /sys/kernel/debug/usb/usbmon/Nu > /tmp/trace_dvr.txt" &
    sudo ./build/WiFiDriverDemo ...

Filter Realtek control writes:

    grep -E "S Co:.* 40 05 " trace.txt | awk '{print $8, $13}'

Important encoding gotcha: usbmon shows wire bytes in transmission
order (= LE u32's byte sequence). To write the same value via
rtw_write32 on a LE host, the u32 value is read-as-LE — so the trace
text "82824001" represents u32 0x01408282 (NOT 0x82824001). This bit
me — the first attempt at the post-fwdl writes used wrong-endian
values and naturally had no effect.

VALIDATION
==========

Single-pair test on trainer-arch + VM, channel 100:

  kernel-TX 8812 → kernel-RX 8821 (baseline)  283 hits ✓
  devourer-TX 8821 → kernel-RX 8814           4663 hits ✓ (8821 TX path solid)
  kernel-TX 8812 → devourer-RX 8821           0 hits ✗ (the asymmetry — unresolved)
  devourer-TX 8821 → devourer-RX 8812         0 hits ✗ (same — TX 8821 doesn't reach 8812 RX in either driver combo)

Other chips (8812, 8814) untouched by this PR — only CHIP_8821
dispatch paths modified.

Refs #30 (initial 8821 port), #34 (full matrix that surfaced the
asymmetry).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@josephnef josephnef merged commit f2bb505 into master May 23, 2026
4 of 5 checks passed
@josephnef josephnef deleted the feat/rtl8821au-trace-derived-parity branch May 23, 2026 12:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant