1use crate::buffer_reader::{BufferReader, IntoBufferReader};
6use crate::{ie, UnalignedView};
7use fidl_fuchsia_wlan_common as fidl_common;
8use ieee80211::MacAddr;
9use num::Unsigned;
10use zerocopy::{Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice};
11
12mod ctrl;
13mod data;
14mod eth;
15mod fields;
16mod frame_class;
17mod mgmt;
18
19pub use ctrl::*;
20pub use data::*;
21pub use eth::*;
22pub use fields::*;
23pub use frame_class::*;
24pub use mgmt::*;
25
26#[macro_export]
27macro_rules! frame_len {
28 () => { 0 };
29 ($only:ty) => { std::mem::size_of::<$only>() };
30 ($first:ty, $($tail:ty),*) => {
31 std::mem::size_of::<$first>() + frame_len!($($tail),*)
32 };
33}
34
35pub type Aid = u16;
37
38pub const MAX_AID: u16 = 2007;
41
42pub trait IntoBytesExt: IntoBytes + KnownLayout + Immutable + Sized {
43 fn as_bytes_ref(&self) -> Ref<&'_ [u8], Self> {
48 Ref::from_bytes(self.as_bytes())
49 .expect("Unaligned or missized byte slice from `IntoBytes` implementation.")
50 }
51}
52
53impl<T> IntoBytesExt for T where T: IntoBytes + Immutable + KnownLayout + Sized {}
54
55#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
56pub enum MacRole {
57 Client,
58 Ap,
59 Mesh,
60}
61
62impl From<MacRole> for fidl_common::WlanMacRole {
63 fn from(role: MacRole) -> Self {
64 match role {
65 MacRole::Client => fidl_common::WlanMacRole::Client,
66 MacRole::Ap => fidl_common::WlanMacRole::Ap,
67 MacRole::Mesh => fidl_common::WlanMacRole::Mesh,
68 }
69 }
70}
71
72impl TryFrom<fidl_common::WlanMacRole> for MacRole {
73 type Error = fidl_common::WlanMacRole;
74
75 fn try_from(role: fidl_common::WlanMacRole) -> Result<Self, Self::Error> {
76 match role {
77 fidl_common::WlanMacRole::Client => Ok(MacRole::Client),
78 fidl_common::WlanMacRole::Ap => Ok(MacRole::Ap),
79 fidl_common::WlanMacRole::Mesh => Ok(MacRole::Mesh),
80 role => Err(role),
81 }
82 }
83}
84
85pub struct CtrlFrame<B> {
86 pub frame_ctrl: FrameControl,
88 pub body: B,
90}
91
92impl<B> CtrlFrame<B>
93where
94 B: SplitByteSlice,
95{
96 pub fn parse(reader: impl IntoBufferReader<B>) -> Option<Self> {
97 let reader = reader.into_buffer_reader();
98 let fc = FrameControl(reader.peek_value()?);
99 matches!(fc.frame_type(), FrameType::CTRL)
100 .then(|| CtrlFrame::parse_frame_type_unchecked(reader))
101 .flatten()
102 }
103
104 fn parse_frame_type_unchecked(reader: impl IntoBufferReader<B>) -> Option<Self> {
105 let mut reader = reader.into_buffer_reader();
106 let fc = reader.read_value()?;
107
108 Some(CtrlFrame { frame_ctrl: fc, body: reader.into_remaining() })
109 }
110
111 pub fn try_into_ctrl_body(self) -> Option<CtrlBody<B>> {
112 CtrlBody::parse(self.ctrl_subtype(), self.body)
113 }
114
115 pub fn ctrl_body(&self) -> Option<CtrlBody<&'_ B::Target>> {
116 CtrlBody::parse(self.ctrl_subtype(), self.body.deref())
117 }
118
119 pub fn frame_ctrl(&self) -> FrameControl {
120 self.frame_ctrl
121 }
122
123 pub fn ctrl_subtype(&self) -> CtrlSubtype {
124 self.frame_ctrl().ctrl_subtype()
125 }
126}
127
128pub struct DataFrame<B> {
129 pub fixed_fields: Ref<B, FixedDataHdrFields>,
131 pub addr4: Option<Ref<B, Addr4>>,
133 pub qos_ctrl: Option<UnalignedView<B, QosControl>>,
134 pub ht_ctrl: Option<UnalignedView<B, HtControl>>,
135 pub body: B,
137}
138
139impl<B> DataFrame<B>
140where
141 B: SplitByteSlice,
142{
143 pub fn parse(reader: impl IntoBufferReader<B>, is_body_aligned: bool) -> Option<Self> {
144 let reader = reader.into_buffer_reader();
145 let fc = FrameControl(reader.peek_value()?);
146 matches!(fc.frame_type(), FrameType::DATA)
147 .then(|| DataFrame::parse_frame_type_unchecked(reader, is_body_aligned))
148 .flatten()
149 }
150
151 fn parse_frame_type_unchecked(
152 reader: impl IntoBufferReader<B>,
153 is_body_aligned: bool,
154 ) -> Option<Self> {
155 let mut reader = reader.into_buffer_reader();
156 let fc = FrameControl(reader.peek_value()?);
157
158 let fixed_fields = reader.read()?;
160
161 let addr4 = if fc.to_ds() && fc.from_ds() { Some(reader.read()?) } else { None };
163 let qos_ctrl = if fc.data_subtype().qos() { Some(reader.read_unaligned()?) } else { None };
164 let ht_ctrl = if fc.htc_order() { Some(reader.read_unaligned()?) } else { None };
165
166 if is_body_aligned {
168 let full_hdr_len = FixedDataHdrFields::len(
169 Presence::<Addr4>::from_bool(addr4.is_some()),
170 Presence::<QosControl>::from_bool(qos_ctrl.is_some()),
171 Presence::<HtControl>::from_bool(ht_ctrl.is_some()),
172 );
173 skip_body_alignment_padding(full_hdr_len, &mut reader)?
174 };
175 Some(DataFrame { fixed_fields, addr4, qos_ctrl, ht_ctrl, body: reader.into_remaining() })
176 }
177
178 pub fn frame_ctrl(&self) -> FrameControl {
179 self.fixed_fields.frame_ctrl
180 }
181
182 pub fn data_subtype(&self) -> DataSubtype {
183 self.frame_ctrl().data_subtype()
184 }
185}
186
187impl<B> IntoIterator for DataFrame<B>
188where
189 B: SplitByteSlice,
190{
191 type IntoIter = IntoMsduIter<B>;
192 type Item = Msdu<B>;
193
194 fn into_iter(self) -> Self::IntoIter {
195 self.into()
196 }
197}
198
199pub struct MgmtFrame<B> {
200 pub mgmt_hdr: Ref<B, MgmtHdr>,
202 pub ht_ctrl: Option<UnalignedView<B, HtControl>>,
204 pub body: B,
206}
207
208impl<B> MgmtFrame<B>
209where
210 B: SplitByteSlice,
211{
212 pub fn parse(reader: impl IntoBufferReader<B>, is_body_aligned: bool) -> Option<Self> {
213 let reader = reader.into_buffer_reader();
214 let fc = FrameControl(reader.peek_value()?);
215 matches!(fc.frame_type(), FrameType::MGMT)
216 .then(|| MgmtFrame::parse_frame_type_unchecked(reader, is_body_aligned))
217 .flatten()
218 }
219
220 fn parse_frame_type_unchecked(
221 reader: impl IntoBufferReader<B>,
222 is_body_aligned: bool,
223 ) -> Option<Self> {
224 let mut reader = reader.into_buffer_reader();
225 let fc = FrameControl(reader.peek_value()?);
226 let mgmt_hdr = reader.read()?;
228
229 let ht_ctrl = if fc.htc_order() { Some(reader.read_unaligned()?) } else { None };
231 if is_body_aligned {
233 let full_hdr_len = MgmtHdr::len(Presence::<HtControl>::from_bool(ht_ctrl.is_some()));
234 skip_body_alignment_padding(full_hdr_len, &mut reader)?
235 }
236 Some(MgmtFrame { mgmt_hdr, ht_ctrl, body: reader.into_remaining() })
237 }
238
239 pub fn try_into_mgmt_body(self) -> (Ref<B, MgmtHdr>, Option<MgmtBody<B>>) {
240 let MgmtFrame { mgmt_hdr, body, .. } = self;
241 let mgmt_subtype = { mgmt_hdr.frame_ctrl }.mgmt_subtype();
242 (mgmt_hdr, MgmtBody::parse(mgmt_subtype, body))
243 }
244
245 pub fn into_ies(self) -> (Ref<B, MgmtHdr>, impl Iterator<Item = (ie::Id, B)>) {
246 let MgmtFrame { mgmt_hdr, body, .. } = self;
247 (mgmt_hdr, ie::Reader::new(body))
248 }
249
250 pub fn ies(&self) -> impl '_ + Iterator<Item = (ie::Id, &'_ B::Target)> {
251 ie::Reader::new(self.body.deref())
252 }
253
254 pub fn frame_ctrl(&self) -> FrameControl {
255 self.mgmt_hdr.frame_ctrl
256 }
257
258 pub fn mgmt_subtype(&self) -> MgmtSubtype {
259 self.frame_ctrl().mgmt_subtype()
260 }
261}
262
263pub enum MacFrame<B> {
264 Mgmt(MgmtFrame<B>),
265 Data(DataFrame<B>),
266 Ctrl(CtrlFrame<B>),
267 Unsupported { frame_ctrl: FrameControl },
268}
269
270impl<B: SplitByteSlice> MacFrame<B> {
271 pub fn parse(bytes: B, is_body_aligned: bool) -> Option<MacFrame<B>> {
275 let reader = BufferReader::new(bytes);
276 let frame_ctrl = FrameControl(reader.peek_value()?);
277 match frame_ctrl.frame_type() {
278 FrameType::MGMT => {
279 MgmtFrame::parse_frame_type_unchecked(reader, is_body_aligned).map(From::from)
280 }
281 FrameType::DATA => {
282 DataFrame::parse_frame_type_unchecked(reader, is_body_aligned).map(From::from)
283 }
284 FrameType::CTRL => CtrlFrame::parse_frame_type_unchecked(reader).map(From::from),
285 _frame_type => Some(MacFrame::Unsupported { frame_ctrl }),
286 }
287 }
288
289 pub fn frame_ctrl(&self) -> FrameControl {
290 match self {
291 MacFrame::Ctrl(ctrl_frame) => ctrl_frame.frame_ctrl(),
292 MacFrame::Data(data_frame) => data_frame.frame_ctrl(),
293 MacFrame::Mgmt(mgmt_frame) => mgmt_frame.frame_ctrl(),
294 MacFrame::Unsupported { frame_ctrl } => *frame_ctrl,
295 }
296 }
297}
298
299impl<B> From<CtrlFrame<B>> for MacFrame<B> {
300 fn from(ctrl: CtrlFrame<B>) -> Self {
301 MacFrame::Ctrl(ctrl)
302 }
303}
304
305impl<B> From<DataFrame<B>> for MacFrame<B> {
306 fn from(data: DataFrame<B>) -> Self {
307 MacFrame::Data(data)
308 }
309}
310
311impl<B> From<MgmtFrame<B>> for MacFrame<B> {
312 fn from(mgmt: MgmtFrame<B>) -> Self {
313 MacFrame::Mgmt(mgmt)
314 }
315}
316
317fn skip_body_alignment_padding<B: SplitByteSlice>(
319 hdr_len: usize,
320 reader: &mut BufferReader<B>,
321) -> Option<()> {
322 const OPTIONAL_BODY_ALIGNMENT_BYTES: usize = 4;
323
324 let padded_len = round_up(hdr_len, OPTIONAL_BODY_ALIGNMENT_BYTES);
325 let padding = padded_len - hdr_len;
326 reader.read_bytes(padding).map(|_| ())
327}
328
329fn round_up<T: Unsigned + Copy>(value: T, multiple: T) -> T {
330 let overshoot = value + multiple - T::one();
331 overshoot - overshoot % multiple
332}
333
334#[cfg(test)]
335mod tests {
336 use super::*;
337 use crate::assert_variant;
338 use crate::test_utils::fake_frames::*;
339
340 #[test]
341 fn parse_mgmt_frame() {
342 let bytes = make_mgmt_frame(false);
343 assert_variant!(
344 MacFrame::parse(&bytes[..], false),
345 Some(MacFrame::Mgmt(MgmtFrame { mgmt_hdr, ht_ctrl, body })) => {
346 assert_eq!(0x0101, { mgmt_hdr.frame_ctrl.0 });
347 assert_eq!(0x0202, { mgmt_hdr.duration });
348 assert_eq!(MacAddr::from([3, 3, 3, 3, 3, 3]), mgmt_hdr.addr1);
349 assert_eq!(MacAddr::from([4, 4, 4, 4, 4, 4]), mgmt_hdr.addr2);
350 assert_eq!(MacAddr::from([5, 5, 5, 5, 5, 5]), mgmt_hdr.addr3);
351 assert_eq!(0x0606, { mgmt_hdr.seq_ctrl.0 });
352 assert!(ht_ctrl.is_none());
353 assert_eq!(&body[..], &[9, 9, 9]);
354 },
355 "expected management frame"
356 );
357 }
358
359 #[test]
360 fn parse_mgmt_frame_too_short_unsupported() {
361 assert!(MacFrame::parse(&[0; 22][..], false).is_none());
363
364 assert_variant!(
366 MacFrame::parse(&[0xFF; 24][..], false),
367 Some(MacFrame::Unsupported { frame_ctrl }) => {
368 assert_eq!(frame_ctrl, FrameControl(0xFFFF))
369 },
370 "expected unsupported frame type"
371 );
372 }
373
374 #[test]
375 fn parse_data_frame() {
376 let bytes = make_data_frame_single_llc(None, None);
377 assert_variant!(
378 MacFrame::parse(&bytes[..], false),
379 Some(MacFrame::Data(DataFrame { fixed_fields, addr4, qos_ctrl, ht_ctrl, body })) => {
380 assert_eq!(0b00000000_10001000, { fixed_fields.frame_ctrl.0 });
381 assert_eq!(0x0202, { fixed_fields.duration });
382 assert_eq!(MacAddr::from([3, 3, 3, 3, 3, 3]), fixed_fields.addr1);
383 assert_eq!(MacAddr::from([4, 4, 4, 4, 4, 4]), fixed_fields.addr2);
384 assert_eq!(MacAddr::from([5, 5, 5, 5, 5, 5]), fixed_fields.addr3);
385 assert_eq!(0x0606, { fixed_fields.seq_ctrl.0 });
386 assert!(addr4.is_none());
387 assert_eq!(0x0101, qos_ctrl.expect("qos_ctrl not present").get().0);
388 assert!(ht_ctrl.is_none());
389 assert_eq!(&body[..], &[7, 7, 7, 8, 8, 8, 9, 10, 11, 11, 11]);
390 },
391 "expected management frame"
392 );
393 }
394
395 #[test]
396 fn parse_ctrl_frame() {
397 assert_variant!(
398 MacFrame::parse(&[
399 0b10100100, 0b00000000, 0b00000001, 0b11000000, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, ][..], false),
404 Some(MacFrame::Ctrl(CtrlFrame { frame_ctrl, body })) => {
405 assert_eq!(0b00000000_10100100, frame_ctrl.0);
406 assert_eq!(&body[..], &[
407 0b00000001, 0b11000000, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, ]);
411 },
412 "expected control frame"
413 );
414 }
415
416 #[test]
417 fn round_up_to_4() {
418 assert_eq!(0, round_up(0u32, 4));
419 assert_eq!(4, round_up(1u32, 4));
420 assert_eq!(4, round_up(2u32, 4));
421 assert_eq!(4, round_up(3u32, 4));
422 assert_eq!(4, round_up(4u32, 4));
423 assert_eq!(8, round_up(5u32, 4));
424 }
425}