1use crate::UnalignedView;
6use crate::buffer_reader::BufferReader;
7use crate::mac::ReasonCode;
8use crate::organization::Oui;
9use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
10use ieee80211::MacAddr;
11use static_assertions::const_assert_eq;
12use std::mem::size_of;
13use wlan_bitfield::bitfield;
14use zerocopy::{
15 ByteSlice, FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned,
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<fidl_ieee80211::HtCapabilities> for HtCapabilities {
227 fn from(cap: fidl_ieee80211::HtCapabilities) -> Self {
228 const_assert_eq!(
230 std::mem::size_of::<HtCapabilities>(),
231 fidl_ieee80211::HT_CAP_LEN as usize,
232 );
233 HtCapabilities::read_from_bytes(&cap.bytes[..]).unwrap()
234 }
235}
236
237impl From<HtCapabilities> for fidl_ieee80211::HtCapabilities {
238 fn from(cap: HtCapabilities) -> Self {
239 let mut fidl_cap = Self { bytes: Default::default() };
240 fidl_cap.bytes.copy_from_slice(&cap.as_bytes()[..]);
241 fidl_cap
242 }
243}
244
245impl From<fidl_ieee80211::VhtCapabilities> for VhtCapabilities {
246 fn from(cap: fidl_ieee80211::VhtCapabilities) -> Self {
247 const_assert_eq!(
249 std::mem::size_of::<VhtCapabilities>(),
250 fidl_ieee80211::VHT_CAP_LEN as usize,
251 );
252 VhtCapabilities::read_from_bytes(&cap.bytes[..]).unwrap()
253 }
254}
255
256impl From<VhtCapabilities> for fidl_ieee80211::VhtCapabilities {
257 fn from(cap: VhtCapabilities) -> 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
264#[bitfield(
266 0 ldpc_coding_cap,
267 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,
273
274 8..=9 rx_stbc, 10 delayed_block_ack, 11..=11 max_amsdu_len as MaxAmsduLen(u8),
277 12 dsss_in_40, 13 _, 14 intolerant_40, 15 lsig_txop_protect,
281)]
282#[repr(C)]
283#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
284pub struct HtCapabilityInfo(pub u16);
285
286#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
287pub struct ChanWidthSet(pub u8);
288impl ChanWidthSet {
289 pub_const!(TWENTY_ONLY, 0);
290 pub_const!(TWENTY_FORTY, 1);
291}
292
293#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
294pub struct SmPowerSave(pub u8);
295impl SmPowerSave {
296 pub_const!(STATIC, 0);
297 pub_const!(DYNAMIC, 1);
298 pub_const!(DISABLED, 3);
300}
301
302#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
303pub struct MaxAmsduLen(pub u8);
304impl MaxAmsduLen {
305 pub_const!(OCTETS_3839, 0);
306 pub_const!(OCTETS_7935, 1);
307}
308
309#[bitfield(
311 0..=1 max_ampdu_exponent as MaxAmpduExponent(u8), 2..=4 min_start_spacing as MinMpduStartSpacing(u8), 5..=7 _, )]
315#[repr(C)]
316#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
317pub struct AmpduParams(pub u8);
318
319#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
320pub struct MaxAmpduExponent(pub u8);
321impl MaxAmpduExponent {
322 pub fn to_len(&self) -> usize {
323 (1 << (13 + self.0)) - 1 as usize
324 }
325}
326
327#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
328pub struct MinMpduStartSpacing(pub u8);
329impl MinMpduStartSpacing {
330 pub_const!(NO_RESTRICT, 0);
331 pub_const!(QUATER_USEC, 1);
332 pub_const!(HALF_USEC, 2);
333 pub_const!(ONE_USEC, 3);
334 pub_const!(TWO_USEC, 4);
335 pub_const!(FOUR_USEC, 5);
336 pub_const!(EIGHT_USEC, 6);
337 pub_const!(SIXTEEN_USEC, 7);
338}
339
340#[bitfield(
344 0..=76 rx_mcs as RxMcsBitmask(u128),
345 77..=79 _, 80..=89 rx_highest_rate, 90..=95 _, 96 tx_set_defined,
350 97 tx_rx_diff,
351 98..=99 tx_max_ss as NumSpatialStreams(u8),
352 100 tx_ueqm, 101..=127 _, )]
355#[repr(C)]
356#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
357pub struct SupportedMcsSet(pub u128);
358
359#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
360pub struct RxMcsBitmask(pub u128);
361impl RxMcsBitmask {
362 pub fn support(&self, mcs_index: u8) -> bool {
363 mcs_index <= 76 && (self.0 & (1 << mcs_index)) != 0
364 }
365}
366
367#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
368pub struct NumSpatialStreams(u8);
369impl NumSpatialStreams {
370 pub_const!(ONE, 0);
372 pub_const!(TWO, 1);
373 pub_const!(THREE, 2);
374 pub_const!(FOUR, 3);
375
376 pub fn to_human(&self) -> u8 {
377 1 + self.0
378 }
379 pub fn from_human(val: u8) -> Result<Self, String> {
380 if Self::ONE.to_human() <= val && val <= Self::FOUR.to_human() {
381 Ok(Self(val - 1))
382 } else {
383 Err(format!("Number of spatial stream must be between 1 and 4. {} is invalid", val))
384 }
385 }
386}
387
388#[bitfield(
390 0 pco,
391 1..=2 pco_transition as PcoTransitionTime(u8),
392 3..=7 _, 8..=9 mcs_feedback as McsFeedback(u8),
394 10 htc_ht_support,
395 11 rd_responder,
396 12..=15 _, )]
398#[repr(C)]
399#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
400pub struct HtExtCapabilities(pub u16);
401
402#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
403pub struct PcoTransitionTime(pub u8);
404impl PcoTransitionTime {
405 pub_const!(PCO_RESERVED, 0); pub_const!(PCO_400_USEC, 1);
407 pub_const!(PCO_1500_USEC, 2);
408 pub_const!(PCO_5000_USEC, 3);
409}
410
411#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
412pub struct McsFeedback(pub u8);
413impl McsFeedback {
414 pub_const!(NO_FEEDBACK, 0);
415 pub_const!(UNSOLICITED, 2);
417 pub_const!(BOTH, 3);
418}
419
420#[bitfield(
422 0 implicit_rx,
423 1 rx_stag_sounding,
424 2 tx_stag_sounding,
425 3 rx_ndp,
426 4 tx_ndp,
427 5 implicit,
428 6..=7 calibration as Calibration(u8),
429
430 8 csi, 9 noncomp_steering, 10 comp_steering, 11..=12 csi_feedback as Feedback(u8),
435 13..=14 noncomp_feedback as Feedback(u8),
436 15..=16 comp_feedback as Feedback(u8),
437 17..=18 min_grouping as MinGroup(u8),
438 19..=20 csi_antennas as NumAntennas(u8),
439
440 21..=22 noncomp_steering_ants as NumAntennas(u8),
441 23..=24 comp_steering_ants as NumAntennas(u8),
442 25..=26 csi_rows as NumCsiRows(u8),
443 27..=28 chan_estimation as NumSpaceTimeStreams(u8),
444 29..=31 _, )]
446#[repr(C)]
447#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
448pub struct TxBfCapability(pub u32);
449
450#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
451pub struct Calibration(pub u8);
452impl Calibration {
453 pub_const!(NONE, 0);
454 pub_const!(RESPOND_NO_INITIATE, 1);
455 pub_const!(RESPOND_INITIATE, 3);
457}
458
459#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
460pub struct Feedback(pub u8);
461impl Feedback {
462 pub_const!(NONE, 0);
463 pub_const!(DELAYED, 1);
464 pub_const!(IMMEDIATE, 2);
465 pub_const!(DELAYED_IMMEDIATE, 3);
466}
467
468#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
469pub struct MinGroup(pub u8);
470impl MinGroup {
471 pub_const!(ONE, 0); pub_const!(TWO, 1);
473 pub_const!(FOUR, 2);
474 pub_const!(TWO_FOUR, 3);
475}
476
477#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
478pub struct NumAntennas(u8);
479impl NumAntennas {
480 pub_const!(ONE, 0);
482 pub_const!(TWO, 1);
483 pub_const!(THREE, 2);
484 pub_const!(FOUR, 3);
485
486 pub fn to_human(&self) -> u8 {
487 1 + self.0
488 }
489 pub fn from_human(val: u8) -> Result<Self, String> {
490 if Self::ONE.to_human() <= val && val <= Self::FOUR.to_human() {
491 Ok(Self(val - 1))
492 } else {
493 Err(format!("Number of antennas must be between 1 and 4. {} is invalid", val))
494 }
495 }
496}
497
498#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
499pub struct NumCsiRows(u8);
500impl NumCsiRows {
501 pub_const!(ONE, 0);
503 pub_const!(TWO, 1);
504 pub_const!(THREE, 2);
505 pub_const!(FOUR, 3);
506
507 pub fn to_human(&self) -> u8 {
508 1 + self.0
509 }
510 pub fn from_human(val: u8) -> Result<Self, String> {
511 if Self::ONE.to_human() <= val && val <= Self::FOUR.to_human() {
512 Ok(Self(val - 1))
513 } else {
514 Err(format!("Number of csi rows must be between 1 and 4. {} is invalid", val))
515 }
516 }
517}
518
519#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
520pub struct NumSpaceTimeStreams(u8);
521impl NumSpaceTimeStreams {
522 pub_const!(ONE, 0);
524 pub_const!(TWO, 1);
525 pub_const!(THREE, 2);
526 pub_const!(FOUR, 3);
527
528 pub fn to_human(&self) -> u8 {
529 1 + self.0
530 }
531 pub fn from_human(val: u8) -> Result<Self, String> {
532 if 1 <= val && val <= 4 {
533 Ok(Self(val - 1))
534 } else {
535 Err(format!("Number of channel estimation must be between 1 and 4. {} is invalid", val))
536 }
537 }
538}
539
540#[bitfield(
542 0 asel,
543 1 csi_feedback_tx_asel, 2 ant_idx_feedback_tx_asel,
545 3 explicit_csi_feedback,
546 4 antenna_idx_feedback,
547 5 rx_asel,
548 6 tx_sounding_ppdu,
549 7 _, )]
551#[repr(C)]
552#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
553pub struct AselCapability(pub u8);
554
555#[repr(C, packed)]
557#[derive(
558 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
559)]
560pub struct HtOperation {
561 pub primary_channel: u8, pub ht_op_info: HtOpInfo,
563 pub basic_ht_mcs_set: SupportedMcsSet, }
565
566impl From<HtOperation> for fidl_ieee80211::HtOperation {
567 fn from(op: HtOperation) -> Self {
568 let mut ht_op = Self { bytes: Default::default() };
569 ht_op.bytes.copy_from_slice(&op.as_bytes()[..]);
570 ht_op
571 }
572}
573
574#[bitfield(
576 0..=1 secondary_chan_offset as SecChanOffset(u8),
577 2..=2 sta_chan_width as StaChanWidth(u8),
578 3 rifs_mode_permitted,
579 4..=7 _, 8..=9 ht_protection as HtProtection(u8),
582 10 nongreenfield_present,
583 11 _, 12 obss_non_ht_stas_present,
586 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,
596 35..=35 pco_phase as PcoPhase(u8),
597 36..=39 _, )]
599#[repr(C)]
600#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
601pub struct HtOpInfo(pub [u8; 5]);
602impl HtOpInfo {
603 pub fn new() -> HtOpInfo {
604 HtOpInfo([0u8; 5])
605 }
606}
607
608#[repr(C, packed)]
609#[derive(
610 Debug,
611 PartialOrd,
612 PartialEq,
613 Eq,
614 Clone,
615 Copy,
616 IntoBytes,
617 KnownLayout,
618 FromBytes,
619 Immutable,
620 Unaligned,
621)]
622pub struct SecChanOffset(pub u8);
623impl SecChanOffset {
624 pub_const!(SECONDARY_NONE, 0); pub_const!(SECONDARY_ABOVE, 1); pub_const!(SECONDARY_BELOW, 3); }
629
630#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy)]
631pub struct StaChanWidth(pub u8);
632impl StaChanWidth {
633 pub_const!(TWENTY_MHZ, 0);
634 pub_const!(ANY, 1); }
636
637#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy)]
638pub struct HtProtection(pub u8);
639impl HtProtection {
640 pub_const!(NONE, 0);
641 pub_const!(NON_MEMBER, 1);
642 pub_const!(TWENTY_MHZ, 2);
643 pub_const!(NON_HT_MIXED, 3);
644}
645
646#[bitfield(
648 0 link_measurement_enabled,
649 1 neighbor_report_enabled,
650 2 parallel_measurements_enabled,
651 3 repeated_measurements_enabled,
652 4 beacon_passive_measurement_enabled,
653 5 beacon_active_measurement_enabled,
654 6 beacon_table_measurement_enabled,
655 7 beacon_measurement_reporting_conditions_enabled,
656 8 frame_measurement_enabled,
657 9 channel_load_measurement_enabled,
658 10 noise_histogram_measurement_enabled,
659 11 statistics_measurement_enabled,
660 12 lci_measurement_enabled,
661 13 lci_azimuth_enabled,
662 14 tx_stream_category_measurement_enabled,
663 15 trigerred_tx_stream_category_measurement_enabled,
664 16 ap_channel_report_enabled,
665 17 rm_mib_enabled,
666 18..=20 operating_channel_max_measurement_duration,
667 21..=23 nonoperating_channel_max_measurement_duration,
668 24..=26 measurement_pilot_capability,
669 27 measurement_pilot_tx_info_enabled,
670 28 neighbor_report_tsf_offset_enabled,
671 29 rcpi_measurement_enabled,
672 30 rsni_measurement_enabled,
673 31 bss_average_access_delay_enabled,
674 32 bss_available_admission_capacity_enabled,
675 33 antenna_enabled,
676 34 ftm_range_report_enabled,
677 35 civic_location_measurement_enabled,
678 36..=39 _,
679)]
680#[repr(C)]
681#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
682pub struct RmEnabledCapabilities(pub [u8; 5]);
683
684#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy)]
685pub struct PcoPhase(pub u8);
686impl PcoPhase {
687 pub_const!(TWENTY_MHZ, 0);
688 pub_const!(FORTY_MHZ, 1);
689}
690
691#[repr(C)]
692#[derive(PartialEq, Eq, Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
693pub struct MpmProtocol(pub u16);
694
695impl MpmProtocol {
697 pub_const!(MPM, 0);
698 pub_const!(AMPE, 1);
699 pub_const!(VENDOR_SPECIFIC, 255);
701 }
703
704pub struct ExtCapabilitiesView<B> {
706 pub ext_caps_octet_1: Option<Ref<B, ExtCapabilitiesOctet1>>,
709 pub ext_caps_octet_2: Option<Ref<B, ExtCapabilitiesOctet2>>,
710 pub ext_caps_octet_3: Option<Ref<B, ExtCapabilitiesOctet3>>,
711 pub remaining: B,
712}
713
714#[bitfield(
715 0 twenty_forty_bss_coexistence_mgmt_support,
716 1 _, 2 extended_channel_switching,
718 3 _, 4 psmp_capability,
720 5 _, 6 s_psmp_support,
722 7 event,
723)]
724#[repr(C)]
725#[derive(
726 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy, Unaligned,
727)]
728pub struct ExtCapabilitiesOctet1(pub u8);
729
730#[bitfield(
731 0 diagnostics,
732 1 multicast_diagnostics,
733 2 location_tracking,
734 3 fms,
735 4 proxy_arp_service,
736 5 collocated_interference_reporting,
737 6 civic_location,
738 7 geospatial_location,
739)]
740#[repr(C)]
741#[derive(
742 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy, Unaligned,
743)]
744pub struct ExtCapabilitiesOctet2(pub u8);
745
746#[bitfield(
747 0 tfs,
748 1 wnm_sleep_mode,
749 2 tim_broadcast,
750 3 bss_transition,
751 4 qos_traffic_capability,
752 5 ac_station_count,
753 6 multiple_bssid,
754 7 timing_measurement,
755)]
756#[repr(C)]
757#[derive(
758 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy, Unaligned,
759)]
760pub struct ExtCapabilitiesOctet3(pub u8);
761
762#[bitfield(
764 0 gate_announcement,
765 1 addressing_mode,
766 2 proactive,
767 3..=5 _, 6 addr_ext,
769 7 _, )]
771#[repr(C)]
772#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
773pub struct PreqFlags(pub u8);
774
775#[repr(C, packed)]
779#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
780pub struct PreqHeader {
781 pub flags: PreqFlags,
782 pub hop_count: u8,
783 pub element_ttl: u8,
784 pub path_discovery_id: u32,
785 pub originator_addr: MacAddr,
786 pub originator_hwmp_seqno: u32,
787}
788
789#[repr(C, packed)]
793#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
794pub struct PreqMiddle {
795 pub lifetime: u32,
796 pub metric: u32,
797 pub target_count: u8,
798}
799
800#[bitfield(
802 0 target_only,
803 1 _, 2 usn,
805 3..=7 _, )]
807#[repr(C)]
808#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
809pub struct PreqPerTargetFlags(pub u8);
810
811#[repr(C, packed)]
814#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
815pub struct PreqPerTarget {
816 pub flags: PreqPerTargetFlags,
817 pub target_addr: MacAddr,
818 pub target_hwmp_seqno: u32,
819}
820
821pub struct PreqView<B> {
822 pub header: Ref<B, PreqHeader>,
823 pub originator_external_addr: Option<Ref<B, MacAddr>>,
824 pub middle: Ref<B, PreqMiddle>,
825 pub targets: Ref<B, [PreqPerTarget]>,
826}
827
828#[bitfield(
830 0..=5 _, 6 addr_ext,
832 7 _, )]
834#[repr(C)]
835#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
836pub struct PrepFlags(pub u8);
837
838#[repr(C, packed)]
842#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
843pub struct PrepHeader {
844 pub flags: PrepFlags,
845 pub hop_count: u8,
846 pub element_ttl: u8,
847 pub target_addr: MacAddr,
848 pub target_hwmp_seqno: u32,
849}
850
851#[repr(C, packed)]
855#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
856pub struct PrepTail {
857 pub lifetime: u32,
858 pub metric: u32,
859 pub originator_addr: MacAddr,
860 pub originator_hwmp_seqno: u32,
861}
862
863pub struct PrepView<B> {
864 pub header: Ref<B, PrepHeader>,
865 pub target_external_addr: Option<Ref<B, MacAddr>>,
866 pub tail: Ref<B, PrepTail>,
867}
868
869#[repr(C, packed)]
873#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
874pub struct PerrHeader {
875 pub element_ttl: u8,
876 pub num_destinations: u8,
877}
878
879#[bitfield(
881 0..=5 _, 6 addr_ext,
883 7 _, )]
885#[repr(C)]
886#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
887pub struct PerrDestinationFlags(pub u8);
888
889#[repr(C, packed)]
893#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
894pub struct PerrDestinationHeader {
895 pub flags: PerrDestinationFlags,
896 pub dest_addr: MacAddr,
897 pub hwmp_seqno: u32,
898}
899
900pub struct PerrDestinationView<B> {
901 pub header: Ref<B, PerrDestinationHeader>,
902 pub ext_addr: Option<Ref<B, MacAddr>>,
903 pub reason_code: UnalignedView<B, ReasonCode>,
904}
905
906pub struct PerrView<B> {
907 pub header: Ref<B, PerrHeader>,
908 pub destinations: PerrDestinationListView<B>,
909}
910
911pub struct PerrDestinationListView<B>(pub B);
912
913impl<B: SplitByteSlice> IntoIterator for PerrDestinationListView<B> {
914 type Item = PerrDestinationView<B>;
915 type IntoIter = PerrDestinationIter<B>;
916
917 fn into_iter(self) -> Self::IntoIter {
918 PerrDestinationIter(BufferReader::new(self.0))
919 }
920}
921
922impl<'a, B: SplitByteSlice> IntoIterator for &'a PerrDestinationListView<B> {
923 type Item = PerrDestinationView<&'a [u8]>;
924 type IntoIter = PerrDestinationIter<&'a [u8]>;
925
926 fn into_iter(self) -> Self::IntoIter {
927 PerrDestinationIter(BufferReader::new(&self.0[..]))
928 }
929}
930
931impl<B: SplitByteSlice> PerrDestinationListView<B> {
932 pub fn iter(&self) -> PerrDestinationIter<&[u8]> {
933 self.into_iter()
934 }
935}
936
937pub struct PerrDestinationIter<B>(BufferReader<B>);
938
939impl<B: SplitByteSlice> Iterator for PerrDestinationIter<B> {
940 type Item = PerrDestinationView<B>;
941
942 fn next(&mut self) -> Option<Self::Item> {
943 let have_ext_addr = self.0.peek::<PerrDestinationHeader>()?.flags.addr_ext();
944 let dest_len = size_of::<PerrDestinationHeader>()
945 + if have_ext_addr { size_of::<MacAddr>() } else { 0 }
946 + size_of::<ReasonCode>();
947 if self.0.bytes_remaining() < dest_len {
948 None
949 } else {
950 let header = self.0.read().unwrap();
952 let ext_addr = if have_ext_addr { Some(self.0.read().unwrap()) } else { None };
953 let reason_code = self.0.read_unaligned().unwrap();
954 Some(PerrDestinationView { header, ext_addr, reason_code })
955 }
956 }
957}
958
959impl<B: SplitByteSlice> PerrDestinationIter<B> {
960 pub fn bytes_remaining(&self) -> usize {
961 self.0.bytes_remaining()
962 }
963}
964
965#[repr(C, packed)]
968#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
969pub struct ChannelSwitchAnnouncement {
970 pub mode: u8,
971 pub new_channel_number: u8,
972 pub channel_switch_count: u8,
973}
974
975#[repr(C, packed)]
979#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
980pub struct ExtendedChannelSwitchAnnouncement {
981 pub mode: u8,
982 pub new_operating_class: u8,
983 pub new_channel_number: u8,
984 pub channel_switch_count: u8,
985}
986
987impl ExtendedChannelSwitchAnnouncement {
988 pub fn get_band(&self) -> fidl_ieee80211::WlanBand {
991 match self.new_operating_class {
992 81..=84 => fidl_ieee80211::WlanBand::TwoGhz,
993 115..=130 => fidl_ieee80211::WlanBand::FiveGhz,
994 131..=137 | _ => fidl_ieee80211::WlanBand::unknown(),
996 }
997 }
998}
999
1000#[repr(C, packed)]
1002#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
1003pub struct WideBandwidthChannelSwitch {
1004 pub new_width: VhtChannelBandwidth,
1005 pub new_center_freq_seg0: u8,
1006 pub new_center_freq_seg1: u8,
1007}
1008
1009#[derive(Clone, Copy, Eq, PartialEq, Debug)]
1011pub struct MaxTransmitPowerUnitInterpretation(pub u8);
1012
1013impl MaxTransmitPowerUnitInterpretation {
1014 pub const EIRP: Self = Self(0);
1015}
1016
1017#[bitfield(
1019 0..=2 max_transmit_power_count,
1020 3..=5 max_transmit_power_unit_interpretation as MaxTransmitPowerUnitInterpretation(u8),
1021 6..=7 _, )]
1023#[repr(C)]
1024#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
1025pub struct TransmitPowerInfo(pub u8);
1026
1027#[repr(C)]
1030#[derive(
1031 Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Eq, PartialEq, Debug,
1032)]
1033pub struct TransmitPower(pub u8);
1034
1035pub struct TransmitPowerEnvelopeView<B> {
1037 pub transmit_power_info: Ref<B, TransmitPowerInfo>,
1038 pub max_transmit_power_20: Ref<B, TransmitPower>,
1039 pub max_transmit_power_40: Option<Ref<B, TransmitPower>>,
1040 pub max_transmit_power_80: Option<Ref<B, TransmitPower>>,
1041 pub max_transmit_power_160: Option<Ref<B, TransmitPower>>,
1042}
1043
1044pub struct ChannelSwitchWrapperView<B> {
1046 pub new_country: Option<CountryView<B>>,
1047 pub wide_bandwidth_channel_switch: Option<Ref<B, WideBandwidthChannelSwitch>>,
1048 pub new_transmit_power_envelope: Option<TransmitPowerEnvelopeView<B>>,
1049}
1050
1051#[derive(Debug)]
1054pub enum VendorIe<B: SplitByteSlice> {
1055 MsftLegacyWpa(B),
1058 Wsc(B),
1061 WmmInfo(B),
1064 WmmParam(B),
1067 OweTransition(B),
1069 Unknown { oui: Oui, body: B },
1071}
1072
1073#[repr(C, packed)]
1075#[derive(
1076 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
1077)]
1078pub struct VhtCapabilities {
1079 pub vht_cap_info: VhtCapabilitiesInfo, pub vht_mcs_nss: VhtMcsNssSet, }
1082
1083#[bitfield(
1085 0..=1 max_mpdu_len as MaxMpduLen(u8),
1086 2..=3 supported_cbw_set, 4 rx_ldpc,
1088 5 sgi_cbw80, 6 sgi_cbw160, 7 tx_stbc,
1091 8..=10 rx_stbc,
1092 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,
1102 23..=25 max_ampdu_exponent as MaxAmpduExponent(u8), 26..=27 link_adapt as VhtLinkAdaptation(u8), 28 rx_ant_pattern,
1106 29 tx_ant_pattern,
1107 30..=31 ext_nss_bw, )]
1111#[repr(C)]
1112#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1113pub struct VhtCapabilitiesInfo(pub u32);
1114
1115#[repr(C, packed)]
1117#[derive(
1118 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy,
1119)]
1120pub struct BssMaxIdlePeriod {
1121 pub max_idle_period: u16,
1124 pub idle_options: IdleOptions,
1125}
1126
1127#[bitfield(
1129 0 protected_keep_alive_required, 1..=7 _, )]
1133#[repr(C)]
1134#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1135pub struct IdleOptions(pub u8);
1136
1137#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
1139pub struct MaxMpduLen(pub u8);
1140impl MaxMpduLen {
1141 pub_const!(OCTECTS_3895, 0);
1142 pub_const!(OCTECTS_7991, 1);
1143 pub_const!(OCTECTS_11454, 2);
1144 }
1146
1147#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
1149pub struct VhtLinkAdaptation(pub u8);
1150impl VhtLinkAdaptation {
1151 pub_const!(NO_FEEDBACK, 0);
1152 pub_const!(UNSOLICITED, 2);
1154 pub_const!(BOTH, 3);
1155}
1156
1157#[bitfield(
1159 0..=15 rx_max_mcs as VhtMcsNssMap(u16),
1160
1161 16..=28 rx_max_data_rate, 29..=31 max_nsts,
1163
1164 32..=47 tx_max_mcs as VhtMcsNssMap(u16),
1165
1166 48..=60 tx_max_data_rate, 61 ext_nss_bw, 62..=63 _, )]
1170#[repr(C)]
1171#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1172pub struct VhtMcsNssSet(pub u64);
1173
1174#[bitfield(
1176 0..=1 ss1 as VhtMcsSet(u8),
1177 2..=3 ss2 as VhtMcsSet(u8),
1178 4..=5 ss3 as VhtMcsSet(u8),
1179 6..=7 ss4 as VhtMcsSet(u8),
1180 8..=9 ss5 as VhtMcsSet(u8),
1181 10..=11 ss6 as VhtMcsSet(u8),
1182 12..=13 ss7 as VhtMcsSet(u8),
1183 14..=15 ss8 as VhtMcsSet(u8),
1184)]
1185#[repr(C)]
1186#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1187pub struct VhtMcsNssMap(pub u16);
1188impl VhtMcsNssMap {
1189 const BIT_WIDTH: u8 = 2;
1190 const MASK: u16 = (1 << Self::BIT_WIDTH) - 1;
1191
1192 pub fn ss(&self, num: u8) -> Result<VhtMcsSet, String> {
1193 if num >= 1 && num <= 8 {
1194 Ok(VhtMcsSet((self.0 >> ((num - 1) * Self::BIT_WIDTH) & Self::MASK) as u8))
1195 } else {
1196 Err(format!("spatial stream number must be between 1 and 8, {} invalid", num))
1197 }
1198 }
1199
1200 pub fn set_ss(&mut self, num: u8, val: VhtMcsSet) -> Result<(), String> {
1201 if num == 0 || num > 8 {
1202 Err(format!("spatial stream number must be between 1 and 8, {} invalid", num))
1203 } else if val.0 > 3 {
1204 Err(format!("bitfield is only 2 bit wide, {} invalid", val.0))
1205 } else {
1206 let offset = (num - 1) * Self::BIT_WIDTH;
1207 let mask = Self::MASK << offset;
1208 self.0 = (self.0 & (!mask)) | (((val.0 as u16) & Self::MASK) << offset);
1209 Ok(())
1210 }
1211 }
1212}
1213
1214#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
1215pub struct VhtMcsSet(pub u8);
1216impl VhtMcsSet {
1217 pub_const!(UP_TO_7, 0);
1218 pub_const!(UP_TO_8, 1);
1219 pub_const!(UP_TO_9, 2);
1220 pub_const!(NONE, 3);
1221}
1222
1223#[repr(C, packed)]
1225#[derive(
1226 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
1227)]
1228pub struct VhtOperation {
1230 pub vht_cbw: VhtChannelBandwidth, pub center_freq_seg0: u8, pub center_freq_seg1: u8, pub basic_mcs_nss: VhtMcsNssMap, }
1236
1237impl From<VhtOperation> for fidl_ieee80211::VhtOperation {
1238 fn from(op: VhtOperation) -> Self {
1239 let mut fidl_op = Self { bytes: Default::default() };
1240 fidl_op.bytes.copy_from_slice(&op.as_bytes()[..]);
1241 fidl_op
1242 }
1243}
1244
1245#[repr(C)]
1247#[derive(
1248 Debug,
1249 PartialOrd,
1250 PartialEq,
1251 Eq,
1252 Hash,
1253 IntoBytes,
1254 KnownLayout,
1255 FromBytes,
1256 Immutable,
1257 Clone,
1258 Copy,
1259)]
1260pub struct VhtChannelBandwidth(pub u8);
1261impl VhtChannelBandwidth {
1262 pub_const!(CBW_20_40, 0);
1263 pub_const!(CBW_80_160_80P80, 1);
1264 pub_const!(CBW_160, 2); pub_const!(CBW_80P80, 3); }
1268
1269#[derive(Debug)]
1271pub struct RsnxeView<B: ByteSlice> {
1272 pub rsnxe_octet_1: Option<Ref<B, RsnxeOctet1>>,
1273 pub remaining: B,
1274}
1275
1276#[bitfield(
1277 0..=3 field_length,
1278 4 protected_twt_operations_support,
1279 5 sae_hash_to_element,
1280 6..=7 _,
1281)]
1282#[repr(C)]
1283#[derive(
1284 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy, Unaligned,
1285)]
1286pub struct RsnxeOctet1(pub u8);
1287
1288#[derive(Debug)]
1290pub struct DiffieHellmanParamView<B: ByteSlice> {
1291 pub group: u16,
1292 pub public_key: B,
1293}
1294
1295#[cfg(test)]
1296mod tests {
1297 use super::*;
1298
1299 #[test]
1300 fn ht_cap_mcs_set_conversion() {
1301 let from = fidl_ieee80211::HtCapabilities {
1302 bytes: [
1303 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11,
1306 0x12, 0, 0x13, 0, 0, 0, 0x14, 0x15, ],
1311 };
1312 let ht_cap = Ref::<&[u8], HtCapabilities>::from_bytes(&from.bytes[..]).unwrap();
1313 let mcs_set = ht_cap.mcs_set;
1314 assert_eq!(
1315 mcs_set.as_bytes(),
1316 [3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12]
1317 );
1318 }
1319
1320 #[test]
1321 fn perr_iter_empty() {
1322 let empty: [u8; 0] = [];
1323 let mut iter = PerrDestinationListView(&empty[..]).into_iter();
1324 assert!(iter.next().is_none());
1325 assert_eq!(0, iter.bytes_remaining());
1326 }
1327
1328 #[test]
1329 fn perr_iter_two_destinations() {
1330 #[rustfmt::skip]
1331 let data = [
1332 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, ];
1344 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1345 assert!(iter.bytes_remaining() > 0);
1346
1347 {
1348 let target = iter.next().expect("expected first target");
1349 assert_eq!(0x44332211, { target.header.hwmp_seqno });
1350 let ext_addr = target.ext_addr.expect("expected external addr");
1351 assert_eq!(MacAddr::from([0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a]), *ext_addr);
1352 assert_eq!(0x6655, target.reason_code.get().0);
1353 }
1354
1355 assert!(iter.bytes_remaining() > 0);
1356
1357 {
1358 let target = iter.next().expect("expected second target");
1359 assert_eq!(0xaa998877, { target.header.hwmp_seqno });
1360 assert!(target.ext_addr.is_none());
1361 assert_eq!(0xccbb, target.reason_code.get().0);
1362 }
1363
1364 assert_eq!(0, iter.bytes_remaining());
1365 assert!(iter.next().is_none());
1366 assert_eq!(0, iter.bytes_remaining());
1367 }
1368
1369 #[test]
1370 fn perr_iter_too_short_for_header() {
1371 #[rustfmt::skip]
1372 let data = [
1373 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, ];
1377 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1378 assert_eq!(data.len(), iter.bytes_remaining());
1379 assert!(iter.next().is_none());
1380 assert_eq!(data.len(), iter.bytes_remaining());
1381 }
1382
1383 #[test]
1384 fn perr_iter_too_short_for_ext_addr() {
1385 #[rustfmt::skip]
1386 let data = [
1387 0x40, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, 0x44, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, ];
1393 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1394 assert_eq!(data.len(), iter.bytes_remaining());
1395 assert!(iter.next().is_none());
1396 assert_eq!(data.len(), iter.bytes_remaining());
1397 }
1398
1399 #[test]
1400 fn perr_iter_too_short_for_reason_code() {
1401 #[rustfmt::skip]
1402 let data = [
1403 0x40, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, 0x44, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x55, ];
1410 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1411 assert_eq!(data.len(), iter.bytes_remaining());
1412 assert!(iter.next().is_none());
1413 assert_eq!(data.len(), iter.bytes_remaining());
1414 }
1415
1416 #[test]
1417 fn vht_mcs_nss_map_accessor() {
1418 let mut map = VhtMcsNssMap(0x00ff);
1419 assert_eq!(map.ss(1), Ok(VhtMcsSet(3)));
1420 assert_eq!(map.ss(5), Ok(VhtMcsSet(0)));
1421 assert_eq!(map.set_ss(1, VhtMcsSet(2)), Ok(()));
1422 assert_eq!(map.set_ss(8, VhtMcsSet(3)), Ok(()));
1423 assert_eq!(map.ss(1), Ok(VhtMcsSet(2)));
1424 assert_eq!(map.ss(8), Ok(VhtMcsSet(3)));
1425 assert_eq!(map.0, 0xc0fe);
1426 }
1427
1428 #[test]
1429 fn vht_mcs_nss_map_accssor_error() {
1430 let mut map = VhtMcsNssMap(0);
1431 assert_eq!(
1432 map.ss(0),
1433 Err("spatial stream number must be between 1 and 8, 0 invalid".to_string())
1434 );
1435 assert_eq!(
1436 map.ss(9),
1437 Err("spatial stream number must be between 1 and 8, 9 invalid".to_string())
1438 );
1439 assert_eq!(
1440 map.set_ss(0, VhtMcsSet(3)),
1441 Err("spatial stream number must be between 1 and 8, 0 invalid".to_string())
1442 );
1443 assert_eq!(
1444 map.set_ss(9, VhtMcsSet(3)),
1445 Err("spatial stream number must be between 1 and 8, 9 invalid".to_string())
1446 );
1447 assert_eq!(
1448 map.set_ss(1, VhtMcsSet(4)),
1449 Err("bitfield is only 2 bit wide, 4 invalid".to_string())
1450 );
1451 }
1452
1453 #[test]
1454 fn successfully_convert_ht_operation_to_fidl() {
1455 let ht_op = crate::ie::fake_ies::fake_ht_operation();
1456 let ddk: fidl_ieee80211::HtOperation = ht_op.into();
1457 assert_eq!(ht_op.as_bytes(), ddk.bytes);
1458 }
1459
1460 #[test]
1461 fn successfully_convert_vht_operation_to_fidl() {
1462 let vht_op = crate::ie::fake_ies::fake_vht_operation();
1463 let ddk: fidl_ieee80211::VhtOperation = vht_op.into();
1464 assert_eq!(vht_op.as_bytes(), ddk.bytes);
1465 }
1466}