1use 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
37simple_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!(wide_bandwidth_channel_switch);
49simple_parse_func!(sec_chan_offset);
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 validate!(!raw_body.is_empty(), "Empty Supported Rates IE");
64 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 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 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 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 Some(WMM_OUI_TYPE) if reader.bytes_remaining() >= 3 => {
213 let body = reader.into_remaining();
214 let subtype = body[1];
215 if body[2] != 0x01 {
218 return Err(FrameParseError(format!("Unexpected WMM Version byte")));
219 }
220 match subtype {
221 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 struct Buf {
302 b: [u8; 3],
303 _t: u16, }
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 #[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 #[rustfmt::skip]
381 let raw_body = [
382 0x55, 0x53, 0x20, 0x24, 0x04, 0x24, 0x34, 0x04, 0x1e, 0x64, 0x0c, 0x1e, 0x95, 0x05, 0x24, 0x00, ];
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_valid_2g() {
418 let raw_ecsa = [1, 81, 30, 40];
419 let ecsa = parse_extended_channel_switch_announcement(&raw_ecsa[..])
420 .expect("valid ECSA should result in OK");
421 assert_eq!(ecsa.mode, 1);
422 assert_eq!(ecsa.new_operating_class, 81);
423 assert_eq!(ecsa.new_channel_number, 30);
424 assert_eq!(ecsa.channel_switch_count, 40);
425 assert_eq!(ecsa.get_band(), fidl_ieee80211::WlanBand::TwoGhz);
426 }
427
428 #[test]
429 pub fn extended_channel_switch_announcement_valid_5g() {
430 let raw_ecsa = [1, 115, 30, 40];
431 let ecsa = parse_extended_channel_switch_announcement(&raw_ecsa[..])
432 .expect("valid ECSA should result in OK");
433 assert_eq!(ecsa.get_band(), fidl_ieee80211::WlanBand::FiveGhz);
434 }
435
436 #[test]
437 pub fn extended_channel_switch_announcement_invalid_op_class() {
438 let raw_ecsa = [1, 20, 30, 40];
439 let ecsa = parse_extended_channel_switch_announcement(&raw_ecsa[..])
440 .expect("valid ECSA should result in OK even with invalid op class");
441 assert_eq!(ecsa.get_band(), fidl_ieee80211::WlanBand::unknown());
442 }
443
444 #[test]
445 pub fn wide_bandwidth_channel_switch() {
446 let raw_wbcs = [0, 10, 20];
447 let wbcs = parse_wide_bandwidth_channel_switch(&raw_wbcs[..])
448 .expect("valid WBCS should result in OK");
449 assert_eq!(wbcs.new_width, VhtChannelBandwidth::CBW_20_40);
450 assert_eq!(wbcs.new_center_freq_seg0, 10);
451 assert_eq!(wbcs.new_center_freq_seg1, 20);
452 }
453
454 #[test]
455 pub fn transmit_power_envelope_view() {
456 #[rustfmt::skip]
457 let raw_tpe = [
458 0b00_000_011,
460 20, 40, 80, 160,
461 ];
462 let tpe =
463 parse_transmit_power_envelope(&raw_tpe[..]).expect("valid TPE should result in OK");
464 assert_eq!(tpe.transmit_power_info.max_transmit_power_count(), 3);
465 assert_eq!(
466 tpe.transmit_power_info.max_transmit_power_unit_interpretation(),
467 MaxTransmitPowerUnitInterpretation::EIRP
468 );
469 assert_eq!(*tpe.max_transmit_power_20, TransmitPower(20));
470 assert_eq!(tpe.max_transmit_power_40.map(|t| *t), Some(TransmitPower(40)));
471 assert_eq!(tpe.max_transmit_power_80.map(|t| *t), Some(TransmitPower(80)));
472 assert_eq!(tpe.max_transmit_power_160.map(|t| *t), Some(TransmitPower(160)));
473 }
474
475 #[test]
476 pub fn transmit_power_envelope_view_20_only() {
477 #[rustfmt::skip]
478 let raw_tpe = [
479 0b00_000_000,
481 20,
482 ];
483 let tpe =
484 parse_transmit_power_envelope(&raw_tpe[..]).expect("valid TPE should result in OK");
485 assert_eq!(tpe.transmit_power_info.max_transmit_power_count(), 0);
486 assert_eq!(
487 tpe.transmit_power_info.max_transmit_power_unit_interpretation(),
488 MaxTransmitPowerUnitInterpretation::EIRP
489 );
490 assert_eq!(*tpe.max_transmit_power_20, TransmitPower(20));
491 assert_eq!(tpe.max_transmit_power_40, None);
492 assert_eq!(tpe.max_transmit_power_80, None);
493 assert_eq!(tpe.max_transmit_power_160, None);
494 }
495
496 #[test]
497 pub fn transmit_power_envelope_view_too_long() {
498 #[rustfmt::skip]
499 let raw_tpe = [
500 0b00_000_000,
502 20, 40, 80, 160
503 ];
504 let err = parse_transmit_power_envelope(&raw_tpe[..]).err().expect("expected Err");
505 assert_eq!(
506 "Error parsing frame: Transmit Power Envelope element too long",
507 &err.to_string()
508 );
509 }
510
511 #[test]
512 pub fn transmit_power_envelope_view_too_short() {
513 #[rustfmt::skip]
514 let raw_tpe = [
515 0b00_000_001,
517 20,
518 ];
519 let err = parse_transmit_power_envelope(&raw_tpe[..]).err().expect("expected Err");
520 assert_eq!(
521 "Error parsing frame: Transmit Power Envelope element too short",
522 &err.to_string()
523 );
524 }
525
526 #[test]
527 pub fn transmit_power_envelope_invalid_count() {
528 #[rustfmt::skip]
529 let raw_tpe = [
530 0b00_000_100,
532 20,
533 ];
534 let err = parse_transmit_power_envelope(&raw_tpe[..]).err().expect("expected Err");
535 assert_eq!(
536 "Error parsing frame: Invalid transmit power count for Transmit Power Envelope element",
537 &err.to_string()
538 );
539 }
540
541 #[test]
542 pub fn channel_switch_wrapper_view() {
543 #[rustfmt::skip]
544 let raw_csw = [
545 Id::COUNTRY.0, 3, b'U', b'S', b'O',
546 Id::WIDE_BANDWIDTH_CHANNEL_SWITCH.0, 3, 0, 10, 20,
547 Id::TRANSMIT_POWER_ENVELOPE.0, 2, 0b00_000_000, 20,
548 ];
549 let csw =
550 parse_channel_switch_wrapper(&raw_csw[..]).expect("valid CSW should result in OK");
551 let country = csw.new_country.expect("New country present in CSW.");
552 assert_eq!(country.country_code, [b'U', b'S']);
553 assert_eq!(country.environment, CountryEnvironment::OUTDOOR);
554 assert_matches!(csw.wide_bandwidth_channel_switch, Some(wbcs) => {
555 assert_eq!(wbcs.new_width, VhtChannelBandwidth::CBW_20_40);
556 assert_eq!(wbcs.new_center_freq_seg0, 10);
557 assert_eq!(wbcs.new_center_freq_seg1, 20);
558 });
559 let tpe = csw.new_transmit_power_envelope.expect("Transmit power present in CSW.");
560 assert_eq!(*tpe.max_transmit_power_20, TransmitPower(20));
561 assert_eq!(tpe.max_transmit_power_40, None);
562 assert_eq!(tpe.max_transmit_power_80, None);
563 assert_eq!(tpe.max_transmit_power_160, None);
564 }
565
566 #[test]
567 pub fn partial_channel_switch_wrapper_view() {
568 #[rustfmt::skip]
569 let raw_csw = [
570 Id::WIDE_BANDWIDTH_CHANNEL_SWITCH.0, 3, 0, 10, 20,
571 ];
572 let csw =
573 parse_channel_switch_wrapper(&raw_csw[..]).expect("valid CSW should result in OK");
574 assert!(csw.new_country.is_none());
575 assert_matches!(csw.wide_bandwidth_channel_switch, Some(wbcs) => {
576 assert_eq!(wbcs.new_width, VhtChannelBandwidth::CBW_20_40);
577 assert_eq!(wbcs.new_center_freq_seg0, 10);
578 assert_eq!(wbcs.new_center_freq_seg1, 20);
579 });
580 assert!(csw.new_transmit_power_envelope.is_none());
581 }
582
583 #[test]
584 pub fn channel_switch_wrapper_view_unexpected_subelement() {
585 #[rustfmt::skip]
586 let raw_csw = [
587 Id::WIDE_BANDWIDTH_CHANNEL_SWITCH.0, 3, 40, 10, 20,
588 Id::HT_OPERATION.0, 3, 1, 2, 3,
589 ];
590 let err = parse_channel_switch_wrapper(&raw_csw[..]).err().expect("expected Err");
591 assert_eq!(
592 "Error parsing frame: Unexpected sub-element Id in Channel Switch Wrapper",
593 &err.to_string()
594 );
595 }
596
597 #[test]
598 fn ht_capabilities_ok() {
599 #[rustfmt::skip]
601 let raw_body = [
602 0x4e, 0x11, 0x1b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
605 0x00, 0x00, 0xab, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0xc0, 0xb0, 0xcb, 0x13, 0x00, ];
610 let ht_cap = parse_ht_capabilities(&raw_body[..]).expect("valid frame should result in OK");
611
612 let ht_cap_info = ht_cap.ht_cap_info;
613 assert_eq!(ht_cap_info.0, 0x114e);
614 assert_eq!(ht_cap_info.chan_width_set(), ChanWidthSet::TWENTY_FORTY);
615 assert_eq!(ht_cap_info.sm_power_save(), SmPowerSave::DISABLED);
616 assert_eq!(ht_cap_info.max_amsdu_len(), MaxAmsduLen::OCTETS_3839);
617
618 let ampdu_params = ht_cap.ampdu_params;
619 assert_eq!(ampdu_params.0, 0x1b);
620 assert_eq!(ampdu_params.max_ampdu_exponent().to_len(), 65535);
621 assert_eq!(ampdu_params.min_start_spacing(), MinMpduStartSpacing::EIGHT_USEC);
622
623 let mcs_set = ht_cap.mcs_set;
624 assert_eq!(mcs_set.0, 0x00000000_cdab0000_00000000_000000ff);
625 assert_eq!(mcs_set.rx_mcs().0, 0xff);
626 assert_eq!(mcs_set.rx_mcs().support(7), true);
627 assert_eq!(mcs_set.rx_mcs().support(8), false);
628 assert_eq!(mcs_set.rx_highest_rate(), 0x01ab);
629
630 let ht_ext_cap = ht_cap.ht_ext_cap;
631 let raw_value = ht_ext_cap.0;
632 assert_eq!(raw_value, 0x0306);
633 assert_eq!(ht_ext_cap.pco_transition(), PcoTransitionTime::PCO_5000_USEC);
634 assert_eq!(ht_ext_cap.mcs_feedback(), McsFeedback::BOTH);
635
636 let txbf_cap = ht_cap.txbf_cap;
637 let raw_value = txbf_cap.0;
638 assert_eq!(raw_value, 0x13cbb0c0);
639 assert_eq!(txbf_cap.calibration(), Calibration::RESPOND_INITIATE);
640 assert_eq!(txbf_cap.csi_feedback(), Feedback::IMMEDIATE);
641 assert_eq!(txbf_cap.noncomp_feedback(), Feedback::DELAYED);
642 assert_eq!(txbf_cap.min_grouping(), MinGroup::TWO);
643
644 assert_eq!(txbf_cap.csi_antennas().to_human(), 2);
646 assert_eq!(txbf_cap.noncomp_steering_ants().to_human(), 3);
647 assert_eq!(txbf_cap.comp_steering_ants().to_human(), 4);
648 assert_eq!(txbf_cap.csi_rows().to_human(), 2);
649 assert_eq!(txbf_cap.chan_estimation().to_human(), 3);
650
651 let asel_cap = ht_cap.asel_cap;
652 assert_eq!(asel_cap.0, 0);
653 }
654
655 #[test]
656 pub fn extended_supported_rates_ok() {
657 let r = parse_extended_supported_rates(&[1, 2, 3][..]).expect("expected Ok");
658 assert_eq!(&[SupportedRate(1), SupportedRate(2), SupportedRate(3)][..], &r[..]);
659 }
660
661 #[test]
662 pub fn extended_supported_rates_empty() {
663 let err = parse_extended_supported_rates(&[][..]).expect_err("expected Err");
664 assert_eq!("Error parsing frame: Empty Extended Supported Rates IE", &err.to_string());
665 }
666
667 #[test]
668 fn ht_operation_ok() {
669 #[rustfmt::skip]
671 let raw_body = [
672 99, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676 0x00, 0x00, 0xab, 0xcd, 0x00, 0x00, 0x00, 0x00,
677 ];
678 let ht_op = parse_ht_operation(&raw_body[..]).expect("valid frame should result in OK");
679
680 assert_eq!(ht_op.primary_channel, 99);
681
682 let ht_op_info = ht_op.ht_op_info;
683 assert_eq!(ht_op_info.secondary_chan_offset(), SecChanOffset::SECONDARY_BELOW);
684 assert_eq!(ht_op_info.sta_chan_width(), StaChanWidth::ANY);
685 assert_eq!(ht_op_info.ht_protection(), HtProtection::TWENTY_MHZ);
686 assert_eq!(ht_op_info.pco_phase(), PcoPhase::FORTY_MHZ);
687
688 let basic_mcs_set = ht_op.basic_ht_mcs_set;
689 assert_eq!(basic_mcs_set.0, 0x00000000_cdab0000_00000000_000000ff);
690 }
691
692 #[test]
693 fn rm_enabled_capabilities_ok() {
694 #[rustfmt::skip]
695 let raw_body = [
696 0x03, 0x00, 0x00, 0x00, 0x02, ];
698
699 let caps =
700 parse_rm_enabled_capabilities(&raw_body[..]).expect("valid frame should result in OK");
701 assert!(caps.link_measurement_enabled());
702 assert!(caps.neighbor_report_enabled());
703 assert!(!caps.lci_azimuth_enabled());
704 assert!(caps.antenna_enabled());
705 assert!(!caps.ftm_range_report_enabled());
706 }
707
708 #[test]
709 fn sec_chan_offset_ok() {
710 let sec_chan_offset =
711 parse_sec_chan_offset(&[3][..]).expect("valid sec chan offset should result in OK");
712 assert_eq!(sec_chan_offset.0, 3);
713 }
714
715 #[test]
716 fn ext_capabilities_ok() {
717 let data = [0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40];
718 let ext_capabilities = parse_ext_capabilities(&data[..]);
719 assert_matches!(ext_capabilities.ext_caps_octet_1, Some(caps) => {
720 assert!(caps.extended_channel_switching());
721 assert!(!caps.psmp_capability());
722 });
723 assert_matches!(ext_capabilities.ext_caps_octet_2, Some(caps) => {
724 assert!(!caps.civic_location());
725 });
726 assert_matches!(ext_capabilities.ext_caps_octet_3, Some(caps) => {
727 assert!(caps.bss_transition());
728 assert!(!caps.ac_station_count());
729 });
730 assert_eq!(ext_capabilities.remaining, &[0x00, 0x00, 0x00, 0x00, 0x40]);
731 }
732
733 #[test]
734 fn vht_capabilities_ok() {
735 #[rustfmt::skip]
737 let raw_body = [
738 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0x00, 0x00, 0x55, 0xff, 0x00, 0x00, ];
741 let vht_cap = parse_vht_capabilities(&raw_body[..]).expect("expected OK from valid frames");
742
743 let cap_info = vht_cap.vht_cap_info;
744 assert_eq!(cap_info.max_mpdu_len(), MaxMpduLen::OCTECTS_11454);
745 assert_eq!(cap_info.link_adapt(), VhtLinkAdaptation::BOTH);
746 let max_ampdu_component = cap_info.max_ampdu_exponent();
747 assert_eq!(max_ampdu_component.to_len(), 1048575);
748
749 let mcs_nss = vht_cap.vht_mcs_nss;
750 assert_eq!(mcs_nss.rx_max_mcs().ss1(), VhtMcsSet::NONE);
751 assert_eq!(mcs_nss.rx_max_mcs().ss7(), VhtMcsSet::UP_TO_9);
752 assert_eq!(mcs_nss.tx_max_mcs().ss1(), VhtMcsSet::UP_TO_8);
753 assert_eq!(mcs_nss.tx_max_mcs().ss7(), VhtMcsSet::NONE);
754
755 assert_eq!(mcs_nss.rx_max_mcs().ss(2), Ok(VhtMcsSet::NONE));
756 assert_eq!(mcs_nss.rx_max_mcs().ss(6), Ok(VhtMcsSet::UP_TO_9));
757 assert_eq!(mcs_nss.tx_max_mcs().ss(2), Ok(VhtMcsSet::UP_TO_8));
758 assert_eq!(mcs_nss.tx_max_mcs().ss(6), Ok(VhtMcsSet::NONE));
759 }
760
761 #[test]
762 fn vht_operation_ok() {
763 #[rustfmt::skip]
765 let raw_body = [
766 231, 232, 233, 0xff, 0x66, ];
771 let vht_op = parse_vht_operation(&raw_body[..]).expect("expected OK from valid frames");
772 assert_eq!(231, vht_op.vht_cbw.0);
773 assert_eq!(232, vht_op.center_freq_seg0);
774 assert_eq!(233, vht_op.center_freq_seg1);
775 }
776
777 #[test]
778 fn rsnxe_ok() {
779 let data = [0b00100001, 0x00, 0x00, 0x40];
780 let rsnxe = parse_rsnxe(&data[..]);
781 assert_matches!(rsnxe.rsnxe_octet_1, Some(oct1) => {
782 assert_eq!(oct1.field_length(), 1);
783 assert!(!oct1.protected_twt_operations_support());
784 assert!(oct1.sae_hash_to_element());
785 });
786 assert_eq!(rsnxe.remaining, &[0x00, 0x00, 0x40]);
787 }
788
789 #[test]
790 fn diffie_hellman_param_ok() {
791 let raw_body: Vec<u8> = vec![
792 0xaa, 0x00, 0xde, 0xad, 0xbe, 0xef, ];
795 let dh_param =
796 parse_diffie_hellman_param(&raw_body[..]).expect("failed to parse DH param ie");
797 assert_eq!(dh_param.group, 0xaa);
798 assert_eq!(dh_param.public_key, &raw_body[2..]);
799 }
800
801 #[test]
802 fn parse_wpa_ie_ok() {
803 let raw_body: Vec<u8> = vec![
804 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, ];
810 let wpa_ie = parse_vendor_ie(&raw_body[..]).expect("failed to parse wpa vendor ie");
811 assert_matches!(wpa_ie, VendorIe::MsftLegacyWpa(wpa_body) => {
812 parse_wpa_ie(&wpa_body[..]).expect("failed to parse wpa vendor ie")
813 });
814 }
815
816 #[test]
817 fn parse_bad_wpa_ie() {
818 let raw_body: Vec<u8> = vec![
819 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, ];
824 let wpa_ie = parse_vendor_ie(&raw_body[..]).expect("failed to parse wpa vendor ie");
827 assert_matches!(wpa_ie, VendorIe::MsftLegacyWpa(wpa_body) => {
828 parse_wpa_ie(&wpa_body[..]).expect_err("parsed truncated wpa ie")
829 });
830 }
831
832 #[test]
833 fn parse_wmm_info_ie_ok() {
834 let raw_body = [
835 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x80, ];
839 let wmm_info_ie = parse_vendor_ie(&raw_body[..]).expect("expected Ok");
840 assert_matches!(wmm_info_ie, VendorIe::WmmInfo(body) => {
841 assert_matches!(parse_wmm_info(&body[..]), Ok(wmm_info) => {
842 assert_eq!(wmm_info.0, 0x80);
843 })
844 });
845 }
846
847 #[test]
848 fn parse_wmm_info_ie_too_short() {
849 let raw_body = [
850 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, ];
854 let wmm_info_ie = parse_vendor_ie(&raw_body[..]).expect("expected Ok");
855 assert_matches!(wmm_info_ie, VendorIe::WmmInfo(body) => {
856 parse_wmm_info(&body[..]).expect_err("parsed truncated WMM info ie")
857 });
858 }
859
860 #[test]
861 fn parse_wmm_param_ie_ok() {
862 let raw_body = [
863 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x80, 0x00, 0x03, 0xa4, 0x00, 0x00, 0x27, 0xa4, 0x00, 0x00, 0x42, 0x43, 0x5e, 0x00, 0x62, 0x32, 0x2f, 0x00, ];
872 let wmm_param_ie = parse_vendor_ie(&raw_body[..]).expect("expected Ok");
873 assert_matches!(wmm_param_ie, VendorIe::WmmParam(body) => {
874 assert_matches!(parse_wmm_param(&body[..]), Ok(wmm_param) => {
875 assert_eq!(wmm_param.wmm_info.0, 0x80);
876 let ac_be = wmm_param.ac_be_params;
877 assert_eq!(ac_be.aci_aifsn.aifsn(), 3);
878 assert_eq!(ac_be.aci_aifsn.acm(), false);
879 assert_eq!(ac_be.aci_aifsn.aci(), 0);
880 assert_eq!(ac_be.ecw_min_max.ecw_min(), 4);
881 assert_eq!(ac_be.ecw_min_max.ecw_max(), 10);
882 assert_eq!({ ac_be.txop_limit }, 0);
883
884 let ac_bk = wmm_param.ac_bk_params;
885 assert_eq!(ac_bk.aci_aifsn.aifsn(), 7);
886 assert_eq!(ac_bk.aci_aifsn.acm(), false);
887 assert_eq!(ac_bk.aci_aifsn.aci(), 1);
888 assert_eq!(ac_bk.ecw_min_max.ecw_min(), 4);
889 assert_eq!(ac_bk.ecw_min_max.ecw_max(), 10);
890 assert_eq!({ ac_bk.txop_limit }, 0);
891
892 let ac_vi = wmm_param.ac_vi_params;
893 assert_eq!(ac_vi.aci_aifsn.aifsn(), 2);
894 assert_eq!(ac_vi.aci_aifsn.acm(), false);
895 assert_eq!(ac_vi.aci_aifsn.aci(), 2);
896 assert_eq!(ac_vi.ecw_min_max.ecw_min(), 3);
897 assert_eq!(ac_vi.ecw_min_max.ecw_max(), 4);
898 assert_eq!({ ac_vi.txop_limit }, 94);
899
900 let ac_vo = wmm_param.ac_vo_params;
901 assert_eq!(ac_vo.aci_aifsn.aifsn(), 2);
902 assert_eq!(ac_vo.aci_aifsn.acm(), false);
903 assert_eq!(ac_vo.aci_aifsn.aci(), 3);
904 assert_eq!(ac_vo.ecw_min_max.ecw_min(), 2);
905 assert_eq!(ac_vo.ecw_min_max.ecw_max(), 3);
906 assert_eq!({ ac_vo.txop_limit }, 47);
907 });
908 });
909 }
910
911 #[test]
912 fn parse_wmm_param_ie_too_short() {
913 let raw_body = [
914 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x80, 0x00, ];
920 let wmm_param_ie = parse_vendor_ie(&raw_body[..]).expect("expected Ok");
921 assert_matches!(wmm_param_ie, VendorIe::WmmParam(body) => {
922 parse_wmm_param(&body[..]).expect_err("parsed truncated WMM param ie")
923 });
924 }
925
926 #[test]
927 fn parse_unknown_msft_ie() {
928 let raw_body: Vec<u8> = vec![
929 0x00, 0x50, 0xf2, 0xff, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, ];
935 let ie = parse_vendor_ie(&raw_body[..]).expect("failed to parse ie");
936 assert_matches!(ie, VendorIe::Unknown { .. });
937 }
938
939 #[test]
940 fn parse_unknown_vendor_ie() {
941 let raw_body: Vec<u8> = vec![0x00, 0x12, 0x34]; let ie = parse_vendor_ie(&raw_body[..]).expect("failed to parse wpa vendor ie");
943 assert_matches!(ie, VendorIe::Unknown { .. });
944 }
945
946 #[test]
947 fn to_and_from_fidl_ht_cap() {
948 fidl_ieee80211::HtCapabilities {
949 bytes: fake_ht_capabilities().as_bytes().try_into().expect("HT Cap to FIDL"),
950 };
951 let fidl =
952 fidl_ieee80211::HtCapabilities { bytes: [0; fidl_ieee80211::HT_CAP_LEN as usize] };
953 assert!(parse_ht_capabilities(&fidl.bytes[..]).is_ok());
954 }
955
956 #[test]
957 fn to_and_from_fidl_vht_cap() {
958 fidl_ieee80211::VhtCapabilities {
959 bytes: fake_vht_capabilities().as_bytes().try_into().expect("VHT Cap to FIDL"),
960 };
961 let fidl =
962 fidl_ieee80211::VhtCapabilities { bytes: [0; fidl_ieee80211::VHT_CAP_LEN as usize] };
963 assert!(parse_vht_capabilities(&fidl.bytes[..]).is_ok());
964 }
965
966 #[test]
967 fn to_and_from_fidl_ht_op() {
968 fidl_ieee80211::HtOperation {
969 bytes: fake_ht_operation().as_bytes().try_into().expect("HT Op to FIDL"),
970 };
971 let fidl = fidl_ieee80211::HtOperation { bytes: [0; fidl_ieee80211::HT_OP_LEN as usize] };
972 assert!(parse_ht_operation(&fidl.bytes[..]).is_ok());
973 }
974
975 #[test]
976 fn to_and_from_fidl_vht_op() {
977 fidl_ieee80211::VhtOperation {
978 bytes: fake_vht_operation().as_bytes().try_into().expect("VHT Op to FIDL"),
979 };
980 let fidl = fidl_ieee80211::VhtOperation { bytes: [0; fidl_ieee80211::VHT_OP_LEN as usize] };
981 assert!(parse_vht_operation(&fidl.bytes[..]).is_ok());
982 }
983}