Skip to main content

Devourer Parity Audit

This page tracks the driver-level audit against the current devourer tree. The goal is practical parity: openipc-rs should issue the same class of USB, firmware, MAC, RF, RX, and TX operations while keeping a Rust-native API and using nusb instead of libusb directly.

The reference commit used for this pass was:

OpenIPC/devourer 011f7d3 Jaguar3 (RTL8822CU / RTL8812CU) userspace port (#102)

Audit Plan

The risky parts of this rewrite are the places where small byte/register differences do not fail at compile time. This is the checklist used for each chip family:

AreaWhat to compareRust locationFailure mode
USB discoveryVID/PID table, interface claim, endpoint selection, endpoint overrideopenipc-rtl88xx::SUPPORTED_DEVICES, RealtekDevicewrong adapter, wrong bulk OUT endpoint, no TX
Control transfer ABIRealtek vendor request, register width, endian orderasync_driver.rs, device.rsreads look plausible but write wrong registers
Firmware loadpower-on state, chunking, reserved-page/DDMA flow, firmware-ready pollsasync_firmware*.rs, async_jaguar3.rswarm-start works, cold-plug fails
MAC setupqueue/FIFO, DMA, RX engine, WMAC optionsasync_mac.rs, async_jaguar3.rsno bulk-IN frames or FIFO stalls
EFUSE/RFElogical-map decoding, RFE pinmux/table choices, TX power dataasync_efuse.rs, async_tables.rs, async_tx_power.rsworks on one dongle revision, fails on another
PHY/RF tablestable data, conditional opcodes, pseudo-delay entries, write orderrtl_data.rs, data/*, table loadersno RX sensitivity, wrong band, unstable TX
Channel/BWRF18 band bits, SCO, DFIR, 5/10 MHz reclock, 40/80 fallback behaviorasync_radio.rs, async_jaguar3.rstuned to the wrong channel or sample rate
RX descriptorsfield offsets, packet/C2H split, drvinfo/shift offset, 8-byte aggregate alignmentopenipc-core::realtekcorrupted 802.11 frames or missed C2H reports
TX descriptorsradiotap RATE/MCS/VHT parsing, 5 GHz CCK clamp, descriptor checksumopenipc-rtl88xx::txbulk OUT succeeds but nothing goes on-air
Runtime pollingcoex keepalive, thermal power tracking, PHYDM/watchdog hooksapp-owned RX loop plus explicit driver APIssustained TX degrades or stops
Shutdownstop TRX, close RX filter, power-off sequenceshutdown_monitor*adapter wedges until unplug/replug

Current Mapping

openipc-rs deliberately does not copy devourer's class layout. The important boundaries are:

  • openipc-rtl88xx owns USB, registers, firmware, RF, TX descriptor building, diagnostics, and explicit runtime hooks.
  • openipc-core owns byte-level RX aggregate parsing plus WFB/RTP/FEC payload handling.
  • apps own scheduling: receive loops, periodic diagnostics, WebUSB UI timing, and Tauri worker threads.

Executed Checks

Jaguar3 RTL8812CU / RTL8822CU

The current Rust driver includes the new devourer Jaguar3 work:

  • PIDs 0bda:c812, 0bda:c82c, and 0bda:c82e.
  • 24-byte Jaguar3 RX descriptor layout with packet length, CRC/ICV flags, driver-info size, shift size, RX rate, and C2H report bit.
  • 48-byte Jaguar3 TX descriptor layout, including the 16-bit descriptor checksum algorithm from cal_txdesc_chksum_8822c.
  • Firmware, MAC, USB, BB/AGC/RF, RFK, DACK, IQK, beamforming setup, monitor RX filters, TX path enable, WiFi-only coex setup, H2C keepalives, and thermal power/LCK tracking.
  • 5 MHz and 10 MHz narrowband retiming on top of 20 MHz channel tuning.
  • 40/80 MHz requests degrade to the 20 MHz path for Jaguar3, matching devourer's current behavior rather than pretending those modes are fully ported.
  • TX power override writes the same flat TXAGC reference class used by devourer for monitor inject/adaptive-link experiments.
  • Clean shutdown now mirrors devourer Stop(): halt TRX through CR, close RCR, then run the 8822C card-disable power sequence.

Regression tests now lock several high-risk bytes:

  • Jaguar3 RX descriptor field positions and payload offset after drvinfo/shift.
  • C2H report detection through descriptor word2 bit 28.
  • Jaguar3 TX descriptor field offsets.
  • 8822C TX descriptor checksum recomputation.
  • 5 GHz CCK-rate requests clamped to OFDM before descriptor encoding.

Jaguar1 RTL8812AU / RTL8821AU / RTL8814AU

The Rust code tracks the devourer behavior that matters for OpenIPC use:

  • supported Realtek/OEM VID/PID discovery,
  • firmware load and MAC/RF bring-up,
  • RFE-aware table selection,
  • EFUSE TX power data,
  • monitor filters and RX aggregate parsing,
  • radiotap-driven TX descriptor building,
  • RTL8814 firmware mode/chunk controls,
  • RTL8812/RTL8814 IQK,
  • RTL8812 power tracking,
  • PHYDM false-alarm/DIG watchdog hooks,
  • C2H and RTL8814 TX-status report surfacing.

The Rust crate keeps these as explicit APIs. The app decides whether they run in a native worker thread, a Tauri command, a browser loop, or a Web Worker.

Why App-Owned Polling

Devourer is a native process and can create background threads around libusb. openipc-rs is also a library for browsers and Tauri. A hidden polling thread inside the driver would not map cleanly to WebUSB and would make app shutdown harder to reason about.

For Jaguar3, devourer's coex thread does two jobs:

  1. drain firmware C2H reports from bulk-IN;
  2. every roughly two seconds, re-apply 5 GHz coex, power tracking, and H2C heartbeats.

OpenIPC Station already keeps bulk-IN transfers posted in its RX loop. The app also calls run_jaguar3_coex_keepalive and tick_power_tracking_8822c on a two-second cadence. The driver exposes the hooks; the app owns scheduling.

Test Strategy

No test can prove RF without hardware, but the repo should catch translation drift early:

  • unit tests for descriptor bit positions and checksums,
  • parser tests for aggregate alignment and C2H reports,
  • generated-table sanity tests for known table lengths and boundary values,
  • protocol tests for WFB session/decrypt/FEC behavior,
  • optional PixelPilot/zfex reference tests for FEC parity when the fixture path is available,
  • real-device cold-plug runs for each supported chip family,
  • register-trace comparison against devourer for cold start and channel switch,
  • sustained RX/TX tests with adaptive-link enabled.

The hardware tests are still required before claiming a specific adapter model is proven. Matching source code and byte-level tests greatly reduce risk, but they do not replace checking real USB timing, EFUSE variants, and RF behavior.

Remaining Validation Boundary

The implementation is standalone and does not link devourer. The current audit found one concrete parity gap and fixed it: Jaguar3 shutdown/deinit. The remaining boundary is hardware proof:

  • cold-plug RTL8812AU, RTL8821AU, RTL8814AU, RTL8812CU, and RTL8822CU runs,
  • register traces for init, channel switch, and shutdown,
  • sustained WebUSB receive,
  • sustained native/WebUSB adaptive TX,
  • adapter matrix across Linux, macOS, Windows, Android, and browser WebUSB.