1use crate::buffer_reader::BufferReader;
6use crate::mac::ReasonCode;
7use crate::organization::Oui;
8use crate::UnalignedView;
9use ieee80211::MacAddr;
10use static_assertions::const_assert_eq;
11use std::mem::size_of;
12use wlan_bitfield::bitfield;
13use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned};
14use {
15 banjo_fuchsia_wlan_ieee80211 as banjo_ieee80211, fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211,
16};
17
18macro_rules! pub_const {
19 ($name:ident, $val:expr) => {
20 pub const $name: Self = Self($val);
21 };
22}
23
24#[bitfield(
26 0..=6 rate,
27 7 basic,
28)]
29#[repr(C)]
30#[derive(
31 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy,
32)]
33pub struct SupportedRate(pub u8);
34
35impl SupportedRate {
36 pub fn is_bss_membership_selector(&self) -> bool {
43 match self.0 {
44 0xFF | 0xFE => true,
47 _ => false,
48 }
49 }
50}
51
52#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
54#[repr(C)]
55pub struct DsssParamSet {
56 pub current_channel: u8,
57}
58
59#[bitfield(
61 0 group_traffic,
62 1..=7 offset,
63)]
64#[repr(C)]
65#[derive(
66 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy,
67)]
68pub struct BitmapControl(pub u8);
69
70#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, Clone, Copy)]
72#[repr(C, packed)]
73pub struct TimHeader {
74 pub dtim_count: u8,
75 pub dtim_period: u8,
76 pub bmp_ctrl: BitmapControl,
77}
78
79pub struct TimView<B> {
80 pub header: TimHeader,
81 pub bitmap: B,
82}
83
84#[bitfield(
86 0..=7 union {
87 client_wmm_info as ClientWmmInfo(u8),
88 ap_wmm_info as ApWmmInfo(u8),
89 }
90)]
91#[repr(C)]
92#[derive(
93 PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Default,
94)]
95pub struct WmmInfo(pub u8);
96
97#[bitfield(
99 0..=3 parameter_set_count,
100 4..=6 _, 7 uapsd
102)]
103#[repr(C)]
104#[derive(PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
105pub struct ApWmmInfo(pub u8);
106
107#[bitfield(
109 0 ac_vo_uapsd,
110 1 ac_vi_uapsd,
111 2 ac_bk_uapsd,
112 3 ac_be_uapsd,
113 4 _, 5..=6 max_sp_length,
115 7 _ )]
117#[repr(C)]
118#[derive(PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
119pub struct ClientWmmInfo(pub u8);
120
121#[repr(C, packed)]
123#[derive(
124 PartialEq,
125 Eq,
126 Clone,
127 Copy,
128 Debug,
129 IntoBytes,
130 KnownLayout,
131 FromBytes,
132 Immutable,
133 Unaligned,
134 Default,
135)]
136pub struct WmmParam {
137 pub wmm_info: WmmInfo,
138 pub _reserved: u8,
139 pub ac_be_params: WmmAcParams,
140 pub ac_bk_params: WmmAcParams,
141 pub ac_vi_params: WmmAcParams,
142 pub ac_vo_params: WmmAcParams,
143}
144
145#[repr(C, packed)]
147#[derive(
148 PartialEq,
149 Eq,
150 Clone,
151 Copy,
152 Debug,
153 IntoBytes,
154 KnownLayout,
155 FromBytes,
156 Immutable,
157 Unaligned,
158 Default,
159)]
160pub struct WmmAcParams {
161 pub aci_aifsn: WmmAciAifsn,
162 pub ecw_min_max: EcwMinMax,
163 pub txop_limit: u16,
165}
166
167#[bitfield(
171 0..=3 aifsn,
172 4 acm,
173 5..=6 aci,
174 7 _ )]
176#[repr(C)]
177#[derive(
178 PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Default,
179)]
180pub struct WmmAciAifsn(pub u8);
181
182#[bitfield(
184 0..=3 ecw_min,
185 4..=7 ecw_max,
186)]
187#[repr(C)]
188#[derive(
189 PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Default,
190)]
191pub struct EcwMinMax(pub u8);
192
193pub struct CountryView<B> {
195 pub country_code: [u8; 2],
196 pub environment: CountryEnvironment,
197 pub subbands: B,
199}
200
201#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
203pub struct CountryEnvironment(pub u8);
204
205impl CountryEnvironment {
206 pub const INDOOR: Self = Self(b'I');
207 pub const OUTDOOR: Self = Self(b'O');
208 pub const NON_COUNTRY: Self = Self(b'X');
209 pub const ANY: Self = Self(b' ');
210}
211
212#[repr(C, packed)]
214#[derive(
215 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
216)]
217pub struct HtCapabilities {
218 pub ht_cap_info: HtCapabilityInfo, pub ampdu_params: AmpduParams, pub mcs_set: SupportedMcsSet, pub ht_ext_cap: HtExtCapabilities, pub txbf_cap: TxBfCapability, pub asel_cap: AselCapability, }
225
226impl From<banjo_ieee80211::HtCapabilities> for HtCapabilities {
227 fn from(cap: banjo_ieee80211::HtCapabilities) -> Self {
228 const_assert_eq!(
230 std::mem::size_of::<HtCapabilities>(),
231 banjo_ieee80211::HT_CAP_LEN as usize,
232 );
233 HtCapabilities::read_from_bytes(&cap.bytes[..]).unwrap()
234 }
235}
236
237impl From<HtCapabilities> for banjo_ieee80211::HtCapabilities {
238 fn from(cap: HtCapabilities) -> Self {
239 let mut banjo_cap = Self { bytes: Default::default() };
240 banjo_cap.bytes.copy_from_slice(&cap.as_bytes()[..]);
241 banjo_cap
242 }
243}
244
245impl From<fidl_ieee80211::HtCapabilities> for HtCapabilities {
246 fn from(cap: fidl_ieee80211::HtCapabilities) -> Self {
247 const_assert_eq!(
249 std::mem::size_of::<HtCapabilities>(),
250 fidl_ieee80211::HT_CAP_LEN as usize,
251 );
252 HtCapabilities::read_from_bytes(&cap.bytes[..]).unwrap()
253 }
254}
255
256impl From<HtCapabilities> for fidl_ieee80211::HtCapabilities {
257 fn from(cap: HtCapabilities) -> Self {
258 let mut fidl_cap = Self { bytes: Default::default() };
259 fidl_cap.bytes.copy_from_slice(&cap.as_bytes()[..]);
260 fidl_cap
261 }
262}
263
264impl From<fidl_ieee80211::VhtCapabilities> for VhtCapabilities {
265 fn from(cap: fidl_ieee80211::VhtCapabilities) -> Self {
266 const_assert_eq!(
268 std::mem::size_of::<VhtCapabilities>(),
269 fidl_ieee80211::VHT_CAP_LEN as usize,
270 );
271 VhtCapabilities::read_from_bytes(&cap.bytes[..]).unwrap()
272 }
273}
274
275impl From<VhtCapabilities> for fidl_ieee80211::VhtCapabilities {
276 fn from(cap: VhtCapabilities) -> Self {
277 let mut fidl_cap = Self { bytes: Default::default() };
278 fidl_cap.bytes.copy_from_slice(&cap.as_bytes()[..]);
279 fidl_cap
280 }
281}
282
283#[bitfield(
285 0 ldpc_coding_cap,
286 1..=1 chan_width_set as ChanWidthSet(u8), 2..=3 sm_power_save as SmPowerSave(u8), 4 greenfield, 5 short_gi_20, 6 short_gi_40, 7 tx_stbc,
292
293 8..=9 rx_stbc, 10 delayed_block_ack, 11..=11 max_amsdu_len as MaxAmsduLen(u8),
296 12 dsss_in_40, 13 _, 14 intolerant_40, 15 lsig_txop_protect,
300)]
301#[repr(C)]
302#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
303pub struct HtCapabilityInfo(pub u16);
304
305#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
306pub struct ChanWidthSet(pub u8);
307impl ChanWidthSet {
308 pub_const!(TWENTY_ONLY, 0);
309 pub_const!(TWENTY_FORTY, 1);
310}
311
312#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
313pub struct SmPowerSave(pub u8);
314impl SmPowerSave {
315 pub_const!(STATIC, 0);
316 pub_const!(DYNAMIC, 1);
317 pub_const!(DISABLED, 3);
319}
320
321#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
322pub struct MaxAmsduLen(pub u8);
323impl MaxAmsduLen {
324 pub_const!(OCTETS_3839, 0);
325 pub_const!(OCTETS_7935, 1);
326}
327
328#[bitfield(
330 0..=1 max_ampdu_exponent as MaxAmpduExponent(u8), 2..=4 min_start_spacing as MinMpduStartSpacing(u8), 5..=7 _, )]
334#[repr(C)]
335#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
336pub struct AmpduParams(pub u8);
337
338#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
339pub struct MaxAmpduExponent(pub u8);
340impl MaxAmpduExponent {
341 pub fn to_len(&self) -> usize {
342 (1 << (13 + self.0)) - 1 as usize
343 }
344}
345
346#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
347pub struct MinMpduStartSpacing(pub u8);
348impl MinMpduStartSpacing {
349 pub_const!(NO_RESTRICT, 0);
350 pub_const!(QUATER_USEC, 1);
351 pub_const!(HALF_USEC, 2);
352 pub_const!(ONE_USEC, 3);
353 pub_const!(TWO_USEC, 4);
354 pub_const!(FOUR_USEC, 5);
355 pub_const!(EIGHT_USEC, 6);
356 pub_const!(SIXTEEN_USEC, 7);
357}
358
359#[bitfield(
363 0..=76 rx_mcs as RxMcsBitmask(u128),
364 77..=79 _, 80..=89 rx_highest_rate, 90..=95 _, 96 tx_set_defined,
369 97 tx_rx_diff,
370 98..=99 tx_max_ss as NumSpatialStreams(u8),
371 100 tx_ueqm, 101..=127 _, )]
374#[repr(C)]
375#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
376pub struct SupportedMcsSet(pub u128);
377
378#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
379pub struct RxMcsBitmask(pub u128);
380impl RxMcsBitmask {
381 pub fn support(&self, mcs_index: u8) -> bool {
382 mcs_index <= 76 && (self.0 & (1 << mcs_index)) != 0
383 }
384}
385
386#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
387pub struct NumSpatialStreams(u8);
388impl NumSpatialStreams {
389 pub_const!(ONE, 0);
391 pub_const!(TWO, 1);
392 pub_const!(THREE, 2);
393 pub_const!(FOUR, 3);
394
395 pub fn to_human(&self) -> u8 {
396 1 + self.0
397 }
398 pub fn from_human(val: u8) -> Result<Self, String> {
399 if Self::ONE.to_human() <= val && val <= Self::FOUR.to_human() {
400 Ok(Self(val - 1))
401 } else {
402 Err(format!("Number of spatial stream must be between 1 and 4. {} is invalid", val))
403 }
404 }
405}
406
407#[bitfield(
409 0 pco,
410 1..=2 pco_transition as PcoTransitionTime(u8),
411 3..=7 _, 8..=9 mcs_feedback as McsFeedback(u8),
413 10 htc_ht_support,
414 11 rd_responder,
415 12..=15 _, )]
417#[repr(C)]
418#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
419pub struct HtExtCapabilities(pub u16);
420
421#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
422pub struct PcoTransitionTime(pub u8);
423impl PcoTransitionTime {
424 pub_const!(PCO_RESERVED, 0); pub_const!(PCO_400_USEC, 1);
426 pub_const!(PCO_1500_USEC, 2);
427 pub_const!(PCO_5000_USEC, 3);
428}
429
430#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
431pub struct McsFeedback(pub u8);
432impl McsFeedback {
433 pub_const!(NO_FEEDBACK, 0);
434 pub_const!(UNSOLICITED, 2);
436 pub_const!(BOTH, 3);
437}
438
439#[bitfield(
441 0 implicit_rx,
442 1 rx_stag_sounding,
443 2 tx_stag_sounding,
444 3 rx_ndp,
445 4 tx_ndp,
446 5 implicit,
447 6..=7 calibration as Calibration(u8),
448
449 8 csi, 9 noncomp_steering, 10 comp_steering, 11..=12 csi_feedback as Feedback(u8),
454 13..=14 noncomp_feedback as Feedback(u8),
455 15..=16 comp_feedback as Feedback(u8),
456 17..=18 min_grouping as MinGroup(u8),
457 19..=20 csi_antennas as NumAntennas(u8),
458
459 21..=22 noncomp_steering_ants as NumAntennas(u8),
460 23..=24 comp_steering_ants as NumAntennas(u8),
461 25..=26 csi_rows as NumCsiRows(u8),
462 27..=28 chan_estimation as NumSpaceTimeStreams(u8),
463 29..=31 _, )]
465#[repr(C)]
466#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
467pub struct TxBfCapability(pub u32);
468
469#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
470pub struct Calibration(pub u8);
471impl Calibration {
472 pub_const!(NONE, 0);
473 pub_const!(RESPOND_NO_INITIATE, 1);
474 pub_const!(RESPOND_INITIATE, 3);
476}
477
478#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
479pub struct Feedback(pub u8);
480impl Feedback {
481 pub_const!(NONE, 0);
482 pub_const!(DELAYED, 1);
483 pub_const!(IMMEDIATE, 2);
484 pub_const!(DELAYED_IMMEDIATE, 3);
485}
486
487#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
488pub struct MinGroup(pub u8);
489impl MinGroup {
490 pub_const!(ONE, 0); pub_const!(TWO, 1);
492 pub_const!(FOUR, 2);
493 pub_const!(TWO_FOUR, 3);
494}
495
496#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
497pub struct NumAntennas(u8);
498impl NumAntennas {
499 pub_const!(ONE, 0);
501 pub_const!(TWO, 1);
502 pub_const!(THREE, 2);
503 pub_const!(FOUR, 3);
504
505 pub fn to_human(&self) -> u8 {
506 1 + self.0
507 }
508 pub fn from_human(val: u8) -> Result<Self, String> {
509 if Self::ONE.to_human() <= val && val <= Self::FOUR.to_human() {
510 Ok(Self(val - 1))
511 } else {
512 Err(format!("Number of antennas must be between 1 and 4. {} is invalid", val))
513 }
514 }
515}
516
517#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
518pub struct NumCsiRows(u8);
519impl NumCsiRows {
520 pub_const!(ONE, 0);
522 pub_const!(TWO, 1);
523 pub_const!(THREE, 2);
524 pub_const!(FOUR, 3);
525
526 pub fn to_human(&self) -> u8 {
527 1 + self.0
528 }
529 pub fn from_human(val: u8) -> Result<Self, String> {
530 if Self::ONE.to_human() <= val && val <= Self::FOUR.to_human() {
531 Ok(Self(val - 1))
532 } else {
533 Err(format!("Number of csi rows must be between 1 and 4. {} is invalid", val))
534 }
535 }
536}
537
538#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
539pub struct NumSpaceTimeStreams(u8);
540impl NumSpaceTimeStreams {
541 pub_const!(ONE, 0);
543 pub_const!(TWO, 1);
544 pub_const!(THREE, 2);
545 pub_const!(FOUR, 3);
546
547 pub fn to_human(&self) -> u8 {
548 1 + self.0
549 }
550 pub fn from_human(val: u8) -> Result<Self, String> {
551 if 1 <= val && val <= 4 {
552 Ok(Self(val - 1))
553 } else {
554 Err(format!("Number of channel estimation must be between 1 and 4. {} is invalid", val))
555 }
556 }
557}
558
559#[bitfield(
561 0 asel,
562 1 csi_feedback_tx_asel, 2 ant_idx_feedback_tx_asel,
564 3 explicit_csi_feedback,
565 4 antenna_idx_feedback,
566 5 rx_asel,
567 6 tx_sounding_ppdu,
568 7 _, )]
570#[repr(C)]
571#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
572pub struct AselCapability(pub u8);
573
574#[repr(C, packed)]
576#[derive(
577 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
578)]
579pub struct HtOperation {
580 pub primary_channel: u8, pub ht_op_info: HtOpInfo,
582 pub basic_ht_mcs_set: SupportedMcsSet, }
584
585impl From<HtOperation> for fidl_ieee80211::HtOperation {
586 fn from(op: HtOperation) -> Self {
587 let mut ht_op = Self { bytes: Default::default() };
588 ht_op.bytes.copy_from_slice(&op.as_bytes()[..]);
589 ht_op
590 }
591}
592
593#[bitfield(
595 0..=1 secondary_chan_offset as SecChanOffset(u8),
596 2..=2 sta_chan_width as StaChanWidth(u8),
597 3 rifs_mode_permitted,
598 4..=7 _, 8..=9 ht_protection as HtProtection(u8),
601 10 nongreenfield_present,
602 11 _, 12 obss_non_ht_stas_present,
605 13..=20 center_freq_seg2, 21..=23 _, 24..=29 _, 30 dual_beacon, 31 dual_cts_protection, 32 stbc_beacon, 33 lsig_txop_protection, 34 pco_active,
615 35..=35 pco_phase as PcoPhase(u8),
616 36..=39 _, )]
618#[repr(C)]
619#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
620pub struct HtOpInfo(pub [u8; 5]);
621impl HtOpInfo {
622 pub fn new() -> HtOpInfo {
623 HtOpInfo([0u8; 5])
624 }
625}
626
627#[repr(C, packed)]
628#[derive(
629 Debug,
630 PartialOrd,
631 PartialEq,
632 Eq,
633 Clone,
634 Copy,
635 IntoBytes,
636 KnownLayout,
637 FromBytes,
638 Immutable,
639 Unaligned,
640)]
641pub struct SecChanOffset(pub u8);
642impl SecChanOffset {
643 pub_const!(SECONDARY_NONE, 0); pub_const!(SECONDARY_ABOVE, 1); pub_const!(SECONDARY_BELOW, 3); }
648
649#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy)]
650pub struct StaChanWidth(pub u8);
651impl StaChanWidth {
652 pub_const!(TWENTY_MHZ, 0);
653 pub_const!(ANY, 1); }
655
656#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy)]
657pub struct HtProtection(pub u8);
658impl HtProtection {
659 pub_const!(NONE, 0);
660 pub_const!(NON_MEMBER, 1);
661 pub_const!(TWENTY_MHZ, 2);
662 pub_const!(NON_HT_MIXED, 3);
663}
664
665#[bitfield(
667 0 link_measurement_enabled,
668 1 neighbor_report_enabled,
669 2 parallel_measurements_enabled,
670 3 repeated_measurements_enabled,
671 4 beacon_passive_measurement_enabled,
672 5 beacon_active_measurement_enabled,
673 6 beacon_table_measurement_enabled,
674 7 beacon_measurement_reporting_conditions_enabled,
675 8 frame_measurement_enabled,
676 9 channel_load_measurement_enabled,
677 10 noise_histogram_measurement_enabled,
678 11 statistics_measurement_enabled,
679 12 lci_measurement_enabled,
680 13 lci_azimuth_enabled,
681 14 tx_stream_category_measurement_enabled,
682 15 trigerred_tx_stream_category_measurement_enabled,
683 16 ap_channel_report_enabled,
684 17 rm_mib_enabled,
685 18..=20 operating_channel_max_measurement_duration,
686 21..=23 nonoperating_channel_max_measurement_duration,
687 24..=26 measurement_pilot_capability,
688 27 measurement_pilot_tx_info_enabled,
689 28 neighbor_report_tsf_offset_enabled,
690 29 rcpi_measurement_enabled,
691 30 rsni_measurement_enabled,
692 31 bss_average_access_delay_enabled,
693 32 bss_available_admission_capacity_enabled,
694 33 antenna_enabled,
695 34 ftm_range_report_enabled,
696 35 civic_location_measurement_enabled,
697 36..=39 _,
698)]
699#[repr(C)]
700#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
701pub struct RmEnabledCapabilities(pub [u8; 5]);
702
703#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy)]
704pub struct PcoPhase(pub u8);
705impl PcoPhase {
706 pub_const!(TWENTY_MHZ, 0);
707 pub_const!(FORTY_MHZ, 1);
708}
709
710#[repr(C)]
711#[derive(PartialEq, Eq, Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
712pub struct MpmProtocol(pub u16);
713
714impl MpmProtocol {
716 pub_const!(MPM, 0);
717 pub_const!(AMPE, 1);
718 pub_const!(VENDOR_SPECIFIC, 255);
720 }
722
723pub struct ExtCapabilitiesView<B> {
725 pub ext_caps_octet_1: Option<Ref<B, ExtCapabilitiesOctet1>>,
728 pub ext_caps_octet_2: Option<Ref<B, ExtCapabilitiesOctet2>>,
729 pub ext_caps_octet_3: Option<Ref<B, ExtCapabilitiesOctet3>>,
730 pub remaining: B,
731}
732
733#[bitfield(
734 0 twenty_forty_bss_coexistence_mgmt_support,
735 1 _, 2 extended_channel_switching,
737 3 _, 4 psmp_capability,
739 5 _, 6 s_psmp_support,
741 7 event,
742)]
743#[repr(C)]
744#[derive(
745 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy, Unaligned,
746)]
747pub struct ExtCapabilitiesOctet1(pub u8);
748
749#[bitfield(
750 0 diagnostics,
751 1 multicast_diagnostics,
752 2 location_tracking,
753 3 fms,
754 4 proxy_arp_service,
755 5 collocated_interference_reporting,
756 6 civic_location,
757 7 geospatial_location,
758)]
759#[repr(C)]
760#[derive(
761 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy, Unaligned,
762)]
763pub struct ExtCapabilitiesOctet2(pub u8);
764
765#[bitfield(
766 0 tfs,
767 1 wnm_sleep_mode,
768 2 tim_broadcast,
769 3 bss_transition,
770 4 qos_traffic_capability,
771 5 ac_station_count,
772 6 multiple_bssid,
773 7 timing_measurement,
774)]
775#[repr(C)]
776#[derive(
777 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy, Unaligned,
778)]
779pub struct ExtCapabilitiesOctet3(pub u8);
780
781#[bitfield(
783 0 gate_announcement,
784 1 addressing_mode,
785 2 proactive,
786 3..=5 _, 6 addr_ext,
788 7 _, )]
790#[repr(C)]
791#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
792pub struct PreqFlags(pub u8);
793
794#[repr(C, packed)]
798#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
799pub struct PreqHeader {
800 pub flags: PreqFlags,
801 pub hop_count: u8,
802 pub element_ttl: u8,
803 pub path_discovery_id: u32,
804 pub originator_addr: MacAddr,
805 pub originator_hwmp_seqno: u32,
806}
807
808#[repr(C, packed)]
812#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
813pub struct PreqMiddle {
814 pub lifetime: u32,
815 pub metric: u32,
816 pub target_count: u8,
817}
818
819#[bitfield(
821 0 target_only,
822 1 _, 2 usn,
824 3..=7 _, )]
826#[repr(C)]
827#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
828pub struct PreqPerTargetFlags(pub u8);
829
830#[repr(C, packed)]
833#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
834pub struct PreqPerTarget {
835 pub flags: PreqPerTargetFlags,
836 pub target_addr: MacAddr,
837 pub target_hwmp_seqno: u32,
838}
839
840pub struct PreqView<B> {
841 pub header: Ref<B, PreqHeader>,
842 pub originator_external_addr: Option<Ref<B, MacAddr>>,
843 pub middle: Ref<B, PreqMiddle>,
844 pub targets: Ref<B, [PreqPerTarget]>,
845}
846
847#[bitfield(
849 0..=5 _, 6 addr_ext,
851 7 _, )]
853#[repr(C)]
854#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
855pub struct PrepFlags(pub u8);
856
857#[repr(C, packed)]
861#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
862pub struct PrepHeader {
863 pub flags: PrepFlags,
864 pub hop_count: u8,
865 pub element_ttl: u8,
866 pub target_addr: MacAddr,
867 pub target_hwmp_seqno: u32,
868}
869
870#[repr(C, packed)]
874#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
875pub struct PrepTail {
876 pub lifetime: u32,
877 pub metric: u32,
878 pub originator_addr: MacAddr,
879 pub originator_hwmp_seqno: u32,
880}
881
882pub struct PrepView<B> {
883 pub header: Ref<B, PrepHeader>,
884 pub target_external_addr: Option<Ref<B, MacAddr>>,
885 pub tail: Ref<B, PrepTail>,
886}
887
888#[repr(C, packed)]
892#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
893pub struct PerrHeader {
894 pub element_ttl: u8,
895 pub num_destinations: u8,
896}
897
898#[bitfield(
900 0..=5 _, 6 addr_ext,
902 7 _, )]
904#[repr(C)]
905#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
906pub struct PerrDestinationFlags(pub u8);
907
908#[repr(C, packed)]
912#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
913pub struct PerrDestinationHeader {
914 pub flags: PerrDestinationFlags,
915 pub dest_addr: MacAddr,
916 pub hwmp_seqno: u32,
917}
918
919pub struct PerrDestinationView<B> {
920 pub header: Ref<B, PerrDestinationHeader>,
921 pub ext_addr: Option<Ref<B, MacAddr>>,
922 pub reason_code: UnalignedView<B, ReasonCode>,
923}
924
925pub struct PerrView<B> {
926 pub header: Ref<B, PerrHeader>,
927 pub destinations: PerrDestinationListView<B>,
928}
929
930pub struct PerrDestinationListView<B>(pub B);
931
932impl<B: SplitByteSlice> IntoIterator for PerrDestinationListView<B> {
933 type Item = PerrDestinationView<B>;
934 type IntoIter = PerrDestinationIter<B>;
935
936 fn into_iter(self) -> Self::IntoIter {
937 PerrDestinationIter(BufferReader::new(self.0))
938 }
939}
940
941impl<'a, B: SplitByteSlice> IntoIterator for &'a PerrDestinationListView<B> {
942 type Item = PerrDestinationView<&'a [u8]>;
943 type IntoIter = PerrDestinationIter<&'a [u8]>;
944
945 fn into_iter(self) -> Self::IntoIter {
946 PerrDestinationIter(BufferReader::new(&self.0[..]))
947 }
948}
949
950impl<B: SplitByteSlice> PerrDestinationListView<B> {
951 pub fn iter(&self) -> PerrDestinationIter<&[u8]> {
952 self.into_iter()
953 }
954}
955
956pub struct PerrDestinationIter<B>(BufferReader<B>);
957
958impl<B: SplitByteSlice> Iterator for PerrDestinationIter<B> {
959 type Item = PerrDestinationView<B>;
960
961 fn next(&mut self) -> Option<Self::Item> {
962 let have_ext_addr = self.0.peek::<PerrDestinationHeader>()?.flags.addr_ext();
963 let dest_len = size_of::<PerrDestinationHeader>()
964 + if have_ext_addr { size_of::<MacAddr>() } else { 0 }
965 + size_of::<ReasonCode>();
966 if self.0.bytes_remaining() < dest_len {
967 None
968 } else {
969 let header = self.0.read().unwrap();
971 let ext_addr = if have_ext_addr { Some(self.0.read().unwrap()) } else { None };
972 let reason_code = self.0.read_unaligned().unwrap();
973 Some(PerrDestinationView { header, ext_addr, reason_code })
974 }
975 }
976}
977
978impl<B: SplitByteSlice> PerrDestinationIter<B> {
979 pub fn bytes_remaining(&self) -> usize {
980 self.0.bytes_remaining()
981 }
982}
983
984#[repr(C, packed)]
987#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
988pub struct ChannelSwitchAnnouncement {
989 pub mode: u8,
990 pub new_channel_number: u8,
991 pub channel_switch_count: u8,
992}
993
994#[repr(C, packed)]
998#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
999pub struct ExtendedChannelSwitchAnnouncement {
1000 pub mode: u8,
1001 pub new_operating_class: u8,
1002 pub new_channel_number: u8,
1003 pub channel_switch_count: u8,
1004}
1005
1006#[repr(C, packed)]
1008#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
1009pub struct WideBandwidthChannelSwitch {
1010 pub new_width: VhtChannelBandwidth,
1011 pub new_center_freq_seg0: u8,
1012 pub new_center_freq_seg1: u8,
1013}
1014
1015#[derive(Clone, Copy, Eq, PartialEq, Debug)]
1017pub struct MaxTransmitPowerUnitInterpretation(pub u8);
1018
1019impl MaxTransmitPowerUnitInterpretation {
1020 pub const EIRP: Self = Self(0);
1021}
1022
1023#[bitfield(
1025 0..=2 max_transmit_power_count,
1026 3..=5 max_transmit_power_unit_interpretation as MaxTransmitPowerUnitInterpretation(u8),
1027 6..=7 _, )]
1029#[repr(C)]
1030#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
1031pub struct TransmitPowerInfo(pub u8);
1032
1033#[repr(C)]
1036#[derive(
1037 Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Eq, PartialEq, Debug,
1038)]
1039pub struct TransmitPower(pub u8);
1040
1041pub struct TransmitPowerEnvelopeView<B> {
1043 pub transmit_power_info: Ref<B, TransmitPowerInfo>,
1044 pub max_transmit_power_20: Ref<B, TransmitPower>,
1045 pub max_transmit_power_40: Option<Ref<B, TransmitPower>>,
1046 pub max_transmit_power_80: Option<Ref<B, TransmitPower>>,
1047 pub max_transmit_power_160: Option<Ref<B, TransmitPower>>,
1048}
1049
1050pub struct ChannelSwitchWrapperView<B> {
1052 pub new_country: Option<CountryView<B>>,
1053 pub wide_bandwidth_channel_switch: Option<Ref<B, WideBandwidthChannelSwitch>>,
1054 pub new_transmit_power_envelope: Option<TransmitPowerEnvelopeView<B>>,
1055}
1056
1057#[derive(Debug)]
1060pub enum VendorIe<B: SplitByteSlice> {
1061 MsftLegacyWpa(B),
1064 Wsc(B),
1067 WmmInfo(B),
1070 WmmParam(B),
1073 Unknown { oui: Oui, body: B },
1075}
1076
1077#[repr(C, packed)]
1079#[derive(
1080 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
1081)]
1082pub struct VhtCapabilities {
1083 pub vht_cap_info: VhtCapabilitiesInfo, pub vht_mcs_nss: VhtMcsNssSet, }
1086
1087impl From<banjo_ieee80211::VhtCapabilities> for VhtCapabilities {
1088 fn from(cap: banjo_ieee80211::VhtCapabilities) -> Self {
1089 const_assert_eq!(
1091 std::mem::size_of::<VhtCapabilities>(),
1092 banjo_ieee80211::VHT_CAP_LEN as usize,
1093 );
1094 VhtCapabilities::read_from_bytes(&cap.bytes[..]).unwrap()
1095 }
1096}
1097
1098impl From<VhtCapabilities> for banjo_ieee80211::VhtCapabilities {
1099 fn from(cap: VhtCapabilities) -> Self {
1100 let mut banjo_cap = Self { bytes: Default::default() };
1101 banjo_cap.bytes.copy_from_slice(&cap.as_bytes()[..]);
1102 banjo_cap
1103 }
1104}
1105
1106#[bitfield(
1108 0..=1 max_mpdu_len as MaxMpduLen(u8),
1109 2..=3 supported_cbw_set, 4 rx_ldpc,
1111 5 sgi_cbw80, 6 sgi_cbw160, 7 tx_stbc,
1114 8..=10 rx_stbc,
1115 11 su_bfer, 12 su_bfee, 13..=15 bfee_sts, 16..=18 num_sounding, 19 mu_bfer, 20 mu_bfee, 21 txop_ps, 22 htc_vht,
1125 23..=25 max_ampdu_exponent as MaxAmpduExponent(u8), 26..=27 link_adapt as VhtLinkAdaptation(u8), 28 rx_ant_pattern,
1129 29 tx_ant_pattern,
1130 30..=31 ext_nss_bw, )]
1134#[repr(C)]
1135#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1136pub struct VhtCapabilitiesInfo(pub u32);
1137
1138#[repr(C, packed)]
1140#[derive(
1141 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy,
1142)]
1143pub struct BssMaxIdlePeriod {
1144 pub max_idle_period: u16,
1147 pub idle_options: IdleOptions,
1148}
1149
1150#[bitfield(
1152 0 protected_keep_alive_required, 1..=7 _, )]
1156#[repr(C)]
1157#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1158pub struct IdleOptions(pub u8);
1159
1160#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
1162pub struct MaxMpduLen(pub u8);
1163impl MaxMpduLen {
1164 pub_const!(OCTECTS_3895, 0);
1165 pub_const!(OCTECTS_7991, 1);
1166 pub_const!(OCTECTS_11454, 2);
1167 }
1169
1170#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
1172pub struct VhtLinkAdaptation(pub u8);
1173impl VhtLinkAdaptation {
1174 pub_const!(NO_FEEDBACK, 0);
1175 pub_const!(UNSOLICITED, 2);
1177 pub_const!(BOTH, 3);
1178}
1179
1180#[bitfield(
1182 0..=15 rx_max_mcs as VhtMcsNssMap(u16),
1183
1184 16..=28 rx_max_data_rate, 29..=31 max_nsts,
1186
1187 32..=47 tx_max_mcs as VhtMcsNssMap(u16),
1188
1189 48..=60 tx_max_data_rate, 61 ext_nss_bw, 62..=63 _, )]
1193#[repr(C)]
1194#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1195pub struct VhtMcsNssSet(pub u64);
1196
1197#[bitfield(
1199 0..=1 ss1 as VhtMcsSet(u8),
1200 2..=3 ss2 as VhtMcsSet(u8),
1201 4..=5 ss3 as VhtMcsSet(u8),
1202 6..=7 ss4 as VhtMcsSet(u8),
1203 8..=9 ss5 as VhtMcsSet(u8),
1204 10..=11 ss6 as VhtMcsSet(u8),
1205 12..=13 ss7 as VhtMcsSet(u8),
1206 14..=15 ss8 as VhtMcsSet(u8),
1207)]
1208#[repr(C)]
1209#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1210pub struct VhtMcsNssMap(pub u16);
1211impl VhtMcsNssMap {
1212 const BIT_WIDTH: u8 = 2;
1213 const MASK: u16 = (1 << Self::BIT_WIDTH) - 1;
1214
1215 pub fn ss(&self, num: u8) -> Result<VhtMcsSet, String> {
1216 if num >= 1 && num <= 8 {
1217 Ok(VhtMcsSet((self.0 >> ((num - 1) * Self::BIT_WIDTH) & Self::MASK) as u8))
1218 } else {
1219 Err(format!("spatial stream number must be between 1 and 8, {} invalid", num))
1220 }
1221 }
1222
1223 pub fn set_ss(&mut self, num: u8, val: VhtMcsSet) -> Result<(), String> {
1224 if num == 0 || num > 8 {
1225 Err(format!("spatial stream number must be between 1 and 8, {} invalid", num))
1226 } else if val.0 > 3 {
1227 Err(format!("bitfield is only 2 bit wide, {} invalid", val.0))
1228 } else {
1229 let offset = (num - 1) * Self::BIT_WIDTH;
1230 let mask = Self::MASK << offset;
1231 self.0 = (self.0 & (!mask)) | (((val.0 as u16) & Self::MASK) << offset);
1232 Ok(())
1233 }
1234 }
1235}
1236
1237#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
1238pub struct VhtMcsSet(pub u8);
1239impl VhtMcsSet {
1240 pub_const!(UP_TO_7, 0);
1241 pub_const!(UP_TO_8, 1);
1242 pub_const!(UP_TO_9, 2);
1243 pub_const!(NONE, 3);
1244}
1245
1246#[repr(C, packed)]
1248#[derive(
1249 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
1250)]
1251pub struct VhtOperation {
1253 pub vht_cbw: VhtChannelBandwidth, pub center_freq_seg0: u8, pub center_freq_seg1: u8, pub basic_mcs_nss: VhtMcsNssMap, }
1259
1260impl From<VhtOperation> for fidl_ieee80211::VhtOperation {
1261 fn from(op: VhtOperation) -> Self {
1262 let mut banjo_op = Self { bytes: Default::default() };
1263 banjo_op.bytes.copy_from_slice(&op.as_bytes()[..]);
1264 banjo_op
1265 }
1266}
1267
1268#[repr(C)]
1270#[derive(
1271 Debug,
1272 PartialOrd,
1273 PartialEq,
1274 Eq,
1275 Hash,
1276 IntoBytes,
1277 KnownLayout,
1278 FromBytes,
1279 Immutable,
1280 Clone,
1281 Copy,
1282)]
1283pub struct VhtChannelBandwidth(pub u8);
1284impl VhtChannelBandwidth {
1285 pub_const!(CBW_20_40, 0);
1286 pub_const!(CBW_80_160_80P80, 1);
1287 pub_const!(CBW_160, 2); pub_const!(CBW_80P80, 3); }
1291
1292#[cfg(test)]
1293mod tests {
1294 use super::*;
1295
1296 #[test]
1297 fn ht_cap_mcs_set_conversion() {
1298 let from = banjo_ieee80211::HtCapabilities {
1299 bytes: [
1300 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11,
1303 0x12, 0, 0x13, 0, 0, 0, 0x14, 0x15, ],
1308 };
1309 let ht_cap = Ref::<&[u8], HtCapabilities>::from_bytes(&from.bytes[..]).unwrap();
1310 let mcs_set = ht_cap.mcs_set;
1311 assert_eq!(
1312 mcs_set.as_bytes(),
1313 [3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12]
1314 );
1315 }
1316
1317 #[test]
1318 fn perr_iter_empty() {
1319 let empty: [u8; 0] = [];
1320 let mut iter = PerrDestinationListView(&empty[..]).into_iter();
1321 assert!(iter.next().is_none());
1322 assert_eq!(0, iter.bytes_remaining());
1323 }
1324
1325 #[test]
1326 fn perr_iter_two_destinations() {
1327 #[rustfmt::skip]
1328 let data = [
1329 0x40, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, 0x44, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x55, 0x66, 0, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, ];
1341 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1342 assert!(iter.bytes_remaining() > 0);
1343
1344 {
1345 let target = iter.next().expect("expected first target");
1346 assert_eq!(0x44332211, { target.header.hwmp_seqno });
1347 let ext_addr = target.ext_addr.expect("expected external addr");
1348 assert_eq!(MacAddr::from([0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a]), *ext_addr);
1349 assert_eq!(0x6655, target.reason_code.get().0);
1350 }
1351
1352 assert!(iter.bytes_remaining() > 0);
1353
1354 {
1355 let target = iter.next().expect("expected second target");
1356 assert_eq!(0xaa998877, { target.header.hwmp_seqno });
1357 assert!(target.ext_addr.is_none());
1358 assert_eq!(0xccbb, target.reason_code.get().0);
1359 }
1360
1361 assert_eq!(0, iter.bytes_remaining());
1362 assert!(iter.next().is_none());
1363 assert_eq!(0, iter.bytes_remaining());
1364 }
1365
1366 #[test]
1367 fn perr_iter_too_short_for_header() {
1368 #[rustfmt::skip]
1369 let data = [
1370 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, ];
1374 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1375 assert_eq!(data.len(), iter.bytes_remaining());
1376 assert!(iter.next().is_none());
1377 assert_eq!(data.len(), iter.bytes_remaining());
1378 }
1379
1380 #[test]
1381 fn perr_iter_too_short_for_ext_addr() {
1382 #[rustfmt::skip]
1383 let data = [
1384 0x40, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, 0x44, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, ];
1390 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1391 assert_eq!(data.len(), iter.bytes_remaining());
1392 assert!(iter.next().is_none());
1393 assert_eq!(data.len(), iter.bytes_remaining());
1394 }
1395
1396 #[test]
1397 fn perr_iter_too_short_for_reason_code() {
1398 #[rustfmt::skip]
1399 let data = [
1400 0x40, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, 0x44, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x55, ];
1407 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1408 assert_eq!(data.len(), iter.bytes_remaining());
1409 assert!(iter.next().is_none());
1410 assert_eq!(data.len(), iter.bytes_remaining());
1411 }
1412
1413 #[test]
1414 fn vht_mcs_nss_map_accessor() {
1415 let mut map = VhtMcsNssMap(0x00ff);
1416 assert_eq!(map.ss(1), Ok(VhtMcsSet(3)));
1417 assert_eq!(map.ss(5), Ok(VhtMcsSet(0)));
1418 assert_eq!(map.set_ss(1, VhtMcsSet(2)), Ok(()));
1419 assert_eq!(map.set_ss(8, VhtMcsSet(3)), Ok(()));
1420 assert_eq!(map.ss(1), Ok(VhtMcsSet(2)));
1421 assert_eq!(map.ss(8), Ok(VhtMcsSet(3)));
1422 assert_eq!(map.0, 0xc0fe);
1423 }
1424
1425 #[test]
1426 fn vht_mcs_nss_map_accssor_error() {
1427 let mut map = VhtMcsNssMap(0);
1428 assert_eq!(
1429 map.ss(0),
1430 Err("spatial stream number must be between 1 and 8, 0 invalid".to_string())
1431 );
1432 assert_eq!(
1433 map.ss(9),
1434 Err("spatial stream number must be between 1 and 8, 9 invalid".to_string())
1435 );
1436 assert_eq!(
1437 map.set_ss(0, VhtMcsSet(3)),
1438 Err("spatial stream number must be between 1 and 8, 0 invalid".to_string())
1439 );
1440 assert_eq!(
1441 map.set_ss(9, VhtMcsSet(3)),
1442 Err("spatial stream number must be between 1 and 8, 9 invalid".to_string())
1443 );
1444 assert_eq!(
1445 map.set_ss(1, VhtMcsSet(4)),
1446 Err("bitfield is only 2 bit wide, 4 invalid".to_string())
1447 );
1448 }
1449
1450 #[test]
1451 fn successfully_convert_ht_operation_to_fidl() {
1452 let ht_op = crate::ie::fake_ies::fake_ht_operation();
1453 let ddk: fidl_ieee80211::HtOperation = ht_op.into();
1454 assert_eq!(ht_op.as_bytes(), ddk.bytes);
1455 }
1456
1457 #[test]
1458 fn successfully_convert_vht_operation_to_fidl() {
1459 let vht_op = crate::ie::fake_ies::fake_vht_operation();
1460 let ddk: fidl_ieee80211::VhtOperation = vht_op.into();
1461 assert_eq!(vht_op.as_bytes(), ddk.bytes);
1462 }
1463}