use crate::mac::{FrameControl, HtControl, MacAddr, OptionalField, Presence, SequenceControl};
use wlan_bitfield::bitfield;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
#[bitfield(
0..=3 tid,
4 eosp,
5..=6 ack_policy,
7 amsdu_present,
8..=15 high_byte, )]
#[repr(C)]
#[derive(IntoBytes, KnownLayout, FromBytes, Immutable, Copy, Clone, PartialEq, Eq)]
pub struct QosControl(pub u16);
pub type Addr4 = MacAddr;
#[derive(
KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq, Eq, Clone, Copy, Debug,
)]
#[repr(C, packed)]
pub struct FixedDataHdrFields {
pub frame_ctrl: FrameControl,
pub duration: u16,
pub addr1: MacAddr,
pub addr2: MacAddr,
pub addr3: MacAddr,
pub seq_ctrl: SequenceControl,
}
impl FixedDataHdrFields {
pub fn len(
has_addr4: Presence<Addr4>,
has_qos_ctrl: Presence<QosControl>,
has_ht_ctrl: Presence<HtControl>,
) -> usize {
let mut bytes = std::mem::size_of::<Self>();
bytes += match has_addr4 {
Addr4::PRESENT => std::mem::size_of::<MacAddr>(),
Addr4::ABSENT => 0,
};
bytes += match has_qos_ctrl {
QosControl::PRESENT => std::mem::size_of::<QosControl>(),
QosControl::ABSENT => 0,
};
bytes += match has_ht_ctrl {
HtControl::PRESENT => std::mem::size_of::<HtControl>(),
HtControl::ABSENT => 0,
};
bytes
}
}
pub struct OptionalDataHdrFields {
pub addr4: Option<Addr4>,
pub qos_ctrl: Option<QosControl>,
pub ht_ctrl: Option<HtControl>,
}
impl OptionalDataHdrFields {
pub fn none() -> Self {
Self { addr4: None, qos_ctrl: None, ht_ctrl: None }
}
}
pub fn data_dst_addr(hdr: &FixedDataHdrFields) -> MacAddr {
let fc = hdr.frame_ctrl;
if fc.to_ds() {
hdr.addr3
} else {
hdr.addr1
}
}
pub fn data_src_addr(hdr: &FixedDataHdrFields, addr4: Option<MacAddr>) -> Option<MacAddr> {
let fc = hdr.frame_ctrl;
match (fc.to_ds(), fc.from_ds()) {
(_, false) => Some(hdr.addr2),
(false, true) => Some(hdr.addr3),
(true, true) => addr4,
}
}
pub fn data_transmitter_addr(hdr: &FixedDataHdrFields) -> MacAddr {
hdr.addr2
}
pub fn data_receiver_addr(hdr: &FixedDataHdrFields) -> MacAddr {
hdr.addr1
}
pub fn data_bssid(hdr: &FixedDataHdrFields) -> Option<MacAddr> {
let fc = hdr.frame_ctrl;
match (fc.to_ds(), fc.from_ds()) {
(false, false) => Some(hdr.addr3),
(false, true) => Some(hdr.addr2),
(true, false) => Some(hdr.addr1),
(true, true) => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mac::*;
use crate::test_utils::fake_frames::*;
#[test]
fn fixed_fields_len() {
assert_eq!(
FixedDataHdrFields::len(Addr4::ABSENT, QosControl::ABSENT, HtControl::ABSENT),
24
);
assert_eq!(
FixedDataHdrFields::len(Addr4::PRESENT, QosControl::ABSENT, HtControl::ABSENT),
30
);
assert_eq!(
FixedDataHdrFields::len(Addr4::ABSENT, QosControl::PRESENT, HtControl::ABSENT),
26
);
assert_eq!(
FixedDataHdrFields::len(Addr4::ABSENT, QosControl::ABSENT, HtControl::PRESENT),
28
);
assert_eq!(
FixedDataHdrFields::len(Addr4::PRESENT, QosControl::PRESENT, HtControl::ABSENT),
32
);
assert_eq!(
FixedDataHdrFields::len(Addr4::ABSENT, QosControl::PRESENT, HtControl::PRESENT),
30
);
assert_eq!(
FixedDataHdrFields::len(Addr4::PRESENT, QosControl::ABSENT, HtControl::PRESENT),
34
);
assert_eq!(
FixedDataHdrFields::len(Addr4::PRESENT, QosControl::PRESENT, HtControl::PRESENT),
36
);
}
#[test]
fn fixed_fields_dst_addr() {
let mut fixed_fields = make_data_hdr(None, [0, 0], None);
let (mut fixed_fields, _) =
Ref::<_, FixedDataHdrFields>::from_prefix(&mut fixed_fields[..])
.expect("invalid data header");
let mut fc = FrameControl(0);
fc.set_to_ds(true);
fixed_fields.frame_ctrl = fc;
assert_eq!(data_dst_addr(&fixed_fields), MacAddr::from([5; 6])); fc.set_to_ds(false);
fixed_fields.frame_ctrl = fc;
assert_eq!(data_dst_addr(&fixed_fields), MacAddr::from([3; 6])); }
#[test]
fn fixed_fields_src_addr() {
let mut fixed_fields = make_data_hdr(None, [0, 0], None);
let (mut fixed_fields, _) =
Ref::<_, FixedDataHdrFields>::from_prefix(&mut fixed_fields[..])
.expect("invalid data header");
let mut fc = FrameControl(0);
fixed_fields.frame_ctrl = fc;
assert_eq!(data_src_addr(&fixed_fields, None), Some(MacAddr::from([4; 6]))); fc.set_to_ds(true);
fixed_fields.frame_ctrl = fc;
assert_eq!(data_src_addr(&fixed_fields, None), Some(MacAddr::from([4; 6]))); fc.set_from_ds(true);
fixed_fields.frame_ctrl = fc;
assert_eq!(
data_src_addr(&fixed_fields, Some(MacAddr::from([11; 6]))),
Some(MacAddr::from([11; 6])) );
fc.set_to_ds(false);
fixed_fields.frame_ctrl = fc;
assert_eq!(
data_src_addr(&fixed_fields, None),
Some(MacAddr::from([5; 6])) );
}
#[test]
fn fixed_fields_ta() {
let mut fixed_fields = make_data_hdr(None, [0, 0], None);
let (fixed_fields, _) = Ref::<_, FixedDataHdrFields>::from_prefix(&mut fixed_fields[..])
.expect("invalid data header");
assert_eq!(
data_transmitter_addr(&fixed_fields),
MacAddr::from([4; 6]) );
}
#[test]
fn fixed_fields_ra() {
let mut fixed_fields = make_data_hdr(None, [0, 0], None);
let (fixed_fields, _) = Ref::<_, FixedDataHdrFields>::from_prefix(&mut fixed_fields[..])
.expect("invalid data header");
assert_eq!(data_receiver_addr(&fixed_fields), MacAddr::from([3; 6])); }
#[test]
fn fixed_fields_bssid() {
let mut fixed_fields = make_data_hdr(None, [0, 0], None);
let (mut fixed_fields, _) =
Ref::<_, FixedDataHdrFields>::from_prefix(&mut fixed_fields[..])
.expect("invalid data header");
let mut fc = FrameControl(0);
fixed_fields.frame_ctrl = fc;
assert_eq!(data_bssid(&fixed_fields), Some(MacAddr::from([5; 6]))); fc.set_to_ds(true);
fixed_fields.frame_ctrl = fc;
assert_eq!(data_bssid(&fixed_fields), Some(MacAddr::from([3; 6]))); fc.set_from_ds(true);
fixed_fields.frame_ctrl = fc;
assert_eq!(data_bssid(&fixed_fields), None);
fc.set_to_ds(false);
fixed_fields.frame_ctrl = fc;
assert_eq!(data_bssid(&fixed_fields), Some(MacAddr::from([4; 6]))); }
}