Skip to content

Commit 34d12cb

Browse files
committed
Fix emit inconsitencies and add tests
1 parent c3e57b9 commit 34d12cb

File tree

3 files changed

+199
-26
lines changed

3 files changed

+199
-26
lines changed

src/element.rs

+65-19
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,11 @@ impl Emitable for Nl80211Element {
172172
v.as_slice().iter().map(|v| u8::from(*v)).collect();
173173
payload.copy_from_slice(raw.as_slice());
174174
}
175-
Self::Channel(v) => buffer[0] = *v,
176-
Self::Country(v) => v.emit(buffer),
177-
Self::Rsn(v) => v.emit(buffer),
178-
Self::Vendor(v) => buffer[..v.len()].copy_from_slice(v.as_slice()),
179-
Self::HtCapability(v) => v.emit(buffer),
175+
Self::Channel(v) => payload[0] = *v,
176+
Self::Country(v) => v.emit(payload),
177+
Self::Rsn(v) => v.emit(payload),
178+
Self::Vendor(v) => payload[..v.len()].copy_from_slice(v.as_slice()),
179+
Self::HtCapability(v) => v.emit(payload),
180180
Self::Other(_, data) => {
181181
payload.copy_from_slice(data.as_slice());
182182
}
@@ -193,9 +193,10 @@ const BSS_MEMBERSHIP_SELECTOR_HT_PHY: u8 = 127;
193193
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
194194
#[non_exhaustive]
195195
pub enum Nl80211RateAndSelector {
196-
/// BSS basic rate set in Mb/s.
196+
/// BSS basic rate in units of 500 kb/s, if necessary rounded up to the
197+
/// next 500 kbs.
197198
BssBasicRateSet(u8),
198-
/// Rate in Mb/s.
199+
/// Rate in units of 500 kb/s, if necessary rounded up to the next 500 kbs.
199200
Rate(u8),
200201
SelectorHt,
201202
SelectorVht,
@@ -216,43 +217,45 @@ pub enum Nl80211RateAndSelector {
216217

217218
impl From<u8> for Nl80211RateAndSelector {
218219
fn from(d: u8) -> Self {
219-
let msb: bool = (d & 1 << 7) > 0;
220-
let value = d & 0b01111111;
220+
const MSB_MASK: u8 = 0b1000_0000;
221+
let msb: bool = (d & MSB_MASK) == MSB_MASK;
222+
let value = d & !MSB_MASK;
221223
if msb {
222224
match value {
223225
BSS_MEMBERSHIP_SELECTOR_SAE_HASH => Self::SelectorSaeHash,
224226
BSS_MEMBERSHIP_SELECTOR_EPD => Self::SelectorEpd,
225227
BSS_MEMBERSHIP_SELECTOR_GLK => Self::SelectorGlk,
226228
BSS_MEMBERSHIP_SELECTOR_VHT_PHY => Self::SelectorVht,
227229
BSS_MEMBERSHIP_SELECTOR_HT_PHY => Self::SelectorHt,
228-
_ => Self::BssBasicRateSet(value / 2),
230+
_ => Self::BssBasicRateSet(value),
229231
}
230232
} else {
231-
Self::Rate(value / 2)
233+
Self::Rate(value)
232234
}
233235
}
234236
}
235237

236238
impl From<Nl80211RateAndSelector> for u8 {
237239
fn from(v: Nl80211RateAndSelector) -> u8 {
240+
const MSB: u8 = 0b1000_0000;
238241
match v {
239-
Nl80211RateAndSelector::BssBasicRateSet(r) => (r * 2) & 1 << 7,
242+
Nl80211RateAndSelector::BssBasicRateSet(r) => r & !MSB | MSB,
240243
Nl80211RateAndSelector::SelectorHt => {
241-
BSS_MEMBERSHIP_SELECTOR_HT_PHY & 1 << 7
244+
BSS_MEMBERSHIP_SELECTOR_HT_PHY | MSB
242245
}
243246
Nl80211RateAndSelector::SelectorVht => {
244-
BSS_MEMBERSHIP_SELECTOR_VHT_PHY & 1 << 7
247+
BSS_MEMBERSHIP_SELECTOR_VHT_PHY | MSB
245248
}
246249
Nl80211RateAndSelector::SelectorGlk => {
247-
BSS_MEMBERSHIP_SELECTOR_GLK & 1 << 7
250+
BSS_MEMBERSHIP_SELECTOR_GLK | MSB
248251
}
249252
Nl80211RateAndSelector::SelectorEpd => {
250-
BSS_MEMBERSHIP_SELECTOR_EPD & 1 << 7
253+
BSS_MEMBERSHIP_SELECTOR_EPD | MSB
251254
}
252255
Nl80211RateAndSelector::SelectorSaeHash => {
253-
BSS_MEMBERSHIP_SELECTOR_SAE_HASH & 1 << 7
256+
BSS_MEMBERSHIP_SELECTOR_SAE_HASH | MSB
254257
}
255-
Nl80211RateAndSelector::Rate(r) => r * 2,
258+
Nl80211RateAndSelector::Rate(r) => r,
256259
}
257260
}
258261
}
@@ -312,7 +315,7 @@ impl Emitable for Nl80211ElementCountry {
312315
buffer[0] = self.country.as_bytes()[0];
313316
buffer[1] = self.country.as_bytes()[1];
314317
}
315-
buffer[3] = self.environment.into();
318+
buffer[2] = self.environment.into();
316319
for (i, triplet) in self.triplets.as_slice().iter().enumerate() {
317320
triplet.emit(&mut buffer[(i + 1) * 3..(i + 2) * 3]);
318321
}
@@ -991,3 +994,46 @@ impl Nl80211Pmkid {
991994
}
992995
}
993996
}
997+
998+
#[cfg(test)]
999+
mod test {
1000+
use super::*;
1001+
use crate::macros::test::roundtrip_emit_parse_test;
1002+
1003+
roundtrip_emit_parse_test!(
1004+
ssid,
1005+
Nl80211Element,
1006+
Nl80211Element::Ssid("test-ssid".to_owned()),
1007+
);
1008+
roundtrip_emit_parse_test!(
1009+
rates_and_selectors,
1010+
Nl80211Element,
1011+
Nl80211Element::SupportedRatesAndSelectors(vec![
1012+
Nl80211RateAndSelector::BssBasicRateSet(1),
1013+
Nl80211RateAndSelector::Rate(1),
1014+
Nl80211RateAndSelector::SelectorHt,
1015+
Nl80211RateAndSelector::SelectorVht,
1016+
Nl80211RateAndSelector::SelectorGlk,
1017+
])
1018+
);
1019+
roundtrip_emit_parse_test!(
1020+
channel,
1021+
Nl80211Element,
1022+
Nl80211Element::Channel(7)
1023+
);
1024+
roundtrip_emit_parse_test!(
1025+
country,
1026+
Nl80211Element,
1027+
Nl80211Element::Country(Nl80211ElementCountry {
1028+
country: "DE".to_owned(),
1029+
environment: Nl80211ElementCountryEnvironment::IndoorAndOutdoor,
1030+
triplets: vec![Nl80211ElementCountryTriplet::Subband(
1031+
Nl80211ElementSubBand {
1032+
channel_start: 1,
1033+
channel_count: 13,
1034+
max_power_level: 20,
1035+
}
1036+
)],
1037+
}),
1038+
);
1039+
}

