c_its_parser/pcap/mod.rs
1use alloc::string::ToString;
2
3/// Strips Radiotap, IEEE 802.11p and LLC headers from a binary message buffer
4///
5/// Convenience function combining [`remove_radiotap_hdr`], [`remove_80211_hdr`] and [`remove_llc_hdr`].
6///
7/// # Errors
8/// Returns a human-readable error when parsing failed
9pub fn remove_pcap_headers(data: &[u8]) -> Result<&[u8], alloc::string::String> {
10 remove_radiotap_hdr(data).and_then(remove_wlan_headers)
11}
12
13/// Strips IEEE 802.11p and LLC headers from a binary message buffer
14///
15/// Convenience function combining [`remove_80211_hdr`] and [`remove_llc_hdr`].
16///
17/// IEEE 802.11 data frames always have an LLC header.
18/// Since `remove_80211_hdr` only allows data frames, we usually need to remove them, too.
19///
20/// # Errors
21/// Returns a human-readable error when parsing failed
22pub fn remove_wlan_headers(data: &[u8]) -> Result<&[u8], alloc::string::String> {
23 remove_80211_hdr(data).and_then(remove_llc_hdr)
24}
25
26/// Strips Radiotap header from a binary message buffer
27///
28/// # Errors
29/// Return a human-readable error when parsing failed
30pub fn remove_radiotap_hdr(data: &[u8]) -> Result<&[u8], alloc::string::String> {
31 extract_radiotap_hdr(data).map(|(_, remaining)| remaining)
32}
33
34/// Extracts Radiotap header from a binary message buffer and returns the header and remaining buffer
35///
36/// # Errors
37/// Return a human-readable error when parsing failed
38pub fn extract_radiotap_hdr(data: &[u8]) -> Result<(&[u8], &[u8]), alloc::string::String> {
39 /*
40 * Radiotap Header has the following format
41 * - u_int8_t header version (currently always zero)
42 * - u_int8_t (padding for byte alignment);
43 * - u_int16_t entire header length;
44 * - u_int32_t bitmask which subsequent data is present
45 */
46
47 let radiotap_version: u8 = data[0];
48 if radiotap_version != 0 {
49 return Err(alloc::format!(
50 "Unknown header version {radiotap_version:#x}"
51 ));
52 }
53
54 let hdr_len: usize = u16::from_le_bytes([data[2], data[3]]).into();
55 Ok(data.split_at(hdr_len))
56}
57
58/// Strips IEEE 802.11p header from a binary message buffer
59///
60/// # Errors
61/// Return a human-readable error when parsing failed
62pub fn remove_80211_hdr(data: &[u8]) -> Result<&[u8], alloc::string::String> {
63 extract_80211_hdr(data).map(|(_, remaining)| remaining)
64}
65
66/// Extracts IEEE 802.11p header from a binary message buffer and returns the header and remaining buffer
67///
68/// # Errors
69/// Return a human-readable error when parsing failed
70pub fn extract_80211_hdr(data: &[u8]) -> Result<(&[u8], &[u8]), alloc::string::String> {
71 /*
72 * IEEE 802.11 Header has the following format (24-26 bytes)
73 * - 2 bytes frame control
74 * byte 0: .... ..00: Version 0
75 * byte 0: .... 10..: Type data frame
76 * byte 0: 1000 ....: QoS Data (or 0 for non-QoS data)
77 * - 2 bytes duration
78 * - 6 bytes addr 1 (receiver)
79 * - 6 bytes addr 2 (transmitter)
80 * - 6 bytes addr 3 (BSSID)
81 * - 2 bytes sequence control
82 * - addr 4 not used in 802.11p mode
83 * - 0 or 2 bytes QOS control
84 * - HT control not used in 802.11p mode
85 */
86
87 let ieee80211_framecontrol: u8 = data[0];
88
89 let ieee80211_fc_version: u8 = ieee80211_framecontrol & 0x03; // 0000.00xx
90 if ieee80211_fc_version != 0 {
91 return Err(
92 alloc::format!("Unknown 802.11 header version {ieee80211_fc_version}").to_string(),
93 );
94 }
95
96 let ieee80211_fc_type: u8 = (ieee80211_framecontrol & 0x0c) >> 2; // 0000.xx00
97 if ieee80211_fc_type != 0b10 {
98 // only select data frames
99 return Err(
100 alloc::format!("Unsupported 802.11 frame type {ieee80211_fc_type}").to_string(),
101 );
102 }
103
104 let ieee80211_fc_subtype: u8 = (ieee80211_framecontrol & 0xf0) >> 4; // xxxx.0000
105 let qos_hdr_bytes = if ieee80211_fc_subtype == 0b1000 {
106 2
107 } else if ieee80211_fc_subtype == 0b0000 {
108 0
109 } else {
110 // only select QoS or "normal" data frames
111 return Err(
112 alloc::format!("Unsupported 802.11 frame subtype {ieee80211_fc_subtype:#04x}")
113 .to_string(),
114 );
115 };
116
117 let hdr_len: usize = 24 + qos_hdr_bytes;
118 Ok(data.split_at(hdr_len))
119}
120
121/// Strips LLC header from a binary message buffer
122///
123/// # Errors
124/// Return a human-readable error when parsing failed
125pub fn remove_llc_hdr(data: &[u8]) -> Result<&[u8], alloc::string::String> {
126 extract_llc_hdr(data).map(|(_, remaining)| remaining)
127}
128
129/// Extracts LLC header from a binary message buffer and returns the header and remaining buffer
130///
131/// # Errors
132/// Return a human-readable error when parsing failed
133pub fn extract_llc_hdr(data: &[u8]) -> Result<(&[u8], &[u8]), alloc::string::String> {
134 /*
135 * LLC Header has the following format (8 bytes)
136 * - 1 bytes DSAP
137 * - 1 bytes SSAP
138 * - 1 bytes control field
139 * - 3 bytes organization code
140 * - 2 bytes Type (0x8947 BE is GeoNetworking)
141 */
142
143 let llc_type: u16 = (u16::from(data[6]) << 8) | u16::from(data[7]);
144
145 if llc_type != 0x8947 {
146 return Err(alloc::format!("Unknown LLC payload type {llc_type:#x}").to_string());
147 }
148
149 let hdr_len: usize = 8; // TODO: Is this the right size?
150 Ok(data.split_at(hdr_len))
151}