use crate::ap::TimedEvent;
use crate::device::DeviceOps;
use crate::disconnect::LocallyInitiated;
use crate::error::Error;
use anyhow::format_err;
use fdf::ArenaStaticBox;
use ieee80211::{Bssid, MacAddr, MacAddrBytes, Ssid};
use wlan_common::big_endian::BigEndianU16;
use wlan_common::ie::rsn::rsne;
use wlan_common::ie::{self};
use wlan_common::mac::{self, Aid, AuthAlgorithmNumber, StatusCode};
use wlan_common::sequence::SequenceManager;
use wlan_common::timer::{EventId, Timer};
use wlan_common::{data_writer, mgmt_writer, wmm, TimeUnit};
use wlan_frame_writer::{write_frame, write_frame_with_fixed_slice};
use {fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211, fidl_fuchsia_wlan_mlme as fidl_mlme};
pub struct BeaconOffloadParams {
pub tim_ele_offset: usize,
}
pub struct Context<D> {
pub device: D,
pub timer: Timer<TimedEvent>,
pub seq_mgr: SequenceManager,
pub bssid: Bssid,
}
impl<D> Context<D> {
pub fn new(device: D, timer: Timer<TimedEvent>, bssid: Bssid) -> Self {
Self { device, timer, seq_mgr: SequenceManager::new(), bssid }
}
pub fn schedule_after(
&mut self,
duration: zx::MonotonicDuration,
event: TimedEvent,
) -> EventId {
self.timer.schedule_after(duration, event)
}
pub fn make_auth_frame(
&mut self,
addr: MacAddr,
auth_alg_num: AuthAlgorithmNumber,
auth_txn_seq_num: u16,
status_code: StatusCode,
) -> Result<ArenaStaticBox<[u8]>, Error> {
Ok(write_frame!({
headers: {
mac::MgmtHdr: &mgmt_writer::mgmt_hdr_from_ap(
mac::FrameControl(0)
.with_frame_type(mac::FrameType::MGMT)
.with_mgmt_subtype(mac::MgmtSubtype::AUTH),
addr,
self.bssid,
mac::SequenceControl(0).with_seq_num(self.seq_mgr.next_sns1(&addr) as u16)
),
mac::AuthHdr: &mac::AuthHdr { auth_alg_num, auth_txn_seq_num, status_code },
}
})?)
}
pub fn make_assoc_resp_frame(
&mut self,
addr: MacAddr,
capabilities: mac::CapabilityInfo,
aid: Aid,
rates: &[u8],
max_idle_period: Option<u16>,
) -> Result<ArenaStaticBox<[u8]>, Error> {
Ok(write_frame!({
headers: {
mac::MgmtHdr: &mgmt_writer::mgmt_hdr_from_ap(
mac::FrameControl(0)
.with_frame_type(mac::FrameType::MGMT)
.with_mgmt_subtype(mac::MgmtSubtype::ASSOC_RESP),
addr,
self.bssid,
mac::SequenceControl(0).with_seq_num(self.seq_mgr.next_sns1(&addr) as u16)
),
mac::AssocRespHdr: &mac::AssocRespHdr {
capabilities,
status_code: fidl_ieee80211::StatusCode::Success.into(),
aid
},
},
ies: {
supported_rates: &rates,
extended_supported_rates: {},
bss_max_idle_period?: if let Some(max_idle_period) = max_idle_period {
ie::BssMaxIdlePeriod {
max_idle_period,
idle_options: ie::IdleOptions(0)
.with_protected_keep_alive_required(false),
}
},
}
})?)
}
pub fn make_assoc_resp_frame_error(
&mut self,
addr: MacAddr,
capabilities: mac::CapabilityInfo,
status_code: StatusCode,
) -> Result<ArenaStaticBox<[u8]>, Error> {
Ok(write_frame!({
headers: {
mac::MgmtHdr: &mgmt_writer::mgmt_hdr_from_ap(
mac::FrameControl(0)
.with_frame_type(mac::FrameType::MGMT)
.with_mgmt_subtype(mac::MgmtSubtype::ASSOC_RESP),
addr,
self.bssid,
mac::SequenceControl(0).with_seq_num(self.seq_mgr.next_sns1(&addr) as u16)
),
mac::AssocRespHdr: &mac::AssocRespHdr {
capabilities,
status_code,
aid: 0,
},
},
})?)
}
pub fn make_deauth_frame(
&mut self,
addr: MacAddr,
reason_code: mac::ReasonCode,
) -> Result<ArenaStaticBox<[u8]>, Error> {
Ok(write_frame!({
headers: {
mac::MgmtHdr: &mgmt_writer::mgmt_hdr_from_ap(
mac::FrameControl(0)
.with_frame_type(mac::FrameType::MGMT)
.with_mgmt_subtype(mac::MgmtSubtype::DEAUTH),
addr,
self.bssid,
mac::SequenceControl(0).with_seq_num(self.seq_mgr.next_sns1(&addr) as u16)
),
mac::DeauthHdr: &mac::DeauthHdr { reason_code },
},
})?)
}
pub fn make_disassoc_frame(
&mut self,
addr: MacAddr,
reason_code: mac::ReasonCode,
) -> Result<ArenaStaticBox<[u8]>, Error> {
Ok(write_frame!({
headers: {
mac::MgmtHdr: &mgmt_writer::mgmt_hdr_from_ap(
mac::FrameControl(0)
.with_frame_type(mac::FrameType::MGMT)
.with_mgmt_subtype(mac::MgmtSubtype::DISASSOC),
addr,
self.bssid,
mac::SequenceControl(0).with_seq_num(self.seq_mgr.next_sns1(&addr) as u16)
),
mac::DisassocHdr: &mac::DisassocHdr { reason_code },
},
})?)
}
pub fn make_probe_resp_frame(
&mut self,
addr: MacAddr,
beacon_interval: TimeUnit,
capabilities: mac::CapabilityInfo,
ssid: &Ssid,
rates: &[u8],
channel: u8,
rsne: &[u8],
) -> Result<ArenaStaticBox<[u8]>, Error> {
let rsne = (!rsne.is_empty())
.then(|| match rsne::from_bytes(rsne) {
Ok((_, x)) => Ok(x),
Err(e) => Err(format_err!("error parsing rsne {:?} : {:?}", rsne, e)),
})
.transpose()?;
Ok(write_frame!({
headers: {
mac::MgmtHdr: &mgmt_writer::mgmt_hdr_from_ap(
mac::FrameControl(0)
.with_frame_type(mac::FrameType::MGMT)
.with_mgmt_subtype(mac::MgmtSubtype::PROBE_RESP),
addr,
self.bssid,
mac::SequenceControl(0).with_seq_num(self.seq_mgr.next_sns1(&addr) as u16)
),
mac::ProbeRespHdr: &mac::ProbeRespHdr::new(beacon_interval, capabilities),
},
ies: {
ssid: ssid,
supported_rates: rates,
dsss_param_set: &ie::DsssParamSet { current_channel: channel },
extended_supported_rates: {},
rsne?: rsne,
}
})?)
}
pub fn make_beacon_frame(
&self,
beacon_interval: TimeUnit,
capabilities: mac::CapabilityInfo,
ssid: &Ssid,
rates: &[u8],
channel: u8,
tim_header: ie::TimHeader,
tim_bitmap: &[u8],
rsne: &[u8],
) -> Result<(ArenaStaticBox<[u8]>, BeaconOffloadParams), Error> {
let mut tim_ele_offset = 0;
let rsne = (!rsne.is_empty())
.then(|| match rsne::from_bytes(rsne) {
Ok((_, x)) => Ok(x),
Err(e) => Err(format_err!("error parsing rsne {:?} : {:?}", rsne, e)),
})
.transpose()?;
let buffer = write_frame!({
headers: {
mac::MgmtHdr: &mgmt_writer::mgmt_hdr_from_ap(
mac::FrameControl(0)
.with_frame_type(mac::FrameType::MGMT)
.with_mgmt_subtype(mac::MgmtSubtype::BEACON),
ieee80211::BROADCAST_ADDR,
self.bssid,
mac::SequenceControl(0)
),
mac::BeaconHdr: &mac::BeaconHdr::new(beacon_interval, capabilities),
},
ies: {
ssid: ssid,
supported_rates: rates,
dsss_param_set: &ie::DsssParamSet { current_channel: channel },
tim_ele_offset @ tim: ie::TimView {
header: tim_header,
bitmap: tim_bitmap,
},
extended_supported_rates: {},
rsne?: rsne,
}
})?;
Ok((buffer, BeaconOffloadParams { tim_ele_offset }))
}
pub fn make_data_frame(
&mut self,
dst: MacAddr,
src: MacAddr,
protected: bool,
qos_ctrl: bool,
ether_type: u16,
payload: &[u8],
) -> Result<ArenaStaticBox<[u8]>, Error> {
let qos_ctrl = if qos_ctrl {
Some(
wmm::derive_tid(ether_type, payload)
.map_or(mac::QosControl(0), |tid| mac::QosControl(0).with_tid(tid as u16)),
)
} else {
None
};
Ok(write_frame!({
headers: {
mac::FixedDataHdrFields: &mac::FixedDataHdrFields {
frame_ctrl: mac::FrameControl(0)
.with_frame_type(mac::FrameType::DATA)
.with_data_subtype(mac::DataSubtype(0).with_qos(qos_ctrl.is_some()))
.with_protected(protected)
.with_from_ds(true),
duration: 0,
addr1: dst,
addr2: self.bssid.into(),
addr3: src,
seq_ctrl: mac::SequenceControl(0).with_seq_num(
match qos_ctrl.as_ref() {
None => self.seq_mgr.next_sns1(&dst),
Some(qos_ctrl) => self.seq_mgr.next_sns2(&dst, qos_ctrl.tid()),
} as u16
),
},
mac::QosControl?: qos_ctrl,
mac::LlcHdr: &data_writer::make_snap_llc_hdr(ether_type),
},
payload: payload,
})?)
}
pub fn make_eapol_frame(
&mut self,
dst_addr: MacAddr,
src_addr: MacAddr,
is_protected: bool,
eapol_frame: &[u8],
) -> Result<ArenaStaticBox<[u8]>, Error> {
self.make_data_frame(
dst_addr,
src_addr,
is_protected,
false, mac::ETHER_TYPE_EAPOL,
eapol_frame,
)
}
}
impl<D: DeviceOps> Context<D> {
pub fn send_mlme_start_conf(
&mut self,
result_code: fidl_mlme::StartResultCode,
) -> Result<(), Error> {
self.device
.send_mlme_event(fidl_mlme::MlmeEvent::StartConf {
resp: fidl_mlme::StartConfirm { result_code },
})
.map_err(|e| e.into())
}
pub fn send_mlme_stop_conf(
&mut self,
result_code: fidl_mlme::StopResultCode,
) -> Result<(), Error> {
self.device
.send_mlme_event(fidl_mlme::MlmeEvent::StopConf {
resp: fidl_mlme::StopConfirm { result_code },
})
.map_err(|e| e.into())
}
pub fn send_mlme_eapol_conf(
&mut self,
result_code: fidl_mlme::EapolResultCode,
dst_addr: MacAddr,
) -> Result<(), Error> {
self.device
.send_mlme_event(fidl_mlme::MlmeEvent::EapolConf {
resp: fidl_mlme::EapolConfirm { result_code, dst_addr: dst_addr.to_array() },
})
.map_err(|e| e.into())
}
pub fn send_mlme_auth_ind(
&mut self,
peer_sta_address: MacAddr,
auth_type: fidl_mlme::AuthenticationTypes,
) -> Result<(), Error> {
self.device
.send_mlme_event(fidl_mlme::MlmeEvent::AuthenticateInd {
ind: fidl_mlme::AuthenticateIndication {
peer_sta_address: peer_sta_address.to_array(),
auth_type,
},
})
.map_err(|e| e.into())
}
pub fn send_mlme_deauth_ind(
&mut self,
peer_sta_address: MacAddr,
reason_code: fidl_ieee80211::ReasonCode,
locally_initiated: LocallyInitiated,
) -> Result<(), Error> {
self.device
.send_mlme_event(fidl_mlme::MlmeEvent::DeauthenticateInd {
ind: fidl_mlme::DeauthenticateIndication {
peer_sta_address: peer_sta_address.to_array(),
reason_code,
locally_initiated: locally_initiated.0,
},
})
.map_err(|e| e.into())
}
pub fn send_mlme_assoc_ind(
&mut self,
peer_sta_address: MacAddr,
listen_interval: u16,
ssid: Option<Ssid>,
capabilities: mac::CapabilityInfo,
rates: Vec<ie::SupportedRate>,
rsne: Option<Vec<u8>>,
) -> Result<(), Error> {
self.device
.send_mlme_event(fidl_mlme::MlmeEvent::AssociateInd {
ind: fidl_mlme::AssociateIndication {
peer_sta_address: peer_sta_address.to_array(),
listen_interval,
ssid: ssid.map(|s| s.into()),
capability_info: capabilities.raw(),
rates: rates.iter().map(|r| r.0).collect(),
rsne,
},
})
.map_err(|e| e.into())
}
pub fn send_mlme_disassoc_ind(
&mut self,
peer_sta_address: MacAddr,
reason_code: fidl_ieee80211::ReasonCode,
locally_initiated: LocallyInitiated,
) -> Result<(), Error> {
self.device
.send_mlme_event(fidl_mlme::MlmeEvent::DisassociateInd {
ind: fidl_mlme::DisassociateIndication {
peer_sta_address: peer_sta_address.to_array(),
reason_code,
locally_initiated: locally_initiated.0,
},
})
.map_err(|e| e.into())
}
pub fn send_mlme_eapol_ind(
&mut self,
dst_addr: MacAddr,
src_addr: MacAddr,
data: &[u8],
) -> Result<(), Error> {
self.device
.send_mlme_event(fidl_mlme::MlmeEvent::EapolInd {
ind: fidl_mlme::EapolIndication {
dst_addr: dst_addr.to_array(),
src_addr: src_addr.to_array(),
data: data.to_vec(),
},
})
.map_err(|e| e.into())
}
pub fn deliver_eth_frame(
&mut self,
dst_addr: MacAddr,
src_addr: MacAddr,
protocol_id: u16,
body: &[u8],
) -> Result<(), Error> {
let mut packet = [0u8; mac::MAX_ETH_FRAME_LEN];
let (frame_start, frame_end) = write_frame_with_fixed_slice!(&mut packet[..], {
headers: {
mac::EthernetIIHdr: &mac::EthernetIIHdr {
da: dst_addr,
sa: src_addr,
ether_type: BigEndianU16::from_native(protocol_id),
},
},
payload: body,
})?;
self.device
.deliver_eth_frame(&packet[frame_start..frame_end])
.map_err(|s| Error::Status(format!("could not deliver Ethernet II frame"), s))
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::ap::ClientEvent;
use crate::device::FakeDevice;
use lazy_static::lazy_static;
use wlan_common::assert_variant;
use wlan_common::timer::{self, create_timer};
lazy_static! {
static ref CLIENT_ADDR: MacAddr = [1u8; 6].into();
static ref BSSID: Bssid = [2u8; 6].into();
static ref CLIENT_ADDR2: MacAddr = [3u8; 6].into();
}
fn make_context(
fake_device: FakeDevice,
) -> (Context<FakeDevice>, timer::EventStream<TimedEvent>) {
let (timer, time_stream) = create_timer();
(Context::new(fake_device, timer, *BSSID), time_stream)
}
#[fuchsia::test(allow_stalls = false)]
async fn send_mlme_auth_ind() {
let (fake_device, fake_device_state) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
ctx.send_mlme_auth_ind(*CLIENT_ADDR, fidl_mlme::AuthenticationTypes::OpenSystem)
.expect("expected OK");
let msg = fake_device_state
.lock()
.next_mlme_msg::<fidl_mlme::AuthenticateIndication>()
.expect("expected MLME message");
assert_eq!(
msg,
fidl_mlme::AuthenticateIndication {
peer_sta_address: CLIENT_ADDR.to_array(),
auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
},
);
}
#[fuchsia::test(allow_stalls = false)]
async fn send_mlme_deauth_ind() {
let (fake_device, fake_device_state) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
ctx.send_mlme_deauth_ind(
*CLIENT_ADDR,
fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
LocallyInitiated(true),
)
.expect("expected OK");
let msg = fake_device_state
.lock()
.next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
.expect("expected MLME message");
assert_eq!(
msg,
fidl_mlme::DeauthenticateIndication {
peer_sta_address: CLIENT_ADDR.to_array(),
reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
locally_initiated: true,
},
);
}
#[fuchsia::test(allow_stalls = false)]
async fn send_mlme_assoc_ind() {
let (fake_device, fake_device_state) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
ctx.send_mlme_assoc_ind(
*CLIENT_ADDR,
1,
Some(Ssid::try_from("coolnet").unwrap()),
mac::CapabilityInfo(0),
vec![ie::SupportedRate(1), ie::SupportedRate(2), ie::SupportedRate(3)],
None,
)
.expect("expected OK");
let msg = fake_device_state
.lock()
.next_mlme_msg::<fidl_mlme::AssociateIndication>()
.expect("expected MLME message");
assert_eq!(
msg,
fidl_mlme::AssociateIndication {
peer_sta_address: CLIENT_ADDR.to_array(),
listen_interval: 1,
ssid: Some(Ssid::try_from("coolnet").unwrap().into()),
capability_info: mac::CapabilityInfo(0).raw(),
rates: vec![1, 2, 3],
rsne: None,
},
);
}
#[fuchsia::test(allow_stalls = false)]
async fn send_mlme_disassoc_ind() {
let (fake_device, fake_device_state) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
ctx.send_mlme_disassoc_ind(
*CLIENT_ADDR,
fidl_ieee80211::ReasonCode::LeavingNetworkDisassoc,
LocallyInitiated(true),
)
.expect("expected OK");
let msg = fake_device_state
.lock()
.next_mlme_msg::<fidl_mlme::DisassociateIndication>()
.expect("expected MLME message");
assert_eq!(
msg,
fidl_mlme::DisassociateIndication {
peer_sta_address: CLIENT_ADDR.to_array(),
reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDisassoc,
locally_initiated: true,
},
);
}
#[fuchsia::test(allow_stalls = false)]
async fn send_mlme_eapol_ind() {
let (fake_device, fake_device_state) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
ctx.send_mlme_eapol_ind(*CLIENT_ADDR2, *CLIENT_ADDR, &[1, 2, 3, 4, 5][..])
.expect("expected OK");
let msg = fake_device_state
.lock()
.next_mlme_msg::<fidl_mlme::EapolIndication>()
.expect("expected MLME message");
assert_eq!(
msg,
fidl_mlme::EapolIndication {
dst_addr: CLIENT_ADDR2.to_array(),
src_addr: CLIENT_ADDR.to_array(),
data: vec![1, 2, 3, 4, 5],
},
);
}
#[fuchsia::test(allow_stalls = false)]
async fn schedule_after() {
let (fake_device, _) = FakeDevice::new().await;
let (mut ctx, mut time_stream) = make_context(fake_device);
let event_id = ctx.schedule_after(
zx::MonotonicDuration::from_seconds(5),
TimedEvent::ClientEvent(MacAddr::from([1; 6]), ClientEvent::BssIdleTimeout),
);
let (_, timed_event) =
time_stream.try_next().unwrap().expect("Should have scheduled an event");
assert_eq!(timed_event.id, event_id);
assert_variant!(
timed_event.event,
TimedEvent::ClientEvent(mac_addr, ClientEvent::BssIdleTimeout) => {
assert_eq!(MacAddr::from([1; 6]), mac_addr);
}
);
assert!(time_stream.try_next().is_err());
}
#[fuchsia::test(allow_stalls = false)]
async fn make_auth_frame() {
let (fake_device, _) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
let buffer = ctx
.make_auth_frame(
*CLIENT_ADDR,
AuthAlgorithmNumber::FAST_BSS_TRANSITION,
3,
fidl_ieee80211::StatusCode::TransactionSequenceError.into(),
)
.expect("error making auth frame");
assert_eq!(
&buffer[..],
&[
0b10110000, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0, 2, 0, 3, 0, 14, 0, ][..]
);
}
#[fuchsia::test(allow_stalls = false)]
async fn make_assoc_resp_frame() {
let (fake_device, _) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
let buffer = ctx
.make_assoc_resp_frame(
*CLIENT_ADDR,
mac::CapabilityInfo(0),
1,
&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
Some(99),
)
.expect("error making assoc resp frame");
assert_eq!(
&buffer[..],
&[
0b00010000, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0, 0, 0, 0, 0, 1, 0, 1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 50, 2, 9, 10, 90, 3, 99, 0, 0, ][..]
);
}
#[fuchsia::test(allow_stalls = false)]
async fn make_assoc_resp_frame_error() {
let (fake_device, _) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
let buffer = ctx
.make_assoc_resp_frame_error(
*CLIENT_ADDR,
mac::CapabilityInfo(0),
fidl_ieee80211::StatusCode::RejectedEmergencyServicesNotSupported.into(),
)
.expect("error making assoc resp frame error");
assert_eq!(
&buffer[..],
&[
0b00010000, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0, 0, 0, 94, 0, 0, 0, ][..]
);
}
#[fuchsia::test(allow_stalls = false)]
async fn make_assoc_resp_frame_no_bss_max_idle_period() {
let (fake_device, _) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
let buffer = ctx
.make_assoc_resp_frame(
*CLIENT_ADDR,
mac::CapabilityInfo(0),
1,
&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
None,
)
.expect("error making assoc resp frame");
assert_eq!(
&buffer[..],
&[
0b00010000, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0, 0, 0, 0, 0, 1, 0, 1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 50, 2, 9, 10, ][..]
);
}
#[fuchsia::test(allow_stalls = false)]
async fn make_disassoc_frame() {
let (fake_device, _) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
let buffer = ctx
.make_disassoc_frame(
*CLIENT_ADDR,
fidl_ieee80211::ReasonCode::LeavingNetworkDisassoc.into(),
)
.expect("error making disassoc frame");
assert_eq!(
&buffer[..],
&[
0b10100000, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0, 8, 0, ][..]
);
}
#[fuchsia::test(allow_stalls = false)]
async fn make_probe_resp_frame() {
let (fake_device, _) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
let buffer = ctx
.make_probe_resp_frame(
*CLIENT_ADDR,
TimeUnit(10),
mac::CapabilityInfo(33),
&Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
2,
&[48, 2, 77, 88][..],
)
.expect("error making probe resp frame");
assert_eq!(
&buffer[..],
&[
0b01010000, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 33, 0, 0, 5, 1, 2, 3, 4, 5, 1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 3, 1, 2, 50, 2, 9, 10, 48, 2, 77, 88, ][..]
);
}
#[fuchsia::test(allow_stalls = false)]
async fn make_beacon_frame() {
let (fake_device, _) = FakeDevice::new().await;
let (ctx, _) = make_context(fake_device);
let (buffer, params) = ctx
.make_beacon_frame(
TimeUnit(10),
mac::CapabilityInfo(33),
&Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
2,
ie::TimHeader { dtim_count: 1, dtim_period: 2, bmp_ctrl: ie::BitmapControl(0) },
&[1, 2, 3][..],
&[48, 2, 77, 88][..],
)
.expect("error making probe resp frame");
assert_eq!(
&buffer[..],
&[
0b10000000, 0, 0, 0, 255, 255, 255, 255, 255, 255, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 33, 0, 0, 5, 1, 2, 3, 4, 5, 1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 3, 1, 2, 5, 6, 1, 2, 0, 1, 2, 3, 50, 2, 9, 10, 48, 2, 77, 88, ][..]
);
assert_eq!(params.tim_ele_offset, 56);
}
#[fuchsia::test(allow_stalls = false)]
async fn make_data_frame() {
let (fake_device, _) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
let buffer = ctx
.make_data_frame(*CLIENT_ADDR2, *CLIENT_ADDR, false, false, 0x1234, &[1, 2, 3, 4, 5])
.expect("error making data frame");
assert_eq!(
&buffer[..],
&[
0b00001000, 0b00000010, 0, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0x10, 0, 0xAA, 0xAA, 0x03, 0, 0, 0, 0x12, 0x34, 1, 2, 3, 4, 5,
][..]
);
}
#[fuchsia::test(allow_stalls = false)]
async fn make_data_frame_ipv4_qos() {
let (fake_device, _) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
let buffer = ctx
.make_data_frame(
*CLIENT_ADDR2,
*CLIENT_ADDR,
false,
true,
0x0800, &[1, 0xB0, 3, 4, 5], )
.expect("error making data frame");
assert_eq!(
&buffer[..],
&[
0b10001000, 0b00000010, 0, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0x10, 0, 0x06, 0, 0xAA, 0xAA, 0x03, 0, 0, 0, 0x08, 0x00, 1, 0xB0, 3, 4, 5,
][..]
);
}
#[fuchsia::test(allow_stalls = false)]
async fn make_data_frame_ipv6_qos() {
let (fake_device, _) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
let buffer = ctx
.make_data_frame(
*CLIENT_ADDR2,
*CLIENT_ADDR,
false,
true,
0x86DD, &[0b0101, 0b10000000, 3, 4, 5], )
.expect("error making data frame");
assert_eq!(
&buffer[..],
&[
0b10001000, 0b00000010, 0, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0x10, 0, 0x03, 0, 0xAA, 0xAA, 0x03, 0, 0, 0, 0x86, 0xDD, 0b0101, 0b10000000, 3, 4, 5,
][..]
);
}
#[fuchsia::test(allow_stalls = false)]
async fn make_eapol_frame() {
let (fake_device, _) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
let buffer = ctx
.make_eapol_frame(*CLIENT_ADDR2, *CLIENT_ADDR, false, &[1, 2, 3, 4, 5])
.expect("error making eapol frame");
assert_eq!(
&buffer[..],
&[
0b00001000, 0b00000010, 0, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0x10, 0, 0xAA, 0xAA, 0x03, 0, 0, 0, 0x88, 0x8E, 1, 2, 3, 4, 5,
][..]
);
}
#[fuchsia::test(allow_stalls = false)]
async fn deliver_eth_frame() {
let (fake_device, fake_device_state) = FakeDevice::new().await;
let (mut ctx, _) = make_context(fake_device);
ctx.deliver_eth_frame(*CLIENT_ADDR2, *CLIENT_ADDR, 0x1234, &[1, 2, 3, 4, 5][..])
.expect("expected OK");
assert_eq!(fake_device_state.lock().eth_queue.len(), 1);
#[rustfmt::skip]
assert_eq!(&fake_device_state.lock().eth_queue[0][..], &[
3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 0x12, 0x34, 1, 2, 3, 4, 5,
][..]);
}
}