use crate::mac;
use zerocopy::SplitByteSlice;
#[derive(Copy, Clone, PartialOrd, PartialEq, Debug, Ord, Eq)]
pub enum FrameClass {
Class1 = 1,
Class2 = 2,
Class3 = 3,
}
impl<B: SplitByteSlice> From<&mac::MacFrame<B>> for FrameClass {
fn from(mac_frame: &mac::MacFrame<B>) -> FrameClass {
frame_class(&mac_frame.frame_ctrl())
}
}
pub fn frame_class(fc: &mac::FrameControl) -> FrameClass {
match fc.frame_type() {
mac::FrameType::CTRL => match fc.ctrl_subtype() {
mac::CtrlSubtype::RTS
| mac::CtrlSubtype::CTS
| mac::CtrlSubtype::ACK
| mac::CtrlSubtype::CF_END
| mac::CtrlSubtype::CF_END_ACK => return FrameClass::Class1,
_ => (),
},
mac::FrameType::MGMT => match fc.mgmt_subtype() {
mac::MgmtSubtype::ACTION
| mac::MgmtSubtype::PROBE_REQ
| mac::MgmtSubtype::PROBE_RESP
| mac::MgmtSubtype::BEACON
| mac::MgmtSubtype::AUTH
| mac::MgmtSubtype::DEAUTH
| mac::MgmtSubtype::ATIM => return FrameClass::Class1,
_ => (),
},
_ => (),
};
if let mac::FrameType::MGMT = fc.frame_type() {
match fc.mgmt_subtype() {
mac::MgmtSubtype::ASSOC_REQ
| mac::MgmtSubtype::ASSOC_RESP
| mac::MgmtSubtype::REASSOC_REQ
| mac::MgmtSubtype::REASSOC_RESP
| mac::MgmtSubtype::DISASSOC => return FrameClass::Class2,
_ => (),
}
};
FrameClass::Class3
}
pub fn action_frame_class(category: mac::ActionCategory) -> FrameClass {
match category {
mac::ActionCategory::PUBLIC | mac::ActionCategory::SELF_PROTECTED => FrameClass::Class1,
_ => FrameClass::Class3,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mgmt_frame_class() {
let mut fc = mac::FrameControl(0)
.with_frame_type(mac::FrameType::MGMT)
.with_mgmt_subtype(mac::MgmtSubtype::BEACON);
assert_eq!(FrameClass::Class1, frame_class(&fc));
fc.set_mgmt_subtype(mac::MgmtSubtype::AUTH);
assert_eq!(FrameClass::Class1, frame_class(&fc));
fc.set_mgmt_subtype(mac::MgmtSubtype::DEAUTH);
assert_eq!(FrameClass::Class1, frame_class(&fc));
fc.set_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ);
assert_eq!(FrameClass::Class1, frame_class(&fc));
fc.set_mgmt_subtype(mac::MgmtSubtype::PROBE_RESP);
assert_eq!(FrameClass::Class1, frame_class(&fc));
fc.set_mgmt_subtype(mac::MgmtSubtype::ATIM);
assert_eq!(FrameClass::Class1, frame_class(&fc));
fc.set_mgmt_subtype(mac::MgmtSubtype::ACTION);
assert_eq!(FrameClass::Class1, frame_class(&fc));
fc.set_mgmt_subtype(mac::MgmtSubtype::ASSOC_REQ);
assert_eq!(FrameClass::Class2, frame_class(&fc));
fc.set_mgmt_subtype(mac::MgmtSubtype::ASSOC_RESP);
assert_eq!(FrameClass::Class2, frame_class(&fc));
fc.set_mgmt_subtype(mac::MgmtSubtype::REASSOC_REQ);
assert_eq!(FrameClass::Class2, frame_class(&fc));
fc.set_mgmt_subtype(mac::MgmtSubtype::REASSOC_RESP);
assert_eq!(FrameClass::Class2, frame_class(&fc));
fc.set_mgmt_subtype(mac::MgmtSubtype::DISASSOC);
assert_eq!(FrameClass::Class2, frame_class(&fc));
fc.set_mgmt_subtype(mac::MgmtSubtype::TIMING_AD);
assert_eq!(FrameClass::Class3, frame_class(&fc));
fc.set_mgmt_subtype(mac::MgmtSubtype::ACTION_NO_ACK);
assert_eq!(FrameClass::Class3, frame_class(&fc));
}
#[test]
fn data_frame_class() {
let fc = mac::FrameControl(0).with_frame_type(mac::FrameType::DATA);
assert_eq!(FrameClass::Class3, frame_class(&fc));
}
#[test]
fn ctrl_frame_class() {
let mut fc = mac::FrameControl(0)
.with_frame_type(mac::FrameType::CTRL)
.with_ctrl_subtype(mac::CtrlSubtype::ACK);
assert_eq!(FrameClass::Class1, frame_class(&fc));
fc.set_ctrl_subtype(mac::CtrlSubtype::RTS);
assert_eq!(FrameClass::Class1, frame_class(&fc));
fc.set_ctrl_subtype(mac::CtrlSubtype::CTS);
assert_eq!(FrameClass::Class1, frame_class(&fc));
fc.set_ctrl_subtype(mac::CtrlSubtype::PS_POLL);
assert_eq!(FrameClass::Class3, frame_class(&fc));
fc.set_ctrl_subtype(mac::CtrlSubtype::BLOCK_ACK);
assert_eq!(FrameClass::Class3, frame_class(&fc));
fc.set_ctrl_subtype(mac::CtrlSubtype::BLOCK_ACK_REQ);
assert_eq!(FrameClass::Class3, frame_class(&fc));
}
#[test]
fn action_frames() {
assert_eq!(FrameClass::Class1, action_frame_class(mac::ActionCategory::PUBLIC));
assert_eq!(FrameClass::Class1, action_frame_class(mac::ActionCategory::SELF_PROTECTED));
assert_eq!(FrameClass::Class3, action_frame_class(mac::ActionCategory::BLOCK_ACK));
assert_eq!(FrameClass::Class3, action_frame_class(mac::ActionCategory::MESH));
}
}