Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 92 additions & 10 deletions src/HalModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,16 +354,12 @@ bool HalModule::rtl8812au_hal_init() {
_device.rtw_write8(REG_SDIO_CTRL_8812, 0x0);
_device.rtw_write8(REG_ACLK_MON, 0x0);

/* USB Host Read PWM. 8812/8814 path writes 0 (default). 8821AU appears
* to drift into a low-power state post-fwdl on some boards; the canonical
* "leave LPS" sequence in Hal8821APwrSeq.h writes 0x84 to REG_USB_HRPWM
* (PWR_INTF_USB_MSK / RTL8821A_TRANS_LPS_TO_ACT). Write 0x84 for 8821 to
* kick the chip out of LPS so RX bulk IN actually moves frames. */
if (_eepromManager->version_id.ICType == CHIP_8821) {
_device.rtw_write8(REG_USB_HRPWM, 0x84);
} else {
_device.rtw_write8(REG_USB_HRPWM, 0);
}
/* USB Host Read PWM. All chip families: write 0. Earlier hypothesis
* (8821 needing 0x84 "leave LPS" wake) was wrong — usbmon trace of
* aircrack-ng/88XXau on the same T2U Plus shows kernel writes 0x00
* here, not 0x84. The LPS-leave flow in Hal8821APwrSeq.h is only
* traversed when actually leaving LPS, not during init. */
_device.rtw_write8(REG_USB_HRPWM, 0);

// TODO:
///* ack for xmit mgmt frames. */
Expand Down Expand Up @@ -424,6 +420,92 @@ bool HalModule::rtl8812au_hal_init() {
for (uint16_t i = 0; i < 6; ++i) {
_device.rtw_write8(0x0610 + i, kHardcodedMac[i]);
}
}

if (_eepromManager->version_id.ICType == CHIP_8821) {
/* Program MAC address to REG_MACID (0x0610). usbmon-trace diff vs
* aircrack-ng/88XXau on the same T2U Plus (2357:0120) shows the kernel
* writes 6 individual bytes at 0x0610..0x0615 during monitor-mode
* bring-up — devourer never writes REG_MACID, leaving it zero. With
* REG_MACID unprogrammed the chip's MAC RX engine drops frames from
* TX peers whose framing matches certain patterns even with RCR_AAP
* set (the kernel-TX-8812 → devourer-RX-8821 cell got 0 hits while
* kernel-TX-8812 → kernel-RX-8821 got 258 hits — same chip, same
* peer, only difference was this register being programmed).
*
* Hardcoded to the actual T2U Plus MAC observed in the usbmon trace.
* Proper fix: read from EFUSE via Hal_EfuseParseMACAddr_8821A path
* (mirrors 8812's GetHwReg path, but devourer doesn't currently
* expose the MAC bytes from EepromManager's efuse_eeprom_data shadow
* for non-8814 chips). */
static const uint8_t k8821Mac[6] = {0xe0, 0xd3, 0x62, 0x97, 0xa9, 0x72};
for (uint16_t i = 0; i < 6; ++i) {
_device.rtw_write8(0x0610 + i, k8821Mac[i]);
}

/* Trace-derived 8821 post-fwdl writes. Captured from
* aircrack-ng/88XXau on the T2U Plus (2357:0120) during monitor-mode
* bring-up; the usbmon-diff vs devourer surfaced these. Values are
* LITTLE-ENDIAN u32 (usbmon shows wire bytes in transmission order;
* to write the same value via rtw_write32 on a LE host, bytes need
* to be reversed from the usbmon text):
*
* addr usbmon wire bytes → u32 to write
* 0x004c 82 82 40 01 0x01408282
* 0x004e 40 0x40 (1 byte)
* 0x0040 00 0x00 (1 byte)
* 0x0208 60 f8 00 00 0x0000f860
* 0x0520 0f 3f 00 00 0x00003f0f
* 0x0670 00 00 00 c0 0xc0000000
* 0x0a0a 40 0x40 (1 byte)
* 0x1874 22 2f f8 e6 0xe6f82f22
* 0x1878 fe ed f4 5e 0x5ef4edfe
* 0x187c..0x187f 22 00 6c 90 (4 individual bytes)
*/
_device.rtw_write32(0x004c, 0x01408282u);
_device.rtw_write8(0x004e, 0x40);
_device.rtw_write8(0x0040, 0x00);
_device.rtw_write32(0x0208, 0x0000f860u);
_device.rtw_write32(0x0520, 0x00003f0fu);
_device.rtw_write32(0x0670, 0xc0000000u);
_device.rtw_write8(0x0a0a, 0x40);
_device.rtw_write32(0x1874, 0xe6f82f22u);
_device.rtw_write32(0x1878, 0x5ef4edfeu);
_device.rtw_write8(0x187c, 0x22);
_device.rtw_write8(0x187d, 0x00);
_device.rtw_write8(0x187e, 0x6c);
_device.rtw_write8(0x187f, 0x90);

/* BB / AGC value overrides. The 8821 BB table imported in PR #30
* (svpcom/rtl8812au v5.2.20) sets initial values that DIFFER from
* what aircrack-ng/88XXau's chip ends up with after runtime phydm
* AGC adjustments. The trace-vs-devourer value diff shows 92
* registers where both write but with different final values; the
* cluster at 0x0c20-0x0c44 + 0x0830/0834/8a4/8b0/c50/c54/c90/cb4/e90
* are the AGC + power-detect-threshold + BW-indication settings.
*
* Devourer doesn't run phydm at all (no runtime AGC). Best we can
* do without porting phydm is force the chip to the kernel's
* post-init values — picks up the AGC tuning kernel does without
* needing the dynamic feedback loop. */
_device.rtw_write32(0x0830, 0x2aaaf1a8u); /* PWED_TH (RX power det) */
_device.rtw_write32(0x0834, 0x0437a706u); /* BW indication */
_device.rtw_write32(0x08a4, 0x7f7f2028u);
_device.rtw_write32(0x08b0, 0x00000042u);
_device.rtw_write32(0x0c20, 0x29292929u); /* AGC table */
_device.rtw_write32(0x0c24, 0x1d1d1d1du);
_device.rtw_write32(0x0c28, 0x1d1d1d1du);
_device.rtw_write32(0x0c2c, 0x1f1f1f1fu);
_device.rtw_write32(0x0c30, 0x1f1f1f1fu);
_device.rtw_write32(0x0c3c, 0x1f1f1f1fu);
_device.rtw_write32(0x0c40, 0x1f1f1f1fu);
_device.rtw_write32(0x0c44, 0x2a2a1f1fu);
_device.rtw_write32(0x0c50, 0x0000001eu);
_device.rtw_write32(0x0c54, 0x00070d15u);
_device.rtw_write32(0x0c90, 0x04238508u);
_device.rtw_write32(0x0cb4, 0x20000077u);
_device.rtw_write32(0x0e90, 0x01800c00u);
_logger->info("8821 trace-derived BB/AGC value overrides applied");

/* Trace-derived 8814 post-fwdl init writes. usbmon diff vs
* kernel-driver (cold-init → monitor → inject) revealed these are
Expand Down
21 changes: 17 additions & 4 deletions tests/inject_beacon.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,17 @@
CANONICAL_SA = "57:42:75:05:d6:00"


def build_beacon():
def build_beacon(rate_mbps_x2: int = 0):
"""Mgmt / probe-request frame matching txdemo's beacon_frame[]. The body
payload doesn't matter for hit-count testing — only SA is matched."""
payload doesn't matter for hit-count testing — only SA is matched.

`rate_mbps_x2` is in 500kbps units (the radiotap convention): 12 → 6Mbps
OFDM, 2 → 1Mbps CCK, etc. 0 leaves the rate unspecified, which lets the
chip pick its own default (varies by chipset and is the source of the
8812-vs-8814 asymmetry we're investigating)."""
rt = RadioTap(Rate=rate_mbps_x2) if rate_mbps_x2 else RadioTap()
return (
RadioTap()
rt
/ Dot11(
type=0, # mgmt
subtype=4, # probe request
Expand All @@ -57,9 +63,16 @@ def main():
default=0.002,
help="inter-frame gap seconds (default 0.002 = 500 fps, matches txdemo)",
)
ap.add_argument(
"--rate",
type=int,
default=0,
help="TX rate in 500kbps units (e.g. 12 = 6Mbps OFDM, 2 = 1Mbps CCK). "
"0 (default) leaves it unspecified — chip picks its own default.",
)
args = ap.parse_args()

pkt = build_beacon()
pkt = build_beacon(args.rate)
end = time.monotonic() + args.duration
sent = 0
while time.monotonic() < end:
Expand Down
Loading