Skip to content

Commit 32d6951

Browse files
committed
Support parsing elemtent ID for WIFI5 and WIFI6
Introduced `Nl80211ElementHeCap` and `Nl80211ElementVhtCap` for element ID parsing. Signed-off-by: Gris Ge <[email protected]>
1 parent 97930a9 commit 32d6951

File tree

4 files changed

+168
-13
lines changed

4 files changed

+168
-13
lines changed

src/element.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use netlink_packet_core::{
66

77
use crate::{
88
bytes::{parse_u16_le, write_u16_le, write_u32_le},
9-
Nl80211ElementHtCap,
9+
Nl80211ElementHeCap, Nl80211ElementHtCap, Nl80211ElementVhtCap,
1010
};
1111

1212
/// [Nl80211Elements] Vec
@@ -64,7 +64,10 @@ const ELEMENT_ID_CHANNEL: u8 = 3;
6464
const ELEMENT_ID_COUNTRY: u8 = 7;
6565
const ELEMENT_ID_HT_CAP: u8 = 45;
6666
const ELEMENT_ID_RSN: u8 = 48;
67+
const ELEMENT_ID_VHT_CAP: u8 = 191;
6768
const ELEMENT_ID_VENDOR: u8 = 221;
69+
const ELEMENT_ID_EXTENSION: u8 = 255;
70+
const ELEMENT_ID_EXTENSION_HE_CAP: u8 = 35;
6871

6972
/// IEEE 802.11-2020 `9.4.2 Elements`
7073
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -79,8 +82,10 @@ pub enum Nl80211Element {
7982
Country(Nl80211ElementCountry),
8083
HtCapability(Nl80211ElementHtCap),
8184
Rsn(Nl80211ElementRsn),
85+
VhtCapability(Nl80211ElementVhtCap),
8286
/// Vendor specific data.
8387
Vendor(Vec<u8>),
88+
HeCapability(Nl80211ElementHeCap),
8489
Other(u8, Vec<u8>),
8590
}
8691

@@ -95,6 +100,8 @@ impl Nl80211Element {
95100
Self::Rsn(_) => ELEMENT_ID_RSN,
96101
Self::Vendor(_) => ELEMENT_ID_VENDOR,
97102
Self::HtCapability(_) => ELEMENT_ID_HT_CAP,
103+
Self::VhtCapability(_) => ELEMENT_ID_VHT_CAP,
104+
Self::HeCapability(_) => ELEMENT_ID_EXTENSION,
98105
Self::Other(id, _) => *id,
99106
}
100107
}
@@ -109,6 +116,8 @@ impl Nl80211Element {
109116
Self::Rsn(v) => v.buffer_len() as u8,
110117
Self::Vendor(v) => v.len() as u8,
111118
Self::HtCapability(v) => v.buffer_len() as u8,
119+
Self::VhtCapability(v) => v.buffer_len() as u8,
120+
Self::HeCapability(v) => v.buffer_len() as u8,
112121
Self::Other(_, data) => (data.len()) as u8,
113122
}
114123
}
@@ -147,6 +156,16 @@ impl<T: AsRef<[u8]> + ?Sized> Parseable<T> for Nl80211Element {
147156
ELEMENT_ID_HT_CAP => {
148157
Self::HtCapability(Nl80211ElementHtCap::parse(payload)?)
149158
}
159+
ELEMENT_ID_VHT_CAP => {
160+
Self::VhtCapability(Nl80211ElementVhtCap::parse(payload)?)
161+
}
162+
ELEMENT_ID_EXTENSION => {
163+
if payload[0] == ELEMENT_ID_EXTENSION_HE_CAP {
164+
Self::HeCapability(Nl80211ElementHeCap::parse(payload)?)
165+
} else {
166+
Self::Other(ELEMENT_ID_EXTENSION, payload.to_vec())
167+
}
168+
}
150169
_ => Self::Other(id, payload.to_vec()),
151170
})
152171
}
@@ -160,25 +179,27 @@ impl Emitable for Nl80211Element {
160179
fn emit(&self, buffer: &mut [u8]) {
161180
buffer[0] = self.id();
162181
buffer[1] = self.length();
163-
let payload = &mut buffer[2..self.length() as usize + 2];
182+
let buffer = &mut buffer[2..self.length() as usize + 2];
164183
match self {
165184
Self::Ssid(s) => {
166185
// IEEE 802.11-2020 indicate it is optional to have NULL
167186
// terminator for this string.
168-
payload.copy_from_slice(s.as_bytes());
187+
buffer.copy_from_slice(s.as_bytes());
169188
}
170189
Self::SupportedRatesAndSelectors(v) => {
171190
let raw: Vec<u8> =
172191
v.as_slice().iter().map(|v| u8::from(*v)).collect();
173-
payload.copy_from_slice(raw.as_slice());
192+
buffer.copy_from_slice(raw.as_slice());
174193
}
175194
Self::Channel(v) => buffer[0] = *v,
176195
Self::Country(v) => v.emit(buffer),
177196
Self::Rsn(v) => v.emit(buffer),
178197
Self::Vendor(v) => buffer[..v.len()].copy_from_slice(v.as_slice()),
179198
Self::HtCapability(v) => v.emit(buffer),
199+
Self::VhtCapability(v) => v.emit(buffer),
200+
Self::HeCapability(v) => v.emit(buffer),
180201
Self::Other(_, data) => {
181-
payload.copy_from_slice(data.as_slice());
202+
buffer.copy_from_slice(data.as_slice());
182203
}
183204
}
184205
}

src/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,12 @@ pub use self::wifi4::{
8383
Nl80211HtWiphyChannelType,
8484
};
8585
pub use self::wifi5::{
86-
Nl80211VhtCapInfo, Nl80211VhtCapability, Nl80211VhtMcsInfo,
86+
Nl80211ElementVhtCap, Nl80211VhtCapInfo, Nl80211VhtCapability,
87+
Nl80211VhtMcsInfo,
8788
};
8889
pub use self::wifi6::{
89-
Nl80211He6GhzCapa, Nl80211HeMacCapInfo, Nl80211HeMcsNssSupp,
90-
Nl80211HePhyCapInfo, Nl80211HePpeThreshold,
90+
Nl80211ElementHeCap, Nl80211He6GhzCapa, Nl80211HeMacCapInfo,
91+
Nl80211HeMcsNssSupp, Nl80211HePhyCapInfo, Nl80211HePpeThreshold,
9192
};
9293
pub use self::wifi7::{
9394
Nl80211EhtMacCapInfo, Nl80211EhtMcsNssSupp,

src/wifi5.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const NL80211_BAND_VHT_MCS_INFO_LEN: usize = 8;
1212

1313
// We cannot use buffer! macro here as these u16 are all little endian while
1414
// The `buffer!` does not support little endian yet.
15+
/// IEEE 802-11 2020: 9.4.2.157.3 Supported VHT-MCS and NSS Set field
1516
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1617
pub struct Nl80211VhtMcsInfo {
1718
pub rx_mcs_map: u16,
@@ -105,6 +106,7 @@ const IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN: u32 = 0x20000000;
105106
const IEEE80211_VHT_CAP_EXT_NSS_BW_MASK: u32 = 0xc0000000;
106107

107108
bitflags::bitflags! {
109+
/// IEEE 802-11 2020: 9.4.2.157.2 VHT Capabilities Information field
108110
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
109111
#[non_exhaustive]
110112
pub struct Nl80211VhtCapInfo: u32 {
@@ -223,3 +225,57 @@ impl<T: AsRef<[u8]> + ?Sized> Parseable<T> for Nl80211VhtCapability {
223225
}
224226
}
225227
}
228+
229+
/// IEEE 802-11 2020: 9.4.2.157 VHT Capabilities element
230+
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
231+
pub struct Nl80211ElementVhtCap {
232+
/// Vht Capabilities Info
233+
pub caps: Nl80211VhtCapInfo,
234+
/// Supported VHT-MCS and NSS Set
235+
pub mcs_nss_set: Nl80211VhtMcsInfo,
236+
}
237+
238+
impl Nl80211ElementVhtCap {
239+
// Hard coded by IEEE 802.11-2020: 9.4.2.157
240+
pub const LENGTH: usize = 12;
241+
242+
pub fn parse(buf: &[u8]) -> Result<Self, DecodeError> {
243+
if buf.len() < Self::LENGTH {
244+
return Err(format!(
245+
"Nl80211ElementVhtCap buffer size is smaller than \
246+
required size {}: {buf:?}",
247+
Self::LENGTH
248+
)
249+
.into());
250+
}
251+
let mut offset = 0;
252+
let caps = Nl80211VhtCapInfo::parse(
253+
&buf[offset..offset + Nl80211VhtCapInfo::LENGTH],
254+
)?;
255+
offset += Nl80211VhtCapInfo::LENGTH;
256+
257+
let mcs_nss_set = Nl80211VhtMcsInfo::parse(&buf[offset..])?;
258+
Ok(Self { caps, mcs_nss_set })
259+
}
260+
}
261+
262+
impl Emitable for Nl80211ElementVhtCap {
263+
fn buffer_len(&self) -> usize {
264+
Self::LENGTH
265+
}
266+
267+
fn emit(&self, buffer: &mut [u8]) {
268+
if buffer.len() < Self::LENGTH {
269+
log::error!(
270+
"Nl80211ElementVhtCap buffer size is smaller than \
271+
required size {}: {buffer:?}",
272+
Self::LENGTH
273+
);
274+
return;
275+
}
276+
let mut offset = 0;
277+
self.caps.emit(&mut buffer[offset..]);
278+
offset += Nl80211VhtCapInfo::LENGTH;
279+
self.mcs_nss_set.emit(&mut buffer[offset..]);
280+
}
281+
}

src/wifi6.rs

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const HE_MAC_CAP_INFO_LEN: usize = 6;
1111
/// "HE MAC Capabilities Information field"
1212
///
1313
/// IEEE 802.11ax-2021 section 9.4.2.248.2
14-
#[derive(Debug, PartialEq, Eq, Clone)]
14+
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1515
pub struct Nl80211HeMacCapInfo(pub [u8; HE_MAC_CAP_INFO_LEN]);
1616

1717
impl Nl80211HeMacCapInfo {
@@ -160,7 +160,7 @@ const HE_PHY_CAP_INFO_LEN: usize = 11;
160160
/// "HE PHY Capabilities Information field"
161161
///
162162
/// IEEE 802.11ax-2021 section 9.4.2.248.3
163-
#[derive(Debug, PartialEq, Eq, Clone)]
163+
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
164164
pub struct Nl80211HePhyCapInfo(pub [u8; HE_PHY_CAP_INFO_LEN]);
165165

166166
impl Nl80211HePhyCapInfo {
@@ -204,9 +204,10 @@ const NL80211_HE_MCS_NSS_SUPP_LEN: usize = 12;
204204

205205
/// Tx/Rx HE MCS NSS Support Field
206206
///
207-
/// The released 802.11ax-2021 has no `Tx/Rx HE MCS NSS Support` section, this
208-
/// struct is merely copy of linux kernel `struct ieee80211_he_mcs_nss_supp`.
209-
#[derive(Debug, PartialEq, Eq, Clone)]
207+
/// IEEE 802-11 2020: 9.4.2.157.3 Supported VHT-MCS and NSS Set field
208+
/// The IEEE standard indicate the size is 4, 8, or 12. But kernel
209+
/// struct is `struct ieee80211_he_mcs_nss_supp` which is always size 12.
210+
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
210211
#[non_exhaustive]
211212
pub struct Nl80211HeMcsNssSupp {
212213
/// Rx MCS map 2 bits for each stream, total 8 streams, for channel widths
@@ -414,3 +415,79 @@ impl Emitable for Nl80211He6GhzCapa {
414415
buffer[..IEEE80211_HE_6GHZ_CAP_LEN].copy_from_slice(&self.0)
415416
}
416417
}
418+
419+
const ELEMENT_ID_EXTENSION_HE_CAP: u8 = 35;
420+
421+
/// IEEE 802-11 2024: 9.4.2.247 HE Capabilities element
422+
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
423+
pub struct Nl80211ElementHeCap {
424+
/// HE MAC Capabilities Info
425+
pub mac_caps: Nl80211HeMacCapInfo,
426+
/// HE PHY Capabilities Info
427+
pub phy_caps: Nl80211HePhyCapInfo,
428+
/// Supported VHT-MCS and NSS Set
429+
pub mcs_nss_set: Nl80211HeMcsNssSupp,
430+
}
431+
432+
impl Nl80211ElementHeCap {
433+
// valid size is from 22 to 30
434+
pub const LENGTH: usize = 22;
435+
const MAX_LENGTH: usize = 30;
436+
437+
pub fn parse(buf: &[u8]) -> Result<Self, DecodeError> {
438+
if buf.len() < Self::LENGTH {
439+
return Err(format!(
440+
"Nl80211ElementHeCap buffer size is smaller than \
441+
minimum size {}: {buf:?}",
442+
Self::LENGTH
443+
)
444+
.into());
445+
}
446+
// first byte is extension id 35
447+
let mut offset = 1usize;
448+
let mac_caps =
449+
Nl80211HeMacCapInfo::new(&buf[offset..Nl80211HeMacCapInfo::LENGTH]);
450+
offset += Nl80211HeMacCapInfo::LENGTH;
451+
452+
let phy_caps =
453+
Nl80211HePhyCapInfo::new(&buf[offset..Nl80211HePhyCapInfo::LENGTH]);
454+
offset += Nl80211HePhyCapInfo::LENGTH;
455+
456+
let remains = &buf[offset..];
457+
let mut raw = vec![0u8; Nl80211HeMcsNssSupp::LENGTH];
458+
459+
raw[..remains.len()].copy_from_slice(remains);
460+
461+
let mcs_nss_set = Nl80211HeMcsNssSupp::parse(&raw)?;
462+
463+
Ok(Self {
464+
mac_caps,
465+
phy_caps,
466+
mcs_nss_set,
467+
})
468+
}
469+
}
470+
471+
impl Emitable for Nl80211ElementHeCap {
472+
fn buffer_len(&self) -> usize {
473+
Self::MAX_LENGTH
474+
}
475+
476+
fn emit(&self, buffer: &mut [u8]) {
477+
if buffer.len() < Self::MAX_LENGTH {
478+
log::error!(
479+
"Nl80211ElementHeCap buffer size is smaller than \
480+
required size {}: {buffer:?}",
481+
Self::LENGTH
482+
);
483+
return;
484+
}
485+
buffer[0] = ELEMENT_ID_EXTENSION_HE_CAP;
486+
let mut offset = 1;
487+
self.mac_caps.emit(&mut buffer[offset..]);
488+
offset += Nl80211HeMacCapInfo::LENGTH;
489+
self.phy_caps.emit(&mut buffer[offset..]);
490+
offset += Nl80211HePhyCapInfo::LENGTH;
491+
self.mcs_nss_set.emit(&mut buffer[offset..]);
492+
}
493+
}

0 commit comments

Comments
 (0)