mod error;
pub mod field;
mod prelude;
mod util;
use std::error::Error as StdError;
use std::fmt;
use crate::error::ResultExt;
pub use crate::error::{Error, ErrorKind, Result};
use crate::field::{Kind, Type, VendorNamespace};
use crate::prelude::*;
const VERSION: u8 = 0;
const PRESENCE_DEFAULT_NAMESPACE: u32 = 29;
const PRESENCE_VENDOR_NAMESPACE: u32 = 30;
const PRESENCE_EXT: u32 = 31;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Namespace {
Default,
Vendor(VendorNamespace),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Field {
namespace: Namespace,
bit: u32,
}
#[derive(Debug, Clone)]
pub struct Iter<'a> {
bytes: Bytes<'a>,
length: usize,
presence: Vec<u32>,
position: u32,
namespace: Namespace,
}
#[derive(Debug, Clone)]
pub struct IterDefault<'a> {
inner: Iter<'a>,
}
#[derive(Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct Header {
length: usize,
pub tsft: Option<field::Tsft>,
pub flags: Option<field::Flags>,
pub rate: Option<field::Rate>,
pub channel: Option<field::Channel>,
pub fhss: Option<field::Fhss>,
pub antenna_signal: Option<field::AntennaSignal>,
pub antenna_noise: Option<field::AntennaNoise>,
pub lock_quality: Option<field::LockQuality>,
pub tx_attenuation: Option<field::TxAttenuation>,
pub tx_attenuation_db: Option<field::TxAttenuationDb>,
pub tx_power: Option<field::TxPower>,
pub antenna: Option<field::Antenna>,
pub antenna_signal_db: Option<field::AntennaSignalDb>,
pub antenna_noise_db: Option<field::AntennaNoiseDb>,
pub rx_flags: Option<field::RxFlags>,
pub tx_flags: Option<field::TxFlags>,
pub xchannel: Option<field::XChannel>,
pub mcs: Option<field::Mcs>,
pub ampdu_status: Option<field::AmpduStatus>,
pub vht: Option<field::Vht>,
pub timestamp: Option<field::Timestamp>,
}
impl Field {
pub const fn namespace(&self) -> &Namespace {
&self.namespace
}
pub const fn bit(&self) -> u32 {
self.bit
}
}
impl<'a> Iter<'a> {
pub fn new(bytes: &'a [u8]) -> Result<Self> {
let mut bytes = Bytes::from_slice(bytes);
let version = bytes.read().context(ErrorKind::Header)?;
if version != VERSION {
return Err(Error::new(ErrorKind::UnsupportedVersion(version)));
}
bytes.advance(1).context(ErrorKind::Header)?;
let length = bytes.read::<u16>().context(ErrorKind::Header)?.into();
let mut presence = Vec::new();
loop {
let word = bytes.read().context(ErrorKind::Header)?;
presence.push(word);
if word & (1 << PRESENCE_EXT) == 0 {
break;
}
}
Ok(Self {
bytes,
length,
presence,
position: 0,
namespace: Namespace::Default,
})
}
pub const fn version(&self) -> u8 {
VERSION
}
pub const fn length(&self) -> usize {
self.length
}
pub const fn into_default(self) -> IterDefault<'a> {
IterDefault { inner: self }
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Result<Option<Field>> {
loop {
match self.presence.get((self.position / 32) as usize) {
Some(presence) => {
let bit = self.position % 32;
self.position += 1;
if presence & (1 << bit) == 0 {
continue;
}
match bit {
PRESENCE_DEFAULT_NAMESPACE => {
self.namespace = Namespace::Default;
continue;
}
PRESENCE_VENDOR_NAMESPACE => {
let context =
|| ErrorKind::Read(std::any::type_name::<VendorNamespace>());
self.bytes.align(2).with_context(context)?;
self.namespace =
Namespace::Vendor(self.bytes.read().with_context(context)?);
continue;
}
PRESENCE_EXT => {
continue;
}
bit => {
break Ok(Some(Field {
namespace: self.namespace,
bit,
}))
}
}
}
None => break Ok(None),
}
}
}
pub fn skip<T: Kind>(&mut self, kind: T) -> Result<()> {
self.bytes.align(kind.align()).context(ErrorKind::Skip)?;
self.bytes.advance(kind.size()).context(ErrorKind::Skip)?;
Ok(())
}
pub fn skip_vns(&mut self, vns: &VendorNamespace) -> Result<()> {
self.bytes
.advance(vns.skip_length())
.context(ErrorKind::Skip)
}
pub fn read<T, U, E>(&mut self, kind: T) -> Result<U>
where
T: Kind,
U: FromBytes<Error = E>,
E: Into<Box<dyn StdError + Send + Sync>>,
{
let context = || ErrorKind::Read(std::any::type_name::<U>());
self.bytes.align(kind.align()).with_context(context)?;
let start_pos = self.bytes.position();
let field = U::from_bytes(&mut self.bytes).with_context(context)?;
let end_pos = self.bytes.position();
if end_pos - start_pos != kind.size() {
return Err(Error::new(context()));
}
Ok(field)
}
fn read_some<T, U, E>(&mut self, kind: T) -> Result<Option<U>>
where
T: Kind,
U: FromBytes<Error = E>,
E: Into<Box<dyn StdError + Send + Sync>>,
{
self.read(kind).map(Some)
}
}
impl IterDefault<'_> {
#[inline]
pub const fn version(&self) -> u8 {
self.inner.version()
}
#[inline]
pub const fn length(&self) -> usize {
self.inner.length()
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Result<Option<Type>> {
match self.inner.next()? {
Some(Field {
namespace: Namespace::Default,
bit,
}) => Ok(Type::from_bit(bit)),
Some(Field {
namespace: Namespace::Vendor(vns),
..
}) => {
self.inner.skip_vns(&vns)?;
self.next()
}
None => Ok(None),
}
}
#[inline]
pub fn skip(&mut self, kind: Type) -> Result<()> {
self.inner.skip(kind)
}
#[inline]
pub fn read<U, E>(&mut self, kind: Type) -> Result<U>
where
U: FromBytes<Error = E>,
E: Into<Box<dyn StdError + Send + Sync>>,
{
self.inner.read(kind)
}
#[inline]
fn read_some<U, E>(&mut self, kind: Type) -> Result<Option<U>>
where
U: FromBytes<Error = E>,
E: Into<Box<dyn StdError + Send + Sync>>,
{
self.inner.read_some(kind)
}
}
pub fn parse(capture: &[u8]) -> Result<Header> {
let mut iter = Iter::new(capture)?.into_default();
let mut radiotap = Header {
length: iter.length(),
tsft: None,
flags: None,
rate: None,
channel: None,
fhss: None,
antenna_signal: None,
antenna_noise: None,
lock_quality: None,
tx_attenuation: None,
tx_attenuation_db: None,
tx_power: None,
antenna: None,
antenna_signal_db: None,
antenna_noise_db: None,
rx_flags: None,
tx_flags: None,
xchannel: None,
mcs: None,
ampdu_status: None,
vht: None,
timestamp: None,
};
while let Some(kind) = iter.next()? {
match kind {
Type::Tsft => radiotap.tsft = iter.read_some(kind)?,
Type::Flags => radiotap.flags = iter.read_some(kind)?,
Type::Rate => radiotap.rate = iter.read_some(kind)?,
Type::Channel => radiotap.channel = iter.read_some(kind)?,
Type::Fhss => radiotap.fhss = iter.read_some(kind)?,
Type::AntennaSignal => radiotap.antenna_signal = iter.read_some(kind)?,
Type::AntennaNoise => radiotap.antenna_noise = iter.read_some(kind)?,
Type::LockQuality => radiotap.lock_quality = iter.read_some(kind)?,
Type::TxAttenuation => radiotap.tx_attenuation = iter.read_some(kind)?,
Type::TxAttenuationDb => radiotap.tx_attenuation_db = iter.read_some(kind)?,
Type::TxPower => radiotap.tx_power = iter.read_some(kind)?,
Type::Antenna => radiotap.antenna = iter.read_some(kind)?,
Type::AntennaSignalDb => radiotap.antenna_signal_db = iter.read_some(kind)?,
Type::AntennaNoiseDb => radiotap.antenna_noise_db = iter.read_some(kind)?,
Type::RxFlags => radiotap.rx_flags = iter.read_some(kind)?,
Type::TxFlags => radiotap.tx_flags = iter.read_some(kind)?,
Type::XChannel => radiotap.xchannel = iter.read_some(kind)?,
Type::Mcs => radiotap.mcs = iter.read_some(kind)?,
Type::AmpduStatus => radiotap.ampdu_status = iter.read_some(kind)?,
Type::Vht => radiotap.vht = iter.read_some(kind)?,
Type::Timestamp => radiotap.timestamp = iter.read_some(kind)?,
kind => iter.skip(kind)?,
}
}
Ok(radiotap)
}
impl fmt::Debug for Header {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("radiotap::Header");
d.field("length", &self.length);
macro_rules! field {
($attr:ident) => {
if let Some(field) = &self.$attr {
d.field(stringify!($attr), field);
}
};
}
field!(tsft);
field!(flags);
field!(rate);
field!(channel);
field!(fhss);
field!(antenna_signal);
field!(antenna_noise);
field!(lock_quality);
field!(tx_attenuation);
field!(tx_attenuation_db);
field!(tx_power);
field!(antenna);
field!(antenna_signal_db);
field!(antenna_noise_db);
field!(rx_flags);
field!(tx_flags);
field!(xchannel);
field!(mcs);
field!(ampdu_status);
field!(vht);
field!(timestamp);
d.finish()
}
}
impl Header {
#[inline]
pub const fn version(&self) -> u8 {
VERSION
}
#[inline]
pub const fn length(&self) -> usize {
self.length
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basic() {
let capture = hex::decode(
"000038006f0800c001000040040030309de59b040000000012308509\
8004b4a7008700101800030002000000001018030600400002000000",
)
.unwrap();
let header = parse(&capture).unwrap();
assert_eq!(header.length(), 56);
assert_eq!(header.tsft.unwrap().into_inner(), 77325725);
assert_eq!(
header.flags.unwrap(),
field::Flags::PREAMBLE | field::Flags::FCS
);
assert_eq!(header.rate.unwrap().to_mbps(), 24.0);
}
}