Skip to content
Open
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
32 changes: 16 additions & 16 deletions src/jaguar3/FrameParserJaguar3.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ constexpr size_t RXDESC_SIZE_8822C = 24; /* RX_DESC_SIZE_88XX */
#define SET_TX_DESC_RATE_ID_8822C(d, v) SET_BITS_TO_LE_4BYTE((d) + 0x04, 16, 5, v)
#define SET_TX_DESC_PKT_OFFSET_8822C(d, v) SET_BITS_TO_LE_4BYTE((d) + 0x04, 24, 5, v)
#define SET_TX_DESC_USE_RATE_8822C(d, v) SET_BITS_TO_LE_4BYTE((d) + 0x0C, 8, 1, v)
#define SET_TX_DESC_DISRTSFB_8822C(d, v) SET_BITS_TO_LE_4BYTE((d) + 0x0C, 9, 1, v)
#define SET_TX_DESC_DISDATAFB_8822C(d, v) SET_BITS_TO_LE_4BYTE((d) + 0x0C, 10, 1, v)
#define SET_TX_DESC_NAVUSEHDR_8822C(d, v) SET_BITS_TO_LE_4BYTE((d) + 0x0C, 15, 1, v)
#define SET_TX_DESC_NDPA_8822C(d, v) SET_BITS_TO_LE_4BYTE((d) + 0x0C, 22, 2, v)
Expand Down Expand Up @@ -82,6 +83,7 @@ constexpr size_t RXDESC_SIZE_8822C = 24; /* RX_DESC_SIZE_88XX */
* cal_txdesc_chksum_8822c. */
#define SET_TX_DESC_DMA_TXAGG_NUM_8822C(d, v) SET_BITS_TO_LE_4BYTE((d) + 0x1C, 24, 8, v)
#define SET_TX_DESC_EN_HWSEQ_8822C(d, v) SET_BITS_TO_LE_4BYTE((d) + 0x20, 15, 1, v)
#define SET_TX_DESC_SW_SEQ_8822C(d, v) SET_BITS_TO_LE_4BYTE((d) + 0x24, 12, 12, v)
#define GET_TX_DESC_PKT_OFFSET_8822C(d) LE_BITS_TO_4BYTE((d) + 0x04, 24, 5)

