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::{
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
987#[repr(C, packed)]
989#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
990pub struct WideBandwidthChannelSwitch {
991 pub new_width: VhtChannelBandwidth,
992 pub new_center_freq_seg0: u8,
993 pub new_center_freq_seg1: u8,
994}
995
996#[derive(Clone, Copy, Eq, PartialEq, Debug)]
998pub struct MaxTransmitPowerUnitInterpretation(pub u8);
999
1000impl MaxTransmitPowerUnitInterpretation {
1001 pub const EIRP: Self = Self(0);
1002}
1003
1004#[bitfield(
1006 0..=2 max_transmit_power_count,
1007 3..=5 max_transmit_power_unit_interpretation as MaxTransmitPowerUnitInterpretation(u8),
1008 6..=7 _, )]
1010#[repr(C)]
1011#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
1012pub struct TransmitPowerInfo(pub u8);
1013
1014#[repr(C)]
1017#[derive(
1018 Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Eq, PartialEq, Debug,
1019)]
1020pub struct TransmitPower(pub u8);
1021
1022pub struct TransmitPowerEnvelopeView<B> {
1024 pub transmit_power_info: Ref<B, TransmitPowerInfo>,
1025 pub max_transmit_power_20: Ref<B, TransmitPower>,
1026 pub max_transmit_power_40: Option<Ref<B, TransmitPower>>,
1027 pub max_transmit_power_80: Option<Ref<B, TransmitPower>>,
1028 pub max_transmit_power_160: Option<Ref<B, TransmitPower>>,
1029}
1030
1031pub struct ChannelSwitchWrapperView<B> {
1033 pub new_country: Option<CountryView<B>>,
1034 pub wide_bandwidth_channel_switch: Option<Ref<B, WideBandwidthChannelSwitch>>,
1035 pub new_transmit_power_envelope: Option<TransmitPowerEnvelopeView<B>>,
1036}
1037
1038#[derive(Debug)]
1041pub enum VendorIe<B: SplitByteSlice> {
1042 MsftLegacyWpa(B),
1045 Wsc(B),
1048 WmmInfo(B),
1051 WmmParam(B),
1054 Unknown { oui: Oui, body: B },
1056}
1057
1058#[repr(C, packed)]
1060#[derive(
1061 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
1062)]
1063pub struct VhtCapabilities {
1064 pub vht_cap_info: VhtCapabilitiesInfo, pub vht_mcs_nss: VhtMcsNssSet, }
1067
1068#[bitfield(
1070 0..=1 max_mpdu_len as MaxMpduLen(u8),
1071 2..=3 supported_cbw_set, 4 rx_ldpc,
1073 5 sgi_cbw80, 6 sgi_cbw160, 7 tx_stbc,
1076 8..=10 rx_stbc,
1077 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,
1087 23..=25 max_ampdu_exponent as MaxAmpduExponent(u8), 26..=27 link_adapt as VhtLinkAdaptation(u8), 28 rx_ant_pattern,
1091 29 tx_ant_pattern,
1092 30..=31 ext_nss_bw, )]
1096#[repr(C)]
1097#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1098pub struct VhtCapabilitiesInfo(pub u32);
1099
1100#[repr(C, packed)]
1102#[derive(
1103 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy,
1104)]
1105pub struct BssMaxIdlePeriod {
1106 pub max_idle_period: u16,
1109 pub idle_options: IdleOptions,
1110}
1111
1112#[bitfield(
1114 0 protected_keep_alive_required, 1..=7 _, )]
1118#[repr(C)]
1119#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1120pub struct IdleOptions(pub u8);
1121
1122#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
1124pub struct MaxMpduLen(pub u8);
1125impl MaxMpduLen {
1126 pub_const!(OCTECTS_3895, 0);
1127 pub_const!(OCTECTS_7991, 1);
1128 pub_const!(OCTECTS_11454, 2);
1129 }
1131
1132#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
1134pub struct VhtLinkAdaptation(pub u8);
1135impl VhtLinkAdaptation {
1136 pub_const!(NO_FEEDBACK, 0);
1137 pub_const!(UNSOLICITED, 2);
1139 pub_const!(BOTH, 3);
1140}
1141
1142#[bitfield(
1144 0..=15 rx_max_mcs as VhtMcsNssMap(u16),
1145
1146 16..=28 rx_max_data_rate, 29..=31 max_nsts,
1148
1149 32..=47 tx_max_mcs as VhtMcsNssMap(u16),
1150
1151 48..=60 tx_max_data_rate, 61 ext_nss_bw, 62..=63 _, )]
1155#[repr(C)]
1156#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1157pub struct VhtMcsNssSet(pub u64);
1158
1159#[bitfield(
1161 0..=1 ss1 as VhtMcsSet(u8),
1162 2..=3 ss2 as VhtMcsSet(u8),
1163 4..=5 ss3 as VhtMcsSet(u8),
1164 6..=7 ss4 as VhtMcsSet(u8),
1165 8..=9 ss5 as VhtMcsSet(u8),
1166 10..=11 ss6 as VhtMcsSet(u8),
1167 12..=13 ss7 as VhtMcsSet(u8),
1168 14..=15 ss8 as VhtMcsSet(u8),
1169)]
1170#[repr(C)]
1171#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
1172pub struct VhtMcsNssMap(pub u16);
1173impl VhtMcsNssMap {
1174 const BIT_WIDTH: u8 = 2;
1175 const MASK: u16 = (1 << Self::BIT_WIDTH) - 1;
1176
1177 pub fn ss(&self, num: u8) -> Result<VhtMcsSet, String> {
1178 if num >= 1 && num <= 8 {
1179 Ok(VhtMcsSet((self.0 >> ((num - 1) * Self::BIT_WIDTH) & Self::MASK) as u8))
1180 } else {
1181 Err(format!("spatial stream number must be between 1 and 8, {} invalid", num))
1182 }
1183 }
1184
1185 pub fn set_ss(&mut self, num: u8, val: VhtMcsSet) -> Result<(), String> {
1186 if num == 0 || num > 8 {
1187 Err(format!("spatial stream number must be between 1 and 8, {} invalid", num))
1188 } else if val.0 > 3 {
1189 Err(format!("bitfield is only 2 bit wide, {} invalid", val.0))
1190 } else {
1191 let offset = (num - 1) * Self::BIT_WIDTH;
1192 let mask = Self::MASK << offset;
1193 self.0 = (self.0 & (!mask)) | (((val.0 as u16) & Self::MASK) << offset);
1194 Ok(())
1195 }
1196 }
1197}
1198
1199#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
1200pub struct VhtMcsSet(pub u8);
1201impl VhtMcsSet {
1202 pub_const!(UP_TO_7, 0);
1203 pub_const!(UP_TO_8, 1);
1204 pub_const!(UP_TO_9, 2);
1205 pub_const!(NONE, 3);
1206}
1207
1208#[repr(C, packed)]
1210#[derive(
1211 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
1212)]
1213pub struct VhtOperation {
1215 pub vht_cbw: VhtChannelBandwidth, pub center_freq_seg0: u8, pub center_freq_seg1: u8, pub basic_mcs_nss: VhtMcsNssMap, }
1221
1222impl From<VhtOperation> for fidl_ieee80211::VhtOperation {
1223 fn from(op: VhtOperation) -> Self {
1224 let mut fidl_op = Self { bytes: Default::default() };
1225 fidl_op.bytes.copy_from_slice(&op.as_bytes()[..]);
1226 fidl_op
1227 }
1228}
1229
1230#[repr(C)]
1232#[derive(
1233 Debug,
1234 PartialOrd,
1235 PartialEq,
1236 Eq,
1237 Hash,
1238 IntoBytes,
1239 KnownLayout,
1240 FromBytes,
1241 Immutable,
1242 Clone,
1243 Copy,
1244)]
1245pub struct VhtChannelBandwidth(pub u8);
1246impl VhtChannelBandwidth {
1247 pub_const!(CBW_20_40, 0);
1248 pub_const!(CBW_80_160_80P80, 1);
1249 pub_const!(CBW_160, 2); pub_const!(CBW_80P80, 3); }
1253
1254#[derive(Debug)]
1256pub struct RsnxeView<B: ByteSlice> {
1257 pub rsnxe_octet_1: Option<Ref<B, RsnxeOctet1>>,
1258 pub remaining: B,
1259}
1260
1261#[bitfield(
1262 0..=3 field_length,
1263 4 protected_twt_operations_support,
1264 5 sae_hash_to_element,
1265 6..=7 _,
1266)]
1267#[repr(C)]
1268#[derive(
1269 PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy, Unaligned,
1270)]
1271pub struct RsnxeOctet1(pub u8);
1272
1273#[cfg(test)]
1274mod tests {
1275 use super::*;
1276
1277 #[test]
1278 fn ht_cap_mcs_set_conversion() {
1279 let from = fidl_ieee80211::HtCapabilities {
1280 bytes: [
1281 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11,
1284 0x12, 0, 0x13, 0, 0, 0, 0x14, 0x15, ],
1289 };
1290 let ht_cap = Ref::<&[u8], HtCapabilities>::from_bytes(&from.bytes[..]).unwrap();
1291 let mcs_set = ht_cap.mcs_set;
1292 assert_eq!(
1293 mcs_set.as_bytes(),
1294 [3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12]
1295 );
1296 }
1297
1298 #[test]
1299 fn perr_iter_empty() {
1300 let empty: [u8; 0] = [];
1301 let mut iter = PerrDestinationListView(&empty[..]).into_iter();
1302 assert!(iter.next().is_none());
1303 assert_eq!(0, iter.bytes_remaining());
1304 }
1305
1306 #[test]
1307 fn perr_iter_two_destinations() {
1308 #[rustfmt::skip]
1309 let data = [
1310 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, ];
1322 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1323 assert!(iter.bytes_remaining() > 0);
1324
1325 {
1326 let target = iter.next().expect("expected first target");
1327 assert_eq!(0x44332211, { target.header.hwmp_seqno });
1328 let ext_addr = target.ext_addr.expect("expected external addr");
1329 assert_eq!(MacAddr::from([0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a]), *ext_addr);
1330 assert_eq!(0x6655, target.reason_code.get().0);
1331 }
1332
1333 assert!(iter.bytes_remaining() > 0);
1334
1335 {
1336 let target = iter.next().expect("expected second target");
1337 assert_eq!(0xaa998877, { target.header.hwmp_seqno });
1338 assert!(target.ext_addr.is_none());
1339 assert_eq!(0xccbb, target.reason_code.get().0);
1340 }
1341
1342 assert_eq!(0, iter.bytes_remaining());
1343 assert!(iter.next().is_none());
1344 assert_eq!(0, iter.bytes_remaining());
1345 }
1346
1347 #[test]
1348 fn perr_iter_too_short_for_header() {
1349 #[rustfmt::skip]
1350 let data = [
1351 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, ];
1355 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1356 assert_eq!(data.len(), iter.bytes_remaining());
1357 assert!(iter.next().is_none());
1358 assert_eq!(data.len(), iter.bytes_remaining());
1359 }
1360
1361 #[test]
1362 fn perr_iter_too_short_for_ext_addr() {
1363 #[rustfmt::skip]
1364 let data = [
1365 0x40, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, 0x44, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, ];
1371 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1372 assert_eq!(data.len(), iter.bytes_remaining());
1373 assert!(iter.next().is_none());
1374 assert_eq!(data.len(), iter.bytes_remaining());
1375 }
1376
1377 #[test]
1378 fn perr_iter_too_short_for_reason_code() {
1379 #[rustfmt::skip]
1380 let data = [
1381 0x40, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, 0x44, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x55, ];
1388 let mut iter = PerrDestinationListView(&data[..]).into_iter();
1389 assert_eq!(data.len(), iter.bytes_remaining());
1390 assert!(iter.next().is_none());
1391 assert_eq!(data.len(), iter.bytes_remaining());
1392 }
1393
1394 #[test]
1395 fn vht_mcs_nss_map_accessor() {
1396 let mut map = VhtMcsNssMap(0x00ff);
1397 assert_eq!(map.ss(1), Ok(VhtMcsSet(3)));
1398 assert_eq!(map.ss(5), Ok(VhtMcsSet(0)));
1399 assert_eq!(map.set_ss(1, VhtMcsSet(2)), Ok(()));
1400 assert_eq!(map.set_ss(8, VhtMcsSet(3)), Ok(()));
1401 assert_eq!(map.ss(1), Ok(VhtMcsSet(2)));
1402 assert_eq!(map.ss(8), Ok(VhtMcsSet(3)));
1403 assert_eq!(map.0, 0xc0fe);
1404 }
1405
1406 #[test]
1407 fn vht_mcs_nss_map_accssor_error() {
1408 let mut map = VhtMcsNssMap(0);
1409 assert_eq!(
1410 map.ss(0),
1411 Err("spatial stream number must be between 1 and 8, 0 invalid".to_string())
1412 );
1413 assert_eq!(
1414 map.ss(9),
1415 Err("spatial stream number must be between 1 and 8, 9 invalid".to_string())
1416 );
1417 assert_eq!(
1418 map.set_ss(0, VhtMcsSet(3)),
1419 Err("spatial stream number must be between 1 and 8, 0 invalid".to_string())
1420 );
1421 assert_eq!(
1422 map.set_ss(9, VhtMcsSet(3)),
1423 Err("spatial stream number must be between 1 and 8, 9 invalid".to_string())
1424 );
1425 assert_eq!(
1426 map.set_ss(1, VhtMcsSet(4)),
1427 Err("bitfield is only 2 bit wide, 4 invalid".to_string())
1428 );
1429 }
1430
1431 #[test]
1432 fn successfully_convert_ht_operation_to_fidl() {
1433 let ht_op = crate::ie::fake_ies::fake_ht_operation();
1434 let ddk: fidl_ieee80211::HtOperation = ht_op.into();
1435 assert_eq!(ht_op.as_bytes(), ddk.bytes);
1436 }
1437
1438 #[test]
1439 fn successfully_convert_vht_operation_to_fidl() {
1440 let vht_op = crate::ie::fake_ies::fake_vht_operation();
1441 let ddk: fidl_ieee80211::VhtOperation = vht_op.into();
1442 assert_eq!(vht_op.as_bytes(), ddk.bytes);
1443 }
1444}