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