ieee80211/common/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
use core::{mem::discriminant, time::Duration};

use bitfield_struct::bitfield;
use macro_bits::bit;
use scroll::{
    ctx::{MeasureWith, TryFromCtx, TryIntoCtx},
    Endian, Pread, Pwrite,
};

mod subtypes;
pub use subtypes::*;
mod read_iterator;
pub use read_iterator::*;
mod capabilities;
pub use capabilities::*;
mod reason;
pub use reason::*;
mod status_code;
pub use status_code::*;
mod type_state;
pub use type_state::*;
mod auth_algo_num;
pub use auth_algo_num::*;
mod aid;
pub use aid::*;
mod sig;
pub use sig::*;

/// This is one **T**ime **U**nit, which equalls 1024µs.
pub const TU: Duration = Duration::from_micros(1024);

pub const IEEE_OUI: [u8; 3] = [0x00, 0x0f, 0xac];
pub const WIFI_ALLIANCE_OUI: [u8; 3] = [0x50, 0x6f, 0x9a];

#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
/// The frame type of an IEEE 802.11 frame.
pub enum FrameType {
    Management(ManagementFrameSubtype),
    Control(ControlFrameSubtype),
    Data(DataFrameSubtype),
    Unknown(u8),
}
impl FrameType {
    /// Constructs the frame type from it's representation.
    pub const fn from_bits(value: u8) -> Self {
        let frame_type = value & bit!(0, 1);
        let frame_subtype = (value & bit!(2, 3, 4, 5)) >> 2;
        match frame_type {
            0b00 => Self::Management(ManagementFrameSubtype::from_bits(frame_subtype)),
            0b01 => Self::Control(ControlFrameSubtype::from_bits(frame_subtype)),
            0b10 => Self::Data(DataFrameSubtype::from_bits(frame_subtype)),
            _ => Self::Unknown(frame_subtype),
        }
    }
    /// Turns the frame type into it's representation.
    pub const fn into_bits(self) -> u8 {
        match self {
            FrameType::Management(subtype) => subtype.into_bits() << 2,
            FrameType::Control(subtype) => 0b01 | (subtype.into_bits() << 2),
            FrameType::Data(subtype) => 0b10 | (subtype.into_bits() << 2),
            FrameType::Unknown(subtype) => 0b11 | (subtype << 2),
        }
    }
    /// Check if just the frame type matches.
    pub fn type_matches(&self, other: Self) -> bool {
        discriminant(self) == discriminant(&other)
    }
    /// Checks if the frame type has a sequence control field.
    pub const fn has_sequence_control(&self) -> bool {
        matches!(self, FrameType::Data(_) | FrameType::Management(_))
    }
    /// Checks if the frame type has a second address.
    pub const fn has_address_2(&self) -> bool {
        match self {
            Self::Data(_) | Self::Management(_) => true,
            Self::Control(subtype) => subtype.has_address_2(),
            _ => false,
        }
    }
    /// Checks if the frame type has a third address.
    pub const fn has_address_3(&self) -> bool {
        matches!(self, Self::Data(_) | Self::Management(_))
    }
}
impl From<u16> for FrameType {
    fn from(value: u16) -> Self {
        Self::from_bits(value as u8)
    }
}
impl From<FrameType> for u16 {
    fn from(value: FrameType) -> Self {
        value.into_bits() as u16
    }
}

/// These are the flags included in the frame control field.
#[bitfield(u8, defmt = cfg(feature = "defmt"))]
#[derive(PartialEq, Eq, Hash)]
pub struct FCFFlags {
    /// This frame is going to the distribution system.
    pub to_ds: bool,
    /// This frame is coming from the distribution system.
    pub from_ds: bool,
    /// This frame was fragmented and more are following.
    pub more_fragments: bool,
    /// This frame is a retransmission.
    pub retry: bool,
    // TODO: Docs
    pub pwr_mgmt: bool,
    // TODO: Docs
    pub more_data: bool,
    /// This frames contents are encrypted.
    pub protected: bool,
    // TODO: Docs
    pub order: bool,
}
#[bitfield(u16, defmt = cfg(feature = "defmt"))]
#[derive(PartialEq, Eq, Hash)]
/// This is the frame control field, which is at the beginning of every frame.
pub struct FrameControlField {
    #[bits(2)]
    pub version: u8,
    #[bits(6)]
    pub frame_type: FrameType,
    #[bits(8)]
    pub flags: FCFFlags,
}
#[bitfield(u16, defmt = cfg(feature = "defmt"))]
#[derive(PartialEq, Eq, Hash)]
/// This is information about the sequence number and the potential fragment number.
pub struct SequenceControl {
    #[bits(4)]
    pub fragment_number: u8,
    #[bits(12)]
    pub sequence_number: u16,
}

#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
/// An empty type, used for filling empty generics.
pub struct Empty;
impl<'a> TryFromCtx<'a> for Empty {
    type Error = scroll::Error;
    fn try_from_ctx(_: &'a [u8], _: ()) -> Result<(Self, usize), Self::Error> {
        Ok((Self, 0))
    }
}
impl MeasureWith<()> for Empty {
    fn measure_with(&self, _: &()) -> usize {
        0
    }
}
impl TryIntoCtx for Empty {
    type Error = scroll::Error;
    fn try_into_ctx(self, _: &mut [u8], _: ()) -> Result<usize, Self::Error> {
        Ok(0)
    }
}

pub(crate) fn strip_and_validate_fcs(bytes: &[u8]) -> Result<&[u8], scroll::Error> {
    let (slice_without_fcs, fcs) = bytes.split_at(bytes.len() - 4);
    if fcs.pread_with::<u32>(0, Endian::Little)? == crc32fast::hash(slice_without_fcs) {
        Ok(slice_without_fcs)
    } else {
        Err(scroll::Error::BadInput {
            size: 0,
            msg: "FCS check failed.",
        })
    }
}

pub(crate) fn attach_fcs(buf: &mut [u8], offset: &mut usize) -> Result<usize, scroll::Error> {
    let fcs = crc32fast::hash(&buf[..*offset]);
    buf.gwrite_with(fcs, offset, Endian::Little)
}