1pub const RX_DESC_SIZE: usize = 24;
2pub const DEFAULT_RX_TRANSFER_SIZE: usize = 32 * 1024;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum RxPacketType {
6 NormalRx,
7 C2hPacket,
8}
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct RxPacketAttrib {
12 pub pkt_len: u16,
13 pub physt: bool,
14 pub drvinfo_sz: u8,
15 pub shift_sz: u8,
16 pub qos: bool,
17 pub priority: u8,
18 pub mdata: bool,
19 pub seq_num: u16,
20 pub frag_num: u8,
21 pub mfrag: bool,
22 pub bdecrypted: bool,
23 pub encrypt: u8,
24 pub crc_err: bool,
25 pub icv_err: bool,
26 pub tsfl: u32,
27 pub data_rate: u8,
28 pub bw: u8,
29 pub stbc: u8,
30 pub ldpc: u8,
31 pub sgi: u8,
32 pub scrambler: u8,
33 pub rssi: [u8; 4],
34 pub snr: [i8; 4],
35 pub evm: [i8; 4],
36 pub pkt_rpt_type: RxPacketType,
37}
38
39impl Default for RxPacketAttrib {
40 fn default() -> Self {
41 Self {
42 pkt_len: 0,
43 physt: false,
44 drvinfo_sz: 0,
45 shift_sz: 0,
46 qos: false,
47 priority: 0,
48 mdata: false,
49 seq_num: 0,
50 frag_num: 0,
51 mfrag: false,
52 bdecrypted: false,
53 encrypt: 0,
54 crc_err: false,
55 icv_err: false,
56 tsfl: 0,
57 data_rate: 0,
58 bw: 0,
59 stbc: 0,
60 ldpc: 0,
61 sgi: 0,
62 scrambler: 0,
63 rssi: [0; 4],
64 snr: [0; 4],
65 evm: [0; 4],
66 pkt_rpt_type: RxPacketType::NormalRx,
67 }
68 }
69}
70
71#[derive(Debug, Clone, Copy)]
72pub struct RealtekRxPacket<'a> {
73 pub attrib: RxPacketAttrib,
74 pub data: &'a [u8],
75}
76
77#[derive(Debug, Clone, PartialEq, Eq)]
78pub enum AggregateError {
79 DescriptorTooShort,
80 InvalidPacketLength {
81 pkt_len: u16,
82 pkt_offset: usize,
83 remaining: usize,
84 },
85}
86
87impl std::fmt::Display for AggregateError {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 match self {
90 Self::DescriptorTooShort => write!(f, "RX descriptor is shorter than {RX_DESC_SIZE} bytes"),
91 Self::InvalidPacketLength {
92 pkt_len,
93 pkt_offset,
94 remaining,
95 } => write!(
96 f,
97 "invalid RX packet length: pkt_len={pkt_len}, pkt_offset={pkt_offset}, remaining={remaining}"
98 ),
99 }
100 }
101}
102
103impl std::error::Error for AggregateError {}
104
105pub fn parse_rx_descriptor(desc: &[u8]) -> Result<RxPacketAttrib, AggregateError> {
106 if desc.len() < RX_DESC_SIZE {
107 return Err(AggregateError::DescriptorTooShort);
108 }
109
110 let d0 = le32(desc, 0);
111 let d1 = le32(desc, 4);
112 let d2 = le32(desc, 8);
113 let d3 = le32(desc, 12);
114 let d4 = le32(desc, 16);
115 let d5 = le32(desc, 20);
116
117 Ok(RxPacketAttrib {
118 pkt_len: bits(d0, 0, 14) as u16,
119 crc_err: bits(d0, 14, 1) != 0,
120 icv_err: bits(d0, 15, 1) != 0,
121 drvinfo_sz: (bits(d0, 16, 4) * 8) as u8,
122 encrypt: bits(d0, 20, 3) as u8,
123 qos: bits(d0, 23, 1) != 0,
124 shift_sz: bits(d0, 24, 2) as u8,
125 physt: bits(d0, 26, 1) != 0,
126 bdecrypted: bits(d0, 27, 1) == 0,
127 priority: bits(d1, 8, 4) as u8,
128 mdata: bits(d1, 26, 1) != 0,
129 mfrag: bits(d1, 27, 1) != 0,
130 seq_num: bits(d2, 0, 12) as u16,
131 frag_num: bits(d2, 12, 4) as u8,
132 pkt_rpt_type: if bits(d2, 28, 1) != 0 {
133 RxPacketType::C2hPacket
134 } else {
135 RxPacketType::NormalRx
136 },
137 data_rate: bits(d3, 0, 7) as u8,
138 sgi: bits(d4, 0, 1) as u8,
139 ldpc: bits(d4, 1, 1) as u8,
140 stbc: bits(d4, 2, 1) as u8,
141 bw: bits(d4, 4, 2) as u8,
142 scrambler: bits(d4, 9, 7) as u8,
143 tsfl: d5,
144 ..Default::default()
145 })
146}
147
148pub fn parse_rx_aggregate(buf: &[u8]) -> Result<Vec<RealtekRxPacket<'_>>, AggregateError> {
149 let mut packets = Vec::new();
150 let mut offset = 0usize;
151
152 while offset < buf.len() {
153 let remaining = buf.len() - offset;
154 if remaining < RX_DESC_SIZE {
155 break;
156 }
157
158 let desc = &buf[offset..offset + RX_DESC_SIZE];
159 let mut attrib = parse_rx_descriptor(desc)?;
160 let data_start =
161 offset + RX_DESC_SIZE + attrib.drvinfo_sz as usize + attrib.shift_sz as usize;
162 let pkt_offset = RX_DESC_SIZE
163 + attrib.drvinfo_sz as usize
164 + attrib.shift_sz as usize
165 + attrib.pkt_len as usize;
166 if attrib.pkt_len == 0 || pkt_offset > remaining {
167 return Err(AggregateError::InvalidPacketLength {
168 pkt_len: attrib.pkt_len,
169 pkt_offset,
170 remaining,
171 });
172 }
173
174 if attrib.pkt_rpt_type == RxPacketType::NormalRx {
175 let phy_start = offset + RX_DESC_SIZE;
176 let phy_end = phy_start + attrib.drvinfo_sz as usize;
177 parse_phy_status(&mut attrib, &buf[phy_start..phy_end]);
178 }
179
180 let data_end = data_start + attrib.pkt_len as usize;
181 packets.push(RealtekRxPacket {
182 attrib,
183 data: &buf[data_start..data_end],
184 });
185
186 let aligned = round_up_8(pkt_offset);
187 if aligned >= remaining {
188 break;
189 }
190 offset += aligned;
191 }
192
193 Ok(packets)
194}
195
196const fn round_up_8(value: usize) -> usize {
197 (value + 7) & !7
198}
199
200fn le32(bytes: &[u8], offset: usize) -> u32 {
201 u32::from_le_bytes(
202 bytes[offset..offset + 4]
203 .try_into()
204 .expect("descriptor length checked"),
205 )
206}
207
208const fn bits(word: u32, offset: u8, len: u8) -> u32 {
209 if len == 32 {
210 word
211 } else {
212 (word >> offset) & ((1u32 << len) - 1)
213 }
214}
215
216fn parse_phy_status(attrib: &mut RxPacketAttrib, phy: &[u8]) {
217 if phy.len() < 2 {
218 return;
219 }
220
221 attrib.rssi[0] = phy[0];
222 attrib.rssi[1] = phy[1];
223
224 if phy.len() < 28 {
225 return;
226 }
227
228 attrib.rssi[2] = phy[23];
229 attrib.rssi[3] = phy[24];
230 attrib.snr[0] = phy[15] as i8;
231 attrib.snr[1] = phy[16] as i8;
232 attrib.snr[2] = phy[21] as i8;
233 attrib.snr[3] = phy[22] as i8;
234 attrib.evm[0] = phy[13] as i8;
235 attrib.evm[1] = phy[14] as i8;
236 attrib.evm[2] = phy[19] as i8;
237 attrib.evm[3] = phy[20] as i8;
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243
244 fn put_bits(word: &mut u32, offset: u8, len: u8, value: u32) {
245 let mask = ((1u32 << len) - 1) << offset;
246 *word = (*word & !mask) | ((value << offset) & mask);
247 }
248
249 fn descriptor(pkt_len: u16, drvinfo_units: u8, shift: u8, seq: u16) -> [u8; RX_DESC_SIZE] {
250 let mut desc = [0; RX_DESC_SIZE];
251 let mut d0 = 0u32;
252 put_bits(&mut d0, 0, 14, pkt_len as u32);
253 put_bits(&mut d0, 16, 4, drvinfo_units as u32);
254 put_bits(&mut d0, 24, 2, shift as u32);
255 let mut d2 = 0u32;
256 put_bits(&mut d2, 0, 12, seq as u32);
257 desc[0..4].copy_from_slice(&d0.to_le_bytes());
258 desc[8..12].copy_from_slice(&d2.to_le_bytes());
259 desc
260 }
261
262 #[test]
263 fn parses_single_rx_packet() {
264 let mut aggregate = Vec::new();
265 aggregate.extend_from_slice(&descriptor(4, 0, 0, 77));
266 aggregate.extend_from_slice(&[1, 2, 3, 4]);
267
268 let packets = parse_rx_aggregate(&aggregate).unwrap();
269 assert_eq!(packets.len(), 1);
270 assert_eq!(packets[0].attrib.pkt_len, 4);
271 assert_eq!(packets[0].attrib.seq_num, 77);
272 assert_eq!(packets[0].data, &[1, 2, 3, 4]);
273 }
274
275 #[test]
276 fn advances_by_jaguar_eight_byte_alignment() {
277 let mut aggregate = Vec::new();
278 aggregate.extend_from_slice(&descriptor(5, 0, 0, 1));
279 aggregate.extend_from_slice(&[1, 2, 3, 4, 5]);
280 aggregate.extend_from_slice(&[0, 0, 0]);
281 aggregate.extend_from_slice(&descriptor(3, 0, 0, 2));
282 aggregate.extend_from_slice(&[6, 7, 8]);
283
284 let packets = parse_rx_aggregate(&aggregate).unwrap();
285 assert_eq!(packets.len(), 2);
286 assert_eq!(packets[0].data, &[1, 2, 3, 4, 5]);
287 assert_eq!(packets[1].data, &[6, 7, 8]);
288 }
289}