wlan_common/ie/
parse.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use super::*;
6use crate::buffer_reader::BufferReader;
7use crate::error::{FrameParseError, FrameParseResult};
8use crate::organization::Oui;
9use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
10use paste::paste;
11use zerocopy::{Ref, SplitByteSlice};
12
13macro_rules! validate {
14    ( $condition:expr, $message:expr ) => {
15        if !$condition {
16            return Err($crate::error::FrameParseError(format!($message)));
17        }
18    };
19}
20
21macro_rules! simple_parse_func {
22    ( $ie_snake_case:ident ) => {
23        paste! {
24            pub fn [<parse_ $ie_snake_case>]<B: SplitByteSlice>(
25                raw_body: B,
26            ) -> FrameParseResult<Ref<B, [<$ie_snake_case:camel>]>> {
27                Ref::from_bytes(raw_body)
28                    .map_err(|_| FrameParseError(
29                        format!(concat!(
30                            "Invalid length or alignment for ",
31                            stringify!([<$ie_snake_case:camel>])))))
32            }
33        }
34    };
35}
36
37// Each of the following creates a `parse_some_ie()` function associated with a `SomeIe` type.
38simple_parse_func!(dsss_param_set);
39simple_parse_func!(ht_capabilities);
40simple_parse_func!(ht_operation);
41simple_parse_func!(rm_enabled_capabilities);
42simple_parse_func!(vht_capabilities);
43simple_parse_func!(vht_operation);
44simple_parse_func!(wmm_info);
45simple_parse_func!(wmm_param);
46simple_parse_func!(channel_switch_announcement);
47simple_parse_func!(extended_channel_switch_announcement);
48simple_parse_func!(sec_chan_offset);
49simple_parse_func!(wide_bandwidth_channel_switch);
50
51pub fn parse_ssid<B: SplitByteSlice>(raw_body: B) -> FrameParseResult<B> {
52    validate!(raw_body.len() <= (fidl_ieee80211::MAX_SSID_BYTE_LEN as usize), "SSID is too long");
53    Ok(raw_body)
54}
55
56pub fn parse_supported_rates<B: SplitByteSlice>(
57    raw_body: B,
58) -> FrameParseResult<Ref<B, [SupportedRate]>> {
59    // IEEE Std 802.11-2016, 9.2.4.3 specifies that the Supported Rates IE may contain at most
60    // eight rates. However, in practice some devices transmit more (rather than using Extended
61    // Supported Rates). As the rates are encoded in a standard IE, this function does not validate
62    // the number of rates to improve interoperability.
63    validate!(!raw_body.is_empty(), "Empty Supported Rates IE");
64    // unwrap() is OK because sizeof(SupportedRate) is 1, and any slice length is a multiple of 1
65    Ok(Ref::from_bytes(raw_body).unwrap())
66}
67
68pub fn parse_extended_supported_rates<B: SplitByteSlice>(
69    raw_body: B,
70) -> FrameParseResult<Ref<B, [SupportedRate]>> {
71    validate!(!raw_body.is_empty(), "Empty Extended Supported Rates IE");
72    // The maximum number of extended supported rates (each a single u8) is the same as the
73    // maximum number of bytes in an IE. Therefore, there is no need to check the max length
74    // of the extended supported rates IE body.
75    // unwrap() is OK because sizeof(SupportedRate) is 1, and any slice length is a multiple of 1
76    Ok(Ref::from_bytes(raw_body).unwrap())
77}
78
79pub fn parse_tim<B: SplitByteSlice>(raw_body: B) -> FrameParseResult<TimView<B>> {
80    let (header, bitmap) = Ref::<B, TimHeader>::from_prefix(raw_body).map_err(Into::into).map_err(
81        |_: zerocopy::SizeError<_, _>| {
82            FrameParseError(format!("Element body is too short to include a TIM header"))
83        },
84    )?;
85    validate!(!bitmap.is_empty(), "Bitmap in TIM is empty");
86    validate!(bitmap.len() <= TIM_MAX_BITMAP_LEN, "Bitmap in TIM is too long");
87    Ok(TimView { header: *header, bitmap })
88}
89
90pub fn parse_country<B: SplitByteSlice>(raw_body: B) -> FrameParseResult<CountryView<B>> {
91    let mut reader = BufferReader::new(raw_body);
92    let country_code = reader.read::<[u8; 2]>().ok_or_else(|| {
93        FrameParseError(format!("Element body is too short to include a country code"))
94    })?;
95    let environment = reader.read_byte().ok_or_else(|| {
96        FrameParseError(format!("Element body is too short to include the whole country string"))
97    })?;
98    Ok(CountryView {
99        country_code: *country_code,
100        environment: CountryEnvironment(environment),
101        subbands: reader.into_remaining(),
102    })
103}
104
105pub fn parse_ext_capabilities<B: SplitByteSlice>(raw_body: B) -> ExtCapabilitiesView<B> {
106    let mut reader = BufferReader::new(raw_body);
107    let ext_caps_octet_1 = reader.read();
108    let ext_caps_octet_2 = reader.read();
109    let ext_caps_octet_3 = reader.read();
110    ExtCapabilitiesView {
111        ext_caps_octet_1,
112        ext_caps_octet_2,
113        ext_caps_octet_3,
114        remaining: reader.into_remaining(),
115    }
116}
117
118pub fn parse_wpa_ie<B: SplitByteSlice>(raw_body: B) -> FrameParseResult<wpa::WpaIe> {
119    wpa::from_bytes(&raw_body[..])
120        .map(|(_, r)| r)
121        .map_err(|_| FrameParseError(format!("Failed to parse WPA IE")))
122}
123
124pub fn parse_transmit_power_envelope<B: SplitByteSlice>(
125    raw_body: B,
126) -> FrameParseResult<TransmitPowerEnvelopeView<B>> {
127    let mut reader = BufferReader::new(raw_body);
128    let transmit_power_info = reader
129        .read::<TransmitPowerInfo>()
130        .ok_or_else(|| FrameParseError(format!("Transmit Power Envelope element too short")))?;
131    if transmit_power_info.max_transmit_power_count() > 3 {
132        return FrameParseResult::Err(FrameParseError(format!(
133            "Invalid transmit power count for Transmit Power Envelope element"
134        )));
135    }
136    let expected_bytes_remaining = transmit_power_info.max_transmit_power_count() as usize + 1;
137    if reader.bytes_remaining() < expected_bytes_remaining {
138        return FrameParseResult::Err(FrameParseError(format!(
139            "Transmit Power Envelope element too short"
140        )));
141    } else if reader.bytes_remaining() > expected_bytes_remaining {
142        return FrameParseResult::Err(FrameParseError(format!(
143            "Transmit Power Envelope element too long"
144        )));
145    }
146    // Unwrap safe due to checks above.
147    let max_transmit_power_20 = reader.read().unwrap();
148    let max_transmit_power_40 = reader.read();
149    let max_transmit_power_80 = reader.read();
150    let max_transmit_power_160 = reader.read();
151    FrameParseResult::Ok(TransmitPowerEnvelopeView {
152        transmit_power_info,
153        max_transmit_power_20,
154        max_transmit_power_40,
155        max_transmit_power_80,
156        max_transmit_power_160,
157    })
158}
159
160pub fn parse_channel_switch_wrapper<B: SplitByteSlice>(
161    raw_body: B,
162) -> FrameParseResult<ChannelSwitchWrapperView<B>> {
163    let mut result = ChannelSwitchWrapperView {
164        new_country: None,
165        wide_bandwidth_channel_switch: None,
166        new_transmit_power_envelope: None,
167    };
168    let ie_reader = crate::ie::Reader::new(raw_body);
169    for (ie_id, ie_body) in ie_reader {
170        match ie_id {
171            Id::COUNTRY => {
172                result.new_country.replace(parse_country(ie_body)?);
173            }
174            Id::WIDE_BANDWIDTH_CHANNEL_SWITCH => {
175                result
176                    .wide_bandwidth_channel_switch
177                    .replace(parse_wide_bandwidth_channel_switch(ie_body)?);
178            }
179            Id::TRANSMIT_POWER_ENVELOPE => {
180                result.new_transmit_power_envelope.replace(parse_transmit_power_envelope(ie_body)?);
181            }
182            _ => {
183                return Err(FrameParseError(format!(
184                    "Unexpected sub-element Id in Channel Switch Wrapper"
185                )));
186            }
187        }
188    }
189    FrameParseResult::Ok(result)
190}
191
192pub fn parse_vendor_ie<B: SplitByteSlice>(raw_body: B) -> FrameParseResult<VendorIe<B>> {
193    let mut reader = BufferReader::new(raw_body);
194    let oui = *reader
195        .read::<Oui>()
196        .ok_or_else(|| FrameParseError(format!("Failed to read vendor OUI")))?;
197    let vendor_ie = match oui {
198        Oui::MSFT => {
199            let ie_type = reader.peek_byte();
200            match ie_type {
201                Some(wpa::VENDOR_SPECIFIC_TYPE) => {
202                    // We already know from our peek_byte that at least one byte remains, so this
203                    // split will not panic.
204                    let (_type, body) = reader.into_remaining().split_at(1).ok().unwrap();
205                    VendorIe::MsftLegacyWpa(body)
206                }
207                Some(wsc::VENDOR_SPECIFIC_TYPE) => {
208                    let (_type, body) = reader.into_remaining().split_at(1).ok().unwrap();
209                    VendorIe::Wsc(body)
210                }
211                // The first three bytes after OUI are OUI type, OUI subtype, and version.
212                Some(WMM_OUI_TYPE) if reader.bytes_remaining() >= 3 => {
213                    let body = reader.into_remaining();
214                    let subtype = body[1];
215                    // The version byte is 0x01 for both WMM Information and Parameter elements
216                    // as of WFA WMM v1.2.0.
217                    if body[2] != 0x01 {
218                        return Err(FrameParseError(format!("Unexpected WMM Version byte")));
219                    }
220                    match subtype {
221                        // Safe to split because we already checked that there are at least 3
222                        // bytes remaining.
223                        WMM_INFO_OUI_SUBTYPE => VendorIe::WmmInfo(body.split_at(3).ok().unwrap().1),
224                        WMM_PARAM_OUI_SUBTYPE => {
225                            VendorIe::WmmParam(body.split_at(3).ok().unwrap().1)
226                        }
227                        _ => VendorIe::Unknown { oui, body },
228                    }
229                }
230                _ => VendorIe::Unknown { oui, body: reader.into_remaining() },
231            }
232        }
233        Oui::WFA => {
234            let ie_type = reader.peek_byte();
235            match ie_type {
236                Some(owe_transition::VENDOR_SPECIFIC_TYPE) => {
237                    let (_type, body) = reader.into_remaining().split_at(1).ok().unwrap();
238                    VendorIe::OweTransition(body)
239                }
240                _ => VendorIe::Unknown { oui, body: reader.into_remaining() },
241            }
242        }
243        _ => VendorIe::Unknown { oui, body: reader.into_remaining() },
244    };
245    Ok(vendor_ie)
246}
247
248pub fn parse_rsnxe<B: SplitByteSlice>(raw_body: B) -> RsnxeView<B> {
249    let mut reader = BufferReader::new(raw_body);
250    let rsnxe_octet_1 = reader.read();
251    RsnxeView { rsnxe_octet_1, remaining: reader.into_remaining() }
252}
253
254pub fn parse_diffie_hellman_param<B: SplitByteSlice>(
255    raw_body: B,
256) -> FrameParseResult<DiffieHellmanParamView<B>> {
257    let mut reader = BufferReader::new(raw_body);
258    let group = reader
259        .read_value::<u16>()
260        .ok_or_else(|| FrameParseError(format!("Element body is too short to include DH group")))?;
261    let public_key = reader.into_remaining();
262    Ok(DiffieHellmanParamView { group, public_key })
263}
264
265#[cfg(test)]
266mod tests {
267    use super::*;
268    use assert_matches::assert_matches;
269    use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
270
271    #[repr(C)]
272    #[derive(IntoBytes, KnownLayout, FromBytes, Immutable)]
273    pub struct SomeIe {
274        some_field: u16,
275    }
276    simple_parse_func!(some_ie);
277
278    #[test]
279    pub fn simple_parse_func_ok() {
280        let some_ie = parse_some_ie(&[0xfa, 0xde][..]).unwrap();
281        assert_eq!(some_ie.some_field, 0xdefa);
282    }
283
284    #[test]
285    pub fn simple_parse_func_wrong_size() {
286        let err_too_short = parse_some_ie(&[0xfa][..]).err().unwrap();
287        assert_eq!(
288            "Error parsing frame: Invalid length or alignment for SomeIe",
289            &err_too_short.to_string()
290        );
291        let err_too_long = parse_some_ie(&[0xfa, 0xde, 0xed][..]).err().unwrap();
292        assert_eq!(
293            "Error parsing frame: Invalid length or alignment for SomeIe",
294            &err_too_long.to_string()
295        );
296    }
297
298    #[test]
299    pub fn simple_parse_func_wrong_alignment() {
300        // Construct valid length but incorrectly aligned SomeIe
301        struct Buf {
302            b: [u8; 3],
303            _t: u16, // Make Buf align to u16
304        }
305        let buf = Buf { b: [0x00, 0xfa, 0xde], _t: 0 };
306        let buf_slice = &buf.b[1..];
307        assert_eq!(buf_slice.len(), std::mem::size_of::<SomeIe>());
308
309        let err_not_aligned = parse_some_ie(buf_slice).err().unwrap();
310        assert_eq!(
311            "Error parsing frame: Invalid length or alignment for SomeIe",
312            &err_not_aligned.to_string()
313        );
314    }
315
316    #[test]
317    pub fn ssid_ok() {
318        assert_eq!(Ok(&[][..]), parse_ssid(&[][..]));
319        assert_eq!(Ok(&[1, 2, 3][..]), parse_ssid(&[1, 2, 3][..]));
320    }
321
322    #[test]
323    pub fn ssid_too_long() {
324        assert_eq!(Err(FrameParseError(format!("SSID is too long"))), parse_ssid(&[0u8; 33][..]));
325    }
326
327    #[test]
328    pub fn supported_rates_ok() {
329        let r = parse_supported_rates(&[1, 2, 3][..]).expect("expected Ok");
330        assert_eq!(&[SupportedRate(1), SupportedRate(2), SupportedRate(3)][..], &r[..]);
331    }
332
333    #[test]
334    pub fn supported_rates_empty() {
335        let err = parse_supported_rates(&[][..]).expect_err("expected Err");
336        assert_eq!("Error parsing frame: Empty Supported Rates IE", &err.to_string());
337    }
338
339    // This test expects to pass despite IEEE Std 802.11-2016, 9.2.4.3 specifying a limit of eight
340    // rates. This limit is intentionally ignored when parsing Supported Rates to improve
341    // interoperability with devices that write more than eight rates into the IE.
342    #[test]
343    pub fn supported_rates_ok_overloaded() {
344        let rates =
345            parse_supported_rates(&[0u8; 9][..]).expect("rejected overloaded Supported Rates IE");
346        assert_eq!(&rates[..], &[SupportedRate(0); 9][..],);
347    }
348
349    #[test]
350    pub fn tim_ok() {
351        let r = parse_tim(&[1, 2, 3, 4, 5][..]).expect("expected Ok");
352        assert_eq!(2, r.header.dtim_period);
353        assert_eq!(&[4, 5][..], r.bitmap);
354    }
355
356    #[test]
357    pub fn tim_too_short_for_header() {
358        let err = parse_tim(&[1, 2][..]).err().expect("expected Err");
359        assert_eq!(
360            "Error parsing frame: Element body is too short to include a TIM header",
361            &err.to_string()
362        );
363    }
364
365    #[test]
366    pub fn tim_empty_bitmap() {
367        let err = parse_tim(&[1, 2, 3][..]).err().expect("expected Err");
368        assert_eq!("Error parsing frame: Bitmap in TIM is empty", &err.to_string());
369    }
370
371    #[test]
372    pub fn tim_bitmap_too_long() {
373        let err = parse_tim(&[0u8; 255][..]).err().expect("expected Err");
374        assert_eq!("Error parsing frame: Bitmap in TIM is too long", &err.to_string());
375    }
376
377    #[test]
378    pub fn country_ok() {
379        // Country element without Element Id and length
380        #[rustfmt::skip]
381        let raw_body = [
382            0x55, 0x53, // Country: US
383            0x20, // Environment: Any
384            0x24, 0x04, 0x24, // Subband triplet 1
385            0x34, 0x04, 0x1e, // Subband triplet 2
386            0x64, 0x0c, 0x1e, // Subband triplet 3
387            0x95, 0x05, 0x24, // Subband triplet 4
388            0x00, // padding
389        ];
390        let country = parse_country(&raw_body[..]).expect("valid frame should result in OK");
391
392        assert_eq!(country.country_code, [0x55, 0x53]);
393        assert_eq!(country.environment, CountryEnvironment::ANY);
394        assert_eq!(country.subbands, &raw_body[3..]);
395    }
396
397    #[test]
398    pub fn country_too_short() {
399        let err = parse_country(&[0x55, 0x53][..]).err().expect("expected Err");
400        assert_eq!(
401            "Error parsing frame: Element body is too short to include the whole country string",
402            &err.to_string()
403        );
404    }
405
406    #[test]
407    pub fn channel_switch_announcement() {
408        let raw_csa = [1, 30, 40];
409        let csa =
410            parse_channel_switch_announcement(&raw_csa[..]).expect("valid CSA should result in OK");
411        assert_eq!(csa.mode, 1);
412        assert_eq!(csa.new_channel_number, 30);
413        assert_eq!(csa.channel_switch_count, 40);
414    }
415
416    #[test]
417    pub fn extended_channel_switch_announcement() {
418        let raw_ecsa = [1, 20, 30, 40];
419        let ecsa = parse_extended_channel_switch_announcement(&raw_ecsa[..])
420            .expect("valid CSA should result in OK");
421        assert_eq!(ecsa.mode, 1);
422        assert_eq!(ecsa.new_operating_class, 20);
423        assert_eq!(ecsa.new_channel_number, 30);
424        assert_eq!(ecsa.channel_switch_count, 40);
425    }
426
427    #[test]
428    pub fn wide_bandwidth_channel_switch() {
429        let raw_wbcs = [0, 10, 20];
430        let wbcs = parse_wide_bandwidth_channel_switch(&raw_wbcs[..])
431            .expect("valid WBCS should result in OK");
432        assert_eq!(wbcs.new_width, VhtChannelBandwidth::CBW_20_40);
433        assert_eq!(wbcs.new_center_freq_seg0, 10);
434        assert_eq!(wbcs.new_center_freq_seg1, 20);
435    }
436
437    #[test]
438    pub fn transmit_power_envelope_view() {
439        #[rustfmt::skip]
440        let raw_tpe = [
441            // transmit power information: All fields present, EIRP unit
442            0b00_000_011,
443            20, 40, 80, 160,
444        ];
445        let tpe =
446            parse_transmit_power_envelope(&raw_tpe[..]).expect("valid TPE should result in OK");
447        assert_eq!(tpe.transmit_power_info.max_transmit_power_count(), 3);
448        assert_eq!(
449            tpe.transmit_power_info.max_transmit_power_unit_interpretation(),
450            MaxTransmitPowerUnitInterpretation::EIRP
451        );
452        assert_eq!(*tpe.max_transmit_power_20, TransmitPower(20));
453        assert_eq!(tpe.max_transmit_power_40.map(|t| *t), Some(TransmitPower(40)));
454        assert_eq!(tpe.max_transmit_power_80.map(|t| *t), Some(TransmitPower(80)));
455        assert_eq!(tpe.max_transmit_power_160.map(|t| *t), Some(TransmitPower(160)));
456    }
457
458    #[test]
459    pub fn transmit_power_envelope_view_20_only() {
460        #[rustfmt::skip]
461        let raw_tpe = [
462            // transmit power information: Only 20 MHz, EIRP unit
463            0b00_000_000,
464            20,
465        ];
466        let tpe =
467            parse_transmit_power_envelope(&raw_tpe[..]).expect("valid TPE should result in OK");
468        assert_eq!(tpe.transmit_power_info.max_transmit_power_count(), 0);
469        assert_eq!(
470            tpe.transmit_power_info.max_transmit_power_unit_interpretation(),
471            MaxTransmitPowerUnitInterpretation::EIRP
472        );
473        assert_eq!(*tpe.max_transmit_power_20, TransmitPower(20));
474        assert_eq!(tpe.max_transmit_power_40, None);
475        assert_eq!(tpe.max_transmit_power_80, None);
476        assert_eq!(tpe.max_transmit_power_160, None);
477    }
478
479    #[test]
480    pub fn transmit_power_envelope_view_too_long() {
481        #[rustfmt::skip]
482        let raw_tpe = [
483            // transmit power information: Only 20 MHz, EIRP unit
484            0b00_000_000,
485            20, 40, 80, 160
486        ];
487        let err = parse_transmit_power_envelope(&raw_tpe[..]).err().expect("expected Err");
488        assert_eq!(
489            "Error parsing frame: Transmit Power Envelope element too long",
490            &err.to_string()
491        );
492    }
493
494    #[test]
495    pub fn transmit_power_envelope_view_too_short() {
496        #[rustfmt::skip]
497        let raw_tpe = [
498            // transmit power information: 20 + 40 MHz, EIRP unit
499            0b00_000_001,
500            20,
501        ];
502        let err = parse_transmit_power_envelope(&raw_tpe[..]).err().expect("expected Err");
503        assert_eq!(
504            "Error parsing frame: Transmit Power Envelope element too short",
505            &err.to_string()
506        );
507    }
508
509    #[test]
510    pub fn transmit_power_envelope_invalid_count() {
511        #[rustfmt::skip]
512        let raw_tpe = [
513            // transmit power information: Invalid count (4), EIRP unit
514            0b00_000_100,
515            20,
516        ];
517        let err = parse_transmit_power_envelope(&raw_tpe[..]).err().expect("expected Err");
518        assert_eq!(
519            "Error parsing frame: Invalid transmit power count for Transmit Power Envelope element",
520            &err.to_string()
521        );
522    }
523
524    #[test]
525    pub fn channel_switch_wrapper_view() {
526        #[rustfmt::skip]
527        let raw_csw = [
528            Id::COUNTRY.0, 3, b'U', b'S', b'O',
529            Id::WIDE_BANDWIDTH_CHANNEL_SWITCH.0, 3, 0, 10, 20,
530            Id::TRANSMIT_POWER_ENVELOPE.0, 2, 0b00_000_000, 20,
531        ];
532        let csw =
533            parse_channel_switch_wrapper(&raw_csw[..]).expect("valid CSW should result in OK");
534        let country = csw.new_country.expect("New country present in CSW.");
535        assert_eq!(country.country_code, [b'U', b'S']);
536        assert_eq!(country.environment, CountryEnvironment::OUTDOOR);
537        assert_matches!(csw.wide_bandwidth_channel_switch, Some(wbcs) => {
538            assert_eq!(wbcs.new_width, VhtChannelBandwidth::CBW_20_40);
539            assert_eq!(wbcs.new_center_freq_seg0, 10);
540            assert_eq!(wbcs.new_center_freq_seg1, 20);
541        });
542        let tpe = csw.new_transmit_power_envelope.expect("Transmit power present in CSW.");
543        assert_eq!(*tpe.max_transmit_power_20, TransmitPower(20));
544        assert_eq!(tpe.max_transmit_power_40, None);
545        assert_eq!(tpe.max_transmit_power_80, None);
546        assert_eq!(tpe.max_transmit_power_160, None);
547    }
548
549    #[test]
550    pub fn partial_channel_switch_wrapper_view() {
551        #[rustfmt::skip]
552        let raw_csw = [
553            Id::WIDE_BANDWIDTH_CHANNEL_SWITCH.0, 3, 0, 10, 20,
554        ];
555        let csw =
556            parse_channel_switch_wrapper(&raw_csw[..]).expect("valid CSW should result in OK");
557        assert!(csw.new_country.is_none());
558        assert_matches!(csw.wide_bandwidth_channel_switch, Some(wbcs) => {
559            assert_eq!(wbcs.new_width, VhtChannelBandwidth::CBW_20_40);
560            assert_eq!(wbcs.new_center_freq_seg0, 10);
561            assert_eq!(wbcs.new_center_freq_seg1, 20);
562        });
563        assert!(csw.new_transmit_power_envelope.is_none());
564    }
565
566    #[test]
567    pub fn channel_switch_wrapper_view_unexpected_subelement() {
568        #[rustfmt::skip]
569        let raw_csw = [
570            Id::WIDE_BANDWIDTH_CHANNEL_SWITCH.0, 3, 40, 10, 20,
571            Id::HT_OPERATION.0, 3, 1, 2, 3,
572        ];
573        let err = parse_channel_switch_wrapper(&raw_csw[..]).err().expect("expected Err");
574        assert_eq!(
575            "Error parsing frame: Unexpected sub-element Id in Channel Switch Wrapper",
576            &err.to_string()
577        );
578    }
579
580    #[test]
581    fn ht_capabilities_ok() {
582        // HtCapabilities element without Element Id and length
583        #[rustfmt::skip]
584        let raw_body = [
585            0x4e, 0x11, // HtCapabilitiInfo(u16)
586            0x1b, // AmpduParams(u8)
587            0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588            0x00, 0x00, 0xab, 0xcd, 0x00, 0x00, 0x00, 0x00, // SupportedMcsSet(u128)
589            0x06, 0x03, // HtExtCapabilities(u16)
590            0xc0, 0xb0, 0xcb, 0x13, // TxBfCapability(u32)
591            0x00, // AselCapability(u8)
592        ];
593        let ht_cap = parse_ht_capabilities(&raw_body[..]).expect("valid frame should result in OK");
594
595        let ht_cap_info = ht_cap.ht_cap_info;
596        assert_eq!(ht_cap_info.0, 0x114e);
597        assert_eq!(ht_cap_info.chan_width_set(), ChanWidthSet::TWENTY_FORTY);
598        assert_eq!(ht_cap_info.sm_power_save(), SmPowerSave::DISABLED);
599        assert_eq!(ht_cap_info.max_amsdu_len(), MaxAmsduLen::OCTETS_3839);
600
601        let ampdu_params = ht_cap.ampdu_params;
602        assert_eq!(ampdu_params.0, 0x1b);
603        assert_eq!(ampdu_params.max_ampdu_exponent().to_len(), 65535);
604        assert_eq!(ampdu_params.min_start_spacing(), MinMpduStartSpacing::EIGHT_USEC);
605
606        let mcs_set = ht_cap.mcs_set;
607        assert_eq!(mcs_set.0, 0x00000000_cdab0000_00000000_000000ff);
608        assert_eq!(mcs_set.rx_mcs().0, 0xff);
609        assert_eq!(mcs_set.rx_mcs().support(7), true);
610        assert_eq!(mcs_set.rx_mcs().support(8), false);
611        assert_eq!(mcs_set.rx_highest_rate(), 0x01ab);
612
613        let ht_ext_cap = ht_cap.ht_ext_cap;
614        let raw_value = ht_ext_cap.0;
615        assert_eq!(raw_value, 0x0306);
616        assert_eq!(ht_ext_cap.pco_transition(), PcoTransitionTime::PCO_5000_USEC);
617        assert_eq!(ht_ext_cap.mcs_feedback(), McsFeedback::BOTH);
618
619        let txbf_cap = ht_cap.txbf_cap;
620        let raw_value = txbf_cap.0;
621        assert_eq!(raw_value, 0x13cbb0c0);
622        assert_eq!(txbf_cap.calibration(), Calibration::RESPOND_INITIATE);
623        assert_eq!(txbf_cap.csi_feedback(), Feedback::IMMEDIATE);
624        assert_eq!(txbf_cap.noncomp_feedback(), Feedback::DELAYED);
625        assert_eq!(txbf_cap.min_grouping(), MinGroup::TWO);
626
627        // human-readable representation
628        assert_eq!(txbf_cap.csi_antennas().to_human(), 2);
629        assert_eq!(txbf_cap.noncomp_steering_ants().to_human(), 3);
630        assert_eq!(txbf_cap.comp_steering_ants().to_human(), 4);
631        assert_eq!(txbf_cap.csi_rows().to_human(), 2);
632        assert_eq!(txbf_cap.chan_estimation().to_human(), 3);
633
634        let asel_cap = ht_cap.asel_cap;
635        assert_eq!(asel_cap.0, 0);
636    }
637
638    #[test]
639    pub fn extended_supported_rates_ok() {
640        let r = parse_extended_supported_rates(&[1, 2, 3][..]).expect("expected Ok");
641        assert_eq!(&[SupportedRate(1), SupportedRate(2), SupportedRate(3)][..], &r[..]);
642    }
643
644    #[test]
645    pub fn extended_supported_rates_empty() {
646        let err = parse_extended_supported_rates(&[][..]).expect_err("expected Err");
647        assert_eq!("Error parsing frame: Empty Extended Supported Rates IE", &err.to_string());
648    }
649
650    #[test]
651    fn ht_operation_ok() {
652        // HtOperation element without Element Id and length
653        #[rustfmt::skip]
654        let raw_body = [
655            99, // primary_channel
656            0xff, 0xfe, 0xff, 0xff, 0xff, // ht_op_info
657            // basic_ht_mcs_set
658            0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659            0x00, 0x00, 0xab, 0xcd, 0x00, 0x00, 0x00, 0x00,
660        ];
661        let ht_op = parse_ht_operation(&raw_body[..]).expect("valid frame should result in OK");
662
663        assert_eq!(ht_op.primary_channel, 99);
664
665        let ht_op_info = ht_op.ht_op_info;
666        assert_eq!(ht_op_info.secondary_chan_offset(), SecChanOffset::SECONDARY_BELOW);
667        assert_eq!(ht_op_info.sta_chan_width(), StaChanWidth::ANY);
668        assert_eq!(ht_op_info.ht_protection(), HtProtection::TWENTY_MHZ);
669        assert_eq!(ht_op_info.pco_phase(), PcoPhase::FORTY_MHZ);
670
671        let basic_mcs_set = ht_op.basic_ht_mcs_set;
672        assert_eq!(basic_mcs_set.0, 0x00000000_cdab0000_00000000_000000ff);
673    }
674
675    #[test]
676    fn rm_enabled_capabilities_ok() {
677        #[rustfmt::skip]
678        let raw_body = [
679            0x03, 0x00, 0x00, 0x00, 0x02, // rm_enabled_capabilities
680        ];
681
682        let caps =
683            parse_rm_enabled_capabilities(&raw_body[..]).expect("valid frame should result in OK");
684        assert!(caps.link_measurement_enabled());
685        assert!(caps.neighbor_report_enabled());
686        assert!(!caps.lci_azimuth_enabled());
687        assert!(caps.antenna_enabled());
688        assert!(!caps.ftm_range_report_enabled());
689    }
690
691    #[test]
692    fn sec_chan_offset_ok() {
693        let sec_chan_offset =
694            parse_sec_chan_offset(&[3][..]).expect("valid sec chan offset should result in OK");
695        assert_eq!(sec_chan_offset.0, 3);
696    }
697
698    #[test]
699    fn ext_capabilities_ok() {
700        let data = [0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40];
701        let ext_capabilities = parse_ext_capabilities(&data[..]);
702        assert_matches!(ext_capabilities.ext_caps_octet_1, Some(caps) => {
703            assert!(caps.extended_channel_switching());
704            assert!(!caps.psmp_capability());
705        });
706        assert_matches!(ext_capabilities.ext_caps_octet_2, Some(caps) => {
707            assert!(!caps.civic_location());
708        });
709        assert_matches!(ext_capabilities.ext_caps_octet_3, Some(caps) => {
710            assert!(caps.bss_transition());
711            assert!(!caps.ac_station_count());
712        });
713        assert_eq!(ext_capabilities.remaining, &[0x00, 0x00, 0x00, 0x00, 0x40]);
714    }
715
716    #[test]
717    fn vht_capabilities_ok() {
718        // VhtCapabilities element without Element Id and length
719        #[rustfmt::skip]
720        let raw_body = [
721            0xfe, 0xff, 0xff, 0xff, // VhtCapabilitiesInfo(u32)
722            0xff, 0xaa, 0x00, 0x00, 0x55, 0xff, 0x00, 0x00, // VhtMcsNssSet(u64)
723        ];
724        let vht_cap = parse_vht_capabilities(&raw_body[..]).expect("expected OK from valid frames");
725
726        let cap_info = vht_cap.vht_cap_info;
727        assert_eq!(cap_info.max_mpdu_len(), MaxMpduLen::OCTECTS_11454);
728        assert_eq!(cap_info.link_adapt(), VhtLinkAdaptation::BOTH);
729        let max_ampdu_component = cap_info.max_ampdu_exponent();
730        assert_eq!(max_ampdu_component.to_len(), 1048575);
731
732        let mcs_nss = vht_cap.vht_mcs_nss;
733        assert_eq!(mcs_nss.rx_max_mcs().ss1(), VhtMcsSet::NONE);
734        assert_eq!(mcs_nss.rx_max_mcs().ss7(), VhtMcsSet::UP_TO_9);
735        assert_eq!(mcs_nss.tx_max_mcs().ss1(), VhtMcsSet::UP_TO_8);
736        assert_eq!(mcs_nss.tx_max_mcs().ss7(), VhtMcsSet::NONE);
737
738        assert_eq!(mcs_nss.rx_max_mcs().ss(2), Ok(VhtMcsSet::NONE));
739        assert_eq!(mcs_nss.rx_max_mcs().ss(6), Ok(VhtMcsSet::UP_TO_9));
740        assert_eq!(mcs_nss.tx_max_mcs().ss(2), Ok(VhtMcsSet::UP_TO_8));
741        assert_eq!(mcs_nss.tx_max_mcs().ss(6), Ok(VhtMcsSet::NONE));
742    }
743
744    #[test]
745    fn vht_operation_ok() {
746        // VhtOperation element without Element Id and length
747        #[rustfmt::skip]
748        let raw_body = [
749            231, // vht_cbw(u8)
750            232, // center_freq_seg0(u8)
751            233, // center_freq_seg1(u8)
752            0xff, 0x66, // basic_mcs_nss(VhtMcsNssMap(u16))
753        ];
754        let vht_op = parse_vht_operation(&raw_body[..]).expect("expected OK from valid frames");
755        assert_eq!(231, vht_op.vht_cbw.0);
756        assert_eq!(232, vht_op.center_freq_seg0);
757        assert_eq!(233, vht_op.center_freq_seg1);
758    }
759
760    #[test]
761    fn rsnxe_ok() {
762        let data = [0b00100001, 0x00, 0x00, 0x40];
763        let rsnxe = parse_rsnxe(&data[..]);
764        assert_matches!(rsnxe.rsnxe_octet_1, Some(oct1) => {
765            assert_eq!(oct1.field_length(), 1);
766            assert!(!oct1.protected_twt_operations_support());
767            assert!(oct1.sae_hash_to_element());
768        });
769        assert_eq!(rsnxe.remaining, &[0x00, 0x00, 0x40]);
770    }
771
772    #[test]
773    fn diffie_hellman_param_ok() {
774        let raw_body: Vec<u8> = vec![
775            0xaa, 0x00, // group
776            0xde, 0xad, 0xbe, 0xef, // public key (truncated)
777        ];
778        let dh_param =
779            parse_diffie_hellman_param(&raw_body[..]).expect("failed to parse DH param ie");
780        assert_eq!(dh_param.group, 0xaa);
781        assert_eq!(dh_param.public_key, &raw_body[2..]);
782    }
783
784    #[test]
785    fn parse_wpa_ie_ok() {
786        let raw_body: Vec<u8> = vec![
787            0x00, 0x50, 0xf2, // MSFT OUI
788            0x01, 0x01, 0x00, // WPA IE header
789            0x00, 0x50, 0xf2, 0x02, // multicast cipher: AKM
790            0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 unicast cipher: TKIP
791            0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 AKM: PSK
792        ];
793        let wpa_ie = parse_vendor_ie(&raw_body[..]).expect("failed to parse wpa vendor ie");
794        assert_matches!(wpa_ie, VendorIe::MsftLegacyWpa(wpa_body) => {
795            parse_wpa_ie(&wpa_body[..]).expect("failed to parse wpa vendor ie")
796        });
797    }
798
799    #[test]
800    fn parse_bad_wpa_ie() {
801        let raw_body: Vec<u8> = vec![
802            0x00, 0x50, 0xf2, // MSFT OUI
803            0x01, 0x01, 0x00, // WPA IE header
804            0x00, 0x50, 0xf2, 0x02, // multicast cipher: AKM
805                  // truncated
806        ];
807        // parse_vendor_ie does not validate the actual wpa ie body, so this
808        // succeeds.
809        let wpa_ie = parse_vendor_ie(&raw_body[..]).expect("failed to parse wpa vendor ie");
810        assert_matches!(wpa_ie, VendorIe::MsftLegacyWpa(wpa_body) => {
811            parse_wpa_ie(&wpa_body[..]).expect_err("parsed truncated wpa ie")
812        });
813    }
814
815    #[test]
816    fn parse_wmm_info_ie_ok() {
817        let raw_body = [
818            0x00, 0x50, 0xf2, // MSFT OUI
819            0x02, 0x00, 0x01, // WMM Info IE header
820            0x80, // QoS Info: U-APSD enabled
821        ];
822        let wmm_info_ie = parse_vendor_ie(&raw_body[..]).expect("expected Ok");
823        assert_matches!(wmm_info_ie, VendorIe::WmmInfo(body) => {
824            assert_matches!(parse_wmm_info(&body[..]), Ok(wmm_info) => {
825                assert_eq!(wmm_info.0, 0x80);
826            })
827        });
828    }
829
830    #[test]
831    fn parse_wmm_info_ie_too_short() {
832        let raw_body = [
833            0x00, 0x50, 0xf2, // MSFT OUI
834            0x02, 0x00, 0x01, // WMM Info IE header
835                  // truncated
836        ];
837        let wmm_info_ie = parse_vendor_ie(&raw_body[..]).expect("expected Ok");
838        assert_matches!(wmm_info_ie, VendorIe::WmmInfo(body) => {
839            parse_wmm_info(&body[..]).expect_err("parsed truncated WMM info ie")
840        });
841    }
842
843    #[test]
844    fn parse_wmm_param_ie_ok() {
845        let raw_body = [
846            0x00, 0x50, 0xf2, // MSFT OUI
847            0x02, 0x01, 0x01, // WMM Param IE header
848            0x80, // QoS Info: U-APSD enabled
849            0x00, // reserved
850            0x03, 0xa4, 0x00, 0x00, // AC_BE Params - ACM no, AIFSN 3, ECWmin/max 4/10, TXOP 0
851            0x27, 0xa4, 0x00, 0x00, // AC_BK Params - ACM no, AIFSN 7, ECWmin/max 4/10, TXOP 0
852            0x42, 0x43, 0x5e, 0x00, // AC_VI Params - ACM no, AIFSN 2, ECWmin/max 3/4, TXOP 94
853            0x62, 0x32, 0x2f, 0x00, // AC_VO Params - ACM no, AIFSN 2, ECWmin/max 2/3, TXOP 47
854        ];
855        let wmm_param_ie = parse_vendor_ie(&raw_body[..]).expect("expected Ok");
856        assert_matches!(wmm_param_ie, VendorIe::WmmParam(body) => {
857            assert_matches!(parse_wmm_param(&body[..]), Ok(wmm_param) => {
858                assert_eq!(wmm_param.wmm_info.0, 0x80);
859                let ac_be = wmm_param.ac_be_params;
860                assert_eq!(ac_be.aci_aifsn.aifsn(), 3);
861                assert_eq!(ac_be.aci_aifsn.acm(), false);
862                assert_eq!(ac_be.aci_aifsn.aci(), 0);
863                assert_eq!(ac_be.ecw_min_max.ecw_min(), 4);
864                assert_eq!(ac_be.ecw_min_max.ecw_max(), 10);
865                assert_eq!({ ac_be.txop_limit }, 0);
866
867                let ac_bk = wmm_param.ac_bk_params;
868                assert_eq!(ac_bk.aci_aifsn.aifsn(), 7);
869                assert_eq!(ac_bk.aci_aifsn.acm(), false);
870                assert_eq!(ac_bk.aci_aifsn.aci(), 1);
871                assert_eq!(ac_bk.ecw_min_max.ecw_min(), 4);
872                assert_eq!(ac_bk.ecw_min_max.ecw_max(), 10);
873                assert_eq!({ ac_bk.txop_limit }, 0);
874
875                let ac_vi = wmm_param.ac_vi_params;
876                assert_eq!(ac_vi.aci_aifsn.aifsn(), 2);
877                assert_eq!(ac_vi.aci_aifsn.acm(), false);
878                assert_eq!(ac_vi.aci_aifsn.aci(), 2);
879                assert_eq!(ac_vi.ecw_min_max.ecw_min(), 3);
880                assert_eq!(ac_vi.ecw_min_max.ecw_max(), 4);
881                assert_eq!({ ac_vi.txop_limit }, 94);
882
883                let ac_vo = wmm_param.ac_vo_params;
884                assert_eq!(ac_vo.aci_aifsn.aifsn(), 2);
885                assert_eq!(ac_vo.aci_aifsn.acm(), false);
886                assert_eq!(ac_vo.aci_aifsn.aci(), 3);
887                assert_eq!(ac_vo.ecw_min_max.ecw_min(), 2);
888                assert_eq!(ac_vo.ecw_min_max.ecw_max(), 3);
889                assert_eq!({ ac_vo.txop_limit }, 47);
890            });
891        });
892    }
893
894    #[test]
895    fn parse_wmm_param_ie_too_short() {
896        let raw_body = [
897            0x00, 0x50, 0xf2, // MSFT OUI
898            0x02, 0x01, 0x01, // WMM Param IE header
899            0x80, // QoS Info: U-APSD enabled
900            0x00, // reserved
901                  // truncated
902        ];
903        let wmm_param_ie = parse_vendor_ie(&raw_body[..]).expect("expected Ok");
904        assert_matches!(wmm_param_ie, VendorIe::WmmParam(body) => {
905            parse_wmm_param(&body[..]).expect_err("parsed truncated WMM param ie")
906        });
907    }
908
909    #[test]
910    fn parse_unknown_msft_ie() {
911        let raw_body: Vec<u8> = vec![
912            0x00, 0x50, 0xf2, // MSFT OUI
913            0xff, 0x01, 0x00, // header with unknown vendor specific IE type
914            0x00, 0x50, 0xf2, 0x02, // multicast cipher: AKM
915            0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 unicast cipher: TKIP
916            0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 AKM: PSK
917        ];
918        let ie = parse_vendor_ie(&raw_body[..]).expect("failed to parse ie");
919        assert_matches!(ie, VendorIe::Unknown { .. });
920    }
921
922    #[test]
923    fn parse_unknown_vendor_ie() {
924        let raw_body: Vec<u8> = vec![0x00, 0x12, 0x34]; // Made up OUI
925        let ie = parse_vendor_ie(&raw_body[..]).expect("failed to parse wpa vendor ie");
926        assert_matches!(ie, VendorIe::Unknown { .. });
927    }
928
929    #[test]
930    fn to_and_from_fidl_ht_cap() {
931        fidl_ieee80211::HtCapabilities {
932            bytes: fake_ht_capabilities().as_bytes().try_into().expect("HT Cap to FIDL"),
933        };
934        let fidl =
935            fidl_ieee80211::HtCapabilities { bytes: [0; fidl_ieee80211::HT_CAP_LEN as usize] };
936        assert!(parse_ht_capabilities(&fidl.bytes[..]).is_ok());
937    }
938
939    #[test]
940    fn to_and_from_fidl_vht_cap() {
941        fidl_ieee80211::VhtCapabilities {
942            bytes: fake_vht_capabilities().as_bytes().try_into().expect("VHT Cap to FIDL"),
943        };
944        let fidl =
945            fidl_ieee80211::VhtCapabilities { bytes: [0; fidl_ieee80211::VHT_CAP_LEN as usize] };
946        assert!(parse_vht_capabilities(&fidl.bytes[..]).is_ok());
947    }
948
949    #[test]
950    fn to_and_from_fidl_ht_op() {
951        fidl_ieee80211::HtOperation {
952            bytes: fake_ht_operation().as_bytes().try_into().expect("HT Op to FIDL"),
953        };
954        let fidl = fidl_ieee80211::HtOperation { bytes: [0; fidl_ieee80211::HT_OP_LEN as usize] };
955        assert!(parse_ht_operation(&fidl.bytes[..]).is_ok());
956    }
957
958    #[test]
959    fn to_and_from_fidl_vht_op() {
960        fidl_ieee80211::VhtOperation {
961            bytes: fake_vht_operation().as_bytes().try_into().expect("VHT Op to FIDL"),
962        };
963        let fidl = fidl_ieee80211::VhtOperation { bytes: [0; fidl_ieee80211::VHT_OP_LEN as usize] };
964        assert!(parse_vht_operation(&fidl.bytes[..]).is_ok());
965    }
966}