mirror of
https://github.com/shenmintao/aic8800d80.git
synced 2026-11-10 16:49:17 +00:00
fix: use confirmation descriptors for monitor raw frames
Route raw frames through the USB/SDIO confirmation rings, as reported by ggorbi99-dev in issue #123. Keep monitor support opt-in and document the limits of firmware and rate validation.
This commit is contained in:
1 parent
4536a96e48
commit
85b6678b6b
3 files changed
+163
-2
No files matched your search
@@ -642,7 +642,8 @@ void rwnx_tx_push(struct rwnx_hw *rwnx_hw, struct rwnx_txhdr *txhdr, int flags)
|
|||||||
rwnx_ipc_txdesc_push(rwnx_hw, &sw_txhdr->desc, skb, hw_queue, user);
|
rwnx_ipc_txdesc_push(rwnx_hw, &sw_txhdr->desc, skb, hw_queue, user);
|
||||||
#else
|
#else
|
||||||
#ifdef AICWF_SDIO_SUPPORT
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
if( ((sw_txhdr->desc.host.flags & TXU_CNTRL_MGMT) && \
|
/* Raw monitor frames also need a firmware confirmation-ring descriptor. */
|
||||||
|
if( sw_txhdr->raw_frame || ((sw_txhdr->desc.host.flags & TXU_CNTRL_MGMT) && \
|
||||||
((*(skb->data+sw_txhdr->headroom)==0xd0) || (*(skb->data+sw_txhdr->headroom)==0x10) || (*(skb->data+sw_txhdr->headroom)==0x30))) || \
|
((*(skb->data+sw_txhdr->headroom)==0xd0) || (*(skb->data+sw_txhdr->headroom)==0x10) || (*(skb->data+sw_txhdr->headroom)==0x30))) || \
|
||||||
(sw_txhdr->desc.host.ethertype == 0x8e88) ) { // 0xd0:Action, 0x10:AssocRsp, 0x8e88:EAPOL
|
(sw_txhdr->desc.host.ethertype == 0x8e88) ) { // 0xd0:Action, 0x10:AssocRsp, 0x8e88:EAPOL
|
||||||
sw_txhdr->need_cfm = 1;
|
sw_txhdr->need_cfm = 1;
|
||||||
@@ -671,7 +672,8 @@ void rwnx_tx_push(struct rwnx_hw *rwnx_hw, struct rwnx_txhdr *txhdr, int flags)
|
|||||||
aicwf_frame_tx((void *)(rwnx_hw->sdiodev), skb);
|
aicwf_frame_tx((void *)(rwnx_hw->sdiodev), skb);
|
||||||
#endif
|
#endif
|
||||||
#ifdef AICWF_USB_SUPPORT
|
#ifdef AICWF_USB_SUPPORT
|
||||||
if( ((sw_txhdr->desc.host.flags & TXU_CNTRL_MGMT) && \
|
/* Bit 30's fixed-rate descriptor silently drops injected D80 frames. */
|
||||||
|
if( sw_txhdr->raw_frame || ((sw_txhdr->desc.host.flags & TXU_CNTRL_MGMT) && \
|
||||||
((*(skb->data+sw_txhdr->headroom)==0xd0) || (*(skb->data+sw_txhdr->headroom)==0x10) || (*(skb->data+sw_txhdr->headroom)==0x30))) || \
|
((*(skb->data+sw_txhdr->headroom)==0xd0) || (*(skb->data+sw_txhdr->headroom)==0x10) || (*(skb->data+sw_txhdr->headroom)==0x30))) || \
|
||||||
(sw_txhdr->desc.host.ethertype == 0x8e88) || (sw_txhdr->desc.host.ethertype == 0xb488)) {
|
(sw_txhdr->desc.host.ethertype == 0x8e88) || (sw_txhdr->desc.host.ethertype == 0xb488)) {
|
||||||
// 0xd0:Action, 0x10:AssocRsp, 0x8e88:EAPOL, 0xb488: WAPI
|
// 0xd0:Action, 0x10:AssocRsp, 0x8e88:EAPOL, 0xb488: WAPI
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# Monitor TX confirmation regression
|
||||||
|
|
||||||
|
Run `python3 tests/monitor/test_tx_confirm.py`. The fixture compiles the actual
|
||||||
|
USB and SDIO descriptor-selection blocks from `rwnx_tx_push()` with mocked
|
||||||
|
transport functions. It checks raw frames, normal management frames, EAPOL,
|
||||||
|
USB-specific WAPI handling, ordinary/fixed-rate data, ring registration before
|
||||||
|
transport submission, and accounting deferred until confirmation. It does not
|
||||||
|
send frames or model firmware, USB completion, or radio behavior.
|
||||||
|
|
||||||
|
To compare another revision, pass `--source /path/to/rwnx_tx.c`.
|
||||||
|
|
||||||
|
Build the optional monitor path with prepared kernel headers:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bash tests/kernel-build/build.sh /path/to/kernel/build CC=gcc-14 CONFIG_RWNX_MON_DATA=y
|
||||||
|
```
|
||||||
|
|
||||||
|
`CONFIG_RWNX_MON_XMIT` already defaults to `y`; `CONFIG_RWNX_MON_DATA` remains
|
||||||
|
opt-in. For hardware verification, re-open the monitor interface before setting
|
||||||
|
its channel and use a second radio on the same channel to capture a short
|
||||||
|
beacon/probe-request test on equipment you control. Check both 2.4 and 5 GHz,
|
||||||
|
normal station traffic after the test, and interface teardown/recreation.
|
||||||
|
|
||||||
|
The confirmation descriptor carries a ring index instead of the fixed-rate
|
||||||
|
encoding. Radiotap-selected rates are not established by this check. Other
|
||||||
|
chips, SDIO hardware and arbitrary raw data frames also require hardware
|
||||||
|
validation.
|
||||||
|
|
||||||
|
Based on ggorbi99-dev's [issue #123](https://github.com/shenmintao/aic8800d80/issues/123).
|
||||||
|
The contributor reports over-the-air validation on a D80 MCU1 USB adapter;
|
||||||
|
that report is not a hardware test of these commits or of the `main` firmware.
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Test descriptor routing using the actual USB/SDIO rwnx_tx_push blocks."""
|
||||||
|
from pathlib import Path
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--source", type=Path,
|
||||||
|
default=ROOT / "drivers/aic8800/aic8800_fdrv/rwnx_tx.c")
|
||||||
|
args, remaining = parser.parse_known_args()
|
||||||
|
|
||||||
|
PRELUDE = r'''
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#define TXU_CNTRL_MGMT (1 << 3)
|
||||||
|
#define AICWFDBG(...) ((void)0)
|
||||||
|
struct sk_buff { unsigned char data[80]; };
|
||||||
|
struct vif { struct { int tx_packets, tx_bytes; } net_stats; };
|
||||||
|
struct rwnx_sw_txhdr {
|
||||||
|
struct { struct { unsigned int flags, ethertype, status_desc_addr, staid; } host; } desc;
|
||||||
|
int raw_frame, fixed_rate, need_cfm, headroom, frame_len;
|
||||||
|
unsigned int rate_config;
|
||||||
|
struct vif *rwnx_vif;
|
||||||
|
};
|
||||||
|
struct env { unsigned int txdesc_free_idx[1]; };
|
||||||
|
struct rwnx_hw {
|
||||||
|
struct env usb_env, sdio_env;
|
||||||
|
struct { unsigned long last_tx; } stats;
|
||||||
|
void *usbdev, *sdiodev;
|
||||||
|
};
|
||||||
|
static int registrations, submissions;
|
||||||
|
static struct sk_buff packet;
|
||||||
|
static struct rwnx_sw_txhdr hdr;
|
||||||
|
static struct vif vif;
|
||||||
|
static struct rwnx_hw hw;
|
||||||
|
static unsigned long jiffies = 1234;
|
||||||
|
static void push(struct env *env, int queue, long host_id) {
|
||||||
|
assert(host_id == (long)&packet && queue == 0 && submissions == 0);
|
||||||
|
registrations++; env->txdesc_free_idx[0]++;
|
||||||
|
}
|
||||||
|
#define aicwf_usb_host_txdesc_push push
|
||||||
|
#define aicwf_sdio_host_txdesc_push push
|
||||||
|
static void aicwf_frame_tx(void *dev, struct sk_buff *skb) {
|
||||||
|
assert(skb == &packet && dev == &hw);
|
||||||
|
assert(registrations == hdr.need_cfm);
|
||||||
|
submissions++;
|
||||||
|
}
|
||||||
|
static void tx(struct rwnx_hw *rwnx_hw, struct rwnx_sw_txhdr *sw_txhdr,
|
||||||
|
struct sk_buff *skb) {
|
||||||
|
'''
|
||||||
|
|
||||||
|
CHECKS = r'''
|
||||||
|
}
|
||||||
|
static void check(unsigned char fc, int raw, int mgmt, unsigned int ether,
|
||||||
|
int fixed_rate, int expect_confirm) {
|
||||||
|
memset(&hdr, 0, sizeof(hdr)); memset(&hw, 0, sizeof(hw));
|
||||||
|
memset(&vif, 0, sizeof(vif)); memset(&packet, 0, sizeof(packet));
|
||||||
|
registrations = submissions = 0;
|
||||||
|
hdr.headroom = 8; packet.data[8] = fc; hdr.frame_len = 24;
|
||||||
|
hdr.raw_frame = raw; hdr.fixed_rate = fixed_rate; hdr.rate_config = 0x123;
|
||||||
|
hdr.desc.host.flags = mgmt ? TXU_CNTRL_MGMT : 0;
|
||||||
|
hdr.desc.host.ethertype = ether;
|
||||||
|
hdr.rwnx_vif = &vif;
|
||||||
|
hw.usbdev = hw.sdiodev = &hw;
|
||||||
|
hw.usb_env.txdesc_free_idx[0] = hw.sdio_env.txdesc_free_idx[0] = 7;
|
||||||
|
tx(&hw, &hdr, &packet);
|
||||||
|
assert(submissions == 1 && registrations == expect_confirm);
|
||||||
|
assert(hdr.need_cfm == expect_confirm);
|
||||||
|
if (expect_confirm) {
|
||||||
|
assert(hdr.desc.host.status_desc_addr == ((1U << 31) | 7));
|
||||||
|
/* The real confirmation callback accounts for these packets later. */
|
||||||
|
assert(!vif.net_stats.tx_packets && !vif.net_stats.tx_bytes);
|
||||||
|
assert(!hw.stats.last_tx);
|
||||||
|
} else {
|
||||||
|
assert(hdr.desc.host.status_desc_addr == (fixed_rate ? ((1U << 30) | 0x123) : 0));
|
||||||
|
assert(vif.net_stats.tx_packets == 1 && vif.net_stats.tx_bytes == 24);
|
||||||
|
assert(hw.stats.last_tx == jiffies);
|
||||||
|
}
|
||||||
|
assert(hdr.desc.host.flags == (mgmt ? TXU_CNTRL_MGMT : 0));
|
||||||
|
}
|
||||||
|
int main(void) {
|
||||||
|
const unsigned char injected[] = {0x80, 0x40, 0xd0, 0xb0, 0xc0, 0x08};
|
||||||
|
for (unsigned int i = 0; i < sizeof(injected); i++) {
|
||||||
|
check(injected[i], 1, 1, 0, 1, 1);
|
||||||
|
check(injected[i], 1, 1, 0, 0, 1);
|
||||||
|
}
|
||||||
|
check(0xd0, 0, 1, 0, 0, 1);
|
||||||
|
check(0x10, 0, 1, 0, 0, 1);
|
||||||
|
check(0x30, 0, 1, 0, 0, 1);
|
||||||
|
check(0x80, 0, 1, 0, 0, 0);
|
||||||
|
check(0xd0, 0, 0, 0, 0, 0);
|
||||||
|
check(0x08, 0, 0, 0, 0, 0);
|
||||||
|
check(0x08, 0, 0, 0, 1, 0);
|
||||||
|
check(0x08, 0, 0, 0x8e88, 0, 1);
|
||||||
|
#ifdef AICWF_USB_SUPPORT
|
||||||
|
check(0x08, 0, 0, 0xb488, 0, 1);
|
||||||
|
#else
|
||||||
|
check(0x08, 0, 0, 0xb488, 0, 0);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
class MonitorTxTests(unittest.TestCase):
|
||||||
|
def test_descriptor_registration_and_accounting(self):
|
||||||
|
source = args.source.read_text()
|
||||||
|
start = source.index("#ifdef AICWF_SDIO_SUPPORT", source.index("void rwnx_tx_push("))
|
||||||
|
end = source.index("\n#endif", source.index("aicwf_frame_tx((void *)(rwnx_hw->usbdev)", start))
|
||||||
|
block = source[start:end] + "\n#endif\n"
|
||||||
|
for bus in ("USB", "SDIO"):
|
||||||
|
with self.subTest(bus=bus):
|
||||||
|
with tempfile.TemporaryDirectory(prefix="aic-monitor-tx-") as temp:
|
||||||
|
c_file, binary = Path(temp) / "test.c", Path(temp) / "test"
|
||||||
|
c_file.write_text(PRELUDE + block + CHECKS)
|
||||||
|
subprocess.run([os.environ.get("CC", "cc"), "-std=gnu11",
|
||||||
|
"-DAICWF_" + bus + "_SUPPORT", "-o", str(binary),
|
||||||
|
str(c_file)], check=True)
|
||||||
|
subprocess.run([str(binary)], check=True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main(argv=[__file__] + remaining)
|
||||||
Reference in new issue
Block a user