wlan_common/ie/
id.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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
13// IEEE Std 802.11-2016, 9.4.2.1, Table 9-77
14impl 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 EXTENSION: Self = Self(255);
42}
43
44#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
45pub enum IeType {
46    Ieee {
47        id: Id,
48        extension: Option<u8>,
49    },
50    Vendor {
51        // TODO(https://fxbug.dev/42150940): The Vendor Specific element defined by IEEE 802.11-2016 9.4.2.26
52        // does not have a header length of 6. Instead, the OUI is noted to be either 3 or 5
53        // bytes and the vendor determines the remainder of the contents.
54        vendor_ie_hdr: [u8; 6], // OUI, OUI type, version
55    },
56}
57
58macro_rules! ie_type_basic_const {
59    ($id:ident) => {
60        pub const $id: Self = Self::new_basic(Id::$id);
61    };
62}
63
64impl IeType {
65    ie_type_basic_const!(SSID);
66    ie_type_basic_const!(SUPPORTED_RATES);
67    ie_type_basic_const!(DSSS_PARAM_SET);
68    ie_type_basic_const!(TIM);
69    ie_type_basic_const!(COUNTRY);
70    ie_type_basic_const!(CHANNEL_SWITCH_ANNOUNCEMENT);
71    ie_type_basic_const!(HT_CAPABILITIES);
72    ie_type_basic_const!(RSNE);
73    ie_type_basic_const!(EXTENDED_SUPPORTED_RATES);
74    ie_type_basic_const!(MOBILITY_DOMAIN);
75    ie_type_basic_const!(EXTENDED_CHANNEL_SWITCH_ANNOUNCEMENT);
76    ie_type_basic_const!(HT_OPERATION);
77    ie_type_basic_const!(SECONDARY_CHANNEL_OFFSET);
78    ie_type_basic_const!(RM_ENABLED_CAPABILITIES);
79    ie_type_basic_const!(BSS_MAX_IDLE_PERIOD);
80    ie_type_basic_const!(MESH_PEERING_MGMT);
81    ie_type_basic_const!(EXT_CAPABILITIES);
82    ie_type_basic_const!(PREQ);
83    ie_type_basic_const!(PREP);
84    ie_type_basic_const!(PERR);
85    ie_type_basic_const!(VHT_CAPABILITIES);
86    ie_type_basic_const!(VHT_OPERATION);
87    ie_type_basic_const!(WIDE_BANDWIDTH_CHANNEL_SWITCH);
88    ie_type_basic_const!(TRANSMIT_POWER_ENVELOPE);
89    ie_type_basic_const!(CHANNEL_SWITCH_WRAPPER);
90
91    pub const WMM_INFO: Self = Self::new_vendor([0x00, 0x50, 0xf2, 0x02, 0x00, 0x01]);
92    pub const WMM_PARAM: Self = Self::new_vendor([0x00, 0x50, 0xf2, 0x02, 0x01, 0x01]);
93
94    pub const fn new_basic(id: Id) -> Self {
95        Self::Ieee { id, extension: None }
96    }
97
98    pub const fn new_extended(ext_id: u8) -> Self {
99        Self::Ieee { id: Id::EXTENSION, extension: Some(ext_id) }
100    }
101
102    pub const fn new_vendor(vendor_ie_hdr: [u8; 6]) -> Self {
103        Self::Vendor { vendor_ie_hdr }
104    }
105
106    pub const fn basic_id(&self) -> Id {
107        match self {
108            Self::Ieee { id, .. } => *id,
109            Self::Vendor { .. } => Id::VENDOR_SPECIFIC,
110        }
111    }
112
113    /// Number of bytes consumed from the IE body to construct IeType
114    pub fn extra_len(&self) -> usize {
115        self.extra_bytes().len()
116    }
117
118    /// Return the bytes consumed from the IE body (not IE header) to construct IeType
119    pub fn extra_bytes(&self) -> &[u8] {
120        match self {
121            Self::Ieee { extension, .. } => {
122                extension.as_ref().map(|ext_id| std::slice::from_ref(ext_id)).unwrap_or(&[])
123            }
124            Self::Vendor { vendor_ie_hdr } => &vendor_ie_hdr[..],
125        }
126    }
127}
128
129impl std::cmp::PartialOrd for IeType {
130    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
131        Some(self.cmp(other))
132    }
133}
134
135impl std::cmp::Ord for IeType {
136    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
137        match (self, other) {
138            (
139                Self::Ieee { extension: Some(ext_id), .. },
140                Self::Ieee { extension: Some(other_ext_id), .. },
141            ) => ext_id.cmp(other_ext_id),
142            (Self::Vendor { vendor_ie_hdr }, Self::Vendor { vendor_ie_hdr: other_hdr }) => {
143                vendor_ie_hdr.cmp(other_hdr)
144            }
145            _ => self.basic_id().0.cmp(&other.basic_id().0),
146        }
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use super::*;
153
154    #[test]
155    fn test_ie_type() {
156        let basic = IeType::new_basic(Id::SSID);
157        let extended = IeType::new_extended(2);
158        let vendor = IeType::new_vendor([1, 2, 3, 4, 5, 6]);
159
160        assert_eq!(basic, IeType::Ieee { id: Id::SSID, extension: None });
161        assert_eq!(extended, IeType::Ieee { id: Id::EXTENSION, extension: Some(2) });
162        assert_eq!(vendor, IeType::Vendor { vendor_ie_hdr: [1, 2, 3, 4, 5, 6] });
163        assert_eq!(basic.basic_id(), Id::SSID);
164        assert_eq!(extended.basic_id(), Id::EXTENSION);
165        assert_eq!(vendor.basic_id(), Id::VENDOR_SPECIFIC);
166    }
167}