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 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        // TODO(https://fxbug.dev/42150940): The Vendor Specific element defined by IEEE 802.11-2016 9.4.2.26
53        // does not have a header length of 6. Instead, the OUI is noted to be either 3 or 5
54        // bytes and the vendor determines the remainder of the contents.
55        vendor_ie_hdr: [u8; 6], // OUI, OUI type, version
56    },
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    /// Number of bytes consumed from the IE body to construct IeType
116    pub fn extra_len(&self) -> usize {
117        self.extra_bytes().len()
118    }
119
120    /// Return the bytes consumed from the IE body (not IE header) to construct IeType
121    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}