Skip to main content

stackforge_core/layer/dot11/
control.rs

1//! IEEE 802.11 control frame subtypes.
2//!
3//! Control frames are used for assisting delivery of data and management frames.
4//! Most control frames have minimal or no body beyond the 802.11 header addresses.
5
6use crate::layer::field::FieldError;
7
8// ============================================================================
9// Dot11Ack
10// ============================================================================
11
12/// 802.11 ACK frame.
13///
14/// The ACK frame has no body beyond the 802.11 header (FC + Duration + Addr1).
15#[derive(Debug, Clone)]
16pub struct Dot11Ack {
17    pub offset: usize,
18}
19
20impl Dot11Ack {
21    #[must_use]
22    pub fn new(offset: usize) -> Self {
23        Self { offset }
24    }
25
26    /// Header length (no additional fields beyond the main Dot11 header).
27    #[must_use]
28    pub fn header_len(&self) -> usize {
29        0
30    }
31}
32
33// ============================================================================
34// Dot11RTS
35// ============================================================================
36
37/// 802.11 RTS (Request To Send) frame.
38///
39/// The RTS frame has no body beyond the 802.11 header (FC + Duration + Addr1 + Addr2).
40#[derive(Debug, Clone)]
41pub struct Dot11RTS {
42    pub offset: usize,
43}
44
45impl Dot11RTS {
46    #[must_use]
47    pub fn new(offset: usize) -> Self {
48        Self { offset }
49    }
50
51    /// Header length (no additional fields).
52    #[must_use]
53    pub fn header_len(&self) -> usize {
54        0
55    }
56}
57
58// ============================================================================
59// Dot11CTS
60// ============================================================================
61
62/// 802.11 CTS (Clear To Send) frame.
63///
64/// The CTS frame has no body beyond the 802.11 header (FC + Duration + Addr1).
65#[derive(Debug, Clone)]
66pub struct Dot11CTS {
67    pub offset: usize,
68}
69
70impl Dot11CTS {
71    #[must_use]
72    pub fn new(offset: usize) -> Self {
73        Self { offset }
74    }
75
76    /// Header length (no additional fields).
77    #[must_use]
78    pub fn header_len(&self) -> usize {
79        0
80    }
81}
82
83// ============================================================================
84// Dot11BlockAckReq (BAR)
85// ============================================================================
86
87/// 802.11 Block Ack Request (BAR) frame body.
88///
89/// After the 802.11 header (Addr1 + Addr2), contains:
90/// - BAR Control (2 bytes, little-endian)
91/// - Starting Sequence Control (2 bytes, little-endian)
92#[derive(Debug, Clone)]
93pub struct Dot11BlockAckReq {
94    pub offset: usize,
95}
96
97pub const BAR_FIXED_LEN: usize = 4;
98
99impl Dot11BlockAckReq {
100    #[must_use]
101    pub fn new(offset: usize) -> Self {
102        Self { offset }
103    }
104
105    /// BAR Control field (little-endian u16).
106    ///
107    /// Bits 0: BAR Ack Policy
108    /// Bits 1-3: BAR Type
109    /// Bits 4-11: Reserved
110    /// Bits 12-15: `TID_INFO`
111    pub fn bar_control(&self, buf: &[u8]) -> Result<u16, FieldError> {
112        let off = self.offset;
113        if buf.len() < off + 2 {
114            return Err(FieldError::BufferTooShort {
115                offset: off,
116                need: 2,
117                have: buf.len(),
118            });
119        }
120        Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
121    }
122
123    /// BAR Ack Policy (bit 0 of BAR Control).
124    pub fn ack_policy(&self, buf: &[u8]) -> Result<bool, FieldError> {
125        Ok(self.bar_control(buf)? & 0x0001 != 0)
126    }
127
128    /// BAR Type (bits 1-3 of BAR Control).
129    pub fn bar_type(&self, buf: &[u8]) -> Result<u8, FieldError> {
130        Ok(((self.bar_control(buf)? >> 1) & 0x07) as u8)
131    }
132
133    /// TID Info (bits 12-15 of BAR Control).
134    pub fn tid_info(&self, buf: &[u8]) -> Result<u8, FieldError> {
135        Ok(((self.bar_control(buf)? >> 12) & 0x0F) as u8)
136    }
137
138    /// Starting Sequence Control (little-endian u16).
139    pub fn start_seq_ctrl(&self, buf: &[u8]) -> Result<u16, FieldError> {
140        let off = self.offset + 2;
141        if buf.len() < off + 2 {
142            return Err(FieldError::BufferTooShort {
143                offset: off,
144                need: 2,
145                have: buf.len(),
146            });
147        }
148        Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
149    }
150
151    /// Starting sequence number (upper 12 bits of starting sequence control).
152    pub fn start_seq_num(&self, buf: &[u8]) -> Result<u16, FieldError> {
153        Ok(self.start_seq_ctrl(buf)? >> 4)
154    }
155
156    /// Fragment number (lower 4 bits of starting sequence control).
157    pub fn fragment_num(&self, buf: &[u8]) -> Result<u8, FieldError> {
158        Ok((self.start_seq_ctrl(buf)? & 0x0F) as u8)
159    }
160
161    /// Header length.
162    #[must_use]
163    pub fn header_len(&self) -> usize {
164        BAR_FIXED_LEN
165    }
166
167    /// Build BAR body.
168    #[must_use]
169    pub fn build(bar_control: u16, start_seq_ctrl: u16) -> Vec<u8> {
170        let mut out = Vec::with_capacity(BAR_FIXED_LEN);
171        out.extend_from_slice(&bar_control.to_le_bytes());
172        out.extend_from_slice(&start_seq_ctrl.to_le_bytes());
173        out
174    }
175}
176
177// ============================================================================
178// Dot11BlockAck (BA)
179// ============================================================================
180
181/// 802.11 Block Ack (BA) frame body.
182///
183/// After the 802.11 header (Addr1 + Addr2), contains:
184/// - BA Control (2 bytes, little-endian)
185/// - Starting Sequence Control (2 bytes, little-endian)
186/// - Block Ack Bitmap (variable, typically 128 bytes for basic BA)
187#[derive(Debug, Clone)]
188pub struct Dot11BlockAck {
189    pub offset: usize,
190    pub len: usize,
191}
192
193pub const BA_MIN_FIXED_LEN: usize = 4;
194pub const BA_BASIC_BITMAP_LEN: usize = 128;
195
196impl Dot11BlockAck {
197    #[must_use]
198    pub fn new(offset: usize, len: usize) -> Self {
199        Self { offset, len }
200    }
201
202    /// BA Control field (little-endian u16).
203    pub fn ba_control(&self, buf: &[u8]) -> Result<u16, FieldError> {
204        let off = self.offset;
205        if buf.len() < off + 2 {
206            return Err(FieldError::BufferTooShort {
207                offset: off,
208                need: 2,
209                have: buf.len(),
210            });
211        }
212        Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
213    }
214
215    /// BA Ack Policy (bit 0).
216    pub fn ack_policy(&self, buf: &[u8]) -> Result<bool, FieldError> {
217        Ok(self.ba_control(buf)? & 0x0001 != 0)
218    }
219
220    /// BA Type (bits 1-3).
221    pub fn ba_type(&self, buf: &[u8]) -> Result<u8, FieldError> {
222        Ok(((self.ba_control(buf)? >> 1) & 0x07) as u8)
223    }
224
225    /// TID Info (bits 12-15).
226    pub fn tid_info(&self, buf: &[u8]) -> Result<u8, FieldError> {
227        Ok(((self.ba_control(buf)? >> 12) & 0x0F) as u8)
228    }
229
230    /// Starting Sequence Control (little-endian u16).
231    pub fn start_seq_ctrl(&self, buf: &[u8]) -> Result<u16, FieldError> {
232        let off = self.offset + 2;
233        if buf.len() < off + 2 {
234            return Err(FieldError::BufferTooShort {
235                offset: off,
236                need: 2,
237                have: buf.len(),
238            });
239        }
240        Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
241    }
242
243    /// Starting sequence number.
244    pub fn start_seq_num(&self, buf: &[u8]) -> Result<u16, FieldError> {
245        Ok(self.start_seq_ctrl(buf)? >> 4)
246    }
247
248    /// Block Ack Bitmap (variable length, starts at offset+4).
249    pub fn bitmap<'a>(&self, buf: &'a [u8]) -> Result<&'a [u8], FieldError> {
250        let off = self.offset + 4;
251        let end = self.offset + self.len;
252        if buf.len() < end {
253            return Err(FieldError::BufferTooShort {
254                offset: off,
255                need: self.len - 4,
256                have: buf.len().saturating_sub(off),
257            });
258        }
259        Ok(&buf[off..end])
260    }
261
262    /// Header length (entire BA body including bitmap).
263    #[must_use]
264    pub fn header_len(&self) -> usize {
265        self.len
266    }
267
268    /// Build a basic BA body with 128-byte bitmap.
269    #[must_use]
270    pub fn build_basic(ba_control: u16, start_seq_ctrl: u16, bitmap: &[u8; 128]) -> Vec<u8> {
271        let mut out = Vec::with_capacity(BA_MIN_FIXED_LEN + BA_BASIC_BITMAP_LEN);
272        out.extend_from_slice(&ba_control.to_le_bytes());
273        out.extend_from_slice(&start_seq_ctrl.to_le_bytes());
274        out.extend_from_slice(bitmap);
275        out
276    }
277}
278
279// ============================================================================
280// Dot11PSPoll
281// ============================================================================
282
283/// 802.11 PS-Poll frame body.
284///
285/// The PS-Poll uses the Duration/ID field as AID.
286/// No additional body beyond the 802.11 header.
287#[derive(Debug, Clone)]
288pub struct Dot11PSPoll {
289    pub offset: usize,
290}
291
292impl Dot11PSPoll {
293    #[must_use]
294    pub fn new(offset: usize) -> Self {
295        Self { offset }
296    }
297
298    /// Header length (no additional fields).
299    #[must_use]
300    pub fn header_len(&self) -> usize {
301        0
302    }
303}
304
305// ============================================================================
306// Dot11CFEnd
307// ============================================================================
308
309/// 802.11 CF-End frame body.
310///
311/// No additional body beyond the 802.11 header.
312#[derive(Debug, Clone)]
313pub struct Dot11CFEnd {
314    pub offset: usize,
315}
316
317impl Dot11CFEnd {
318    #[must_use]
319    pub fn new(offset: usize) -> Self {
320        Self { offset }
321    }
322
323    /// Header length (no additional fields).
324    #[must_use]
325    pub fn header_len(&self) -> usize {
326        0
327    }
328}
329
330#[cfg(test)]
331mod tests {
332    use super::*;
333
334    #[test]
335    fn test_ack() {
336        let ack = Dot11Ack::new(0);
337        assert_eq!(ack.header_len(), 0);
338    }
339
340    #[test]
341    fn test_rts() {
342        let rts = Dot11RTS::new(0);
343        assert_eq!(rts.header_len(), 0);
344    }
345
346    #[test]
347    fn test_cts() {
348        let cts = Dot11CTS::new(0);
349        assert_eq!(cts.header_len(), 0);
350    }
351
352    #[test]
353    fn test_bar_parse() {
354        let mut buf = vec![0u8; 4];
355        // BAR Control: ack_policy=1, type=0, TID=5 => bit0=1, bits 12-15=5
356        // = 0x5001
357        buf[0..2].copy_from_slice(&0x5001u16.to_le_bytes());
358        // Starting Sequence Control: seq=100 => 100 << 4 = 0x0640
359        buf[2..4].copy_from_slice(&0x0640u16.to_le_bytes());
360
361        let bar = Dot11BlockAckReq::new(0);
362        assert_eq!(bar.bar_control(&buf).unwrap(), 0x5001);
363        assert!(bar.ack_policy(&buf).unwrap());
364        assert_eq!(bar.bar_type(&buf).unwrap(), 0);
365        assert_eq!(bar.tid_info(&buf).unwrap(), 5);
366        assert_eq!(bar.start_seq_num(&buf).unwrap(), 100);
367        assert_eq!(bar.fragment_num(&buf).unwrap(), 0);
368    }
369
370    #[test]
371    fn test_bar_build_roundtrip() {
372        let data = Dot11BlockAckReq::build(0x5001, 0x0640);
373        assert_eq!(data.len(), BAR_FIXED_LEN);
374
375        let bar = Dot11BlockAckReq::new(0);
376        assert_eq!(bar.bar_control(&data).unwrap(), 0x5001);
377        assert_eq!(bar.start_seq_ctrl(&data).unwrap(), 0x0640);
378    }
379
380    #[test]
381    fn test_ba_parse() {
382        let mut buf = vec![0u8; 4 + 128];
383        // BA Control: ack_policy=1, TID=3
384        buf[0..2].copy_from_slice(&0x3001u16.to_le_bytes());
385        // Starting Sequence Control: seq=50 => 50 << 4 = 0x0320
386        buf[2..4].copy_from_slice(&0x0320u16.to_le_bytes());
387        // First byte of bitmap set
388        buf[4] = 0xFF;
389
390        let ba = Dot11BlockAck::new(0, buf.len());
391        assert_eq!(ba.ba_control(&buf).unwrap(), 0x3001);
392        assert!(ba.ack_policy(&buf).unwrap());
393        assert_eq!(ba.tid_info(&buf).unwrap(), 3);
394        assert_eq!(ba.start_seq_num(&buf).unwrap(), 50);
395
396        let bitmap = ba.bitmap(&buf).unwrap();
397        assert_eq!(bitmap.len(), 128);
398        assert_eq!(bitmap[0], 0xFF);
399    }
400
401    #[test]
402    fn test_ba_build_roundtrip() {
403        let mut bitmap = [0u8; 128];
404        bitmap[0] = 0x01;
405        bitmap[127] = 0x80;
406
407        let data = Dot11BlockAck::build_basic(0x3001, 0x0320, &bitmap);
408        assert_eq!(data.len(), BA_MIN_FIXED_LEN + BA_BASIC_BITMAP_LEN);
409
410        let ba = Dot11BlockAck::new(0, data.len());
411        assert_eq!(ba.ba_control(&data).unwrap(), 0x3001);
412        let parsed_bitmap = ba.bitmap(&data).unwrap();
413        assert_eq!(parsed_bitmap[0], 0x01);
414        assert_eq!(parsed_bitmap[127], 0x80);
415    }
416
417    #[test]
418    fn test_pspoll() {
419        let pspoll = Dot11PSPoll::new(0);
420        assert_eq!(pspoll.header_len(), 0);
421    }
422
423    #[test]
424    fn test_cfend() {
425        let cfend = Dot11CFEnd::new(0);
426        assert_eq!(cfend.header_len(), 0);
427    }
428}