1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
//! A parser for the [Radiotap](http://www.radiotap.org/) capture format.
//!
//! # Usage
//!
//! The `Radiotap::from_bytes(&capture)` constructor will parse all present fields into a
//! [Radiotap](struct.Radiotap.html) struct:
//!
//! ```
//! extern crate radiotap;
//! use radiotap::{Radiotap};
//!
//! fn main() {
//!     let capture = [
//!         0, 0, 56, 0, 107, 8, 52, 0, 185, 31, 155, 154, 0, 0, 0, 0, 20, 0, 124, 21, 64, 1, 213,
//!         166, 1, 0, 0, 0, 64, 1, 1, 0, 124, 21, 100, 34, 249, 1, 0, 0, 0, 0, 0, 0, 255, 1, 80,
//!         4, 115, 0, 0, 0, 1, 63, 0, 0
//!     ];
//!
//!     let radiotap = Radiotap::from_bytes(&capture).unwrap();
//!     println!("{:?}", radiotap.vht);
//! }
//!```
//!
//! If you just want to parse a few specific fields from the Radiotap capture you can create an
//! iterator using `RadiotapIterator::from_bytes(&capture)`:
//!
//! ```
//! extern crate radiotap;
//! use radiotap::{RadiotapIterator, field};
//!
//! fn main() {
//!     let capture = [
//!         0, 0, 56, 0, 107, 8, 52, 0, 185, 31, 155, 154, 0, 0, 0, 0, 20, 0, 124, 21, 64, 1, 213,
//!         166, 1, 0, 0, 0, 64, 1, 1, 0, 124, 21, 100, 34, 249, 1, 0, 0, 0, 0, 0, 0, 255, 1, 80,
//!         4, 115, 0, 0, 0, 1, 63, 0, 0
//!     ];
//!
//!     for element in RadiotapIterator::from_bytes(&capture).unwrap() {
//!         match element {
//!             Ok((field::Kind::VHT, data)) => {
//!                 let vht: field::VHT = field::from_bytes(data).unwrap();
//!                 println!("{:?}", vht);
//!             },
//!             _ => {}
//!         }
//!     }
//! }
//! ```

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! {
    /// All errors returned and used by the radiotap module.
    #[derive(Debug)]
    pub enum Error {
        /// The internal cursor on the data returned an IO error.
        ParseError(err: std::io::Error) {
            from()
            description(err.description())
        }
        /// The given data is not a complete Radiotap capture.
        IncompleteError {
            display("The given data is not a complete Radiotap capture")
        }
        /// The given data is shorter than the amount specified in the Radiotap header.
        InvalidLength {
            display("The given data is shorter than the amount specified in the Radiotap header")
        }
        /// The given data is not a valid Radiotap capture.
        InvalidFormat {
            display("The given data is not a valid Radiotap capture")
        }
        /// Unsupported Radiotap header version.
        UnsupportedVersion {
            display("Unsupported Radiotap header version")
        }
        /// Unsupported Radiotap field.
        UnsupportedField {
            display("Unsupported Radiotap field")
        }
    }
}

type Result<T> = result::Result<T, Error>;

/// A trait to align an offset to particular word size, usually 1, 2, 4, or 8.
trait Align {
    /// Aligns the offset to `align` size.
    fn align(&mut self, align: u64);
}

impl<T> Align for Cursor<T> {
    /// Aligns the Cursor position to `align` size.
    fn align(&mut self, align: u64) {
        let p = self.position();
        self.set_position((p + align - 1) & !(align - 1));
    }
}

/// Represents an unparsed Radiotap capture format, only the header field is parsed.
#[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))
    }
}

/// An iterator over Radiotap fields.
#[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) => {
                // Align the cursor to the current field's needed alignment.
                self.cursor.align(kind.align());

                let mut start = self.cursor.position() as usize;
                let mut end = start + kind.size();

                // The header lied about how long the body was
                if end > self.cursor.get_ref().len() {
                    Some(Err(Error::IncompleteError))
                } else {
                    // Switching to a vendor namespace, and we don't know how to handle
                    // so we just return the entire vendor namespace section
                    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,
        }
    }
}

/// Represents a parsed Radiotap capture, including the parsed header and all fields as Option
/// members.
#[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 {
    /// Returns the parsed [Radiotap](struct.Radiotap.html) from an input byte array.
    pub fn from_bytes(input: &[u8]) -> Result<Radiotap> {
        Ok(Radiotap::parse(input)?.0)
    }

    /// Returns the parsed [Radiotap](struct.Radiotap.html) and remaining data from an input byte
    /// array.
    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),
        };
    }
}