1use crate::layer::field::FieldError;
10use crate::layer::{Layer, LayerIndex, LayerKind};
11
12use super::types::radiotap_present;
13
14pub const RADIOTAP_MIN_HEADER_LEN: usize = 8;
16
17pub mod offsets {
19 pub const VERSION: usize = 0;
20 pub const PAD: usize = 1;
21 pub const LENGTH: usize = 2;
22 pub const PRESENT: usize = 4;
23}
24
25fn field_alignment(bit: u32) -> (usize, usize) {
28 match bit {
29 radiotap_present::TSFT => (8, 8),
30 radiotap_present::FLAGS => (1, 1),
31 radiotap_present::RATE => (1, 1),
32 radiotap_present::CHANNEL => (4, 2), radiotap_present::FHSS => (2, 1),
34 radiotap_present::DBM_ANT_SIGNAL => (1, 1),
35 radiotap_present::DBM_ANT_NOISE => (1, 1),
36 radiotap_present::LOCK_QUALITY => (2, 2),
37 radiotap_present::TX_ATTENUATION => (2, 2),
38 radiotap_present::DB_TX_ATTENUATION => (2, 2),
39 radiotap_present::DBM_TX_POWER => (1, 1),
40 radiotap_present::ANTENNA => (1, 1),
41 radiotap_present::DB_ANT_SIGNAL => (1, 1),
42 radiotap_present::DB_ANT_NOISE => (1, 1),
43 radiotap_present::RX_FLAGS => (2, 2),
44 radiotap_present::TX_FLAGS => (2, 2),
45 radiotap_present::MCS => (3, 1), radiotap_present::A_MPDU => (8, 4), radiotap_present::VHT => (12, 2), radiotap_present::HE => (12, 2), _ => (0, 1),
50 }
51}
52
53#[derive(Debug, Clone, Default)]
55pub struct RadioTapFields {
56 pub tsft: Option<u64>,
58 pub flags: Option<u8>,
60 pub rate: Option<u8>,
62 pub channel_freq: Option<u16>,
64 pub channel_flags: Option<u16>,
66 pub dbm_ant_signal: Option<i8>,
68 pub dbm_ant_noise: Option<i8>,
70 pub lock_quality: Option<u16>,
72 pub antenna: Option<u8>,
74 pub db_ant_signal: Option<u8>,
76 pub db_ant_noise: Option<u8>,
78 pub rx_flags: Option<u16>,
80 pub tx_flags: Option<u16>,
82 pub mcs_known: Option<u8>,
84 pub mcs_flags: Option<u8>,
86 pub mcs_index: Option<u8>,
88 pub a_mpdu_ref: Option<u32>,
90 pub a_mpdu_flags: Option<u32>,
92}
93
94#[derive(Debug, Clone)]
99pub struct RadioTapLayer {
100 pub index: LayerIndex,
101}
102
103impl RadioTapLayer {
104 pub fn new(start: usize, end: usize) -> Self {
106 Self {
107 index: LayerIndex::new(LayerKind::Dot11, start, end),
108 }
109 }
110
111 pub fn validate(buf: &[u8], offset: usize) -> Result<(), FieldError> {
113 if buf.len() < offset + RADIOTAP_MIN_HEADER_LEN {
114 return Err(FieldError::BufferTooShort {
115 offset,
116 need: RADIOTAP_MIN_HEADER_LEN,
117 have: buf.len().saturating_sub(offset),
118 });
119 }
120 Ok(())
121 }
122
123 #[inline]
129 pub fn version(&self, buf: &[u8]) -> Result<u8, FieldError> {
130 let off = self.index.start + offsets::VERSION;
131 if buf.len() <= off {
132 return Err(FieldError::BufferTooShort {
133 offset: off,
134 need: 1,
135 have: buf.len(),
136 });
137 }
138 Ok(buf[off])
139 }
140
141 #[inline]
143 pub fn pad(&self, buf: &[u8]) -> Result<u8, FieldError> {
144 let off = self.index.start + offsets::PAD;
145 if buf.len() <= off {
146 return Err(FieldError::BufferTooShort {
147 offset: off,
148 need: 1,
149 have: buf.len(),
150 });
151 }
152 Ok(buf[off])
153 }
154
155 #[inline]
157 pub fn header_length(&self, buf: &[u8]) -> Result<u16, FieldError> {
158 let off = self.index.start + offsets::LENGTH;
159 if buf.len() < off + 2 {
160 return Err(FieldError::BufferTooShort {
161 offset: off,
162 need: 2,
163 have: buf.len(),
164 });
165 }
166 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
167 }
168
169 #[inline]
171 pub fn present(&self, buf: &[u8]) -> Result<u32, FieldError> {
172 let off = self.index.start + offsets::PRESENT;
173 if buf.len() < off + 4 {
174 return Err(FieldError::BufferTooShort {
175 offset: off,
176 need: 4,
177 have: buf.len(),
178 });
179 }
180 Ok(u32::from_le_bytes([
181 buf[off],
182 buf[off + 1],
183 buf[off + 2],
184 buf[off + 3],
185 ]))
186 }
187
188 #[inline]
190 pub fn has_field(&self, buf: &[u8], bit: u32) -> bool {
191 self.present(buf)
192 .map(|p| p & (1 << bit) != 0)
193 .unwrap_or(false)
194 }
195
196 pub fn has_fcs(&self, buf: &[u8]) -> bool {
198 if self.has_field(buf, radiotap_present::FLAGS) {
199 if let Ok(fields) = self.parse_fields(buf) {
200 if let Some(flags) = fields.flags {
201 return flags & super::types::radiotap_flags::FCS != 0;
202 }
203 }
204 }
205 false
206 }
207
208 fn count_present_words(&self, buf: &[u8]) -> usize {
214 let mut count = 1;
215 let mut off = self.index.start + offsets::PRESENT;
216
217 loop {
218 if buf.len() < off + 4 {
219 break;
220 }
221 let word = u32::from_le_bytes([buf[off], buf[off + 1], buf[off + 2], buf[off + 3]]);
222 if word & (1 << radiotap_present::EXT) == 0 {
223 break;
224 }
225 count += 1;
226 off += 4;
227 }
228 count
229 }
230
231 pub fn parse_fields(&self, buf: &[u8]) -> Result<RadioTapFields, FieldError> {
233 let present = self.present(buf)?;
234 let header_len = self.header_length(buf)? as usize;
235 let start = self.index.start;
236
237 if buf.len() < start + header_len {
238 return Err(FieldError::BufferTooShort {
239 offset: start,
240 need: header_len,
241 have: buf.len().saturating_sub(start),
242 });
243 }
244
245 let num_present_words = self.count_present_words(buf);
246 let mut pos = start + 4 + (num_present_words * 4);
248 let end = start + header_len;
249 let mut fields = RadioTapFields::default();
250
251 for bit in 0..28u32 {
253 if present & (1 << bit) == 0 {
254 continue;
255 }
256
257 let (size, align) = field_alignment(bit);
258 if size == 0 {
259 continue;
260 }
261
262 if align > 1 {
264 let base = start + 4 + (num_present_words * 4);
265 let relative = pos - base;
266 let _padding = (align - (relative % align)) % align;
267 let abs_padding = (align - ((pos - start) % align)) % align;
269 pos += abs_padding;
270 }
271
272 if pos + size > end {
273 break;
274 }
275
276 match bit {
277 radiotap_present::TSFT => {
278 fields.tsft = Some(u64::from_le_bytes([
279 buf[pos],
280 buf[pos + 1],
281 buf[pos + 2],
282 buf[pos + 3],
283 buf[pos + 4],
284 buf[pos + 5],
285 buf[pos + 6],
286 buf[pos + 7],
287 ]));
288 }
289 radiotap_present::FLAGS => {
290 fields.flags = Some(buf[pos]);
291 }
292 radiotap_present::RATE => {
293 fields.rate = Some(buf[pos]);
294 }
295 radiotap_present::CHANNEL => {
296 fields.channel_freq = Some(u16::from_le_bytes([buf[pos], buf[pos + 1]]));
297 fields.channel_flags = Some(u16::from_le_bytes([buf[pos + 2], buf[pos + 3]]));
298 }
299 radiotap_present::DBM_ANT_SIGNAL => {
300 fields.dbm_ant_signal = Some(buf[pos] as i8);
301 }
302 radiotap_present::DBM_ANT_NOISE => {
303 fields.dbm_ant_noise = Some(buf[pos] as i8);
304 }
305 radiotap_present::LOCK_QUALITY => {
306 fields.lock_quality = Some(u16::from_le_bytes([buf[pos], buf[pos + 1]]));
307 }
308 radiotap_present::ANTENNA => {
309 fields.antenna = Some(buf[pos]);
310 }
311 radiotap_present::DB_ANT_SIGNAL => {
312 fields.db_ant_signal = Some(buf[pos]);
313 }
314 radiotap_present::DB_ANT_NOISE => {
315 fields.db_ant_noise = Some(buf[pos]);
316 }
317 radiotap_present::RX_FLAGS => {
318 fields.rx_flags = Some(u16::from_le_bytes([buf[pos], buf[pos + 1]]));
319 }
320 radiotap_present::TX_FLAGS => {
321 fields.tx_flags = Some(u16::from_le_bytes([buf[pos], buf[pos + 1]]));
322 }
323 radiotap_present::MCS => {
324 fields.mcs_known = Some(buf[pos]);
325 fields.mcs_flags = Some(buf[pos + 1]);
326 fields.mcs_index = Some(buf[pos + 2]);
327 }
328 radiotap_present::A_MPDU => {
329 fields.a_mpdu_ref = Some(u32::from_le_bytes([
330 buf[pos],
331 buf[pos + 1],
332 buf[pos + 2],
333 buf[pos + 3],
334 ]));
335 fields.a_mpdu_flags = Some(u32::from_le_bytes([
336 buf[pos + 4],
337 buf[pos + 5],
338 buf[pos + 6],
339 buf[pos + 7],
340 ]));
341 }
342 _ => {}
343 }
344
345 pos += size;
346 }
347
348 Ok(fields)
349 }
350}
351
352impl Layer for RadioTapLayer {
353 fn kind(&self) -> LayerKind {
354 LayerKind::Dot11
355 }
356
357 fn summary(&self, buf: &[u8]) -> String {
358 let len = self
359 .header_length(buf)
360 .map(|l| l.to_string())
361 .unwrap_or_else(|_| "?".to_string());
362 let present = self
363 .present(buf)
364 .map(|p| format!("{:#010x}", p))
365 .unwrap_or_else(|_| "?".to_string());
366 format!("RadioTap len={} present={}", len, present)
367 }
368
369 fn header_len(&self, buf: &[u8]) -> usize {
370 self.header_length(buf)
371 .map(|v| v as usize)
372 .unwrap_or(RADIOTAP_MIN_HEADER_LEN)
373 }
374
375 fn field_names(&self) -> &'static [&'static str] {
376 &[
377 "version",
378 "pad",
379 "len",
380 "present",
381 "mac_timestamp",
382 "Flags",
383 "Rate",
384 "ChannelFrequency",
385 "ChannelFlags",
386 "dBm_AntSignal",
387 "dBm_AntNoise",
388 "Antenna",
389 ]
390 }
391}
392
393#[derive(Debug, Clone, Default)]
395pub struct RadioTapBuilder {
396 pub tsft: Option<u64>,
398 pub flags: Option<u8>,
400 pub rate: Option<u8>,
402 pub channel_freq: Option<u16>,
404 pub channel_flags: Option<u16>,
406 pub dbm_ant_signal: Option<i8>,
408 pub dbm_ant_noise: Option<i8>,
410 pub antenna: Option<u8>,
412}
413
414impl RadioTapBuilder {
415 pub fn new() -> Self {
417 Self::default()
418 }
419
420 pub fn tsft(mut self, tsft: u64) -> Self {
421 self.tsft = Some(tsft);
422 self
423 }
424
425 pub fn flags(mut self, flags: u8) -> Self {
426 self.flags = Some(flags);
427 self
428 }
429
430 pub fn rate(mut self, rate: u8) -> Self {
431 self.rate = Some(rate);
432 self
433 }
434
435 pub fn channel(mut self, freq: u16, flags: u16) -> Self {
436 self.channel_freq = Some(freq);
437 self.channel_flags = Some(flags);
438 self
439 }
440
441 pub fn dbm_ant_signal(mut self, signal: i8) -> Self {
442 self.dbm_ant_signal = Some(signal);
443 self
444 }
445
446 pub fn dbm_ant_noise(mut self, noise: i8) -> Self {
447 self.dbm_ant_noise = Some(noise);
448 self
449 }
450
451 pub fn antenna(mut self, antenna: u8) -> Self {
452 self.antenna = Some(antenna);
453 self
454 }
455
456 pub fn build(&self) -> Vec<u8> {
458 let mut present: u32 = 0;
459 let mut fields_data = Vec::new();
460
461 if let Some(tsft) = self.tsft {
463 present |= 1 << radiotap_present::TSFT;
464 while (8 + fields_data.len()) % 8 != 0 {
466 fields_data.push(0);
467 }
468 fields_data.extend_from_slice(&tsft.to_le_bytes());
469 }
470
471 if let Some(flags) = self.flags {
472 present |= 1 << radiotap_present::FLAGS;
473 fields_data.push(flags);
474 }
475
476 if let Some(rate) = self.rate {
477 present |= 1 << radiotap_present::RATE;
478 fields_data.push(rate);
479 }
480
481 if self.channel_freq.is_some() {
482 present |= 1 << radiotap_present::CHANNEL;
483 let header_fixed = 8; let current = header_fixed + fields_data.len();
486 if current % 2 != 0 {
487 fields_data.push(0);
488 }
489 fields_data.extend_from_slice(&self.channel_freq.unwrap_or(0).to_le_bytes());
490 fields_data.extend_from_slice(&self.channel_flags.unwrap_or(0).to_le_bytes());
491 }
492
493 if let Some(signal) = self.dbm_ant_signal {
494 present |= 1 << radiotap_present::DBM_ANT_SIGNAL;
495 fields_data.push(signal as u8);
496 }
497
498 if let Some(noise) = self.dbm_ant_noise {
499 present |= 1 << radiotap_present::DBM_ANT_NOISE;
500 fields_data.push(noise as u8);
501 }
502
503 if let Some(antenna) = self.antenna {
504 present |= 1 << radiotap_present::ANTENNA;
505 fields_data.push(antenna);
506 }
507
508 let total_len = (8 + fields_data.len()) as u16;
509
510 let mut out = Vec::with_capacity(total_len as usize);
511 out.push(0); out.push(0); out.extend_from_slice(&total_len.to_le_bytes());
514 out.extend_from_slice(&present.to_le_bytes());
515 out.extend_from_slice(&fields_data);
516
517 out
518 }
519}
520
521#[cfg(test)]
522mod tests {
523 use super::*;
524
525 fn make_minimal_radiotap() -> Vec<u8> {
527 vec![
528 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ]
533 }
534
535 fn make_radiotap_with_fields() -> Vec<u8> {
537 let present: u32 = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 5);
540 let mut buf = Vec::new();
541 buf.push(0x00); buf.push(0x00); let fields_len = 1 + 1 + 4 + 1; let total_len: u16 = 8 + fields_len;
550 buf.extend_from_slice(&total_len.to_le_bytes());
551 buf.extend_from_slice(&present.to_le_bytes());
552
553 buf.push(0x10); buf.push(0x0C); buf.extend_from_slice(&2437u16.to_le_bytes()); buf.extend_from_slice(&0x00A0u16.to_le_bytes()); buf.push(0xCE_u8); buf
564 }
565
566 #[test]
567 fn test_minimal_radiotap() {
568 let buf = make_minimal_radiotap();
569 let layer = RadioTapLayer::new(0, buf.len());
570
571 assert_eq!(layer.version(&buf).unwrap(), 0);
572 assert_eq!(layer.pad(&buf).unwrap(), 0);
573 assert_eq!(layer.header_length(&buf).unwrap(), 8);
574 assert_eq!(layer.present(&buf).unwrap(), 0);
575 }
576
577 #[test]
578 fn test_radiotap_with_fields() {
579 let buf = make_radiotap_with_fields();
580 let layer = RadioTapLayer::new(0, buf.len());
581
582 assert_eq!(layer.version(&buf).unwrap(), 0);
583 let present = layer.present(&buf).unwrap();
584 assert!(present & (1 << radiotap_present::FLAGS) != 0);
585 assert!(present & (1 << radiotap_present::RATE) != 0);
586 assert!(present & (1 << radiotap_present::CHANNEL) != 0);
587
588 let fields = layer.parse_fields(&buf).unwrap();
589 assert_eq!(fields.flags, Some(0x10));
590 assert_eq!(fields.rate, Some(0x0C));
591 assert_eq!(fields.channel_freq, Some(2437));
592 assert_eq!(fields.dbm_ant_signal, Some(-50));
593 }
594
595 #[test]
596 fn test_has_fcs() {
597 let buf = make_radiotap_with_fields();
598 let layer = RadioTapLayer::new(0, buf.len());
599 assert!(layer.has_fcs(&buf)); }
601
602 #[test]
603 fn test_header_len_trait() {
604 let buf = make_radiotap_with_fields();
605 let layer = RadioTapLayer::new(0, buf.len());
606 assert_eq!(layer.header_len(&buf), 15);
607 }
608
609 #[test]
610 fn test_summary() {
611 let buf = make_radiotap_with_fields();
612 let layer = RadioTapLayer::new(0, buf.len());
613 let s = layer.summary(&buf);
614 assert!(s.contains("RadioTap"));
615 assert!(s.contains("len="));
616 }
617
618 #[test]
619 fn test_builder_minimal() {
620 let header = RadioTapBuilder::new().build();
621 assert_eq!(header.len(), 8);
622 assert_eq!(header[0], 0); assert_eq!(u16::from_le_bytes([header[2], header[3]]), 8); assert_eq!(
625 u32::from_le_bytes([header[4], header[5], header[6], header[7]]),
626 0
627 ); }
629
630 #[test]
631 fn test_builder_with_fields() {
632 let header = RadioTapBuilder::new()
633 .flags(0x10)
634 .rate(12)
635 .channel(2437, 0x00A0)
636 .dbm_ant_signal(-50)
637 .build();
638
639 let layer = RadioTapLayer::new(0, header.len());
640 assert_eq!(layer.version(&header).unwrap(), 0);
641 let present = layer.present(&header).unwrap();
642 assert!(present & (1 << radiotap_present::FLAGS) != 0);
643 assert!(present & (1 << radiotap_present::RATE) != 0);
644 assert!(present & (1 << radiotap_present::CHANNEL) != 0);
645 assert!(present & (1 << radiotap_present::DBM_ANT_SIGNAL) != 0);
646
647 let fields = layer.parse_fields(&header).unwrap();
648 assert_eq!(fields.flags, Some(0x10));
649 assert_eq!(fields.rate, Some(12));
650 assert_eq!(fields.channel_freq, Some(2437));
651 assert_eq!(fields.dbm_ant_signal, Some(-50));
652 }
653
654 #[test]
655 fn test_roundtrip_builder_parse() {
656 let header = RadioTapBuilder::new()
657 .flags(0x02) .rate(22) .antenna(1)
660 .build();
661
662 let layer = RadioTapLayer::new(0, header.len());
663 let fields = layer.parse_fields(&header).unwrap();
664 assert_eq!(fields.flags, Some(0x02));
665 assert_eq!(fields.rate, Some(22));
666 assert_eq!(fields.antenna, Some(1));
667 }
668
669 #[test]
670 fn test_extended_present_words() {
671 let mut buf = vec![0u8; 16];
673 buf[0] = 0x00; buf[1] = 0x00; buf[2] = 0x10; buf[3] = 0x00;
677 let present1: u32 = 1 << 31;
679 buf[4..8].copy_from_slice(&present1.to_le_bytes());
680 buf[8..12].copy_from_slice(&0u32.to_le_bytes());
682 buf[12..16].copy_from_slice(&[0; 4]);
684
685 let layer = RadioTapLayer::new(0, buf.len());
686 assert_eq!(layer.count_present_words(&buf), 2);
687 }
688}