Skip to content

RTL8814AU: devourer-TX produces 0 on-air frames despite 100% URB completion (post-#36) #50

@josephnef

Description

@josephnef

Symptom

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.

Concretely on master after PR #49:

# 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 set type 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:

  1. 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.
  2. 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.
  3. _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.
  4. 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.

Not in scope here

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.
  • The RTL8814AU: devourer TX degrades to LIBUSB_ERROR_IO after USB passthrough cycles #36 amendment comment chain (label correction → libusb refuted → root cause) documents the diagnostic path that landed here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions