blob: 48f56dba0148fd777431b3a0d5c612e08b9f7090 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use proc_macro_hack::proc_macro_hack;
#[proc_macro_hack]
pub use wlan_frame_writer_macro::write_frame;
#[proc_macro_hack]
pub use wlan_frame_writer_macro::write_frame_with_buf;
#[cfg(test)]
mod tests {
use {
super::*,
std::fmt,
thiserror::Error,
wlan_common::{
self as common,
appendable::BufferTooSmall,
ie::{
self,
rsn::{
akm::{Akm, PSK},
cipher::{Cipher, CCMP_128, TKIP},
rsne,
},
wpa,
},
mac::*,
organization::Oui,
},
};
#[derive(Debug, Error, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub enum Error {
FrameWriteError,
BufferTooSmall,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl From<BufferTooSmall> for Error {
fn from(_: BufferTooSmall) -> Self {
Error::BufferTooSmall
}
}
impl From<common::error::FrameWriteError> for Error {
fn from(_: common::error::FrameWriteError) -> Self {
Error::FrameWriteError
}
}
struct BufferProvider;
impl BufferProvider {
fn get_buffer(&mut self, min_len: usize) -> Result<Vec<u8>, Error> {
Ok(vec![0; min_len])
}
}
fn make_mgmt_hdr() -> MgmtHdr {
MgmtHdr {
frame_ctrl: FrameControl(0x4321),
duration: 42,
addr1: [7; 6],
addr2: [6; 6],
addr3: [5; 6],
seq_ctrl: SequenceControl(0x8765),
}
}
#[test]
fn write_buf() {
let (mut buf, bytes_written) = write_frame_with_buf!(vec![0u8; 10], {
ies: { ssid: &b"foobar"[..] }
})
.expect("frame construction failed");
buf.truncate(bytes_written);
assert_eq!(bytes_written, 8);
assert_eq!(&[0, 6, 102, 111, 111, 98, 97, 114,][..], &buf[..]);
}
#[test]
fn write_ssid() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: { ssid: &b"foobar"[..] }
})
.expect("frame construction failed");
assert_eq!(bytes_written, 8);
assert_eq!(&[0, 6, 102, 111, 111, 98, 97, 114,][..], &buf[..]);
}
#[test]
fn write_ssid_empty() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: { ssid: [0u8; 0] }
})
.expect("frame construction failed");
assert_eq!(bytes_written, 2);
assert_eq!(&[0, 0][..], &buf[..]);
}
#[test]
fn write_ssid_max() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: { ssid: [2u8; 32] }
})
.expect("frame construction failed");
assert_eq!(bytes_written, 34);
#[rustfmt::skip]
assert_eq!(
&[
0, 32,
2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
][..],
&buf[..]
);
}
#[test]
fn write_ssid_too_large() {
let buffer_provider = BufferProvider;
let err = write_frame!(buffer_provider, {
ies: { ssid: [2u8; 33] }
})
.expect_err("frame construction succeeded");
assert_eq!(err, Error::FrameWriteError);
}
#[test]
fn write_rates() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: { supported_rates: &[1u8, 2, 3, 4, 5] }
})
.expect("frame construction failed");
assert_eq!(bytes_written, 7);
assert_eq!(&[1, 5, 1, 2, 3, 4, 5,][..], &buf[..]);
}
#[test]
fn write_rates_too_large() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: { supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8, 9] }
})
.expect("frame construction failed");
assert_eq!(bytes_written, 10);
assert_eq!(&[1, 8, 1, 2, 3, 4, 5, 6, 7, 8][..], &buf[..]);
}
#[test]
fn write_rates_empty() {
let buffer_provider = BufferProvider;
let err = write_frame!(buffer_provider, {
ies: { supported_rates: &[] }
})
.expect_err("frame construction succeeded");
assert_eq!(err, Error::FrameWriteError);
}
#[test]
fn write_extended_supported_rates_too_few_rates() {
let buffer_provider = BufferProvider;
let err = write_frame!(buffer_provider, {
ies: {
supported_rates: &[1u8, 2, 3, 4, 5, 6],
extended_supported_rates: &[1u8, 2, 3, 4]
}
})
.expect_err("frame construction succeeded");
assert_eq!(err, Error::FrameWriteError);
}
#[test]
fn write_extended_supported_rates_too_many_rates() {
let buffer_provider = BufferProvider;
let err = write_frame!(buffer_provider, {
ies: {
supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8, 9],
extended_supported_rates: &[1u8, 2, 3, 4]
}
})
.expect_err("frame construction succeeded");
assert_eq!(err, Error::FrameWriteError);
}
#[test]
fn write_extended_supported_rates_continued() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: {
supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8, 9],
extended_supported_rates: {/* continue rates */}
}
})
.expect("frame construction failed");
assert_eq!(bytes_written, 13);
assert_eq!(&[1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 50, 1, 9][..], &buf[..]);
}
#[test]
fn write_extended_supported_rates_separate() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: {
supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8],
extended_supported_rates: &[11u8, 12, 13],
}
})
.expect("frame construction failed");
assert_eq!(bytes_written, 15);
assert_eq!(&[1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 50, 3, 11, 12, 13][..], &buf[..]);
}
#[test]
fn write_rsne() {
let rsne = rsne::Rsne {
version: rsne::VERSION,
group_data_cipher_suite: Some(Cipher::new_dot11(CCMP_128)),
pairwise_cipher_suites: vec![Cipher::new_dot11(CCMP_128)],
akm_suites: vec![Akm::new_dot11(PSK)],
..Default::default()
};
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: { rsne: &rsne, }
})
.expect("frame construction failed");
assert_eq!(bytes_written, 20);
assert_eq!(
&[
48, 18, // Element header
1, 0, // Version
0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
1, 0, 0x00, 0x0F, 0xAC, 2, // 1 AKM: PSK
][..],
&buf[..]
);
}
#[test]
fn write_wpa1() {
let wpa_ie = wpa::WpaIe {
multicast_cipher: Cipher { oui: Oui::MSFT, suite_type: TKIP },
unicast_cipher_list: vec![Cipher { oui: Oui::MSFT, suite_type: TKIP }],
akm_list: vec![Akm { oui: Oui::MSFT, suite_type: PSK }],
};
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: { wpa1: &wpa_ie, }
})
.expect("frame construction failed");
assert_eq!(bytes_written, 24);
assert_eq!(
&[
0xdd, 0x16, // Vendor IE header
0x00, 0x50, 0xf2, // MSFT OUI
0x01, 0x01, 0x00, // WPA IE header
0x00, 0x50, 0xf2, 0x02, // multicast cipher: TKIP
0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 unicast cipher: TKIP
0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 AKM: PSK
][..],
&buf[..]
);
}
#[test]
fn write_match_optional_positive() {
let wpa_ie = wpa::WpaIe {
multicast_cipher: Cipher { oui: Oui::MSFT, suite_type: TKIP },
unicast_cipher_list: vec![Cipher { oui: Oui::MSFT, suite_type: TKIP }],
akm_list: vec![Akm { oui: Oui::MSFT, suite_type: PSK }],
};
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: {
wpa1?: match 2u8 {
1 => None,
2 => Some(&wpa_ie),
_ => None,
},
}
})
.expect("frame construction failed");
assert_eq!(bytes_written, 24);
assert_eq!(
&[
0xdd, 0x16, // Vendor IE header
0x00, 0x50, 0xf2, // MSFT OUI
0x01, 0x01, 0x00, // WPA IE header
0x00, 0x50, 0xf2, 0x02, // multicast cipher: TKIP
0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 unicast cipher: TKIP
0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 AKM: PSK
][..],
&buf[..]
);
}
#[test]
fn write_match_optional_negative() {
let wpa_ie = wpa::WpaIe {
multicast_cipher: Cipher { oui: Oui::MSFT, suite_type: TKIP },
unicast_cipher_list: vec![Cipher { oui: Oui::MSFT, suite_type: TKIP }],
akm_list: vec![Akm { oui: Oui::MSFT, suite_type: PSK }],
};
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: {
wpa1?: match 1u8 {
1 => None,
2 => Some(&wpa_ie),
_ => None,
},
}
})
.expect("frame construction failed");
assert_eq!(bytes_written, 0);
assert!(buf.is_empty());
}
#[test]
fn write_match_required() {
let wpa_ie_first = wpa::WpaIe {
multicast_cipher: Cipher { oui: Oui::MSFT, suite_type: TKIP },
unicast_cipher_list: vec![Cipher { oui: Oui::MSFT, suite_type: TKIP }],
akm_list: vec![Akm { oui: Oui::MSFT, suite_type: PSK }],
};
let wpa_ie_second = wpa::WpaIe {
multicast_cipher: Cipher { oui: Oui::MSFT, suite_type: CCMP_128 },
unicast_cipher_list: vec![Cipher { oui: Oui::MSFT, suite_type: CCMP_128 }],
akm_list: vec![Akm { oui: Oui::MSFT, suite_type: PSK }],
};
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: {
wpa1: match 1u8 {
1 => &wpa_ie_first,
_ => &wpa_ie_second,
},
}
})
.expect("frame construction failed");
assert_eq!(bytes_written, 24);
assert_eq!(
&[
0xdd, 0x16, // Vendor IE header
0x00, 0x50, 0xf2, // MSFT OUI
0x01, 0x01, 0x00, // WPA IE header
0x00, 0x50, 0xf2, 0x02, // multicast cipher: TKIP
0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 unicast cipher: TKIP
0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 AKM: PSK
][..],
&buf[..]
);
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: {
wpa1: match 2u8 {
1 => &wpa_ie_first,
_ => &wpa_ie_second,
},
}
})
.expect("frame construction failed");
assert_eq!(bytes_written, 24);
assert_eq!(
&[
0xdd, 0x16, // Vendor IE header
0x00, 0x50, 0xf2, // MSFT OUI
0x01, 0x01, 0x00, // WPA IE header
0x00, 0x50, 0xf2, 0x04, // multicast cipher: CCMP_128
0x01, 0x00, 0x00, 0x50, 0xf2, 0x04, // 1 unicast cipher: CCMP_128
0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 AKM: PSK
][..],
&buf[..]
);
}
#[test]
fn write_ht_caps() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: {
ht_cap: &ie::HtCapabilities {
ht_cap_info: ie::HtCapabilityInfo(0x1234),
ampdu_params: ie::AmpduParams(42),
mcs_set: ie::SupportedMcsSet(0x1200_3400_5600_7800_9000_1200_3400_5600),
ht_ext_cap: ie::HtExtCapabilities(0x1234),
txbf_cap: ie::TxBfCapability(0x12345678),
asel_cap: ie::AselCapability(43),
},
}
})
.expect("frame construction failed");
assert_eq!(bytes_written, 28);
assert_eq!(
&[
45, 26, // Element header
0x34, 0x12, // ht_cap_info
42, // ampdu_params
0, 0x56, 0, 0x34, 0, 0x12, 0, 0x90, 0, 0x78, 0, 0x56, 0, 0x34, 0,
0x12, // mcs_set
0x34, 0x12, // ht_ext_cap
0x78, 0x56, 0x34, 0x12, // txbf_cap
43, // asel_cap
][..],
&buf[..]
);
}
#[test]
fn write_vht_caps() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: {
vht_cap: &ie::VhtCapabilities {
vht_cap_info: ie::VhtCapabilitiesInfo(0x1200_3400),
vht_mcs_nss: ie::VhtMcsNssSet(0x1200_3400_5600_7800),
},
}
})
.expect("frame construction failed");
assert_eq!(bytes_written, 14);
assert_eq!(
&[
191, 12, // Element header
0, 0x34, 0, 0x12, // vht_cap_info
0, 0x78, 0, 0x56, 0, 0x34, 0, 0x12, // vht_mcs_nss
][..],
&buf[..]
);
}
#[test]
fn write_dsss_param_set() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: {
dsss_param_set: &ie::DsssParamSet {
current_chan: 42
},
}
})
.expect("frame construction failed");
assert_eq!(bytes_written, 3);
assert_eq!(&[3, 1, 42][..], &buf[..]);
}
#[test]
fn write_bss_max_idle_period() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: {
bss_max_idle_period: &ie::BssMaxIdlePeriod {
max_idle_period: 42,
idle_options: ie::IdleOptions(8),
},
}
})
.expect("frame construction failed");
assert_eq!(bytes_written, 5);
assert_eq!(&[90, 3, 42, 0, 8,][..], &buf[..]);
}
#[test]
fn write_fields() {
// Some expression which can't be statically be determined but always returns true.
let v = vec![5; 5];
let always_true = v.len() < 6;
let mut ht_capabilities = None;
if !always_true {
ht_capabilities = Some(ie::HtCapabilities {
ht_cap_info: ie::HtCapabilityInfo(0x1234),
ampdu_params: ie::AmpduParams(42),
mcs_set: ie::SupportedMcsSet(0x1200_3400_5600_7800_9000_1200_3400_5600),
ht_ext_cap: ie::HtExtCapabilities(0x1234),
txbf_cap: ie::TxBfCapability(0x12345678),
asel_cap: ie::AselCapability(43),
});
}
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
ies: {
ssid: if always_true { &[2u8; 2][..] } else { &[2u8; 33][..] },
supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8, 9],
ht_cap?: ht_capabilities,
vht_cap?: if always_true {
&ie::VhtCapabilities {
vht_cap_info: ie::VhtCapabilitiesInfo(0x1200_3400),
vht_mcs_nss: ie::VhtMcsNssSet(0x1200_3400_5600_7800),
}
},
extended_supported_rates: {},
}
})
.expect("frame construction failed");
assert_eq!(bytes_written, 31);
#[rustfmt::skip]
assert_eq!(
&[
0, 2, 2, 2, // SSID
1, 8, 1, 2, 3, 4, 5, 6, 7, 8, // rates
191, 12, // VHT Element header
0, 0x34, 0, 0x12, // vht_cap_info
0, 0x78, 0, 0x56, 0, 0x34, 0, 0x12, // vht_mcs_nss
50, 1, 9, // extended rates
][..],
&buf[..]
);
}
#[test]
fn write_headers() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
headers: {
// Struct expressions:
MgmtHdr: &MgmtHdr {
frame_ctrl: FrameControl(0x1234),
duration: 42,
addr1: [7; 6],
addr2: [6; 6],
addr3: [5; 6],
seq_ctrl: SequenceControl(0x5678),
},
// Block expression:
DeauthHdr: {
&DeauthHdr { reason_code: ReasonCode::MIC_FAILURE }
},
// Repeat and literal expressions:
MacAddr: &[2u8; 6],
u8: &42u8,
// Function invocation:
MgmtHdr: &make_mgmt_hdr(),
}
})
.expect("frame construction failed");
assert_eq!(bytes_written, 57);
#[rustfmt::skip]
assert_eq!(
&[
// Struct expression: MgmtHdr
0x34, 0x12, 42, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 0x78, 0x56,
// Struct expression: DeauthHdr
14, 0,
// Repeat and literal expressions:
2, 2, 2, 2, 2, 2,
42,
// Function call: MgmtHdr
0x21, 0x43, 42, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 0x65, 0x87,
][..],
&buf[..]
);
}
#[test]
fn write_payload() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
payload: &[9u8; 9],
})
.expect("frame construction failed");
assert_eq!(bytes_written, 9);
assert_eq!(&[9, 9, 9, 9, 9, 9, 9, 9, 9][..], &buf[..]);
}
#[test]
fn write_complex() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) = write_frame!(buffer_provider, {
headers: {
MgmtHdr: &MgmtHdr {
frame_ctrl: FrameControl(0x1234),
duration: 42,
addr1: [7; 6],
addr2: [6; 6],
addr3: [5; 6],
seq_ctrl: SequenceControl(0x5678),
},
DeauthHdr: {
&DeauthHdr { reason_code: ReasonCode::MIC_FAILURE }
},
MacAddr: &[2u8; 6],
u8: &42u8,
MgmtHdr: &make_mgmt_hdr(),
},
ies: {
ssid: &[2u8; 2][..],
supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8, 9],
vht_cap: &ie::VhtCapabilities {
vht_cap_info: ie::VhtCapabilitiesInfo(0x1200_3400),
vht_mcs_nss: ie::VhtMcsNssSet(0x1200_3400_5600_7800),
},
extended_supported_rates: {},
},
payload: vec![42u8; 5]
})
.expect("frame construction failed");
assert_eq!(bytes_written, 93);
#[rustfmt::skip]
assert_eq!(
&[
// Headers:
0x34, 0x12, 42, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 0x78, 0x56,
14, 0,
2, 2, 2, 2, 2, 2,
42,
0x21, 0x43, 42, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 0x65, 0x87,
// Fields:
0, 2, 2, 2, // SSID
1, 8, 1, 2, 3, 4, 5, 6, 7, 8, // rates
191, 12, // VHT Element header
0, 0x34, 0, 0x12, // vht_cap_info
0, 0x78, 0, 0x56, 0, 0x34, 0, 0x12, // vht_mcs_nss
50, 1, 9, // extended rates
// Payload:
42, 42, 42, 42, 42,
][..],
&buf[..]
);
}
#[test]
fn write_nothing() {
let buffer_provider = BufferProvider;
let (buf, bytes_written) =
write_frame!(buffer_provider, {}).expect("frame construction failed");
assert_eq!(bytes_written, 0);
assert_eq!(buf.len(), bytes_written);
}
}