1use core::{mem::discriminant, time::Duration};
2
3use bitfield_struct::bitfield;
4use macro_bits::bit;
5use scroll::{
6 ctx::{MeasureWith, TryFromCtx, TryIntoCtx},
7 Endian, Pread, Pwrite,
8};
9
10mod subtypes;
11pub use subtypes::*;
12mod read_iterator;
13pub use read_iterator::*;
14mod capabilities;
15pub use capabilities::*;
16mod reason;
17pub use reason::*;
18mod status_code;
19pub use status_code::*;
20mod type_state;
21pub use type_state::*;
22mod auth_algo_num;
23pub use auth_algo_num::*;
24mod aid;
25pub use aid::*;
26mod sig;
27pub use sig::*;
28
29pub const TU: Duration = Duration::from_micros(1024);
31
32pub const IEEE_OUI: [u8; 3] = [0x00, 0x0f, 0xac];
33pub const WIFI_ALLIANCE_OUI: [u8; 3] = [0x50, 0x6f, 0x9a];
34
35#[cfg_attr(feature = "defmt", derive(defmt::Format))]
36#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
37pub enum FrameType {
39 Management(ManagementFrameSubtype),
40 Control(ControlFrameSubtype),
41 Data(DataFrameSubtype),
42 Unknown(u8),
43}
44impl FrameType {
45 pub const fn from_bits(value: u8) -> Self {
47 let frame_type = value & bit!(0, 1);
48 let frame_subtype = (value & bit!(2, 3, 4, 5)) >> 2;
49 match frame_type {
50 0b00 => Self::Management(ManagementFrameSubtype::from_bits(frame_subtype)),
51 0b01 => Self::Control(ControlFrameSubtype::from_bits(frame_subtype)),
52 0b10 => Self::Data(DataFrameSubtype::from_bits(frame_subtype)),
53 _ => Self::Unknown(frame_subtype),
54 }
55 }
56 pub const fn into_bits(self) -> u8 {
58 match self {
59 FrameType::Management(subtype) => subtype.into_bits() << 2,
60 FrameType::Control(subtype) => 0b01 | (subtype.into_bits() << 2),
61 FrameType::Data(subtype) => 0b10 | (subtype.into_bits() << 2),
62 FrameType::Unknown(subtype) => 0b11 | (subtype << 2),
63 }
64 }
65 pub fn type_matches(&self, other: Self) -> bool {
67 discriminant(self) == discriminant(&other)
68 }
69 pub const fn has_sequence_control(&self) -> bool {
71 matches!(self, FrameType::Data(_) | FrameType::Management(_))
72 }
73 pub const fn has_address_2(&self) -> bool {
75 match self {
76 Self::Data(_) | Self::Management(_) => true,
77 Self::Control(subtype) => subtype.has_address_2(),
78 _ => false,
79 }
80 }
81 pub const fn has_address_3(&self) -> bool {
83 matches!(self, Self::Data(_) | Self::Management(_))
84 }
85}
86impl From<u16> for FrameType {
87 fn from(value: u16) -> Self {
88 Self::from_bits(value as u8)
89 }
90}
91impl From<FrameType> for u16 {
92 fn from(value: FrameType) -> Self {
93 value.into_bits() as u16
94 }
95}
96
97#[bitfield(u8, defmt = cfg(feature = "defmt"))]
99#[derive(PartialEq, Eq, Hash)]
100pub struct FCFFlags {
101 pub to_ds: bool,
103 pub from_ds: bool,
105 pub more_fragments: bool,
107 pub retry: bool,
109 pub pwr_mgmt: bool,
111 pub more_data: bool,
113 pub protected: bool,
115 pub order: bool,
117}
118#[bitfield(u16, defmt = cfg(feature = "defmt"))]
119#[derive(PartialEq, Eq, Hash)]
120pub struct FrameControlField {
122 #[bits(2)]
123 pub version: u8,
124 #[bits(6)]
125 pub frame_type: FrameType,
126 #[bits(8)]
127 pub flags: FCFFlags,
128}
129#[bitfield(u16, defmt = cfg(feature = "defmt"))]
130#[derive(PartialEq, Eq, Hash)]
131pub struct SequenceControl {
133 #[bits(4)]
134 pub fragment_number: u8,
135 #[bits(12)]
136 pub sequence_number: u16,
137}
138
139#[cfg_attr(feature = "defmt", derive(defmt::Format))]
140#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
141pub struct Empty;
143impl<'a> TryFromCtx<'a> for Empty {
144 type Error = scroll::Error;
145 fn try_from_ctx(_: &'a [u8], _: ()) -> Result<(Self, usize), Self::Error> {
146 Ok((Self, 0))
147 }
148}
149impl MeasureWith<()> for Empty {
150 fn measure_with(&self, _: &()) -> usize {
151 0
152 }
153}
154impl TryIntoCtx for Empty {
155 type Error = scroll::Error;
156 fn try_into_ctx(self, _: &mut [u8], _: ()) -> Result<usize, Self::Error> {
157 Ok(0)
158 }
159}
160
161pub(crate) fn strip_and_validate_fcs(bytes: &[u8]) -> Result<&[u8], scroll::Error> {
162 let (slice_without_fcs, fcs) = bytes.split_at(bytes.len() - 4);
163 if fcs.pread_with::<u32>(0, Endian::Little)? == crc32fast::hash(slice_without_fcs) {
164 Ok(slice_without_fcs)
165 } else {
166 Err(scroll::Error::BadInput {
167 size: 0,
168 msg: "FCS check failed.",
169 })
170 }
171}
172
173pub(crate) fn attach_fcs(buf: &mut [u8], offset: &mut usize) -> Result<usize, scroll::Error> {
174 let fcs = crc32fast::hash(&buf[..*offset]);
175 buf.gwrite_with(fcs, offset, Endian::Little)
176}