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 #[must_use]
106 pub fn new(start: usize, end: usize) -> Self {
107 Self {
108 index: LayerIndex::new(LayerKind::Dot11, start, end),
109 }
110 }
111
112 pub fn validate(buf: &[u8], offset: usize) -> Result<(), FieldError> {
114 if buf.len() < offset + RADIOTAP_MIN_HEADER_LEN {
115 return Err(FieldError::BufferTooShort {
116 offset,
117 need: RADIOTAP_MIN_HEADER_LEN,
118 have: buf.len().saturating_sub(offset),
119 });
120 }
121 Ok(())
122 }
123
124 #[inline]
130 pub fn version(&self, buf: &[u8]) -> Result<u8, FieldError> {
131 let off = self.index.start + offsets::VERSION;
132 if buf.len() <= off {
133 return Err(FieldError::BufferTooShort {
134 offset: off,
135 need: 1,
136 have: buf.len(),
137 });
138 }
139 Ok(buf[off])
140 }
141
142 #[inline]
144 pub fn pad(&self, buf: &[u8]) -> Result<u8, FieldError> {
145 let off = self.index.start + offsets::PAD;
146 if buf.len() <= off {
147 return Err(FieldError::BufferTooShort {
148 offset: off,
149 need: 1,
150 have: buf.len(),
151 });
152 }
153 Ok(buf[off])
154 }
155
156 #[inline]
158 pub fn header_length(&self, buf: &[u8]) -> Result<u16, FieldError> {
159 let off = self.index.start + offsets::LENGTH;
160 if buf.len() < off + 2 {
161 return Err(FieldError::BufferTooShort {
162 offset: off,
163 need: 2,
164 have: buf.len(),
165 });
166 }
167 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
168 }
169
170 #[inline]
172 pub fn present(&self, buf: &[u8]) -> Result<u32, FieldError> {
173 let off = self.index.start + offsets::PRESENT;
174 if buf.len() < off + 4 {
175 return Err(FieldError::BufferTooShort {
176 offset: off,
177 need: 4,
178 have: buf.len(),
179 });
180 }
181 Ok(u32::from_le_bytes([
182 buf[off],
183 buf[off + 1],
184 buf[off + 2],
185 buf[off + 3],
186 ]))
187 }
188
189 #[inline]
191 #[must_use]
192 pub fn has_field(&self, buf: &[u8], bit: u32) -> bool {
193 self.present(buf)
194 .map(|p| p & (1 << bit) != 0)
195 .unwrap_or(false)
196 }
197
198 #[must_use]
200 pub fn has_fcs(&self, buf: &[u8]) -> bool {
201 if self.has_field(buf, radiotap_present::FLAGS)
202 && let Ok(fields) = self.parse_fields(buf)
203 && let Some(flags) = fields.flags
204 {
205 return flags & super::types::radiotap_flags::FCS != 0;
206 }
207 false
208 }
209
210 fn count_present_words(&self, buf: &[u8]) -> usize {
216 let mut count = 1;
217 let mut off = self.index.start + offsets::PRESENT;
218
219 loop {
220 if buf.len() < off + 4 {
221 break;
222 }
223 let word = u32::from_le_bytes([buf[off], buf[off + 1], buf[off + 2], buf[off + 3]]);
224 if word & (1 << radiotap_present::EXT) == 0 {
225 break;
226 }
227 count += 1;
228 off += 4;
229 }
230 count
231 }
232
233 pub fn parse_fields(&self, buf: &[u8]) -> Result<RadioTapFields, FieldError> {
235 let present = self.present(buf)?;
236 let header_len = self.header_length(buf)? as usize;
237 let start = self.index.start;
238
239 if buf.len() < start + header_len {
240 return Err(FieldError::BufferTooShort {
241 offset: start,
242 need: header_len,
243 have: buf.len().saturating_sub(start),
244 });
245 }
246
247 let num_present_words = self.count_present_words(buf);
248 let mut pos = start + 4 + (num_present_words * 4);
250 let end = start + header_len;
251 let mut fields = RadioTapFields::default();
252
253 for bit in 0..28u32 {
255 if present & (1 << bit) == 0 {
256 continue;
257 }
258
259 let (size, align) = field_alignment(bit);
260 if size == 0 {
261 continue;
262 }
263
264 if align > 1 {
266 let base = start + 4 + (num_present_words * 4);
267 let relative = pos - base;
268 let _padding = (align - (relative % align)) % align;
269 let abs_padding = (align - ((pos - start) % align)) % align;
271 pos += abs_padding;
272 }
273
274 if pos + size > end {
275 break;
276 }
277
278 match bit {
279 radiotap_present::TSFT => {
280 fields.tsft = Some(u64::from_le_bytes([
281 buf[pos],
282 buf[pos + 1],
283 buf[pos + 2],
284 buf[pos + 3],
285 buf[pos + 4],
286 buf[pos + 5],
287 buf[pos + 6],
288 buf[pos + 7],
289 ]));
290 },
291 radiotap_present::FLAGS => {
292 fields.flags = Some(buf[pos]);
293 },
294 radiotap_present::RATE => {
295 fields.rate = Some(buf[pos]);
296 },
297 radiotap_present::CHANNEL => {
298 fields.channel_freq = Some(u16::from_le_bytes([buf[pos], buf[pos + 1]]));
299 fields.channel_flags = Some(u16::from_le_bytes([buf[pos + 2], buf[pos + 3]]));
300 },
301 radiotap_present::DBM_ANT_SIGNAL => {
302 fields.dbm_ant_signal = Some(buf[pos] as i8);
303 },
304 radiotap_present::DBM_ANT_NOISE => {
305 fields.dbm_ant_noise = Some(buf[pos] as i8);
306 },
307 radiotap_present::LOCK_QUALITY => {
308 fields.lock_quality = Some(u16::from_le_bytes([buf[pos], buf[pos + 1]]));
309 },
310 radiotap_present::ANTENNA => {
311 fields.antenna = Some(buf[pos]);
312 },
313 radiotap_present::DB_ANT_SIGNAL => {
314 fields.db_ant_signal = Some(buf[pos]);
315 },
316 radiotap_present::DB_ANT_NOISE => {
317 fields.db_ant_noise = Some(buf[pos]);
318 },
319 radiotap_present::RX_FLAGS => {
320 fields.rx_flags = Some(u16::from_le_bytes([buf[pos], buf[pos + 1]]));
321 },
322 radiotap_present::TX_FLAGS => {
323 fields.tx_flags = Some(u16::from_le_bytes([buf[pos], buf[pos + 1]]));
324 },
325 radiotap_present::MCS => {
326 fields.mcs_known = Some(buf[pos]);
327 fields.mcs_flags = Some(buf[pos + 1]);
328 fields.mcs_index = Some(buf[pos + 2]);
329 },
330 radiotap_present::A_MPDU => {
331 fields.a_mpdu_ref = Some(u32::from_le_bytes([
332 buf[pos],
333 buf[pos + 1],
334 buf[pos + 2],
335 buf[pos + 3],
336 ]));
337 fields.a_mpdu_flags = Some(u32::from_le_bytes([
338 buf[pos + 4],
339 buf[pos + 5],
340 buf[pos + 6],
341 buf[pos + 7],
342 ]));
343 },
344 _ => {},
345 }
346
347 pos += size;
348 }
349
350 Ok(fields)
351 }
352}
353
354impl Layer for RadioTapLayer {
355 fn kind(&self) -> LayerKind {
356 LayerKind::Dot11
357 }
358
359 fn summary(&self, buf: &[u8]) -> String {
360 let len = self
361 .header_length(buf)
362 .map_or_else(|_| "?".to_string(), |l| l.to_string());
363 let present = self
364 .present(buf)
365 .map_or_else(|_| "?".to_string(), |p| format!("{p:#010x}"));
366 format!("RadioTap len={len} present={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 #[must_use]
417 pub fn new() -> Self {
418 Self::default()
419 }
420
421 #[must_use]
422 pub fn tsft(mut self, tsft: u64) -> Self {
423 self.tsft = Some(tsft);
424 self
425 }
426
427 #[must_use]
428 pub fn flags(mut self, flags: u8) -> Self {
429 self.flags = Some(flags);
430 self
431 }
432
433 #[must_use]
434 pub fn rate(mut self, rate: u8) -> Self {
435 self.rate = Some(rate);
436 self
437 }
438
439 #[must_use]
440 pub fn channel(mut self, freq: u16, flags: u16) -> Self {
441 self.channel_freq = Some(freq);
442 self.channel_flags = Some(flags);
443 self
444 }
445
446 #[must_use]
447 pub fn dbm_ant_signal(mut self, signal: i8) -> Self {
448 self.dbm_ant_signal = Some(signal);
449 self
450 }
451
452 #[must_use]
453 pub fn dbm_ant_noise(mut self, noise: i8) -> Self {
454 self.dbm_ant_noise = Some(noise);
455 self
456 }
457
458 #[must_use]
459 pub fn antenna(mut self, antenna: u8) -> Self {
460 self.antenna = Some(antenna);
461 self
462 }
463
464 #[must_use]
466 pub fn build(&self) -> Vec<u8> {
467 let mut present: u32 = 0;
468 let mut fields_data = Vec::new();
469
470 if let Some(tsft) = self.tsft {
472 present |= 1 << radiotap_present::TSFT;
473 while (8 + fields_data.len()) % 8 != 0 {
475 fields_data.push(0);
476 }
477 fields_data.extend_from_slice(&tsft.to_le_bytes());
478 }
479
480 if let Some(flags) = self.flags {
481 present |= 1 << radiotap_present::FLAGS;
482 fields_data.push(flags);
483 }
484
485 if let Some(rate) = self.rate {
486 present |= 1 << radiotap_present::RATE;
487 fields_data.push(rate);
488 }
489
490 if self.channel_freq.is_some() {
491 present |= 1 << radiotap_present::CHANNEL;
492 let header_fixed = 8; let current = header_fixed + fields_data.len();
495 if current % 2 != 0 {
496 fields_data.push(0);
497 }
498 fields_data.extend_from_slice(&self.channel_freq.unwrap_or(0).to_le_bytes());
499 fields_data.extend_from_slice(&self.channel_flags.unwrap_or(0).to_le_bytes());
500 }
501
502 if let Some(signal) = self.dbm_ant_signal {
503 present |= 1 << radiotap_present::DBM_ANT_SIGNAL;
504 fields_data.push(signal as u8);
505 }
506
507 if let Some(noise) = self.dbm_ant_noise {
508 present |= 1 << radiotap_present::DBM_ANT_NOISE;
509 fields_data.push(noise as u8);
510 }
511
512 if let Some(antenna) = self.antenna {
513 present |= 1 << radiotap_present::ANTENNA;
514 fields_data.push(antenna);
515 }
516
517 let total_len = (8 + fields_data.len()) as u16;
518
519 let mut out = Vec::with_capacity(total_len as usize);
520 out.push(0); out.push(0); out.extend_from_slice(&total_len.to_le_bytes());
523 out.extend_from_slice(&present.to_le_bytes());
524 out.extend_from_slice(&fields_data);
525
526 out
527 }
528}
529
530#[cfg(test)]
531mod tests {
532 use super::*;
533
534 fn make_minimal_radiotap() -> Vec<u8> {
536 vec![
537 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ]
542 }
543
544 fn make_radiotap_with_fields() -> Vec<u8> {
546 let present: u32 = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 5);
549 let mut buf = Vec::new();
550 buf.push(0x00); buf.push(0x00); let fields_len = 1 + 1 + 4 + 1; let total_len: u16 = 8 + fields_len;
559 buf.extend_from_slice(&total_len.to_le_bytes());
560 buf.extend_from_slice(&present.to_le_bytes());
561
562 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
573 }
574
575 #[test]
576 fn test_minimal_radiotap() {
577 let buf = make_minimal_radiotap();
578 let layer = RadioTapLayer::new(0, buf.len());
579
580 assert_eq!(layer.version(&buf).unwrap(), 0);
581 assert_eq!(layer.pad(&buf).unwrap(), 0);
582 assert_eq!(layer.header_length(&buf).unwrap(), 8);
583 assert_eq!(layer.present(&buf).unwrap(), 0);
584 }
585
586 #[test]
587 fn test_radiotap_with_fields() {
588 let buf = make_radiotap_with_fields();
589 let layer = RadioTapLayer::new(0, buf.len());
590
591 assert_eq!(layer.version(&buf).unwrap(), 0);
592 let present = layer.present(&buf).unwrap();
593 assert!(present & (1 << radiotap_present::FLAGS) != 0);
594 assert!(present & (1 << radiotap_present::RATE) != 0);
595 assert!(present & (1 << radiotap_present::CHANNEL) != 0);
596
597 let fields = layer.parse_fields(&buf).unwrap();
598 assert_eq!(fields.flags, Some(0x10));
599 assert_eq!(fields.rate, Some(0x0C));
600 assert_eq!(fields.channel_freq, Some(2437));
601 assert_eq!(fields.dbm_ant_signal, Some(-50));
602 }
603
604 #[test]
605 fn test_has_fcs() {
606 let buf = make_radiotap_with_fields();
607 let layer = RadioTapLayer::new(0, buf.len());
608 assert!(layer.has_fcs(&buf)); }
610
611 #[test]
612 fn test_header_len_trait() {
613 let buf = make_radiotap_with_fields();
614 let layer = RadioTapLayer::new(0, buf.len());
615 assert_eq!(layer.header_len(&buf), 15);
616 }
617
618 #[test]
619 fn test_summary() {
620 let buf = make_radiotap_with_fields();
621 let layer = RadioTapLayer::new(0, buf.len());
622 let s = layer.summary(&buf);
623 assert!(s.contains("RadioTap"));
624 assert!(s.contains("len="));
625 }
626
627 #[test]
628 fn test_builder_minimal() {
629 let header = RadioTapBuilder::new().build();
630 assert_eq!(header.len(), 8);
631 assert_eq!(header[0], 0); assert_eq!(u16::from_le_bytes([header[2], header[3]]), 8); assert_eq!(
634 u32::from_le_bytes([header[4], header[5], header[6], header[7]]),
635 0
636 ); }
638
639 #[test]
640 fn test_builder_with_fields() {
641 let header = RadioTapBuilder::new()
642 .flags(0x10)
643 .rate(12)
644 .channel(2437, 0x00A0)
645 .dbm_ant_signal(-50)
646 .build();
647
648 let layer = RadioTapLayer::new(0, header.len());
649 assert_eq!(layer.version(&header).unwrap(), 0);
650 let present = layer.present(&header).unwrap();
651 assert!(present & (1 << radiotap_present::FLAGS) != 0);
652 assert!(present & (1 << radiotap_present::RATE) != 0);
653 assert!(present & (1 << radiotap_present::CHANNEL) != 0);
654 assert!(present & (1 << radiotap_present::DBM_ANT_SIGNAL) != 0);
655
656 let fields = layer.parse_fields(&header).unwrap();
657 assert_eq!(fields.flags, Some(0x10));
658 assert_eq!(fields.rate, Some(12));
659 assert_eq!(fields.channel_freq, Some(2437));
660 assert_eq!(fields.dbm_ant_signal, Some(-50));
661 }
662
663 #[test]
664 fn test_roundtrip_builder_parse() {
665 let header = RadioTapBuilder::new()
666 .flags(0x02) .rate(22) .antenna(1)
669 .build();
670
671 let layer = RadioTapLayer::new(0, header.len());
672 let fields = layer.parse_fields(&header).unwrap();
673 assert_eq!(fields.flags, Some(0x02));
674 assert_eq!(fields.rate, Some(22));
675 assert_eq!(fields.antenna, Some(1));
676 }
677
678 #[test]
679 fn test_extended_present_words() {
680 let mut buf = vec![0u8; 16];
682 buf[0] = 0x00; buf[1] = 0x00; buf[2] = 0x10; buf[3] = 0x00;
686 let present1: u32 = 1 << 31;
688 buf[4..8].copy_from_slice(&present1.to_le_bytes());
689 buf[8..12].copy_from_slice(&0u32.to_le_bytes());
691 buf[12..16].copy_from_slice(&[0; 4]);
693
694 let layer = RadioTapLayer::new(0, buf.len());
695 assert_eq!(layer.count_present_words(&buf), 2);
696 }
697}