1use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
6
7#[repr(C, packed)]
8#[derive(
9 Eq, PartialEq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Copy, Clone, Debug,
10)]
11pub struct Id(pub u8);
12
13impl Id {
15 pub const SSID: Self = Self(0);
16 pub const SUPPORTED_RATES: Self = Self(1);
17 pub const DSSS_PARAM_SET: Self = Self(3);
18 pub const TIM: Self = Self(5);
19 pub const COUNTRY: Self = Self(7);
20 pub const CHANNEL_SWITCH_ANNOUNCEMENT: Self = Self(37);
21 pub const HT_CAPABILITIES: Self = Self(45);
22 pub const RSNE: Self = Self(48);
23 pub const EXTENDED_SUPPORTED_RATES: Self = Self(50);
24 pub const MOBILITY_DOMAIN: Self = Self(54);
25 pub const EXTENDED_CHANNEL_SWITCH_ANNOUNCEMENT: Self = Self(60);
26 pub const HT_OPERATION: Self = Self(61);
27 pub const SECONDARY_CHANNEL_OFFSET: Self = Self(62);
28 pub const RM_ENABLED_CAPABILITIES: Self = Self(70);
29 pub const BSS_MAX_IDLE_PERIOD: Self = Self(90);
30 pub const MESH_PEERING_MGMT: Self = Self(117);
31 pub const EXT_CAPABILITIES: Self = Self(127);
32 pub const PREQ: Self = Self(130);
33 pub const PREP: Self = Self(131);
34 pub const PERR: Self = Self(132);
35 pub const VHT_CAPABILITIES: Self = Self(191);
36 pub const VHT_OPERATION: Self = Self(192);
37 pub const WIDE_BANDWIDTH_CHANNEL_SWITCH: Self = Self(194);
38 pub const TRANSMIT_POWER_ENVELOPE: Self = Self(195);
39 pub const CHANNEL_SWITCH_WRAPPER: Self = Self(196);
40 pub const VENDOR_SPECIFIC: Self = Self(221);
41 pub const RSNXE: Self = Self(244);
42 pub const EXTENSION: Self = Self(255);
43}
44
45#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
46pub enum IeType {
47 Ieee {
48 id: Id,
49 extension: Option<u8>,
50 },
51 Vendor {
52 vendor_ie_hdr: [u8; 6], },
57}
58
59macro_rules! ie_type_basic_const {
60 ($id:ident) => {
61 pub const $id: Self = Self::new_basic(Id::$id);
62 };
63}
64
65impl IeType {
66 ie_type_basic_const!(SSID);
67 ie_type_basic_const!(SUPPORTED_RATES);
68 ie_type_basic_const!(DSSS_PARAM_SET);
69 ie_type_basic_const!(TIM);
70 ie_type_basic_const!(COUNTRY);
71 ie_type_basic_const!(CHANNEL_SWITCH_ANNOUNCEMENT);
72 ie_type_basic_const!(HT_CAPABILITIES);
73 ie_type_basic_const!(RSNE);
74 ie_type_basic_const!(EXTENDED_SUPPORTED_RATES);
75 ie_type_basic_const!(MOBILITY_DOMAIN);
76 ie_type_basic_const!(EXTENDED_CHANNEL_SWITCH_ANNOUNCEMENT);
77 ie_type_basic_const!(HT_OPERATION);
78 ie_type_basic_const!(SECONDARY_CHANNEL_OFFSET);
79 ie_type_basic_const!(RM_ENABLED_CAPABILITIES);
80 ie_type_basic_const!(BSS_MAX_IDLE_PERIOD);
81 ie_type_basic_const!(MESH_PEERING_MGMT);
82 ie_type_basic_const!(EXT_CAPABILITIES);
83 ie_type_basic_const!(PREQ);
84 ie_type_basic_const!(PREP);
85 ie_type_basic_const!(PERR);
86 ie_type_basic_const!(VHT_CAPABILITIES);
87 ie_type_basic_const!(VHT_OPERATION);
88 ie_type_basic_const!(WIDE_BANDWIDTH_CHANNEL_SWITCH);
89 ie_type_basic_const!(TRANSMIT_POWER_ENVELOPE);
90 ie_type_basic_const!(CHANNEL_SWITCH_WRAPPER);
91 ie_type_basic_const!(RSNXE);
92
93 pub const WMM_INFO: Self = Self::new_vendor([0x00, 0x50, 0xf2, 0x02, 0x00, 0x01]);
94 pub const WMM_PARAM: Self = Self::new_vendor([0x00, 0x50, 0xf2, 0x02, 0x01, 0x01]);
95
96 pub const fn new_basic(id: Id) -> Self {
97 Self::Ieee { id, extension: None }
98 }
99
100 pub const fn new_extended(ext_id: u8) -> Self {
101 Self::Ieee { id: Id::EXTENSION, extension: Some(ext_id) }
102 }
103
104 pub const fn new_vendor(vendor_ie_hdr: [u8; 6]) -> Self {
105 Self::Vendor { vendor_ie_hdr }
106 }
107
108 pub const fn basic_id(&self) -> Id {
109 match self {
110 Self::Ieee { id, .. } => *id,
111 Self::Vendor { .. } => Id::VENDOR_SPECIFIC,
112 }
113 }
114
115 pub fn extra_len(&self) -> usize {
117 self.extra_bytes().len()
118 }
119
120 pub fn extra_bytes(&self) -> &[u8] {
122 match self {
123 Self::Ieee { extension, .. } => {
124 extension.as_ref().map(|ext_id| std::slice::from_ref(ext_id)).unwrap_or(&[])
125 }
126 Self::Vendor { vendor_ie_hdr } => &vendor_ie_hdr[..],
127 }
128 }
129}
130
131impl std::cmp::PartialOrd for IeType {
132 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
133 Some(self.cmp(other))
134 }
135}
136
137impl std::cmp::Ord for IeType {
138 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
139 match (self, other) {
140 (
141 Self::Ieee { extension: Some(ext_id), .. },
142 Self::Ieee { extension: Some(other_ext_id), .. },
143 ) => ext_id.cmp(other_ext_id),
144 (Self::Vendor { vendor_ie_hdr }, Self::Vendor { vendor_ie_hdr: other_hdr }) => {
145 vendor_ie_hdr.cmp(other_hdr)
146 }
147 _ => self.basic_id().0.cmp(&other.basic_id().0),
148 }
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn test_ie_type() {
158 let basic = IeType::new_basic(Id::SSID);
159 let extended = IeType::new_extended(2);
160 let vendor = IeType::new_vendor([1, 2, 3, 4, 5, 6]);
161
162 assert_eq!(basic, IeType::Ieee { id: Id::SSID, extension: None });
163 assert_eq!(extended, IeType::Ieee { id: Id::EXTENSION, extension: Some(2) });
164 assert_eq!(vendor, IeType::Vendor { vendor_ie_hdr: [1, 2, 3, 4, 5, 6] });
165 assert_eq!(basic.basic_id(), Id::SSID);
166 assert_eq!(extended.basic_id(), Id::EXTENSION);
167 assert_eq!(vendor.basic_id(), Id::VENDOR_SPECIFIC);
168 }
169}