1use crate::buffer_reader::BufferReader;
6use crate::mac::ReasonCode;
7use crate::organization::Oui;
8use crate::UnalignedView;
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::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned};
15
16macro_rules! pub_const {
17 ($name:ident, $val:expr) => {
18 pub const $name: Self = Self($val);
19 };
20}
21
22#[bitfield(
24 0..=6 rate,
25 7 basic,
26)]
27#[repr(C)]
28#[derive(
29 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy,
30)]
31pub struct SupportedRate(pub u8);
32
33impl SupportedRate {
34 pub fn is_bss_membership_selector(&self) -> bool {
41 match self.0 {
42 0xFF | 0xFE => true,
45 _ => false,
46 }
47 }
48}
49
50#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
52#[repr(C)]
53pub struct DsssParamSet {
54 pub current_channel: u8,
55}
56
57#[bitfield(
59 0 group_traffic,
60 1..=7 offset,
61)]
62#[repr(C)]
63#[derive(
64 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy,
65)]
66pub struct BitmapControl(pub u8);
67
68#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, Clone, Copy)]
70#[repr(C, packed)]
71pub struct TimHeader {
72 pub dtim_count: u8,
73 pub dtim_period: u8,
74 pub bmp_ctrl: BitmapControl,
75}
76
77pub struct TimView<B> {
78 pub header: TimHeader,
79 pub bitmap: B,
80}
81
82#[bitfield(
84 0..=7 union {
85 client_wmm_info as ClientWmmInfo(u8),
86 ap_wmm_info as ApWmmInfo(u8),
87 }
88)]
89#[repr(C)]
90#[derive(
91 PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Default,
92)]
93pub struct WmmInfo(pub u8);
94
95#[bitfield(
97 0..=3 parameter_set_count,
98 4..=6 _, 7 uapsd
100)]
101#[repr(C)]
102#[derive(PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
103pub struct ApWmmInfo(pub u8);
104
105#[bitfield(
107 0 ac_vo_uapsd,
108 1 ac_vi_uapsd,
109 2 ac_bk_uapsd,
110 3 ac_be_uapsd,
111 4 _, 5..=6 max_sp_length,
113 7 _ )]
115#[repr(C)]
116#[derive(PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
117pub struct ClientWmmInfo(pub u8);
118
119#[repr(C, packed)]
121#[derive(
122 PartialEq,
123 Eq,
124 Clone,
125 Copy,
126 Debug,
127 IntoBytes,
128 KnownLayout,
129 FromBytes,
130 Immutable,
131 Unaligned,
132 Default,
133)]
134pub struct WmmParam {
135 pub wmm_info: WmmInfo,
136 pub _reserved: u8,
137 pub ac_be_params: WmmAcParams,
138 pub ac_bk_params: WmmAcParams,
139 pub ac_vi_params: WmmAcParams,
140 pub ac_vo_params: WmmAcParams,
141}
142
143#[repr(C, packed)]
145#[derive(
146 PartialEq,
147 Eq,
148 Clone,
149 Copy,
150 Debug,
151 IntoBytes,
152 KnownLayout,
153 FromBytes,
154 Immutable,
155 Unaligned,
156 Default,
157)]
158pub struct WmmAcParams {
159 pub aci_aifsn: WmmAciAifsn,
160 pub ecw_min_max: EcwMinMax,
161 pub txop_limit: u16,
163}
164
165#[bitfield(
169 0..=3 aifsn,
170 4 acm,
171 5..=6 aci,
172 7 _ )]
174#[repr(C)]
175#[derive(
176 PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Default,
177)]
178pub struct WmmAciAifsn(pub u8);
179
180#[bitfield(
182 0..=3 ecw_min,
183 4..=7 ecw_max,
184)]
185#[repr(C)]
186#[derive(
187 PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Default,
188)]
189pub struct EcwMinMax(pub u8);
190
191pub struct CountryView<B> {
193 pub country_code: [u8; 2],
194 pub environment: CountryEnvironment,
195 pub subbands: B,
197}
198
199#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
201pub struct CountryEnvironment(pub u8);
202
203impl CountryEnvironment {
204 pub const INDOOR: Self = Self(b'I');
205 pub const OUTDOOR: Self = Self(b'O');
206 pub const NON_COUNTRY: Self = Self(b'X');
207 pub const ANY: Self = Self(b' ');
208}
209
210#[repr(C, packed)]
212#[derive(
213 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
214)]
215pub struct HtCapabilities {
216 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, }
223
224impl From<fidl_ieee80211::HtCapabilities> for HtCapabilities {
225 fn from(cap: fidl_ieee80211::HtCapabilities) -> Self {
226 const_assert_eq!(
228 std::mem::size_of::<HtCapabilities>(),
229 fidl_ieee80211::HT_CAP_LEN as usize,
230 );
231 HtCapabilities::read_from_bytes(&cap.bytes[..]).unwrap()
232 }
233}
234
235impl From<HtCapabilities> for fidl_ieee80211::HtCapabilities {
236 fn from(cap: HtCapabilities) -> Self {
237 let mut fidl_cap = Self { bytes: Default::default() };
238 fidl_cap.bytes.copy_from_slice(&cap.as_bytes()[..]);
239 fidl_cap
240 }
241}
242
243impl From<fidl_ieee80211::VhtCapabilities> for VhtCapabilities {
244 fn from(cap: fidl_ieee80211::VhtCapabilities) -> Self {
245 const_assert_eq!(
247 std::mem::size_of::<VhtCapabilities>(),
248 fidl_ieee80211::VHT_CAP_LEN as usize,
249 );
250 VhtCapabilities::read_from_bytes(&cap.bytes[..]).unwrap()
251 }
252}
253
254impl From<VhtCapabilities> for fidl_ieee80211::VhtCapabilities {
255 fn from(cap: VhtCapabilities) -> Self {
256 let mut fidl_cap = Self { bytes: Default::default() };
257 fidl_cap.bytes.copy_from_slice(&cap.as_bytes()[..]);
258 fidl_cap
259 }
260}
261
262#[bitfield(
264 0 ldpc_coding_cap,
265 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,
271
272 8..=9 rx_stbc, 10 delayed_block_ack, 11..=11 max_amsdu_len as MaxAmsduLen(u8),
275 12 dsss_in_40, 13 _, 14 intolerant_40, 15 lsig_txop_protect,
279)]
280#[repr(C)]
281#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
282pub struct HtCapabilityInfo(pub u16);
283
284#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
285pub struct ChanWidthSet(pub u8);
286impl ChanWidthSet {
287 pub_const!(TWENTY_ONLY, 0);
288 pub_const!(TWENTY_FORTY, 1);
289}
290
291#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
292pub struct SmPowerSave(pub u8);
293impl SmPowerSave {
294 pub_const!(STATIC, 0);
295 pub_const!(DYNAMIC, 1);
296 pub_const!(DISABLED, 3);
298}
299
300#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
301pub struct MaxAmsduLen(pub u8);
302impl MaxAmsduLen {
303 pub_const!(OCTETS_3839, 0);
304 pub_const!(OCTETS_7935, 1);
305}
306
307#[bitfield(
309 0..=1 max_ampdu_exponent as MaxAmpduExponent(u8), 2..=4 min_start_spacing as MinMpduStartSpacing(u8), 5..=7 _, )]
313#[repr(C)]
314#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
315pub struct AmpduParams(pub u8);
316
317#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
318pub struct MaxAmpduExponent(pub u8);
319impl MaxAmpduExponent {
320 pub fn to_len(&self) -> usize {
321 (1 << (13 + self.0)) - 1 as usize
322 }
323}
324
325#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
326pub struct MinMpduStartSpacing(pub u8);
327impl MinMpduStartSpacing {
328 pub_const!(NO_RESTRICT, 0);
329 pub_const!(QUATER_USEC, 1);
330 pub_const!(HALF_USEC, 2);
331 pub_const!(ONE_USEC, 3);
332 pub_const!(TWO_USEC, 4);
333 pub_const!(FOUR_USEC, 5);
334 pub_const!(EIGHT_USEC, 6);
335 pub_const!(SIXTEEN_USEC, 7);
336}
337
338#[bitfield(
342 0..=76 rx_mcs as RxMcsBitmask(u128),
343 77..=79 _, 80..=89 rx_highest_rate, 90..=95 _, 96 tx_set_defined,
348 97 tx_rx_diff,
349 98..=99 tx_max_ss as NumSpatialStreams(u8),
350 100 tx_ueqm, 101..=127 _, )]
353#[repr(C)]
354#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
355pub struct SupportedMcsSet(pub u128);
356
357#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
358pub struct RxMcsBitmask(pub u128);
359impl RxMcsBitmask {
360 pub fn support(&self, mcs_index: u8) -> bool {
361 mcs_index <= 76 && (self.0 & (1 << mcs_index)) != 0
362 }
363}
364
365#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
366pub struct NumSpatialStreams(u8);
367impl NumSpatialStreams {
368 pub_const!(ONE, 0);
370 pub_const!(TWO, 1);
371 pub_const!(THREE, 2);
372 pub_const!(FOUR, 3);
373
374 pub fn to_human(&self) -> u8 {
375 1 + self.0
376 }
377 pub fn from_human(val: u8) -> Result<Self, String> {
378 if Self::ONE.to_human() <= val && val <= Self::FOUR.to_human() {
379 Ok(Self(val - 1))
380 } else {
381 Err(format!("Number of spatial stream must be between 1 and 4. {} is invalid", val))
382 }
383 }
384}
385
386#[bitfield(
388 0 pco,
389 1..=2 pco_transition as PcoTransitionTime(u8),
390 3..=7 _, 8..=9 mcs_feedback as McsFeedback(u8),
392 10 htc_ht_support,
393 11 rd_responder,
394 12..=15 _, )]
396#[repr(C)]
397#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
398pub struct HtExtCapabilities(pub u16);
399
400#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
401pub struct PcoTransitionTime(pub u8);
402impl PcoTransitionTime {
403 pub_const!(PCO_RESERVED, 0); pub_const!(PCO_400_USEC, 1);
405 pub_const!(PCO_1500_USEC, 2);
406 pub_const!(PCO_5000_USEC, 3);
407}
408
409#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
410pub struct McsFeedback(pub u8);
411impl McsFeedback {
412 pub_const!(NO_FEEDBACK, 0);
413 pub_const!(UNSOLICITED, 2);
415 pub_const!(BOTH, 3);
416}
417
418#[bitfield(
420 0 implicit_rx,
421 1 rx_stag_sounding,
422 2 tx_stag_sounding,
423 3 rx_ndp,
424 4 tx_ndp,
425 5 implicit,
426 6..=7 calibration as Calibration(u8),
427
428 8 csi, 9 noncomp_steering, 10 comp_steering, 11..=12 csi_feedback as Feedback(u8),
433 13..=14 noncomp_feedback as Feedback(u8),
434 15..=16 comp_feedback as Feedback(u8),
435 17..=18 min_grouping as MinGroup(u8),
436 19..=20 csi_antennas as NumAntennas(u8),
437
438 21..=22 noncomp_steering_ants as NumAntennas(u8),
439 23..=24 comp_steering_ants as NumAntennas(u8),
440 25..=26 csi_rows as NumCsiRows(u8),
441 27..=28 chan_estimation as NumSpaceTimeStreams(u8),
442 29..=31 _, )]
444#[repr(C)]
445#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
446pub struct TxBfCapability(pub u32);
447
448#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
449pub struct Calibration(pub u8);
450impl Calibration {
451 pub_const!(NONE, 0);
452 pub_const!(RESPOND_NO_INITIATE, 1);
453 pub_const!(RESPOND_INITIATE, 3);
455}
456
457#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
458pub struct Feedback(pub u8);
459impl Feedback {
460 pub_const!(NONE, 0);
461 pub_const!(DELAYED, 1);
462 pub_const!(IMMEDIATE, 2);
463 pub_const!(DELAYED_IMMEDIATE, 3);
464}
465
466#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
467pub struct MinGroup(pub u8);
468impl MinGroup {
469 pub_const!(ONE, 0); pub_const!(TWO, 1);
471 pub_const!(FOUR, 2);
472 pub_const!(TWO_FOUR, 3);
473}
474
475#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
476pub struct NumAntennas(u8);
477impl NumAntennas {
478 pub_const!(ONE, 0);
480 pub_const!(TWO, 1);
481 pub_const!(THREE, 2);
482 pub_const!(FOUR, 3);
483
484 pub fn to_human(&self) -> u8 {
485 1 + self.0
486 }
487 pub fn from_human(val: u8) -> Result<Self, String> {
488 if Self::ONE.to_human() <= val && val <= Self::FOUR.to_human() {
489 Ok(Self(val - 1))
490 } else {
491 Err(format!("Number of antennas must be between 1 and 4. {} is invalid", val))
492 }
493 }
494}
495
496#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
497pub struct NumCsiRows(u8);
498impl NumCsiRows {
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 csi rows must be between 1 and 4. {} is invalid", val))
513 }
514 }
515}
516
517#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
518pub struct NumSpaceTimeStreams(u8);
519impl NumSpaceTimeStreams {
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 1 <= val && val <= 4 {
531 Ok(Self(val - 1))
532 } else {
533 Err(format!("Number of channel estimation must be between 1 and 4. {} is invalid", val))
534 }
535 }
536}
537
538#[bitfield(
540 0 asel,
541 1 csi_feedback_tx_asel, 2 ant_idx_feedback_tx_asel,
543 3 explicit_csi_feedback,
544 4 antenna_idx_feedback,
545 5 rx_asel,
546 6 tx_sounding_ppdu,
547 7 _, )]
549#[repr(C)]
550#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
551pub struct AselCapability(pub u8);
552
553#[repr(C, packed)]
555#[derive(
556 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
557)]
558pub struct HtOperation {
559 pub primary_channel: u8, pub ht_op_info: HtOpInfo,
561 pub basic_ht_mcs_set: SupportedMcsSet, }
563
564impl From<HtOperation> for fidl_ieee80211::HtOperation {
565 fn from(op: HtOperation) -> Self {
566 let mut ht_op = Self { bytes: Default::default() };
567 ht_op.bytes.copy_from_slice(&op.as_bytes()[..]);
568 ht_op
569 }
570}
571
572#[bitfield(
574 0..=1 secondary_chan_offset as SecChanOffset(u8),
575 2..=2 sta_chan_width as StaChanWidth(u8),
576 3 rifs_mode_permitted,
577 4..=7 _, 8..=9 ht_protection as HtProtection(u8),
580 10 nongreenfield_present,
581 11 _, 12 obss_non_ht_stas_present,
584 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,
594 35..=35 pco_phase as PcoPhase(u8),
595 36..=39 _, )]
597#[repr(C)]
598#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
599pub struct HtOpInfo(pub [u8; 5]);
600impl HtOpInfo {
601 pub fn new() -> HtOpInfo {
602 HtOpInfo([0u8; 5])
603 }
604}
605
606#[repr(C, packed)]
607#[derive(
608 Debug,
609 PartialOrd,
610 PartialEq,
611 Eq,
612 Clone,
613 Copy,
614 IntoBytes,
615 KnownLayout,
616 FromBytes,
617 Immutable,
618 Unaligned,
619)]
620pub struct SecChanOffset(pub u8);
621impl SecChanOffset {
622 pub_const!(SECONDARY_NONE, 0); pub_const!(SECONDARY_ABOVE, 1); pub_const!(SECONDARY_BELOW, 3); }
627
628#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy)]
629pub struct StaChanWidth(pub u8);
630impl StaChanWidth {
631 pub_const!(TWENTY_MHZ, 0);
632 pub_const!(ANY, 1); }
634
635#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy)]
636pub struct HtProtection(pub u8);
637impl HtProtection {
638 pub_const!(NONE, 0);
639 pub_const!(NON_MEMBER, 1);
640 pub_const!(TWENTY_MHZ, 2);
641 pub_const!(NON_HT_MIXED, 3);
642}
643
644#[bitfield(
646 0 link_measurement_enabled,
647 1 neighbor_report_enabled,
648 2 parallel_measurements_enabled,
649 3 repeated_measurements_enabled,
650 4 beacon_passive_measurement_enabled,
651 5 beacon_active_measurement_enabled,
652 6 beacon_table_measurement_enabled,
653 7 beacon_measurement_reporting_conditions_enabled,
654 8 frame_measurement_enabled,
655 9 channel_load_measurement_enabled,
656 10 noise_histogram_measurement_enabled,
657 11 statistics_measurement_enabled,
658 12 lci_measurement_enabled,
659 13 lci_azimuth_enabled,
660 14 tx_stream_category_measurement_enabled,
661 15 trigerred_tx_stream_category_measurement_enabled,
662 16 ap_channel_report_enabled,
663 17 rm_mib_enabled,
664 18..=20 operating_channel_max_measurement_duration,
665 21..=23 nonoperating_channel_max_measurement_duration,
666 24..=26 measurement_pilot_capability,
667 27 measurement_pilot_tx_info_enabled,
668 28 neighbor_report_tsf_offset_enabled,
669 29 rcpi_measurement_enabled,
670 30 rsni_measurement_enabled,
671 31 bss_average_access_delay_enabled,
672 32 bss_available_admission_capacity_enabled,
673 33 antenna_enabled,
674 34 ftm_range_report_enabled,
675 35 civic_location_measurement_enabled,
676 36..=39 _,
677)]
678#[repr(C)]
679#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
680pub struct RmEnabledCapabilities(pub [u8; 5]);
681
682#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy)]
683pub struct PcoPhase(pub u8);
684impl PcoPhase {
685 pub_const!(TWENTY_MHZ, 0);
686 pub_const!(FORTY_MHZ, 1);
687}
688
689#[repr(C)]
690#[derive(PartialEq, Eq, Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
691pub struct MpmProtocol(pub u16);
692
693impl MpmProtocol {
695 pub_const!(MPM, 0);
696 pub_const!(AMPE, 1);
697 pub_const!(VENDOR_SPECIFIC, 255);
699 }
701
702pub struct ExtCapabilitiesView<B> {
704 pub ext_caps_octet_1: Option<Ref<B, ExtCapabilitiesOctet1>>,
707 pub ext_caps_octet_2: Option<Ref<B, ExtCapabilitiesOctet2>>,
708 pub ext_caps_octet_3: Option<Ref<B, ExtCapabilitiesOctet3>>,
709 pub remaining: B,
710}
711
712#[bitfield(
713 0 twenty_forty_bss_coexistence_mgmt_support,
714 1 _, 2 extended_channel_switching,
716 3 _, 4 psmp_capability,
718 5 _, 6 s_psmp_support,
720 7 event,
721)]
722#[repr(C)]
723#[derive(
724 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy, Unaligned,
725)]
726pub struct ExtCapabilitiesOctet1(pub u8);
727
728#[bitfield(
729 0 diagnostics,
730 1 multicast_diagnostics,
731 2 location_tracking,
732 3 fms,
733 4 proxy_arp_service,
734 5 collocated_interference_reporting,
735 6 civic_location,
736 7 geospatial_location,
737)]
738#[repr(C)]
739#[derive(
740 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy, Unaligned,
741)]
742pub struct ExtCapabilitiesOctet2(pub u8);
743
744#[bitfield(
745 0 tfs,
746 1 wnm_sleep_mode,
747 2 tim_broadcast,
748 3 bss_transition,
749 4 qos_traffic_capability,
750 5 ac_station_count,
751 6 multiple_bssid,
752 7 timing_measurement,
753)]
754#[repr(C)]
755#[derive(
756 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy, Unaligned,
757)]
758pub struct ExtCapabilitiesOctet3(pub u8);
759
760#[bitfield(
762 0 gate_announcement,
763 1 addressing_mode,
764 2 proactive,
765 3..=5 _, 6 addr_ext,
767 7 _, )]
769#[repr(C)]
770#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
771pub struct PreqFlags(pub u8);
772
773#[repr(C, packed)]
777#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
778pub struct PreqHeader {
779 pub flags: PreqFlags,
780 pub hop_count: u8,
781 pub element_ttl: u8,
782 pub path_discovery_id: u32,
783 pub originator_addr: MacAddr,
784 pub originator_hwmp_seqno: u32,
785}
786
787#[repr(C, packed)]
791#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
792pub struct PreqMiddle {
793 pub lifetime: u32,
794 pub metric: u32,
795 pub target_count: u8,
796}
797
798#[bitfield(
800 0 target_only,
801 1 _, 2 usn,
803 3..=7 _, )]
805#[repr(C)]
806#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
807pub struct PreqPerTargetFlags(pub u8);
808
809#[repr(C, packed)]
812#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
813pub struct PreqPerTarget {
814 pub flags: PreqPerTargetFlags,
815 pub target_addr: MacAddr,
816 pub target_hwmp_seqno: u32,
817}
818
819pub struct PreqView<B> {
820 pub header: Ref<B, PreqHeader>,
821 pub originator_external_addr: Option<Ref<B, MacAddr>>,
822 pub middle: Ref<B, PreqMiddle>,
823 pub targets: Ref<B, [PreqPerTarget]>,
824}
825
826#[bitfield(
828 0..=5 _, 6 addr_ext,
830 7 _, )]
832#[repr(C)]
833#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
834pub struct PrepFlags(pub u8);
835
836#[repr(C, packed)]
840#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
841pub struct PrepHeader {
842 pub flags: PrepFlags,
843 pub hop_count: u8,
844 pub element_ttl: u8,
845 pub target_addr: MacAddr,
846 pub target_hwmp_seqno: u32,
847}
848
849#[repr(C, packed)]
853#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
854pub struct PrepTail {
855 pub lifetime: u32,
856 pub metric: u32,
857 pub originator_addr: MacAddr,
858 pub originator_hwmp_seqno: u32,
859}
860
861pub struct PrepView<B> {
862 pub header: Ref<B, PrepHeader>,
863 pub target_external_addr: Option<Ref<B, MacAddr>>,
864 pub tail: Ref<B, PrepTail>,
865}
866
867#[repr(C, packed)]
871#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
872pub struct PerrHeader {
873 pub element_ttl: u8,
874 pub num_destinations: u8,
875}
876
877#[bitfield(
879 0..=5 _, 6 addr_ext,
881 7 _, )]
883#[repr(C)]
884#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
885pub struct PerrDestinationFlags(pub u8);
886
887#[repr(C, packed)]
891#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
892pub struct PerrDestinationHeader {
893 pub flags: PerrDestinationFlags,
894 pub dest_addr: MacAddr,
895 pub hwmp_seqno: u32,
896}
897
898pub struct PerrDestinationView<B> {
899 pub header: Ref<B, PerrDestinationHeader>,
900 pub ext_addr: Option<Ref<B, MacAddr>>,
901 pub reason_code: UnalignedView<B, ReasonCode>,
902}
903
904pub struct PerrView<B> {
905 pub header: Ref<B, PerrHeader>,
906 pub destinations: PerrDestinationListView<B>,
907}
908
909pub struct PerrDestinationListView<B>(pub B);
910
911impl<B: SplitByteSlice> IntoIterator for PerrDestinationListView<B> {
912 type Item = PerrDestinationView<B>;
913 type IntoIter = PerrDestinationIter<B>;
914
915 fn into_iter(self) -> Self::IntoIter {
916 PerrDestinationIter(BufferReader::new(self.0))
917 }
918}
919
920impl<'a, B: SplitByteSlice> IntoIterator for &'a PerrDestinationListView<B> {
921 type Item = PerrDestinationView<&'a [u8]>;
922 type IntoIter = PerrDestinationIter<&'a [u8]>;
923
924 fn into_iter(self) -> Self::IntoIter {
925 PerrDestinationIter(BufferReader::new(&self.0[..]))
926 }
927}
928
929impl<B: SplitByteSlice> PerrDestinationListView<B> {
930 pub fn iter(&self) -> PerrDestinationIter<&[u8]> {
931 self.into_iter()
932 }
933}
934
935pub struct PerrDestinationIter<B>(BufferReader<B>);
936
937impl<B: SplitByteSlice> Iterator for PerrDestinationIter<B> {
938 type Item = PerrDestinationView<B>;
939
940 fn next(&mut self) -> Option<Self::Item> {
941 let have_ext_addr = self.0.peek::<PerrDestinationHeader>()?.flags.addr_ext();
942 let dest_len = size_of::<PerrDestinationHeader>()
943 + if have_ext_addr { size_of::<MacAddr>() } else { 0 }
944 + size_of::<ReasonCode>();
945 if self.0.bytes_remaining() < dest_len {
946 None
947 } else {
948 let header = self.0.read().unwrap();
950 let ext_addr = if have_ext_addr { Some(self.0.read().unwrap()) } else { None };
951 let reason_code = self.0.read_unaligned().unwrap();
952 Some(PerrDestinationView { header, ext_addr, reason_code })
953 }
954 }
955}
956
957impl<B: SplitByteSlice> PerrDestinationIter<B> {
958 pub fn bytes_remaining(&self) -> usize {
959 self.0.bytes_remaining()
960 }
961}
962
963#[repr(C, packed)]
966#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
967pub struct ChannelSwitchAnnouncement {
968 pub mode: u8,
969 pub new_channel_number: u8,
970 pub channel_switch_count: u8,
971}
972
973#[repr(C, packed)]
977#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
978pub struct ExtendedChannelSwitchAnnouncement {
979 pub mode: u8,
980 pub new_operating_class: u8,
981 pub new_channel_number: u8,
982 pub channel_switch_count: u8,
983}
984
985#[repr(C, packed)]
987#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
988pub struct WideBandwidthChannelSwitch {
989 pub new_width: VhtChannelBandwidth,
990 pub new_center_freq_seg0: u8,
991 pub new_center_freq_seg1: u8,
992}
993
994#[derive(Clone, Copy, Eq, PartialEq, Debug)]
996pub struct MaxTransmitPowerUnitInterpretation(pub u8);
997
998impl MaxTransmitPowerUnitInterpretation {
999 pub const EIRP: Self = Self(0);
1000}
1001
1002#[bitfield(
1004 0..=2 max_transmit_power_count,
1005 3..=5 max_transmit_power_unit_interpretation as MaxTransmitPowerUnitInterpretation(u8),
1006 6..=7 _, )]
1008#[repr(C)]
1009#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
1010pub struct TransmitPowerInfo(pub u8);
1011
1012#[repr(C)]
1015#[derive(
1016 Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Eq, PartialEq, Debug,
1017)]
1018pub struct TransmitPower(pub u8);
1019
1020pub struct TransmitPowerEnvelopeView<B> {
1022 pub transmit_power_info: Ref<B, TransmitPowerInfo>,
1023 pub max_transmit_power_20: Ref<B, TransmitPower>,
1024 pub max_transmit_power_40: Option<Ref<B, TransmitPower>>,
1025 pub max_transmit_power_80: Option<Ref<B, TransmitPower>>,
1026 pub max_transmit_power_160: Option<Ref<B, TransmitPower>>,
1027}
1028
1029pub struct ChannelSwitchWrapperView<B> {
1031 pub new_country: Option<CountryView<B>>,
1032 pub wide_bandwidth_channel_switch: Option<Ref<B, WideBandwidthChannelSwitch>>,
1033 pub new_transmit_power_envelope: Option<TransmitPowerEnvelopeView<B>>,
1034}
1035
1036#[derive(Debug)]
1039pub enum VendorIe<B: SplitByteSlice> {
1040 MsftLegacyWpa(B),
1043 Wsc(B),
1046 WmmInfo(B),
1049 WmmParam(B),
1052 Unknown { oui: Oui, body: B },
1054}
1055
1056#[repr(C, packed)]
1058#[derive(
1059 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
1060)]
1061pub struct VhtCapabilities {
1062 pub vht_cap_info: VhtCapabilitiesInfo, pub vht_mcs_nss: VhtMcsNssSet, }
1065
1066#[bitfield(
1068 0..=1 max_mpdu_len as MaxMpduLen(u8),
1069 2..=3 supported_cbw_set, 4 rx_ldpc,
1071 5 sgi_cbw80, 6 sgi_cbw160, 7 tx_stbc,
1074 8..=10 rx_stbc,
1075 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,
1085 23..=25 max_ampdu_exponent as MaxAmpduExponent(u8), 26..=27 link_adapt as VhtLinkAdaptation(u8), 28 rx_ant_pattern,
1089 29 tx_ant_pattern,
1090 30..=31 ext_nss_bw, )]
1094#[repr(C)]
1095#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1096pub struct VhtCapabilitiesInfo(pub u32);
1097
1098#[repr(C, packed)]
1100#[derive(
1101 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy,
1102)]
1103pub struct BssMaxIdlePeriod {
1104 pub max_idle_period: u16,
1107 pub idle_options: IdleOptions,
1108}
1109
1110#[bitfield(
1112 0 protected_keep_alive_required, 1..=7 _, )]
1116#[repr(C)]
1117#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1118pub struct IdleOptions(pub u8);
1119
1120#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
1122pub struct MaxMpduLen(pub u8);
1123impl MaxMpduLen {
1124 pub_const!(OCTECTS_3895, 0);
1125 pub_const!(OCTECTS_7991, 1);
1126 pub_const!(OCTECTS_11454, 2);
1127 }
1129
1130#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
1132pub struct VhtLinkAdaptation(pub u8);
1133impl VhtLinkAdaptation {
1134 pub_const!(NO_FEEDBACK, 0);
1135 pub_const!(UNSOLICITED, 2);
1137 pub_const!(BOTH, 3);
1138}
1139
1140#[bitfield(
1142 0..=15 rx_max_mcs as VhtMcsNssMap(u16),
1143
1144 16..=28 rx_max_data_rate, 29..=31 max_nsts,
1146
1147 32..=47 tx_max_mcs as VhtMcsNssMap(u16),
1148
1149 48..=60 tx_max_data_rate, 61 ext_nss_bw, 62..=63 _, )]
1153#[repr(C)]
1154#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1155pub struct VhtMcsNssSet(pub u64);
1156
1157#[bitfield(
1159 0..=1 ss1 as VhtMcsSet(u8),
1160 2..=3 ss2 as VhtMcsSet(u8),
1161 4..=5 ss3 as VhtMcsSet(u8),
1162 6..=7 ss4 as VhtMcsSet(u8),
1163 8..=9 ss5 as VhtMcsSet(u8),
1164 10..=11 ss6 as VhtMcsSet(u8),
1165 12..=13 ss7 as VhtMcsSet(u8),
1166 14..=15 ss8 as VhtMcsSet(u8),
1167)]
1168#[repr(C)]
1169#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1170pub struct VhtMcsNssMap(pub u16);
1171impl VhtMcsNssMap {
1172 const BIT_WIDTH: u8 = 2;
1173 const MASK: u16 = (1 << Self::BIT_WIDTH) - 1;
1174
1175 pub fn ss(&self, num: u8) -> Result<VhtMcsSet, String> {
1176 if num >= 1 && num <= 8 {
1177 Ok(VhtMcsSet((self.0 >> ((num - 1) * Self::BIT_WIDTH) & Self::MASK) as u8))
1178 } else {
1179 Err(format!("spatial stream number must be between 1 and 8, {} invalid", num))
1180 }
1181 }
1182
1183 pub fn set_ss(&mut self, num: u8, val: VhtMcsSet) -> Result<(), String> {
1184 if num == 0 || num > 8 {
1185 Err(format!("spatial stream number must be between 1 and 8, {} invalid", num))
1186 } else if val.0 > 3 {
1187 Err(format!("bitfield is only 2 bit wide, {} invalid", val.0))
1188 } else {
1189 let offset = (num - 1) * Self::BIT_WIDTH;
1190 let mask = Self::MASK << offset;
1191 self.0 = (self.0 & (!mask)) | (((val.0 as u16) & Self::MASK) << offset);
1192 Ok(())
1193 }
1194 }
1195}
1196
1197#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
1198pub struct VhtMcsSet(pub u8);
1199impl VhtMcsSet {
1200 pub_const!(UP_TO_7, 0);
1201 pub_const!(UP_TO_8, 1);
1202 pub_const!(UP_TO_9, 2);
1203 pub_const!(NONE, 3);
1204}
1205
1206#[repr(C, packed)]
1208#[derive(
1209 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
1210)]
1211pub struct VhtOperation {
1213 pub vht_cbw: VhtChannelBandwidth, pub center_freq_seg0: u8, pub center_freq_seg1: u8, pub basic_mcs_nss: VhtMcsNssMap, }
1219
1220impl From<VhtOperation> for fidl_ieee80211::VhtOperation {
1221 fn from(op: VhtOperation) -> Self {
1222 let mut fidl_op = Self { bytes: Default::default() };
1223 fidl_op.bytes.copy_from_slice(&op.as_bytes()[..]);
1224 fidl_op
1225 }
1226}
1227
1228#[repr(C)]
1230#[derive(
1231 Debug,
1232 PartialOrd,
1233 PartialEq,
1234 Eq,
1235 Hash,
1236 IntoBytes,
1237 KnownLayout,
1238 FromBytes,
1239 Immutable,
1240 Clone,
1241 Copy,
1242)]
1243pub struct VhtChannelBandwidth(pub u8);
1244impl VhtChannelBandwidth {
1245 pub_const!(CBW_20_40, 0);
1246 pub_const!(CBW_80_160_80P80, 1);
1247 pub_const!(CBW_160, 2); pub_const!(CBW_80P80, 3); }
1251
1252#[cfg(test)]
1253mod tests {
1254 use super::*;
1255
1256 #[test]
1257 fn ht_cap_mcs_set_conversion() {
1258 let from = fidl_ieee80211::HtCapabilities {
1259 bytes: [
1260 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11,
1263 0x12, 0, 0x13, 0, 0, 0, 0x14, 0x15, ],
1268 };
1269 let ht_cap = Ref::<&[u8], HtCapabilities>::from_bytes(&from.bytes[..]).unwrap();
1270 let mcs_set = ht_cap.mcs_set;
1271 assert_eq!(
1272 mcs_set.as_bytes(),
1273 [3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12]
1274 );
1275 }
1276
1277 #[test]
1278 fn perr_iter_empty() {
1279 let empty: [u8; 0] = [];
1280 let mut iter = PerrDestinationListView(&empty[..]).into_iter();
1281 assert!(iter.next().is_none());
1282 assert_eq!(0, iter.bytes_remaining());
1283 }
1284
1285 #[test]
1286 fn perr_iter_two_destinations() {
1287 #[rustfmt::skip]
1288 let data = [
1289 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, ];
1301 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1302 assert!(iter.bytes_remaining() > 0);
1303
1304 {
1305 let target = iter.next().expect("expected first target");
1306 assert_eq!(0x44332211, { target.header.hwmp_seqno });
1307 let ext_addr = target.ext_addr.expect("expected external addr");
1308 assert_eq!(MacAddr::from([0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a]), *ext_addr);
1309 assert_eq!(0x6655, target.reason_code.get().0);
1310 }
1311
1312 assert!(iter.bytes_remaining() > 0);
1313
1314 {
1315 let target = iter.next().expect("expected second target");
1316 assert_eq!(0xaa998877, { target.header.hwmp_seqno });
1317 assert!(target.ext_addr.is_none());
1318 assert_eq!(0xccbb, target.reason_code.get().0);
1319 }
1320
1321 assert_eq!(0, iter.bytes_remaining());
1322 assert!(iter.next().is_none());
1323 assert_eq!(0, iter.bytes_remaining());
1324 }
1325
1326 #[test]
1327 fn perr_iter_too_short_for_header() {
1328 #[rustfmt::skip]
1329 let data = [
1330 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, ];
1334 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1335 assert_eq!(data.len(), iter.bytes_remaining());
1336 assert!(iter.next().is_none());
1337 assert_eq!(data.len(), iter.bytes_remaining());
1338 }
1339
1340 #[test]
1341 fn perr_iter_too_short_for_ext_addr() {
1342 #[rustfmt::skip]
1343 let data = [
1344 0x40, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, 0x44, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, ];
1350 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1351 assert_eq!(data.len(), iter.bytes_remaining());
1352 assert!(iter.next().is_none());
1353 assert_eq!(data.len(), iter.bytes_remaining());
1354 }
1355
1356 #[test]
1357 fn perr_iter_too_short_for_reason_code() {
1358 #[rustfmt::skip]
1359 let data = [
1360 0x40, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, 0x44, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x55, ];
1367 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1368 assert_eq!(data.len(), iter.bytes_remaining());
1369 assert!(iter.next().is_none());
1370 assert_eq!(data.len(), iter.bytes_remaining());
1371 }
1372
1373 #[test]
1374 fn vht_mcs_nss_map_accessor() {
1375 let mut map = VhtMcsNssMap(0x00ff);
1376 assert_eq!(map.ss(1), Ok(VhtMcsSet(3)));
1377 assert_eq!(map.ss(5), Ok(VhtMcsSet(0)));
1378 assert_eq!(map.set_ss(1, VhtMcsSet(2)), Ok(()));
1379 assert_eq!(map.set_ss(8, VhtMcsSet(3)), Ok(()));
1380 assert_eq!(map.ss(1), Ok(VhtMcsSet(2)));
1381 assert_eq!(map.ss(8), Ok(VhtMcsSet(3)));
1382 assert_eq!(map.0, 0xc0fe);
1383 }
1384
1385 #[test]
1386 fn vht_mcs_nss_map_accssor_error() {
1387 let mut map = VhtMcsNssMap(0);
1388 assert_eq!(
1389 map.ss(0),
1390 Err("spatial stream number must be between 1 and 8, 0 invalid".to_string())
1391 );
1392 assert_eq!(
1393 map.ss(9),
1394 Err("spatial stream number must be between 1 and 8, 9 invalid".to_string())
1395 );
1396 assert_eq!(
1397 map.set_ss(0, VhtMcsSet(3)),
1398 Err("spatial stream number must be between 1 and 8, 0 invalid".to_string())
1399 );
1400 assert_eq!(
1401 map.set_ss(9, VhtMcsSet(3)),
1402 Err("spatial stream number must be between 1 and 8, 9 invalid".to_string())
1403 );
1404 assert_eq!(
1405 map.set_ss(1, VhtMcsSet(4)),
1406 Err("bitfield is only 2 bit wide, 4 invalid".to_string())
1407 );
1408 }
1409
1410 #[test]
1411 fn successfully_convert_ht_operation_to_fidl() {
1412 let ht_op = crate::ie::fake_ies::fake_ht_operation();
1413 let ddk: fidl_ieee80211::HtOperation = ht_op.into();
1414 assert_eq!(ht_op.as_bytes(), ddk.bytes);
1415 }
1416
1417 #[test]
1418 fn successfully_convert_vht_operation_to_fidl() {
1419 let vht_op = crate::ie::fake_ies::fake_vht_operation();
1420 let ddk: fidl_ieee80211::VhtOperation = vht_op.into();
1421 assert_eq!(vht_op.as_bytes(), ddk.bytes);
1422 }
1423}