You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
After PR #49 fixed the bulk-OUT FIFO wedge (#36), devourer-TX on RTL8814AU (0bda:8813) achieves 100% URB submission + completion success at the libusb / kernel level — but produces 0 frames on-air as observed by an AR9271 peer sniffer on the same channel filtering for the canonical SA 57:42:75:05:d6:00.
# devourer-TX 12s on 8814AU, ch 6
WiFiDriverTxDemo:
submits: 2203
complete: 2203 ← chip ACK'd every URB at the USB layer
fail: 0
# Concurrent AR9271 sniffer:
canonical-SA frames captured: 0
For RTL8812AU and RTL8821AU under the same harness, on-air capture is ~95% — so this is 8814-specific, not a generic test-rig problem.
Reproduce
# AR9271 (or any chip with vanilla radiotap monitor mode) on the canonical channel
sudo ip link set wlp0s20f0u14 down
sudo iw dev wlp0s20f0u14 settype monitor
sudo ip link set wlp0s20f0u14 up
sudo iw dev wlp0s20f0u14 set channel 6
# Sniffer (background)
sudo tcpdump -i wlp0s20f0u14 -nn -e -s 0 -w /tmp/sniff.pcap \
'wlan addr2 57:42:75:05:d6:00'&# devourer-TX on 8814AU
sudo timeout 12 env DEVOURER_PID=0x8813 DEVOURER_CHANNEL=6 \
./build/WiFiDriverTxDemo
# Count
sudo tcpdump -nn -r /tmp/sniff.pcap | wc -l # expect 0
What's known (from 2026-05-26 investigation)
The same chip, when initialized + driven by the in-kernel aircrack-ng/88XXau driver via qemu USB passthrough to devourer-testrig VM and TX'd via tests/inject_beacon.py, produces ~95% on-air capture (e.g. 237/248 frames at −48 dBm). So the chip hardware + RF chain can TX; the gate is in how devourer drives it.
But the gate is not in the libusb-userspace USB driving layer either:
A direct USBDEVFS_SUBMITURB PoC (no libusb) submitted 500 × 140-byte devourer-format URBs to a chip just initialized by 88XXau in the VM. URBs completed cleanly at the USB layer (500/500 OK, 140 µs mean latency). Sniffer still captured 0 frames on-air.
A separate sister-project (LKL + libusb HCD + aircrack-ng/88XXau driver verbatim, no devourer code) on the same chip with kernel-driver init also produced 0 on-air despite 2000/2000 USB submits clean.
So the gate is above USB driving and above chip RF init — it's most likely in what's being submitted (TX-descriptor format, rate config, or some chip-state mismatch between kernel-init and devourer-init that affects how the chip interprets bulk-OUT payloads).
Candidate hypotheses to test:
TX-descriptor format mismatch. devourer builds a 32-byte TX descriptor wrapping radiotap+frame (src/RtlJaguarDevice.cpp:send_packet). The 8814A's rtl8812a_hal.h macros (SET_TX_DESC_*_8812) are shared with 8812; perhaps 8814 needs a different descriptor variant or different QUEUE_SEL / MACID / RATE_ID bits.
Rate / MCS field interpretation. devourer's TX descriptor sets fixed rate:2 (per log); the chip may need a different RATE_ID for 8814 monitor-mode injection.
_InitQueueReservedPage_8814AUsb page count + auto-LLT result. Today's bisect noted auto-LLT "completes in 0 polls" (REG_AUTO_LLT_8814A=0x00000010) — could be near-instant kernel-style behavior, or could be the BIT16 trigger never actually setting. Read-back of FIFO page counts after init would confirm.
PHY/RF init step missing or out-of-order vs kernel. The kaeru reference RTL8814AU TX gate narrowed to path-A radio table application bisected upstream's 8814au.ko in May 2026 and found phy_RF6052_Config_ParaFile_8814A path-A radio table is essential for on-air TX. devourer ports this table — but the chip-state at table-load time may differ from kernel's.
Acceptance criteria
tests/regress.py --full-matrix --channel 100 --vm-name devourer-testrig --vm-ssh josephnef@... shows ≥ 1 hit in 8814AU devourer-TX cells [2, 4, 6, 8].
Or equivalently: AR9271 sniffer captures ≥ 100 canonical-SA frames during a 12 s WiFiDriverTxDemo run on 8814AU.
8814AU devourer-RX (chip emits frames but devourer doesn't receive them) — separate issue, separate gate, separate ticket.
Diagnostic artifacts from today's session
tools/usbmon_diff.py — kernel-6.18 text-format usbmon parser + diff. Use to compare libusb-routed vs kernel-routed (via qemu-passthrough) URB streams on the same chip. Useful for any follow-up bisect.
/tmp/usbdevfs_poc.c — standalone direct-ioctl bulk-OUT PoC. Reusable for "is libusb the bottleneck?" questions.
Symptom
After PR #49 fixed the bulk-OUT FIFO wedge (#36),
devourer-TXon RTL8814AU (0bda:8813) achieves 100% URB submission + completion success at the libusb / kernel level — but produces 0 frames on-air as observed by an AR9271 peer sniffer on the same channel filtering for the canonical SA57:42:75:05:d6:00.Concretely on master after PR #49:
For RTL8812AU and RTL8821AU under the same harness, on-air capture is ~95% — so this is 8814-specific, not a generic test-rig problem.
Reproduce
What's known (from 2026-05-26 investigation)
The same chip, when initialized + driven by the in-kernel
aircrack-ng/88XXaudriver via qemu USB passthrough todevourer-testrigVM and TX'd viatests/inject_beacon.py, produces ~95% on-air capture (e.g. 237/248 frames at −48 dBm). So the chip hardware + RF chain can TX; the gate is in how devourer drives it.But the gate is not in the libusb-userspace USB driving layer either:
USBDEVFS_SUBMITURBPoC (no libusb) submitted 500 × 140-byte devourer-format URBs to a chip just initialized by 88XXau in the VM. URBs completed cleanly at the USB layer (500/500 OK, 140 µs mean latency). Sniffer still captured 0 frames on-air.So the gate is above USB driving and above chip RF init — it's most likely in what's being submitted (TX-descriptor format, rate config, or some chip-state mismatch between kernel-init and devourer-init that affects how the chip interprets bulk-OUT payloads).
Candidate hypotheses to test:
src/RtlJaguarDevice.cpp:send_packet). The 8814A'srtl8812a_hal.hmacros (SET_TX_DESC_*_8812) are shared with 8812; perhaps 8814 needs a different descriptor variant or differentQUEUE_SEL/MACID/RATE_IDbits.fixed rate:2(per log); the chip may need a different RATE_ID for 8814 monitor-mode injection._InitQueueReservedPage_8814AUsbpage count + auto-LLT result. Today's bisect noted auto-LLT "completes in 0 polls" (REG_AUTO_LLT_8814A=0x00000010) — could be near-instant kernel-style behavior, or could be the BIT16 trigger never actually setting. Read-back of FIFO page counts after init would confirm.RTL8814AU TX gate narrowed to path-A radio table applicationbisected upstream's 8814au.ko in May 2026 and foundphy_RF6052_Config_ParaFile_8814Apath-A radio table is essential for on-air TX. devourer ports this table — but the chip-state at table-load time may differ from kernel's.Acceptance criteria
tests/regress.py --full-matrix --channel 100 --vm-name devourer-testrig --vm-ssh josephnef@...shows ≥ 1 hit in 8814AU devourer-TX cells [2, 4, 6, 8].Or equivalently: AR9271 sniffer captures ≥ 100 canonical-SA frames during a 12 s
WiFiDriverTxDemorun on 8814AU.Not in scope here
devourer-RX(chip emits frames but devourer doesn't receive them) — separate issue, separate gate, separate ticket.Diagnostic artifacts from today's session
tools/usbmon_diff.py— kernel-6.18 text-format usbmon parser + diff. Use to compare libusb-routed vs kernel-routed (via qemu-passthrough) URB streams on the same chip. Useful for any follow-up bisect./tmp/usbdevfs_poc.c— standalone direct-ioctl bulk-OUT PoC. Reusable for "is libusb the bottleneck?" questions.