mod builder;
pub use self::builder::*;
use super::*;
use byteorder::{ByteOrder, LittleEndian};
use std::borrow::Cow;
pub enum FrameLayer<'a> {
Management(ManagementFrame<'a>),
Control(ControlFrame<'a>),
Data(DataFrame<'a>),
}
pub struct Frame<'a> {
bytes: Cow<'a, [u8]>,
}
impl<'a> Frame<'a> {
pub fn new<T: Into<Cow<'a, [u8]>>>(bytes: T) -> Self {
Self {
bytes: bytes.into(),
}
}
pub fn next_layer(&self) -> Option<FrameLayer<'_>> {
match self.type_() {
FrameType::Management => {
Some(FrameLayer::Management(ManagementFrame::new(self.bytes())))
}
FrameType::Control => {
Some(FrameLayer::Control(ControlFrame::new(self.bytes())))
},
FrameType::Data => {
Some(FrameLayer::Data(DataFrame::new(self.bytes())))
},
_ => None,
}
}
}
impl FrameTrait for Frame<'_> {
fn bytes(&self) -> &[u8] {
self.bytes.as_ref()
}
}
pub trait FrameTrait {
fn bytes(&self) -> &[u8];
fn version(&self) -> FrameVersion {
FrameVersion::from_u8(self.bytes()[0] & 0b0000_0011)
}
fn type_(&self) -> FrameType {
FrameType::from_u8((self.bytes()[0] & 0b0000_1100) >> 2)
}
fn subtype(&self) -> FrameSubtype {
let subtype = (self.bytes()[0] & 0b1111_0000) >> 4;
FrameSubtype::from_u8(self.type_(), subtype)
}
fn to_ds(&self) -> bool {
self.bytes()[1] & 0b0000_0001 != 0
}
#[allow(clippy::wrong_self_convention)]
fn from_ds(&self) -> bool {
self.bytes()[1] & 0b0000_0010 != 0
}
fn ds_status(&self) -> DSStatus {
DSStatus::from_bools(self.from_ds(), self.to_ds())
}
fn more_fragments(&self) -> bool {
(self.bytes()[1] & 0b0000_0100) != 0
}
fn retry(&self) -> bool {
(self.bytes()[1] & 0b0000_1000) != 0
}
fn pwr_mgt(&self) -> bool {
(self.bytes()[1] & 0b0001_0000) != 0
}
fn more_data(&self) -> bool {
(self.bytes()[1] & 0b0010_0000) != 0
}
fn protected(&self) -> bool {
(self.bytes()[1] & 0b0100_0000) != 0
}
fn order(&self) -> bool {
(self.bytes()[1] & 0b1000_0000) != 0
}
fn duration_or_id(&self) -> DurationID {
if (self.bytes()[3] & 0b1000_0000) == 0 {
let n = LittleEndian::read_u16(&self.bytes()[2..4]) & 0b0111_1111_1111_1111;
DurationID::Duration(n)
} else {
let n = LittleEndian::read_u16(&self.bytes()[2..4]) & 0b0011_1111_1111_1111;
if n < 1 || n > 2007 {
DurationID::Reserved(n)
} else {
DurationID::AssociationID(n)
}
}
}
fn addr1(&self) -> MacAddress {
MacAddress::from_bytes(&self.bytes()[4..10]).unwrap()
}
fn receiver_address(&self) -> MacAddress {
self.addr1()
}
fn destination_address(&self) -> Option<MacAddress> {
Some(self.receiver_address())
}
}