src/macros.rs

+39
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,42 @@ macro_rules! try_nl80211 {
3030
}
3131
}};
3232
}
33+
34+
#[cfg(test)]
35+
pub(crate) mod test {
36+
#[macro_export]
37+
macro_rules! roundtrip_emit_parse_test {
38+
($name:ident, $ty:ty, $new:expr$(,)?) => {
39+
#[test]
40+
fn $name() {
41+
let val: $ty = $new;
42+
43+
// to check if the type can be emitted to a buffer greater than
44+
// the needed size
45+
let mut buffer = vec![0; val.buffer_len() + 1];
46+
val.emit(buffer.as_mut_slice());
47+
48+
assert_eq!(
49+
<$ty>::parse(&buffer[0..val.buffer_len()]).unwrap(),
50+
val,
51+
);
52+
}
53+
};
54+
}
55+
56+
macro_rules! roundtrip_from_test {
57+
($name:ident, $from:ty => $into:ty, $new:expr$(,)?) => {
58+
#[test]
59+
fn $name() {
60+
let val: $from = $new;
61+
62+
let into: $into = val.into();
63+
64+
assert_eq!(<$from>::from(into), val,);
65+
}
66+
};
67+
}
68+
69+
pub(crate) use roundtrip_emit_parse_test;
70+
pub(crate) use roundtrip_from_test;
71+
}

src/wifi4.rs

+95-7
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ impl Emitable for Nl80211HtCaps {
124124
}
125125

126126
fn emit(&self, buffer: &mut [u8]) {
127-
buffer.copy_from_slice(&self.bits().to_ne_bytes())
127+
buffer[0..self.buffer_len()].copy_from_slice(&self.bits().to_ne_bytes())
128128
}
129129
}
130130

@@ -470,9 +470,9 @@ impl From<Nl80211HtExtendedCap> for [u8; 2] {
470470
fn from(v: Nl80211HtExtendedCap) -> [u8; 2] {
471471
[
472472
v.pco as u8 | (v.pco_trans_time << 1) | (v.mcs_feedback & 0b1) << 7,
473-
((v.mcs_feedback & 0b10) >> 1)
474-
| ((v.support_ht_control as u8) << 1)
475-
| ((v.rd_responder as u8) << 2),
473+
(v.mcs_feedback & 0b11)
474+
| ((v.support_ht_control as u8) << 2)
475+
| ((v.rd_responder as u8) << 3),
476476
]
477477
}
478478
}
@@ -627,7 +627,7 @@ impl Emitable for Nl80211HtTransmitBeamformingCaps {
627627
}
628628

