Skip to main content

stackforge_core/layer/dot11/
mod.rs

1//! IEEE 802.11 (`WiFi` / Dot11) protocol layer implementation.
2//!
3//! Provides full 802.11 frame parsing, building, and field access including:
4//! - Frame Control field parsing (type, subtype, flags)
5//! - Variable address fields (1-4 MAC addresses depending on frame type)
6//! - Sequence control field
7//! - FCS variant (`Dot11FCS`)
8//! - `RadioTap` header support
9//! - Management, control, and data frame subtypes
10//! - Information elements (IEs)
11//! - Security wrappers (WEP, TKIP, CCMP)
12
13pub mod builder;
14pub mod control;
15pub mod data;
16pub mod ie;
17pub mod management;
18pub mod radiotap;
19pub mod security;
20pub mod types;
21
22pub use builder::Dot11Builder;
23pub use control::{
24    Dot11Ack, Dot11BlockAck, Dot11BlockAckReq, Dot11CFEnd, Dot11CTS, Dot11PSPoll, Dot11RTS,
25};
26pub use data::Dot11QoS;
27pub use ie::{Dot11Elt, Dot11EltRSN, Dot11EltRates};
28pub use management::{
29    Dot11Action, Dot11AssocReq, Dot11AssocResp, Dot11Auth, Dot11Beacon, Dot11Deauth, Dot11Disas,
30    Dot11ProbeReq, Dot11ProbeResp, Dot11ReassocReq, Dot11ReassocResp,
31};
32pub use radiotap::{RadioTapBuilder, RadioTapLayer};
33pub use security::{Dot11CCMP, Dot11TKIP, Dot11WEP};
34
35use crate::layer::field::{Field, FieldError, FieldValue, MacAddress};
36use crate::layer::{Layer, LayerIndex, LayerKind};
37
38/// Minimum 802.11 header length: FC(2) + Duration(2) + Addr1(6) = 10 bytes.
39/// Most frames have at least 24 bytes (3 addresses + seq ctrl).
40pub const DOT11_MIN_HEADER_LEN: usize = 10;
41
42/// Standard management/data header length: FC(2) + Dur(2) + Addr1(6) + Addr2(6) + Addr3(6) + SC(2) = 24.
43pub const DOT11_MGMT_HEADER_LEN: usize = 24;
44
45/// WDS (4 address) header length: 24 + Addr4(6) = 30.
46pub const DOT11_WDS_HEADER_LEN: usize = 30;
47
48/// FCS field length.
49pub const DOT11_FCS_LEN: usize = 4;
50
51/// Field offsets within the 802.11 header.
52/// NOTE: Frame Control is little-endian.
53pub mod offsets {
54    /// Frame Control (2 bytes, little-endian).
55    pub const FRAME_CONTROL: usize = 0;
56    /// Duration/ID (2 bytes, little-endian).
57    pub const DURATION: usize = 2;
58    /// Address 1 (6 bytes) - always present.
59    pub const ADDR1: usize = 4;
60    /// Address 2 (6 bytes) - present in most frames.
61    pub const ADDR2: usize = 10;
62    /// Address 3 (6 bytes) - present in management and data frames.
63    pub const ADDR3: usize = 16;
64    /// Sequence Control (2 bytes, little-endian).
65    pub const SEQ_CTRL: usize = 22;
66    /// Address 4 (6 bytes) - only in WDS (`to_DS=1` AND `from_DS=1`).
67    pub const ADDR4: usize = 24;
68}
69
70/// IEEE 802.11 layer - a zero-copy view into the packet buffer.
71///
72/// Provides lazy field access for all 802.11 header fields.
73/// The Frame Control field is always little-endian.
74///
75/// Frame Control layout (2 bytes, little-endian):
76/// ```text
77/// Byte 0: [subtype(4) | type(2) | protocol_version(2)]
78/// Byte 1: [order | protected | more_data | pwr_mgt | retry | more_frag | from_ds | to_ds]
79/// ```
80#[derive(Debug, Clone)]
81pub struct Dot11Layer {
82    pub index: LayerIndex,
83}
84
85impl Dot11Layer {
86    /// Create a new `Dot11Layer` from start/end offsets.
87    #[must_use]
88    pub fn new(start: usize, end: usize) -> Self {
89        Self {
90            index: LayerIndex::new(LayerKind::Dot11, start, end),
91        }
92    }
93
94    /// Validate that the buffer contains enough data for this layer.
95    pub fn validate(buf: &[u8], offset: usize) -> Result<(), FieldError> {
96        if buf.len() < offset + DOT11_MIN_HEADER_LEN {
97            return Err(FieldError::BufferTooShort {
98                offset,
99                need: DOT11_MIN_HEADER_LEN,
100                have: buf.len().saturating_sub(offset),
101            });
102        }
103        Ok(())
104    }
105
106    // ========================================================================
107    // Frame Control field accessors
108    // ========================================================================
109
110    /// Read the raw Frame Control field (2 bytes, little-endian).
111    #[inline]
112    pub fn frame_control_raw(&self, buf: &[u8]) -> Result<u16, FieldError> {
113        let off = self.index.start + offsets::FRAME_CONTROL;
114        if buf.len() < off + 2 {
115            return Err(FieldError::BufferTooShort {
116                offset: off,
117                need: 2,
118                have: buf.len(),
119            });
120        }
121        Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
122    }
123
124    /// Protocol version (2 bits from FC byte 0, bits 0-1).
125    #[inline]
126    pub fn protocol_version(&self, buf: &[u8]) -> Result<u8, FieldError> {
127        let fc = self.frame_control_raw(buf)?;
128        Ok((fc & 0x0003) as u8)
129    }
130
131    /// Frame type (2 bits from FC byte 0, bits 2-3).
132    #[inline]
133    pub fn frame_type(&self, buf: &[u8]) -> Result<u8, FieldError> {
134        let fc = self.frame_control_raw(buf)?;
135        Ok(((fc >> 2) & 0x0003) as u8)
136    }
137
138    /// Frame subtype (4 bits from FC byte 0, bits 4-7).
139    #[inline]
140    pub fn subtype(&self, buf: &[u8]) -> Result<u8, FieldError> {
141        let fc = self.frame_control_raw(buf)?;
142        Ok(((fc >> 4) & 0x000F) as u8)
143    }
144
145    /// Flags byte (FC byte 1, bits 8-15 of the FC word).
146    #[inline]
147    pub fn flags(&self, buf: &[u8]) -> Result<u8, FieldError> {
148        let fc = self.frame_control_raw(buf)?;
149        Ok((fc >> 8) as u8)
150    }
151
152    /// To DS flag (bit 0 of flags byte).
153    #[inline]
154    pub fn to_ds(&self, buf: &[u8]) -> Result<bool, FieldError> {
155        Ok(self.flags(buf)? & types::fc_flags::TO_DS != 0)
156    }
157
158    /// From DS flag (bit 1 of flags byte).
159    #[inline]
160    pub fn from_ds(&self, buf: &[u8]) -> Result<bool, FieldError> {
161        Ok(self.flags(buf)? & types::fc_flags::FROM_DS != 0)
162    }
163
164    /// More Fragments flag (bit 2 of flags byte).
165    #[inline]
166    pub fn more_frag(&self, buf: &[u8]) -> Result<bool, FieldError> {
167        Ok(self.flags(buf)? & types::fc_flags::MORE_FRAG != 0)
168    }
169
170    /// Retry flag (bit 3 of flags byte).
171    #[inline]
172    pub fn retry(&self, buf: &[u8]) -> Result<bool, FieldError> {
173        Ok(self.flags(buf)? & types::fc_flags::RETRY != 0)
174    }
175
176    /// Power Management flag (bit 4 of flags byte).
177    #[inline]
178    pub fn pwr_mgt(&self, buf: &[u8]) -> Result<bool, FieldError> {
179        Ok(self.flags(buf)? & types::fc_flags::PWR_MGT != 0)
180    }
181
182    /// More Data flag (bit 5 of flags byte).
183    #[inline]
184    pub fn more_data(&self, buf: &[u8]) -> Result<bool, FieldError> {
185        Ok(self.flags(buf)? & types::fc_flags::MORE_DATA != 0)
186    }
187
188    /// Protected Frame flag (bit 6 of flags byte).
189    #[inline]
190    pub fn protected(&self, buf: &[u8]) -> Result<bool, FieldError> {
191        Ok(self.flags(buf)? & types::fc_flags::PROTECTED != 0)
192    }
193
194    /// HTC/Order flag (bit 7 of flags byte).
195    #[inline]
196    pub fn htc_order(&self, buf: &[u8]) -> Result<bool, FieldError> {
197        Ok(self.flags(buf)? & types::fc_flags::HTC_ORDER != 0)
198    }
199
200    // ========================================================================
201    // Duration/ID field
202    // ========================================================================
203
204    /// Duration/ID field (2 bytes, little-endian).
205    #[inline]
206    pub fn duration(&self, buf: &[u8]) -> Result<u16, FieldError> {
207        let off = self.index.start + offsets::DURATION;
208        if buf.len() < off + 2 {
209            return Err(FieldError::BufferTooShort {
210                offset: off,
211                need: 2,
212                have: buf.len(),
213            });
214        }
215        Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
216    }
217
218    // ========================================================================
219    // Address fields
220    // ========================================================================
221
222    /// Address 1 (always present, 6 bytes at offset 4).
223    #[inline]
224    pub fn addr1(&self, buf: &[u8]) -> Result<MacAddress, FieldError> {
225        MacAddress::read(buf, self.index.start + offsets::ADDR1)
226    }
227
228    /// Address 2 (present in most frames except some control frames).
229    #[inline]
230    pub fn addr2(&self, buf: &[u8]) -> Result<MacAddress, FieldError> {
231        MacAddress::read(buf, self.index.start + offsets::ADDR2)
232    }
233
234    /// Address 3 (present in management and data frames).
235    #[inline]
236    pub fn addr3(&self, buf: &[u8]) -> Result<MacAddress, FieldError> {
237        MacAddress::read(buf, self.index.start + offsets::ADDR3)
238    }
239
240    /// Address 4 (only present in WDS frames: `to_DS=1` AND `from_DS=1`).
241    #[inline]
242    pub fn addr4(&self, buf: &[u8]) -> Result<MacAddress, FieldError> {
243        MacAddress::read(buf, self.index.start + offsets::ADDR4)
244    }
245
246    /// Check if this frame has a 4th address field (WDS mode).
247    #[inline]
248    #[must_use]
249    pub fn has_addr4(&self, buf: &[u8]) -> bool {
250        if let Ok(ft) = self.frame_type(buf)
251            && ft == types::frame_type::DATA
252            && let Ok(flags) = self.flags(buf)
253        {
254            return (flags & 0x03) == 0x03; // to_DS=1 AND from_DS=1
255        }
256        false
257    }
258
259    /// Check if this is a control frame (which may have fewer addresses).
260    #[inline]
261    #[must_use]
262    pub fn is_control(&self, buf: &[u8]) -> bool {
263        matches!(self.frame_type(buf), Ok(types::frame_type::CONTROL))
264    }
265
266    // ========================================================================
267    // Sequence Control field
268    // ========================================================================
269
270    /// Raw Sequence Control field (2 bytes, little-endian).
271    #[inline]
272    pub fn seq_ctrl_raw(&self, buf: &[u8]) -> Result<u16, FieldError> {
273        let off = self.index.start + offsets::SEQ_CTRL;
274        if buf.len() < off + 2 {
275            return Err(FieldError::BufferTooShort {
276                offset: off,
277                need: 2,
278                have: buf.len(),
279            });
280        }
281        Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
282    }
283
284    /// Fragment number (lower 4 bits of Sequence Control).
285    #[inline]
286    pub fn fragment_num(&self, buf: &[u8]) -> Result<u8, FieldError> {
287        Ok((self.seq_ctrl_raw(buf)? & 0x000F) as u8)
288    }
289
290    /// Sequence number (upper 12 bits of Sequence Control).
291    #[inline]
292    pub fn sequence_num(&self, buf: &[u8]) -> Result<u16, FieldError> {
293        Ok(self.seq_ctrl_raw(buf)? >> 4)
294    }
295
296    // ========================================================================
297    // Header length calculation
298    // ========================================================================
299
300    /// Calculate the actual header length based on frame type and flags.
301    #[must_use]
302    pub fn compute_header_len(&self, buf: &[u8]) -> usize {
303        let ft = self.frame_type(buf).unwrap_or(0);
304        let st = self.subtype(buf).unwrap_or(0);
305
306        match ft {
307            types::frame_type::MANAGEMENT => DOT11_MGMT_HEADER_LEN,
308            types::frame_type::CONTROL => {
309                match st {
310                    types::ctrl_subtype::ACK | types::ctrl_subtype::CTS => {
311                        // FC(2) + Duration(2) + Addr1(6) = 10
312                        10
313                    },
314                    _ => {
315                        // FC(2) + Duration(2) + Addr1(6) + Addr2(6) = 16
316                        16
317                    },
318                }
319            },
320            types::frame_type::DATA => {
321                if self.has_addr4(buf) {
322                    DOT11_WDS_HEADER_LEN
323                } else {
324                    DOT11_MGMT_HEADER_LEN
325                }
326            },
327            types::frame_type::EXTENSION => 10,
328            _ => DOT11_MIN_HEADER_LEN,
329        }
330    }
331
332    // ========================================================================
333    // Field writers
334    // ========================================================================
335
336    /// Write the Frame Control field (little-endian).
337    pub fn set_frame_control(&self, buf: &mut [u8], fc: u16) -> Result<(), FieldError> {
338        let off = self.index.start + offsets::FRAME_CONTROL;
339        if buf.len() < off + 2 {
340            return Err(FieldError::BufferTooShort {
341                offset: off,
342                need: 2,
343                have: buf.len(),
344            });
345        }
346        let bytes = fc.to_le_bytes();
347        buf[off] = bytes[0];
348        buf[off + 1] = bytes[1];
349        Ok(())
350    }
351
352    /// Write the Duration/ID field (little-endian).
353    pub fn set_duration(&self, buf: &mut [u8], dur: u16) -> Result<(), FieldError> {
354        let off = self.index.start + offsets::DURATION;
355        if buf.len() < off + 2 {
356            return Err(FieldError::BufferTooShort {
357                offset: off,
358                need: 2,
359                have: buf.len(),
360            });
361        }
362        let bytes = dur.to_le_bytes();
363        buf[off] = bytes[0];
364        buf[off + 1] = bytes[1];
365        Ok(())
366    }
367
368    /// Write Address 1.
369    pub fn set_addr1(&self, buf: &mut [u8], mac: MacAddress) -> Result<(), FieldError> {
370        mac.write(buf, self.index.start + offsets::ADDR1)
371    }
372
373    /// Write Address 2.
374    pub fn set_addr2(&self, buf: &mut [u8], mac: MacAddress) -> Result<(), FieldError> {
375        mac.write(buf, self.index.start + offsets::ADDR2)
376    }
377
378    /// Write Address 3.
379    pub fn set_addr3(&self, buf: &mut [u8], mac: MacAddress) -> Result<(), FieldError> {
380        mac.write(buf, self.index.start + offsets::ADDR3)
381    }
382
383    /// Write Address 4.
384    pub fn set_addr4(&self, buf: &mut [u8], mac: MacAddress) -> Result<(), FieldError> {
385        mac.write(buf, self.index.start + offsets::ADDR4)
386    }
387
388    /// Write the Sequence Control field (little-endian).
389    pub fn set_seq_ctrl(&self, buf: &mut [u8], sc: u16) -> Result<(), FieldError> {
390        let off = self.index.start + offsets::SEQ_CTRL;
391        if buf.len() < off + 2 {
392            return Err(FieldError::BufferTooShort {
393                offset: off,
394                need: 2,
395                have: buf.len(),
396            });
397        }
398        let bytes = sc.to_le_bytes();
399        buf[off] = bytes[0];
400        buf[off + 1] = bytes[1];
401        Ok(())
402    }
403
404    // ========================================================================
405    // Dynamic field access
406    // ========================================================================
407
408    /// Field names for dynamic access.
409    #[must_use]
410    pub fn field_names() -> &'static [&'static str] {
411        &[
412            "type", "subtype", "proto", "FCfield", "ID", "addr1", "addr2", "addr3", "SC", "addr4",
413        ]
414    }
415
416    /// Get a field value by name.
417    pub fn get_field(&self, buf: &[u8], name: &str) -> Option<Result<FieldValue, FieldError>> {
418        match name {
419            "type" => Some(self.frame_type(buf).map(FieldValue::U8)),
420            "subtype" => Some(self.subtype(buf).map(FieldValue::U8)),
421            "proto" => Some(self.protocol_version(buf).map(FieldValue::U8)),
422            "FCfield" => Some(self.flags(buf).map(FieldValue::U8)),
423            "ID" => Some(self.duration(buf).map(FieldValue::U16)),
424            "addr1" => Some(self.addr1(buf).map(FieldValue::Mac)),
425            "addr2" => Some(self.addr2(buf).map(FieldValue::Mac)),
426            "addr3" => Some(self.addr3(buf).map(FieldValue::Mac)),
427            "SC" => Some(self.seq_ctrl_raw(buf).map(FieldValue::U16)),
428            "addr4" => {
429                if self.has_addr4(buf) {
430                    Some(self.addr4(buf).map(FieldValue::Mac))
431                } else {
432                    None
433                }
434            },
435            _ => None,
436        }
437    }
438
439    /// Set a field value by name.
440    pub fn set_field(
441        &self,
442        buf: &mut [u8],
443        name: &str,
444        value: FieldValue,
445    ) -> Option<Result<(), FieldError>> {
446        match name {
447            "ID" => match value {
448                FieldValue::U16(v) => Some(self.set_duration(buf, v)),
449                _ => Some(Err(FieldError::TypeMismatch {
450                    expected: "u16",
451                    got: "other",
452                })),
453            },
454            "addr1" => match value {
455                FieldValue::Mac(m) => Some(self.set_addr1(buf, m)),
456                _ => Some(Err(FieldError::TypeMismatch {
457                    expected: "mac",
458                    got: "other",
459                })),
460            },
461            "addr2" => match value {
462                FieldValue::Mac(m) => Some(self.set_addr2(buf, m)),
463                _ => Some(Err(FieldError::TypeMismatch {
464                    expected: "mac",
465                    got: "other",
466                })),
467            },
468            "addr3" => match value {
469                FieldValue::Mac(m) => Some(self.set_addr3(buf, m)),
470                _ => Some(Err(FieldError::TypeMismatch {
471                    expected: "mac",
472                    got: "other",
473                })),
474            },
475            "addr4" => match value {
476                FieldValue::Mac(m) => Some(self.set_addr4(buf, m)),
477                _ => Some(Err(FieldError::TypeMismatch {
478                    expected: "mac",
479                    got: "other",
480                })),
481            },
482            "SC" => match value {
483                FieldValue::U16(v) => Some(self.set_seq_ctrl(buf, v)),
484                _ => Some(Err(FieldError::TypeMismatch {
485                    expected: "u16",
486                    got: "other",
487                })),
488            },
489            _ => None,
490        }
491    }
492
493    /// Compute hash for packet matching.
494    #[must_use]
495    pub fn hashret(&self, buf: &[u8]) -> Vec<u8> {
496        let mut hash = Vec::new();
497        if let Ok(addr1) = self.addr1(buf) {
498            hash.extend_from_slice(addr1.as_bytes());
499        }
500        if let Ok(addr2) = self.addr2(buf) {
501            hash.extend_from_slice(addr2.as_bytes());
502        }
503        hash
504    }
505
506    /// Check if this packet answers another 802.11 packet.
507    #[must_use]
508    pub fn answers(&self, buf: &[u8], other: &Dot11Layer, other_buf: &[u8]) -> bool {
509        let self_type = self.frame_type(buf).unwrap_or(255);
510        let other_type = other.frame_type(other_buf).unwrap_or(255);
511
512        if self_type != other_type {
513            return false;
514        }
515
516        match self_type {
517            types::frame_type::MANAGEMENT => {
518                let self_addr1 = self.addr1(buf).unwrap_or(MacAddress::ZERO);
519                let other_addr2 = other.addr2(other_buf).unwrap_or(MacAddress::ZERO);
520                if self_addr1 != other_addr2 {
521                    return false;
522                }
523                let self_sub = self.subtype(buf).unwrap_or(255);
524                let other_sub = other.subtype(other_buf).unwrap_or(255);
525                matches!((other_sub, self_sub), (0, 1) | (2, 3) | (4, 5) | (11, 11))
526            },
527            types::frame_type::CONTROL => false,
528            types::frame_type::DATA => true,
529            _ => false,
530        }
531    }
532}
533
534impl Layer for Dot11Layer {
535    fn kind(&self) -> LayerKind {
536        LayerKind::Dot11
537    }
538
539    fn summary(&self, buf: &[u8]) -> String {
540        let ft = self.frame_type(buf).unwrap_or(0);
541        let st = self.subtype(buf).unwrap_or(0);
542        let type_name = types::frame_type::name(ft);
543        let subtype_name = types::subtype_name(ft, st);
544        let addr2_str = self
545            .addr2(buf)
546            .map_or_else(|_| "?".to_string(), |a| a.to_string());
547        let addr1_str = self
548            .addr1(buf)
549            .map_or_else(|_| "?".to_string(), |a| a.to_string());
550        format!("802.11 {type_name} {subtype_name} {addr2_str} > {addr1_str}")
551    }
552
553    fn header_len(&self, buf: &[u8]) -> usize {
554        self.compute_header_len(buf)
555    }
556
557    fn hashret(&self, data: &[u8]) -> Vec<u8> {
558        self.hashret(data)
559    }
560
561    fn field_names(&self) -> &'static [&'static str] {
562        Dot11Layer::field_names()
563    }
564}
565
566/// IEEE 802.11 FCS layer - same as `Dot11Layer` but includes a 4-byte FCS trailer.
567#[derive(Debug, Clone)]
568pub struct Dot11FcsLayer {
569    pub index: LayerIndex,
570}
571
572impl Dot11FcsLayer {
573    /// Create a new `Dot11FcsLayer` from start/end offsets.
574    #[must_use]
575    pub fn new(start: usize, end: usize) -> Self {
576        Self {
577            index: LayerIndex::new(LayerKind::Dot11, start, end),
578        }
579    }
580
581    /// Get the inner `Dot11Layer` view (excluding FCS).
582    #[must_use]
583    pub fn dot11(&self) -> Dot11Layer {
584        Dot11Layer::new(
585            self.index.start,
586            self.index.end.saturating_sub(DOT11_FCS_LEN),
587        )
588    }
589
590    /// Read the FCS field (4 bytes at end of frame, little-endian).
591    pub fn fcs(&self, buf: &[u8]) -> Result<u32, FieldError> {
592        let off = self.index.end.saturating_sub(DOT11_FCS_LEN);
593        if buf.len() < off + 4 {
594            return Err(FieldError::BufferTooShort {
595                offset: off,
596                need: 4,
597                have: buf.len(),
598            });
599        }
600        Ok(u32::from_le_bytes([
601            buf[off],
602            buf[off + 1],
603            buf[off + 2],
604            buf[off + 3],
605        ]))
606    }
607
608    /// Compute the CRC32 FCS for the frame data (excluding the FCS itself).
609    #[must_use]
610    pub fn compute_fcs(data: &[u8]) -> u32 {
611        crc32_ieee(data)
612    }
613
614    /// Verify that the FCS matches the frame data.
615    pub fn verify_fcs(&self, buf: &[u8]) -> Result<bool, FieldError> {
616        let fcs_val = self.fcs(buf)?;
617        let data_end = self.index.end.saturating_sub(DOT11_FCS_LEN);
618        let data = &buf[self.index.start..data_end];
619        let computed = Self::compute_fcs(data);
620        Ok(fcs_val == computed)
621    }
622
623    /// Delegate field access to the inner `Dot11Layer`.
624    pub fn frame_type(&self, buf: &[u8]) -> Result<u8, FieldError> {
625        self.dot11().frame_type(buf)
626    }
627
628    pub fn subtype(&self, buf: &[u8]) -> Result<u8, FieldError> {
629        self.dot11().subtype(buf)
630    }
631
632    pub fn flags(&self, buf: &[u8]) -> Result<u8, FieldError> {
633        self.dot11().flags(buf)
634    }
635
636    pub fn addr1(&self, buf: &[u8]) -> Result<MacAddress, FieldError> {
637        self.dot11().addr1(buf)
638    }
639
640    pub fn addr2(&self, buf: &[u8]) -> Result<MacAddress, FieldError> {
641        self.dot11().addr2(buf)
642    }
643
644    pub fn addr3(&self, buf: &[u8]) -> Result<MacAddress, FieldError> {
645        self.dot11().addr3(buf)
646    }
647
648    pub fn duration(&self, buf: &[u8]) -> Result<u16, FieldError> {
649        self.dot11().duration(buf)
650    }
651}
652
653impl Layer for Dot11FcsLayer {
654    fn kind(&self) -> LayerKind {
655        LayerKind::Dot11
656    }
657
658    fn summary(&self, buf: &[u8]) -> String {
659        let inner = self.dot11();
660        let base = inner.summary(buf);
661        let fcs_str = self
662            .fcs(buf)
663            .map(|f| format!(" [FCS={f:#010x}]"))
664            .unwrap_or_default();
665        format!("{base}{fcs_str}")
666    }
667
668    fn header_len(&self, buf: &[u8]) -> usize {
669        self.dot11().compute_header_len(buf)
670    }
671
672    fn field_names(&self) -> &'static [&'static str] {
673        Dot11Layer::field_names()
674    }
675}
676
677/// Build a Frame Control u16 value from components.
678///
679/// Frame Control layout (little-endian u16):
680/// Bits 0-1:  Protocol Version
681/// Bits 2-3:  Type
682/// Bits 4-7:  Subtype
683/// Bits 8-15: Flags
684#[must_use]
685pub fn build_frame_control(proto: u8, frame_type: u8, subtype: u8, flags: u8) -> u16 {
686    let byte0 = (proto & 0x03) | ((frame_type & 0x03) << 2) | ((subtype & 0x0F) << 4);
687    u16::from_le_bytes([byte0, flags])
688}
689
690/// Compute IEEE CRC32 (used for FCS).
691#[must_use]
692pub fn crc32_ieee(data: &[u8]) -> u32 {
693    let mut crc: u32 = 0xFFFFFFFF;
694    for &byte in data {
695        crc ^= u32::from(byte);
696        for _ in 0..8 {
697            if crc & 1 != 0 {
698                crc = (crc >> 1) ^ 0xEDB88320;
699            } else {
700                crc >>= 1;
701            }
702        }
703    }
704    crc ^ 0xFFFFFFFF
705}
706
707#[cfg(test)]
708mod tests {
709    use super::*;
710
711    /// Build a minimal beacon frame for testing.
712    fn make_beacon_frame() -> Vec<u8> {
713        let mut buf = vec![0u8; 24];
714        // Frame Control: type=0 (mgmt), subtype=8 (beacon)
715        // byte0: proto=0, type=0, subtype=8 => 0x80
716        // byte1: flags=0
717        buf[0] = 0x80;
718        buf[1] = 0x00;
719        // Duration
720        buf[2] = 0x00;
721        buf[3] = 0x00;
722        // Addr1 (DA) = ff:ff:ff:ff:ff:ff (broadcast)
723        buf[4..10].copy_from_slice(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
724        // Addr2 (SA) = 00:11:22:33:44:55
725        buf[10..16].copy_from_slice(&[0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
726        // Addr3 (BSSID) = 00:11:22:33:44:55
727        buf[16..22].copy_from_slice(&[0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
728        // Sequence Control
729        buf[22] = 0x10;
730        buf[23] = 0x00;
731        buf
732    }
733
734    /// Build an ACK frame (control, subtype=13).
735    fn make_ack_frame() -> Vec<u8> {
736        let mut buf = vec![0u8; 10];
737        // FC: type=1 (control), subtype=13 (ACK)
738        // byte0: proto=0, type=1, subtype=13 => (13 << 4) | (1 << 2) = 0xD4
739        buf[0] = 0xD4;
740        buf[1] = 0x00;
741        buf[2] = 0x00;
742        buf[3] = 0x00;
743        buf[4..10].copy_from_slice(&[0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
744        buf
745    }
746
747    /// Build a data frame with to_DS=1, from_DS=1 (WDS).
748    fn make_wds_data_frame() -> Vec<u8> {
749        let mut buf = vec![0u8; 30];
750        // FC: type=2 (data), subtype=0
751        // byte0: (0 << 4) | (2 << 2) = 0x08
752        buf[0] = 0x08;
753        // byte1: flags to_DS=1, from_DS=1 => 0x03
754        buf[1] = 0x03;
755        buf[2] = 0x00;
756        buf[3] = 0x00;
757        buf[4..10].copy_from_slice(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
758        buf[10..16].copy_from_slice(&[0x11, 0x12, 0x13, 0x14, 0x15, 0x16]);
759        buf[16..22].copy_from_slice(&[0x21, 0x22, 0x23, 0x24, 0x25, 0x26]);
760        buf[22] = 0x00;
761        buf[23] = 0x00;
762        buf[24..30].copy_from_slice(&[0x31, 0x32, 0x33, 0x34, 0x35, 0x36]);
763        buf
764    }
765
766    #[test]
767    fn test_parse_beacon_frame_control() {
768        let buf = make_beacon_frame();
769        let layer = Dot11Layer::new(0, buf.len());
770
771        assert_eq!(layer.protocol_version(&buf).unwrap(), 0);
772        assert_eq!(layer.frame_type(&buf).unwrap(), 0);
773        assert_eq!(layer.subtype(&buf).unwrap(), 8);
774        assert_eq!(layer.flags(&buf).unwrap(), 0);
775    }
776
777    #[test]
778    fn test_parse_beacon_addresses() {
779        let buf = make_beacon_frame();
780        let layer = Dot11Layer::new(0, buf.len());
781
782        assert!(layer.addr1(&buf).unwrap().is_broadcast());
783        assert_eq!(
784            layer.addr2(&buf).unwrap(),
785            MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55])
786        );
787        assert_eq!(
788            layer.addr3(&buf).unwrap(),
789            MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55])
790        );
791    }
792
793    #[test]
794    fn test_parse_beacon_seq_ctrl() {
795        let buf = make_beacon_frame();
796        let layer = Dot11Layer::new(0, buf.len());
797
798        assert_eq!(layer.seq_ctrl_raw(&buf).unwrap(), 0x0010);
799        assert_eq!(layer.fragment_num(&buf).unwrap(), 0);
800        assert_eq!(layer.sequence_num(&buf).unwrap(), 1);
801    }
802
803    #[test]
804    fn test_beacon_header_len() {
805        let buf = make_beacon_frame();
806        let layer = Dot11Layer::new(0, buf.len());
807        assert_eq!(layer.compute_header_len(&buf), 24);
808    }
809
810    #[test]
811    fn test_parse_ack_frame() {
812        let buf = make_ack_frame();
813        let layer = Dot11Layer::new(0, buf.len());
814
815        assert_eq!(layer.frame_type(&buf).unwrap(), 1);
816        assert_eq!(layer.subtype(&buf).unwrap(), 13);
817        assert_eq!(layer.compute_header_len(&buf), 10);
818        assert_eq!(
819            layer.addr1(&buf).unwrap(),
820            MacAddress::new([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF])
821        );
822    }
823
824    #[test]
825    fn test_parse_wds_frame() {
826        let buf = make_wds_data_frame();
827        let layer = Dot11Layer::new(0, buf.len());
828
829        assert_eq!(layer.frame_type(&buf).unwrap(), 2);
830        assert!(layer.to_ds(&buf).unwrap());
831        assert!(layer.from_ds(&buf).unwrap());
832        assert!(layer.has_addr4(&buf));
833        assert_eq!(layer.compute_header_len(&buf), 30);
834        assert_eq!(
835            layer.addr4(&buf).unwrap(),
836            MacAddress::new([0x31, 0x32, 0x33, 0x34, 0x35, 0x36])
837        );
838    }
839
840    #[test]
841    fn test_build_frame_control() {
842        let fc = build_frame_control(0, 0, 8, 0);
843        assert_eq!(fc.to_le_bytes(), [0x80, 0x00]);
844
845        let fc = build_frame_control(0, 1, 13, 0);
846        assert_eq!(fc.to_le_bytes(), [0xD4, 0x00]);
847
848        let fc = build_frame_control(0, 2, 0, 0x01);
849        assert_eq!(fc.to_le_bytes(), [0x08, 0x01]);
850    }
851
852    #[test]
853    fn test_flags_parsing() {
854        let mut buf = make_beacon_frame();
855        buf[1] = types::fc_flags::RETRY | types::fc_flags::PROTECTED;
856        let layer = Dot11Layer::new(0, buf.len());
857
858        assert!(layer.retry(&buf).unwrap());
859        assert!(layer.protected(&buf).unwrap());
860        assert!(!layer.to_ds(&buf).unwrap());
861        assert!(!layer.from_ds(&buf).unwrap());
862    }
863
864    #[test]
865    fn test_summary() {
866        let buf = make_beacon_frame();
867        let layer = Dot11Layer::new(0, buf.len());
868        let summary = layer.summary(&buf);
869        assert!(summary.contains("Management"));
870        assert!(summary.contains("Beacon"));
871    }
872
873    #[test]
874    fn test_field_access() {
875        let buf = make_beacon_frame();
876        let layer = Dot11Layer::new(0, buf.len());
877
878        let ft = layer.get_field(&buf, "type").unwrap().unwrap();
879        assert_eq!(ft, FieldValue::U8(0));
880
881        let st = layer.get_field(&buf, "subtype").unwrap().unwrap();
882        assert_eq!(st, FieldValue::U8(8));
883
884        let a1 = layer.get_field(&buf, "addr1").unwrap().unwrap();
885        assert_eq!(a1, FieldValue::Mac(MacAddress::BROADCAST));
886    }
887
888    #[test]
889    fn test_set_duration() {
890        let mut buf = make_beacon_frame();
891        let layer = Dot11Layer::new(0, buf.len());
892
893        layer.set_duration(&mut buf, 0x1234).unwrap();
894        assert_eq!(layer.duration(&buf).unwrap(), 0x1234);
895    }
896
897    #[test]
898    fn test_crc32() {
899        let data = b"123456789";
900        assert_eq!(crc32_ieee(data), 0xCBF43926);
901    }
902
903    #[test]
904    fn test_fcs_layer() {
905        let mut buf = make_beacon_frame();
906        let fcs = crc32_ieee(&buf);
907        buf.extend_from_slice(&fcs.to_le_bytes());
908
909        let fcs_layer = Dot11FcsLayer::new(0, buf.len());
910        assert_eq!(fcs_layer.fcs(&buf).unwrap(), fcs);
911        assert!(fcs_layer.verify_fcs(&buf).unwrap());
912
913        assert_eq!(fcs_layer.frame_type(&buf).unwrap(), 0);
914        assert_eq!(fcs_layer.subtype(&buf).unwrap(), 8);
915    }
916
917    #[test]
918    fn test_roundtrip_build_parse() {
919        let fc = build_frame_control(0, 0, 8, 0);
920        let mut buf = vec![0u8; 24];
921        buf[0..2].copy_from_slice(&fc.to_le_bytes());
922        buf[2..4].copy_from_slice(&0u16.to_le_bytes());
923        buf[4..10].copy_from_slice(&[0xff; 6]);
924        buf[10..16].copy_from_slice(&[0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
925        buf[16..22].copy_from_slice(&[0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
926        buf[22..24].copy_from_slice(&0x0020u16.to_le_bytes());
927
928        let layer = Dot11Layer::new(0, buf.len());
929        assert_eq!(layer.frame_type(&buf).unwrap(), 0);
930        assert_eq!(layer.subtype(&buf).unwrap(), 8);
931        assert_eq!(layer.sequence_num(&buf).unwrap(), 2);
932        assert_eq!(layer.fragment_num(&buf).unwrap(), 0);
933    }
934
935    #[test]
936    fn test_answers_management() {
937        let mut req = vec![0u8; 24];
938        req[0] = 0x00; // type=0, subtype=0
939        req[4..10].copy_from_slice(&[0xBB; 6]);
940        req[10..16].copy_from_slice(&[0xAA; 6]);
941
942        let mut resp = vec![0u8; 24];
943        resp[0] = 0x10; // type=0, subtype=1
944        resp[4..10].copy_from_slice(&[0xAA; 6]);
945        resp[10..16].copy_from_slice(&[0xBB; 6]);
946
947        let req_layer = Dot11Layer::new(0, req.len());
948        let resp_layer = Dot11Layer::new(0, resp.len());
949
950        assert!(resp_layer.answers(&resp, &req_layer, &req));
951        assert!(!req_layer.answers(&req, &resp_layer, &resp));
952    }
953}