/* --- RX descriptor fields --- */
Expand Down Expand Up @@ -125,38 +127,35 @@ inline void cal_txdesc_chksum_8822c(uint8_t *txdesc) {
/* Fill an 8822C data/monitor-inject TX descriptor (48 bytes, zeroed by caller)
* and finalise its checksum. `bw` is the descriptor BW code (0=20,1=40,2=80),
* `rate_hw` the DESC_RATE* index (MRateToHwRate output), `rate_id` 8(HT)/9(VHT).
* Field choices mirror the Jaguar1 monitor-inject path (MACID 1, USE_RATE,
* DISDATAFB, HW sequence). */
* Field choices mirror SVPcom rtl8812eu's RTL8822E monitor-inject path
* (MACID 1, USE_RATE, DISRTSFB, DISDATAFB, supplied 802.11 sequence). */
inline void fill_data_tx_desc_8822c(uint8_t *d, uint16_t pkt_size,
uint8_t rate_hw, uint8_t rate_id, uint8_t bw,
bool short_gi, bool ldpc, uint8_t stbc,
bool bmc = false, bool ndpa = false,
uint8_t data_sc = 0,
uint8_t pwr_ofset_type = 0,
uint8_t pkt_offset = 0) {
uint8_t pkt_offset = 0,
bool retry = false,
uint16_t seqnum = 0) {
SET_TX_DESC_TXPKTSIZE_8822C(d, pkt_size);
SET_TX_DESC_OFFSET_8822C(d, static_cast<uint32_t>(TXDESC_SIZE_8822C));
SET_TX_DESC_LS_8822C(d, 1);
/* Broadcast/multicast marker: the kernel sets this whenever addr1 is a group
* address, so mark group-addressed frames the same way for a faithful port. */
SET_TX_DESC_BMC_8822C(d, bmc ? 1 : 0);
/* Remaining fields mirror the kernel's 8822e data/inject descriptor so the
* on-wire TXDESC is byte-identical (verified against a usbmon capture of the
* kernel's MCS7 inject): hw-managed sequence (DISQSELSEQ), SU/broadcast group
* (G_ID=63), a bounded per-frame retry limit (RTY_LMT_EN + RTS_DATA_RTY_LMT),
* RA-group 9, and a non-zero SW_DEFINE. NB: these do not change on-air
* throughput (the chip already airs a saturating MCS7 flood at ~77% duty with
* or without them) — they are here for a faithful port, not a fix. */
SET_TX_DESC_DISQSELSEQ_8822C(d, 1);
SET_TX_DESC_G_ID_8822C(d, 0x3f);
/* SVPcom monitor injection keeps the frame's 802.11 sequence number:
* EN_HWSEQ is clear and SW_SEQ is copied from the header. */
SET_TX_DESC_RTY_LMT_EN_8822C(d, 1);
SET_TX_DESC_RTS_DATA_RTY_LMT_8822C(d, 12);
/* RADIOTAP_F_TX_NOACK means zero MAC retries; other injected frames use
* SVPcom's six-attempt limit. */
SET_TX_DESC_RTS_DATA_RTY_LMT_8822C(d, retry ? 6 : 0);
SET_TX_DESC_MACID_8822C(d, 0x01);
SET_TX_DESC_QSEL_8822C(d, 0x12); /* MGMT queue (mirrors Jaguar1 inject) */
SET_TX_DESC_RATE_ID_8822C(d, 9); /* kernel uses RA-group 9 for the inject path */
SET_TX_DESC_USE_RATE_8822C(d, 1);
SET_TX_DESC_DISDATAFB_8822C(d, 0);
SET_TX_DESC_SW_DEFINE_8822C(d, 1);
SET_TX_DESC_DISRTSFB_8822C(d, 1);
SET_TX_DESC_DISDATAFB_8822C(d, 1);
SET_TX_DESC_DATARATE_8822C(d, rate_hw);
SET_TX_DESC_DATA_BW_8822C(d, bw);
/* Data sub-channel: which 20/40 MHz slice of a wider configured channel the
Expand All @@ -170,7 +169,8 @@ inline void fill_data_tx_desc_8822c(uint8_t *d, uint16_t pkt_size,
* descriptor). Inside the checksummed span (0x14) — before the checksum. */
if (pwr_ofset_type)
SET_TX_DESC_TXPWR_OFSET_TYPE_8822C(d, pwr_ofset_type & 0x3);
SET_TX_DESC_EN_HWSEQ_8822C(d, 1);
SET_TX_DESC_EN_HWSEQ_8822C(d, 0);
SET_TX_DESC_SW_SEQ_8822C(d, seqnum & 0x0fff);
/* USB-agg boundary shim: pkt_offset × 8 bytes of pad between this descriptor
* and its frame (halmac PKT_OFFSET, unit 8 B). 0 = none (byte-identical).
* MUST precede the checksum: on the 8822C the checksum span itself extends
Expand Down
13 changes: 12 additions & 1 deletion src/jaguar3/RtlJaguar3Device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1813,6 +1813,7 @@ size_t RtlJaguar3Device::build_tx_block(const uint8_t *packet, size_t length,

uint8_t fixed_rate = MGN_1M;
uint8_t sgi = 0, ldpc = 0, stbc = 0;
uint16_t tx_flags = 0;
ChannelWidth_t bwidth = CHANNEL_WIDTH_20;
bool vht = (radiotap_length != 0x0d);
bool rate_from_radiotap = false; /* did the frame's radiotap carry a rate? */
Expand All @@ -1837,6 +1838,9 @@ size_t RtlJaguar3Device::build_tx_block(const uint8_t *packet, size_t length,
fixed_rate = *it.this_arg;
rate_from_radiotap = true;
break;
case IEEE80211_RADIOTAP_TX_FLAGS:
tx_flags = get_unaligned_le16(it.this_arg);
break;
case IEEE80211_RADIOTAP_CHANNEL:
/* 2 x __le16: frequency (MHz), then flags. Frequency is authoritative
* for the per-packet hop target; flags are ignored (rate/BW come from
Expand Down Expand Up @@ -1964,6 +1968,9 @@ size_t RtlJaguar3Device::build_tx_block(const uint8_t *packet, size_t length,
* the kernel's descriptor for group-addressed frames. */
const uint8_t *dot11 = packet + radiotap_length;
bool bmc = frame_len >= 6 && (dot11[4] & 0x01);
uint16_t seqnum = 0;
if (frame_len >= 24)
seqnum = (get_unaligned_le16(dot11 + 22) >> 4) & 0x0fff;
/* STBC guard (IRtlDevice contract) — 8822C/8822E are 2T2R so this never
* fires today, but keeps the invariant uniform across families: never air an
* STBC frame the chip can't do. */
Expand All @@ -1975,10 +1982,14 @@ size_t RtlJaguar3Device::build_tx_block(const uint8_t *packet, size_t length,
uint8_t pwr_type = _txpkt_dflt_type.load(std::memory_order_relaxed);
if (radiotap_pkt_pwr_db != INT_MIN)
pwr_type = txpkt_type_for_idx(txpkt_idx_for_qdb(radiotap_pkt_pwr_db * 4));
/* SVPcom monitor injection maps RADIOTAP_F_TX_NOACK to no MAC retry.
* wfb-ng sets this for raw-link packets, avoiding a repeated TX burst. */
constexpr uint16_t kRadiotapTxNoAck = 0x0008;
const bool retry = (tx_flags & kRadiotapTxNoAck) == 0;
jaguar3::fill_data_tx_desc_8822c(
out, static_cast<uint16_t>(frame_len), MRateToHwRate(fixed_rate), rate_id,
bw_desc, sgi != 0, ldpc != 0, stbc, bmc, ndpa, data_sc, pwr_type,
pkt_offset);
pkt_offset, retry, seqnum);
if (_cfg.tx.report) {
/* DEVOURER_TX_REPORT: SPE_RPT asks the fw for a per-frame CCX TX report;
* the report echoes SW_DEFINE's low byte, so stamp a rotating tag for
Expand Down
16 changes: 15 additions & 1 deletion tests/txagg_selftest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,21 @@ static void test_desc_8822c() {
jaguar3::fill_data_tx_desc_8822c(blk, 1500, 7, 9, 0, false, false, 0,
/*bmc=*/false, /*ndpa=*/false,
/*data_sc=*/0, /*pwr_ofset_type=*/0,
/*pkt_offset=*/1);
/*pkt_offset=*/1, /*retry=*/false,
/*seqnum=*/0xabc);
CHECK((blk[0x0d] & 0x06) == 0x06,
"8822e: forced-rate fallback bits=0x%02x want DISRTSFB|DISDATAFB",
blk[0x0d] & 0x06);
CHECK((blk[0x12] & 0x02) != 0 && (blk[0x12] & 0xfc) == 0,
"8822e: TX_NOACK retry descriptor byte=0x%02x want enable/limit=0",
blk[0x12]);
CHECK((blk[0x21] & 0x80) == 0 &&
LE_BITS_TO_4BYTE(blk + 0x24, 12, 12) == 0xabc,
"8822e: SW sequence mismatch (hwseq=%u swseq=%u)",
(blk[0x21] >> 7) & 1, LE_BITS_TO_4BYTE(blk + 0x24, 12, 12));
CHECK(LE_BITS_TO_4BYTE(blk + 0x08, 24, 6) == 0 &&
LE_BITS_TO_4BYTE(blk + 0x18, 0, 12) == 0,
"8822e: injected frame must leave G_ID/SW_DEFINE at the SVP defaults");
CHECK((blk[0x07] & 0x1f) == 1, "8822c: pkt_offset field=%u want 1",
blk[0x07] & 0x1f);
const uint16_t ck_pad0 = static_cast<uint16_t>(blk[0x1C] | (blk[0x1D] << 8));
Expand Down