RTL8814AU: end-to-end TX via opt-in kernel-driver init replay#29
Merged
Conversation
Two changes that together let an 8814AU chip actually transmit on-air
under devourer's monitor-mode injection path:
1. TX descriptor now byte-identical to the kernel-driver descriptor.
Verified by usbmon capture of an aircrack-ng/morrownr 8814au
kernel-driver session injecting a probe-request frame on the same
chip and channel, diffed against devourer's descriptor. Seven fields
differed; values previously came from speculative WIP comments that
didn't hold up empirically:
MACID = 1 (was 0) broadcast/default CAM
RATE_ID (non-VHT)= 8 (was 7) rate-table index
GID = 63 (was 0) no-group default
SW_DEFINE = 1 (was 0) DriverFixedRate flag
RETRY_LIMIT_ENABLE=1, DATA_RETRY_LIMIT=12 (were both 0)
SPE_RPT = 0 (was 1) kernel does not set
DISABLE_FB = 0 (was 1) kernel does not set
Devourer's first TX bulk-OUT now reads:
64002885 01120800 0000003f 00010000 00003200 00000000 \
01000000 76a90000
Byte-identical to the kernel-driver's TX descriptor.
2. Opt-in `DEVOURER_OOT_REPLAY=1` runs a verbatim replay of the
kernel-driver's post-fwdl vendor-write sequence at end of init.
Devourer's HAL init (even after PR #25/#26/#27) leaves the chip in
a state that diverges from the working kernel-driver in many small
ways which combine to wedge the chip's USB controller — bulk OUT
EP 0x02 NAKs every TX URB. With the replay applied, devourer's
chip-state matches the kernel byte-for-byte (verified via live
pyusb register dump) and TX URBs drain. Authoritative usbmon
capture during a 5-second steady-state TX window:
140-byte bulk OUT submitted: 566
completed status=0: 566
completed status<0: 0
With replay disabled (default), bulk OUT continues to time out at
the 500ms USB_TIMEOUT (unchanged behaviour vs prior master).
The replay table (hal/Hal8814_PostFwdlReplay.h, 4464 entries
covering the writes between the last fwdl bulk chunk and the first
TX bulk OUT in a kernel-driver usbmon capture) is opt-in because
it also includes BB writes that significantly slow the chip's RX
throughput (RX-packet rate drops ~10x in a 60-second window). The
tradeoff is acceptable for TX-only workloads (e.g. injection-only
monitor mode); RX-only users keep current behaviour by leaving the
env var unset.
Long-term, the replay should be replaced by porting the
equivalent upstream init functions individually
(rtl8814a_hal_init.c + usb_halinit.c) so TX works without the RX
trade-off and without 130KB of opaque trace data shipped in the
binary. The verbatim replay is the minimum that actually unblocks
TX today and serves as a regression checkpoint.
Verified on CF-938AC (0bda:8813, channel 6):
- Default (no env var): 8814 RX unchanged from master.
- DEVOURER_OOT_REPLAY=1: bulk OUT URBs complete status=0 from
the chip (usbmon-verified, repeatable across runs).
- TX descriptor matches kernel-driver byte-for-byte.
Note: on-air sniffer verification was not possible in the current lab
setup (the aircrack-ng 88XXau OOT driver needed for the 8812 sniffer
fails to build against kernel 6.18). The combined evidence
(usbmon-verified URB completions + byte-identical chip-state +
byte-identical descriptor as a known-working kernel-driver TX
session) supports the end-to-end TX claim, but air-side verification
on the receiving adapter is a follow-up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two changes that together let an 8814AU chip actually transmit on-air under devourer's monitor-mode injection path:
1. TX descriptor byte-identical to kernel-driver
Verified by usbmon capture of an aircrack-ng/morrownr 8814au kernel-driver session injecting a probe-request frame on the same chip and channel, diffed against devourer's descriptor. Seven fields differed:
MACIDRATE_ID(non-VHT)GID0x3F)SW_DEFINEDriverFixedRateflagRETRY_LIMIT_ENABLEDATA_RETRY_LIMITrtl8814au_xmit.c:267SPE_RPTDISABLE_FBDevourer's first TX bulk-OUT now reads
64002885 01120800 0000003f 00010000 00003200 00000000 01000000 76a90000— byte-identical to the kernel-driver's TX descriptor.2. Opt-in
DEVOURER_OOT_REPLAY=1Runs a verbatim replay of the kernel-driver's post-fwdl vendor-write sequence (4464 writes between the last fwdl bulk chunk and first TX bulk OUT, captured via usbmon) at end of init.
Devourer's HAL init even after PRs #25/#26/#27 leaves the chip in a state that diverges from the kernel-driver in many small ways which combine to wedge the chip's USB controller — bulk OUT EP 0x02 NAKs every TX URB. With the replay applied, devourer's chip-state matches the kernel byte-for-byte (verified via live pyusb register dump) and TX URBs drain.
Authoritative usbmon capture, 5-second steady-state TX window:
(Repeatable across multiple runs.)
With replay disabled (default), bulk OUT continues to time out at the 500ms
USB_TIMEOUT— unchanged behaviour vs prior master.Why opt-in and not default-on
The replay's BB writes significantly slow the chip's RX throughput (RX-packet rate drops ~10× in a 60-second window). The trade-off is acceptable for TX-only workloads (injection-only monitor mode); RX-only users keep current behaviour by leaving the env var unset.
Long-term path
Replace the verbatim replay by porting the equivalent upstream init functions individually (
rtl8814a_hal_init.c+usb_halinit.c) so TX works without the RX trade-off and without 130 KB of opaque trace data shipped in the binary. The verbatim replay is the minimum that actually unblocks TX today and serves as a regression checkpoint while the functions get ported.How to use
# 8814AU TX from monitor mode: sudo DEVOURER_PID=0x8813 DEVOURER_CHANNEL=6 DEVOURER_OOT_REPLAY=1 \ ./build/WiFiDriverTxDemoVerification done
WiFiDriverDemoon0bda:8813)DEVOURER_OOT_REPLAY=1: bulk OUT URBs completestatus=0from the chip (usbmon-verified across multiple runs)Not verified
On-air sniffer verification was not possible in the current lab setup — the aircrack-ng 88XXau OOT driver needed for the 8812 sniffer fails to build against kernel 6.18. The combined evidence (usbmon-verified URB completions + byte-identical chip-state + byte-identical descriptor as a known-working kernel-driver TX session) supports the end-to-end TX claim, but air-side verification on a receiving adapter is a follow-up.
🤖 Generated with Claude Code