#![doc = include_str!("../README.md")]
pub mod error;
pub mod frame;
mod frame_types;
pub mod parsers;
mod traits;
use crate::error::Error;
use crate::parsers::*;
pub use crate::frame::Frame;
pub use crate::frame_types::*;
pub use crate::traits::*;
use crc::{CRC_32_ISO_HDLC, Crc};
const CRC_32: Crc<u32> = Crc::<u32>::new(&CRC_32_ISO_HDLC);
pub fn parse_frame(input: &[u8], fcs_included: bool) -> Result<Frame, Error> {
if fcs_included {
if input.len() < 4 {
return Err(Error::Incomplete("Incomplete".to_string()));
}
let (frame_data, fcs_bytes) = input.split_at(input.len() - 4);
let crc = CRC_32.checksum(frame_data);
let fcs = u32::from_le_bytes([fcs_bytes[0], fcs_bytes[1], fcs_bytes[2], fcs_bytes[3]]);
if crc != fcs {
return Err(Error::Incomplete(format!(
"(FCS) mismatch {:02x} {:02x}",
crc, fcs
)));
}
}
let (input, frame_control) = parse_frame_control(input)?;
match frame_control.frame_subtype {
FrameSubType::Beacon => parse_beacon(frame_control, input),
FrameSubType::ProbeRequest => parse_probe_request(frame_control, input),
FrameSubType::ProbeResponse => parse_probe_response(frame_control, input),
FrameSubType::AssociationRequest => parse_association_request(frame_control, input),
FrameSubType::AssociationResponse => parse_association_response(frame_control, input),
FrameSubType::ReassociationRequest => parse_reassociation_request(frame_control, input),
FrameSubType::ReassociationResponse => parse_reassociation_response(frame_control, input),
FrameSubType::Authentication => parse_authentication_frame(frame_control, input),
FrameSubType::Deauthentication => parse_deauthentication_frame(frame_control, input),
FrameSubType::Action => parse_action(frame_control, input),
FrameSubType::Rts => parse_rts(frame_control, input),
FrameSubType::Cts => parse_cts(frame_control, input),
FrameSubType::Ack => parse_ack(frame_control, input),
FrameSubType::BlockAckRequest => parse_block_ack_request(frame_control, input),
FrameSubType::BlockAck => parse_block_ack(frame_control, input),
FrameSubType::Data => parse_data(frame_control, input),
FrameSubType::NullData => parse_null_data(frame_control, input),
FrameSubType::QosData => parse_qos_data(frame_control, input),
FrameSubType::QosNull => parse_qos_null(frame_control, input),
FrameSubType::DataCfAck => parse_data_cf_ack(frame_control, input),
FrameSubType::DataCfPoll => parse_data_cf_poll(frame_control, input),
FrameSubType::DataCfAckCfPoll => parse_data_cf_ack_cf_poll(frame_control, input),
FrameSubType::CfAck => parse_cf_ack(frame_control, input),
FrameSubType::CfPoll => parse_cf_poll(frame_control, input),
FrameSubType::CfAckCfPoll => parse_cf_ack_cf_poll(frame_control, input),
FrameSubType::QosDataCfAck => parse_qos_data_cf_ack(frame_control, input),
FrameSubType::QosDataCfPoll => parse_qos_data_cf_poll(frame_control, input),
FrameSubType::QosDataCfAckCfPoll => parse_qos_data_cf_ack_cf_poll(frame_control, input),
FrameSubType::QosCfPoll => parse_qos_cf_poll(frame_control, input),
FrameSubType::QosCfAckCfPoll => parse_qos_cf_ack_cf_poll(frame_control, input),
_ => Err(Error::UnhandledFrameSubtype(frame_control, input.to_vec())),
}
}
#[cfg(doctest)]
doc_comment::doctest!("../../README.md");