629629
fn emit(&self, buffer: &mut [u8]) {
630-
buffer.copy_from_slice(&self.bits().to_ne_bytes())
630+
buffer[0..self.buffer_len()].copy_from_slice(&self.bits().to_ne_bytes())
631631
}
632632
}
633633

@@ -675,6 +675,94 @@ impl Emitable for Nl80211HtAselCaps {
675675
}
676676

677677
fn emit(&self, buffer: &mut [u8]) {
678-
buffer.copy_from_slice(&self.bits().to_ne_bytes())
679-
}
678+
buffer[0..self.buffer_len()].copy_from_slice(&self.bits().to_ne_bytes())
679+
}
680+
}
681+
682+
#[cfg(test)]
683+
mod test {
684+
use super::*;
685+
use crate::macros::test::{roundtrip_emit_parse_test, roundtrip_from_test};
686+
687+
roundtrip_emit_parse_test!(caps, Nl80211HtCaps, Nl80211HtCaps::all());
688+
roundtrip_emit_parse_test!(
689+
asel_caps,
690+
Nl80211HtAselCaps,
691+
Nl80211HtAselCaps::all()
692+
);
693+
roundtrip_emit_parse_test!(
694+
transmit_beamforming_cap,
695+
Nl80211HtTransmitBeamformingCaps,
696+
Nl80211HtTransmitBeamformingCaps::all(),
697+
);
698+
699+
roundtrip_from_test!(tx_params, Nl80211HtTxParameter => u8, Nl80211HtTxParameter {
700+
mcs_set_defined: false,
701+
tx_rx_mcs_set_not_equal: false,
702+
max_spatial_streams: 1,
703+
unequal_modulation_supported: false,
704+
});
705+
706+
roundtrip_from_test!(ht_wiphy_no_ht, Nl80211HtWiphyChannelType => u32, Nl80211HtWiphyChannelType::NoHt);
707+
roundtrip_from_test!(ht_wiphy_ht_20, Nl80211HtWiphyChannelType => u32, Nl80211HtWiphyChannelType::Ht20);
708+
roundtrip_from_test!(ht_wiphy_other, Nl80211HtWiphyChannelType => u32, Nl80211HtWiphyChannelType::Other(NL80211_CHAN_HT40PLUS + 1));
709+
710+
roundtrip_emit_parse_test!(
711+
mcs_info,
712+
Nl80211HtMcsInfo,
713+
Nl80211HtMcsInfo {
714+
rx_mask: [0xA5; IEEE80211_HT_MCS_MASK_LEN],
715+
rx_highest: u16::MAX,
716+
tx_params: Nl80211HtTxParameter {
717+
mcs_set_defined: false,
718+
tx_rx_mcs_set_not_equal: false,
719+
max_spatial_streams: 1,
720+
unequal_modulation_supported: false,
721+
},
722+
},
723+
);
724+
725+
roundtrip_from_test!(a_mpdu_para, Nl80211HtAMpduPara => u8, Nl80211HtAMpduPara {
726+
max_len_exponent: u8::MAX & 0b11,
727+
min_space: u8::MAX & 0b111,
728+
});
729+
730+
roundtrip_from_test!(extend_cap, Nl80211HtExtendedCap => [u8; 2], Nl80211HtExtendedCap {
731+
pco: true,
732+
pco_trans_time: 1,
733+
mcs_feedback: 1,
734+
support_ht_control: true,
735+
rd_responder: true,
736+
});
737+
738+
roundtrip_emit_parse_test!(
739+
cap_mask,
740+
Nl80211ElementHtCap,
741+
Nl80211ElementHtCap {
742+
caps: Nl80211HtCaps::all(),
743+
a_mpdu_para: Nl80211HtAMpduPara {
744+
max_len_exponent: 3,
745+
min_space: 7,
746+
},
747+
mcs_set: Nl80211HtMcsInfo {
748+
rx_mask: [0xA5; IEEE80211_HT_MCS_MASK_LEN],
749+
rx_highest: u16::MAX,
750+
tx_params: Nl80211HtTxParameter {
751+
mcs_set_defined: false,
752+
tx_rx_mcs_set_not_equal: false,
753+
max_spatial_streams: 1,
754+
unequal_modulation_supported: false,
755+
},
756+
},
757+
ht_ext_cap: Nl80211HtExtendedCap {
758+
pco: true,
759+
pco_trans_time: 2,
760+
mcs_feedback: 2,
761+
support_ht_control: true,
762+
rd_responder: true,
763+
},
764+
transmit_beamforming_cap: Nl80211HtTransmitBeamformingCaps::all(),
765+
asel_cap: Nl80211HtAselCaps::all(),
766+
},
767+
);
680768
}

0 commit comments

Comments
 (0)