1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 /// Produce PCAP Radiotap buffers from Hwsim Frames
16 ///
17 /// This module produces the Radiotap buffers used by PCAP and PcapNG
18 /// for logging 802.11 frames.
19 ///
20 /// See https://www.radiotap.org/
21 use crate::wifi::frame::Frame;
22 use crate::wifi::medium;
23 use crate::wifi::medium::HwsimCmdEnum;
24 use log::info;
25
26 #[repr(C, packed)]
27 struct RadiotapHeader {
28 version: u8,
29 pad: u8,
30 len: u16,
31 present: u32,
32 channel: ChannelInfo,
33 signal: u8,
34 }
35
36 #[repr(C)]
37 struct ChannelInfo {
38 freq: u16,
39 flags: u16,
40 }
41
into_pcap(packet: &[u8]) -> Option<Vec<u8>>42 pub fn into_pcap(packet: &[u8]) -> Option<Vec<u8>> {
43 match medium::parse_hwsim_cmd(packet) {
44 Ok(HwsimCmdEnum::Frame(frame)) => frame_into_pcap(*frame).ok(),
45 Ok(_) => None,
46 Err(e) => {
47 info!("Failed to convert packet to pcap format. Err: {}. Packet: {:?}", e, &packet);
48 None
49 }
50 }
51 }
52
frame_into_pcap(frame: Frame) -> anyhow::Result<Vec<u8>>53 pub fn frame_into_pcap(frame: Frame) -> anyhow::Result<Vec<u8>> {
54 // Create an instance of the RadiotapHeader with fields for
55 // Channel and Signal. In the future add more fields from the
56 // Frame.
57
58 let radiotap_hdr: RadiotapHeader = RadiotapHeader {
59 version: 0,
60 pad: 0,
61 len: (std::mem::size_of::<RadiotapHeader>() as u16),
62 present: (1 << 3 /* channel */ | 1 << 5/* signal dBm */),
63 channel: ChannelInfo { freq: frame.freq.unwrap_or(0) as u16, flags: 0 },
64 signal: frame.signal.unwrap_or(0) as u8,
65 };
66
67 // Add the struct fields to the buffer manually in little-endian.
68 let mut buffer = Vec::<u8>::new();
69 buffer.push(radiotap_hdr.version);
70 buffer.push(radiotap_hdr.pad);
71 buffer.extend_from_slice(&radiotap_hdr.len.to_le_bytes());
72 buffer.extend_from_slice(&radiotap_hdr.present.to_le_bytes());
73 buffer.extend_from_slice(&radiotap_hdr.channel.freq.to_le_bytes());
74 buffer.extend_from_slice(&radiotap_hdr.channel.flags.to_le_bytes());
75 buffer.push(radiotap_hdr.signal);
76 buffer.extend_from_slice(&frame.data);
77
78 Ok(buffer)
79 }
80