extern crate bitops;
extern crate byteorder;
#[macro_use]
extern crate quick_error;
pub mod field;
use field::*;
use std::io::Cursor;
use std::result;
quick_error! {
#[derive(Debug)]
pub enum Error {
ParseError(err: std::io::Error) {
from()
description(err.description())
}
IncompleteError {
display("The given data is not a complete Radiotap capture")
}
InvalidLength {
display("The given data is shorter than the amount specified in the Radiotap header")
}
InvalidFormat {
display("The given data is not a valid Radiotap capture")
}
UnsupportedVersion {
display("Unsupported Radiotap header version")
}
UnsupportedField {
display("Unsupported Radiotap field")
}
}
}
type Result<T> = result::Result<T, Error>;
trait Align {
fn align(&mut self, align: u64);
}
impl<T> Align for Cursor<T> {
fn align(&mut self, align: u64) {
let p = self.position();
self.set_position((p + align - 1) & !(align - 1));
}
}
#[derive(Debug, Clone)]
pub struct RadiotapIterator<'a> {
header: Header,
data: &'a [u8],
}
impl<'a> RadiotapIterator<'a> {
pub fn from_bytes(input: &'a [u8]) -> Result<RadiotapIterator<'a>> {
Ok(RadiotapIterator::parse(input)?.0)
}
pub fn parse(input: &'a [u8]) -> Result<(RadiotapIterator<'a>, &'a [u8])> {
let header: Header = from_bytes(input)?;
let (data, rest) = input.split_at(header.length);
Ok((RadiotapIterator { header, data }, rest))
}
}
#[doc(hidden)]
#[derive(Debug, Clone)]
pub struct RadiotapIteratorIntoIter<'a> {
present: Vec<Kind>,
cursor: Cursor<&'a [u8]>,
}
impl<'a> IntoIterator for &'a RadiotapIterator<'a> {
type Item = Result<(Kind, &'a [u8])>;
type IntoIter = RadiotapIteratorIntoIter<'a>;
fn into_iter(self) -> Self::IntoIter {
let present = self.header.present.iter().rev().cloned().collect();
let mut cursor = Cursor::new(self.data);
cursor.set_position(self.header.size as u64);
RadiotapIteratorIntoIter { present, cursor }
}
}
impl<'a> IntoIterator for RadiotapIterator<'a> {
type Item = Result<(Kind, &'a [u8])>;
type IntoIter = RadiotapIteratorIntoIter<'a>;
fn into_iter(self) -> Self::IntoIter {
let present = self.header.present.iter().rev().cloned().collect();
let mut cursor = Cursor::new(self.data);
cursor.set_position(self.header.size as u64);
RadiotapIteratorIntoIter { present, cursor }
}
}
impl<'a> Iterator for RadiotapIteratorIntoIter<'a> {
type Item = Result<(Kind, &'a [u8])>;
fn next(&mut self) -> Option<Self::Item> {
match self.present.pop() {
Some(mut kind) => {
self.cursor.align(kind.align());
let mut start = self.cursor.position() as usize;
let mut end = start + kind.size();
if end > self.cursor.get_ref().len() {
Some(Err(Error::IncompleteError))
} else {
if kind == Kind::VendorNamespace(None) {
match VendorNamespace::from_bytes(&self.cursor.get_ref()[start..end]) {
Ok(vns) => {
start += kind.size();
end += vns.skip_length as usize;
kind = Kind::VendorNamespace(Some(vns));
}
Err(e) => return Some(Err(e)),
}
}
let data = &self.cursor.get_ref()[start..end];
self.cursor.set_position(end as u64);
Some(Ok((kind, data)))
}
}
None => None,
}
}
}
impl Default for Header {
fn default() -> Header {
Header {
version: 0,
length: 8,
present: Vec::new(),
size: 8,
}
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Radiotap {
pub header: Header,
pub tsft: Option<TSFT>,
pub flags: Option<Flags>,
pub rate: Option<Rate>,
pub channel: Option<Channel>,
pub fhss: Option<FHSS>,
pub antenna_signal: Option<AntennaSignal>,
pub antenna_noise: Option<AntennaNoise>,
pub lock_quality: Option<LockQuality>,
pub tx_attenuation: Option<TxAttenuation>,
pub tx_attenuation_db: Option<TxAttenuationDb>,
pub tx_power: Option<TxPower>,
pub antenna: Option<Antenna>,
pub antenna_signal_db: Option<AntennaSignalDb>,
pub antenna_noise_db: Option<AntennaNoiseDb>,
pub rx_flags: Option<RxFlags>,
pub tx_flags: Option<TxFlags>,
pub rts_retries: Option<RTSRetries>,
pub data_retries: Option<DataRetries>,
pub xchannel: Option<XChannel>,
pub mcs: Option<MCS>,
pub ampdu_status: Option<AMPDUStatus>,
pub vht: Option<VHT>,
pub timestamp: Option<Timestamp>,
}
impl Radiotap {
pub fn from_bytes(input: &[u8]) -> Result<Radiotap> {
Ok(Radiotap::parse(input)?.0)
}
pub fn parse(input: &[u8]) -> Result<(Radiotap, &[u8])> {
let (iterator, rest) = RadiotapIterator::parse(input)?;
let mut radiotap = Radiotap {
header: iterator.header.clone(),
..Default::default()
};
for result in &iterator {
let (field_kind, data) = result?;
match field_kind {
Kind::TSFT => radiotap.tsft = from_bytes_some(data)?,
Kind::Flags => radiotap.flags = from_bytes_some(data)?,
Kind::Rate => radiotap.rate = from_bytes_some(data)?,
Kind::Channel => radiotap.channel = from_bytes_some(data)?,
Kind::FHSS => radiotap.fhss = from_bytes_some(data)?,
Kind::AntennaSignal => radiotap.antenna_signal = from_bytes_some(data)?,
Kind::AntennaNoise => radiotap.antenna_noise = from_bytes_some(data)?,
Kind::LockQuality => radiotap.lock_quality = from_bytes_some(data)?,
Kind::TxAttenuation => radiotap.tx_attenuation = from_bytes_some(data)?,
Kind::TxAttenuationDb => radiotap.tx_attenuation_db = from_bytes_some(data)?,
Kind::TxPower => radiotap.tx_power = from_bytes_some(data)?,
Kind::Antenna => radiotap.antenna = from_bytes_some(data)?,
Kind::AntennaSignalDb => radiotap.antenna_signal_db = from_bytes_some(data)?,
Kind::AntennaNoiseDb => radiotap.antenna_noise_db = from_bytes_some(data)?,
Kind::RxFlags => radiotap.rx_flags = from_bytes_some(data)?,
Kind::TxFlags => radiotap.tx_flags = from_bytes_some(data)?,
Kind::RTSRetries => radiotap.rts_retries = from_bytes_some(data)?,
Kind::DataRetries => radiotap.data_retries = from_bytes_some(data)?,
Kind::XChannel => radiotap.xchannel = from_bytes_some(data)?,
Kind::MCS => radiotap.mcs = from_bytes_some(data)?,
Kind::AMPDUStatus => radiotap.ampdu_status = from_bytes_some(data)?,
Kind::VHT => radiotap.vht = from_bytes_some(data)?,
Kind::Timestamp => radiotap.timestamp = from_bytes_some(data)?,
_ => {}
}
}
Ok((radiotap, rest))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn good_vendor() {
let frame = [
0, 0, 39, 0, 46, 72, 0, 192, 0, 0, 0, 128, 0, 0, 0, 160, 4, 0, 0, 0, 16, 2, 158, 9,
160, 0, 227, 5, 0, 0, 255, 255, 255, 255, 2, 0, 222, 173, 4,
];
assert_eq!(
Radiotap::from_bytes(&frame).unwrap().rate.unwrap(),
Rate { value: 2.0 }
);
}
#[test]
fn bad_version() {
let frame = [
1, 0, 39, 0, 46, 72, 0, 192, 0, 0, 0, 128, 0, 0, 0, 160, 4, 0, 0, 0, 16, 2, 158, 9,
160, 0, 227, 5, 0, 0, 255, 255, 255, 255, 2, 0, 222, 173, 4,
];
match Radiotap::from_bytes(&frame).unwrap_err() {
Error::UnsupportedVersion => {}
e => panic!("Error not UnsupportedVersion: {:?}", e),
};
}
#[test]
fn bad_header_length() {
let frame = [
0, 0, 40, 0, 46, 72, 0, 192, 0, 0, 0, 128, 0, 0, 0, 160, 4, 0, 0, 0, 16, 2, 158, 9,
160, 0, 227, 5, 0, 0, 255, 255, 255, 255, 2, 0, 222, 173, 4,
];
match Radiotap::from_bytes(&frame).unwrap_err() {
Error::InvalidLength => {}
e => panic!("Error not InvalidLength: {:?}", e),
};
}
#[test]
fn bad_actual_length() {
let frame = [
0, 0, 39, 0, 47, 72, 0, 192, 0, 0, 0, 128, 0, 0, 0, 160, 4, 0, 0, 0, 16, 2, 158, 9,
160, 0, 227, 5, 0, 0, 255, 255, 255, 255, 2, 0, 222, 173, 4,
];
match Radiotap::from_bytes(&frame).unwrap_err() {
Error::IncompleteError => {}
e => panic!("Error not IncompleteError: {:?}", e),
};
}
#[test]
fn bad_vendor() {
let frame = [
0, 0, 34, 0, 46, 72, 0, 192, 0, 0, 0, 128, 0, 0, 0, 160, 4, 0, 0, 0, 16, 2, 158, 9,
160, 0, 227, 5, 0, 0, 255, 255, 255, 255,
];
match Radiotap::from_bytes(&frame).unwrap_err() {
Error::IncompleteError => {}
e => panic!("Error not IncompleteError: {:?}", e),
};
}
}