• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #![allow(clippy::empty_line_after_doc_comments)]
16 
17 use std::fmt;
18 
19 use anyhow::{anyhow, Context};
20 use netsim_packets::ieee80211::MacAddress;
21 use netsim_packets::mac80211_hwsim::{self, HwsimAttr, HwsimAttrChild::*, TxRate, TxRateFlag};
22 use netsim_packets::netlink::NlAttrHdr;
23 use pdl_runtime::Packet;
24 use std::option::Option;
25 
26 /// Parse or Build the Hwsim attributes into a set.
27 ///
28 /// Hwsim attributes are used to exchange data between kernel's
29 /// mac80211_hwsim subsystem and a user space process and include:
30 ///
31 ///   HWSIM_ATTR_ADDR_TRANSMITTER,
32 ///   HWSIM_ATTR_ADDR_RECEIVER,
33 ///   HWSIM_ATTR_FRAME,
34 ///   HWSIM_ATTR_FLAGS,
35 ///   HWSIM_ATTR_RX_RATE,
36 ///   HWSIM_ATTR_SIGNAL,
37 ///   HWSIM_ATTR_COOKIE,
38 ///   HWSIM_ATTR_FREQ (optional)
39 ///   HWSIM_ATTR_TX_INFO (new use)
40 ///   HWSIM_ATTR_TX_INFO_FLAGS (new use)
41 
42 /// Aligns a length to the specified alignment boundary (`NLA_ALIGNTO`).
43 ///
44 /// # Arguments
45 ///
46 /// * `array_length`: The length in bytes to be aligned.
47 ///
48 /// # Returns
49 ///
50 /// * The aligned length, which is a multiple of `NLA_ALIGNTO`.
51 ///
nla_align(array_length: usize) -> usize52 fn nla_align(array_length: usize) -> usize {
53     const NLA_ALIGNTO: usize = 4;
54     array_length.wrapping_add(NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1)
55 }
56 
57 #[derive(Default)]
58 pub struct HwsimAttrSetBuilder {
59     transmitter: Option<MacAddress>,
60     receiver: Option<MacAddress>,
61     frame: Option<Vec<u8>>,
62     flags: Option<u32>,
63     rx_rate_idx: Option<u32>,
64     signal: Option<u32>,
65     cookie: Option<u64>,
66     freq: Option<u32>,
67     tx_info: Option<Vec<TxRate>>,
68     tx_info_flags: Option<Vec<TxRateFlag>>,
69     attributes: Vec<u8>,
70 }
71 
72 #[derive(Debug)]
73 pub struct HwsimAttrSet {
74     pub transmitter: Option<MacAddress>,
75     pub receiver: Option<MacAddress>,
76     pub frame: Option<Vec<u8>>,
77     pub flags: Option<u32>,
78     pub rx_rate_idx: Option<u32>,
79     pub signal: Option<u32>,
80     pub cookie: Option<u64>,
81     pub freq: Option<u32>,
82     pub tx_info: Option<Vec<TxRate>>,
83     pub tx_info_flags: Option<Vec<TxRateFlag>>,
84     pub attributes: Vec<u8>,
85 }
86 
87 /// Builder pattern for each of the HWSIM_ATTR used in conjunction
88 /// with the HwsimAttr packet formats defined in `mac80211_hwsim.pdl`
89 ///
90 /// Used during `parse` or to create new HwsimCmd packets containing
91 /// an attributes vector.
92 ///
93 /// The attributes field will contain the raw bytes in NLA format
94 /// in the order of method calls.
95 impl HwsimAttrSetBuilder {
96     // Add packet to the attributes vec and pad for proper NLA
97     // alignment. This provides for to_bytes for a HwsimMsg for
98     // packets constructed by the Builder.
99 
extend_attributes<P: Packet>(&mut self, packet: P)100     fn extend_attributes<P: Packet>(&mut self, packet: P) {
101         let mut vec: Vec<u8> = packet.encode_to_vec().unwrap();
102         let nla_padding = nla_align(vec.len()) - vec.len();
103         vec.extend(vec![0; nla_padding]);
104         self.attributes.extend(vec);
105     }
106 
transmitter(&mut self, transmitter: &[u8; 6]) -> &mut Self107     pub fn transmitter(&mut self, transmitter: &[u8; 6]) -> &mut Self {
108         self.extend_attributes(mac80211_hwsim::HwsimAttrAddrTransmitter {
109             address: *transmitter,
110             nla_m: 0,
111             nla_o: 0,
112         });
113         self.transmitter = Some(MacAddress::from(transmitter));
114         self
115     }
116 
receiver(&mut self, receiver: &[u8; 6]) -> &mut Self117     pub fn receiver(&mut self, receiver: &[u8; 6]) -> &mut Self {
118         self.extend_attributes(mac80211_hwsim::HwsimAttrAddrReceiver {
119             address: *receiver,
120             nla_m: 0,
121             nla_o: 0,
122         });
123         self.receiver = Some(MacAddress::from(receiver));
124         self
125     }
126 
frame(&mut self, frame: &[u8]) -> &mut Self127     pub fn frame(&mut self, frame: &[u8]) -> &mut Self {
128         self.extend_attributes(mac80211_hwsim::HwsimAttrFrame {
129             data: (*frame).to_vec(),
130             nla_m: 0,
131             nla_o: 0,
132         });
133         self.frame = Some(frame.to_vec());
134         self
135     }
136 
flags(&mut self, flags: u32) -> &mut Self137     pub fn flags(&mut self, flags: u32) -> &mut Self {
138         self.extend_attributes(mac80211_hwsim::HwsimAttrFlags { flags, nla_m: 0, nla_o: 0 });
139         self.flags = Some(flags);
140         self
141     }
142 
rx_rate(&mut self, rx_rate_idx: u32) -> &mut Self143     pub fn rx_rate(&mut self, rx_rate_idx: u32) -> &mut Self {
144         self.extend_attributes(mac80211_hwsim::HwsimAttrRxRate { rx_rate_idx, nla_m: 0, nla_o: 0 });
145         self.rx_rate_idx = Some(rx_rate_idx);
146         self
147     }
148 
signal(&mut self, signal: u32) -> &mut Self149     pub fn signal(&mut self, signal: u32) -> &mut Self {
150         self.extend_attributes(mac80211_hwsim::HwsimAttrSignal { signal, nla_m: 0, nla_o: 0 });
151         self.signal = Some(signal);
152         self
153     }
154 
cookie(&mut self, cookie: u64) -> &mut Self155     pub fn cookie(&mut self, cookie: u64) -> &mut Self {
156         self.extend_attributes(mac80211_hwsim::HwsimAttrCookie { cookie, nla_m: 0, nla_o: 0 });
157         self.cookie = Some(cookie);
158         self
159     }
160 
freq(&mut self, freq: u32) -> &mut Self161     pub fn freq(&mut self, freq: u32) -> &mut Self {
162         self.extend_attributes(mac80211_hwsim::HwsimAttrFreq { freq, nla_m: 0, nla_o: 0 });
163         self.freq = Some(freq);
164         self
165     }
166 
tx_info(&mut self, tx_info: &[TxRate]) -> &mut Self167     pub fn tx_info(&mut self, tx_info: &[TxRate]) -> &mut Self {
168         self.extend_attributes(mac80211_hwsim::HwsimAttrTxInfo {
169             tx_rates: (*tx_info).to_vec(),
170             nla_m: 0,
171             nla_o: 0,
172         });
173         self.tx_info = Some(tx_info.to_vec());
174         self
175     }
176 
tx_info_flags(&mut self, tx_rate_flags: &[TxRateFlag]) -> &mut Self177     pub fn tx_info_flags(&mut self, tx_rate_flags: &[TxRateFlag]) -> &mut Self {
178         self.extend_attributes(mac80211_hwsim::HwsimAttrTxInfoFlags {
179             tx_rate_flags: (*tx_rate_flags).to_vec(),
180             nla_m: 0,
181             nla_o: 0,
182         });
183         self.tx_info_flags = Some(tx_rate_flags.to_vec());
184         self
185     }
186 
build(self) -> anyhow::Result<HwsimAttrSet>187     pub fn build(self) -> anyhow::Result<HwsimAttrSet> {
188         Ok(HwsimAttrSet {
189             transmitter: self.transmitter,
190             receiver: self.receiver,
191             cookie: self.cookie,
192             flags: self.flags,
193             rx_rate_idx: self.rx_rate_idx,
194             signal: self.signal,
195             frame: self.frame,
196             freq: self.freq,
197             tx_info: self.tx_info,
198             tx_info_flags: self.tx_info_flags,
199             attributes: self.attributes,
200         })
201     }
202 }
203 
204 impl fmt::Display for HwsimAttrSet {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result205     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206         write!(f, "{{ ")?;
207         self.transmitter.map(|v| write!(f, "transmitter: {}, ", v));
208         self.receiver.map(|v| write!(f, "receiver: {}, ", v));
209         self.cookie.map(|v| write!(f, "cookie: {}, ", v));
210         self.flags.map(|v| write!(f, "flags: {}, ", v));
211         self.rx_rate_idx.map(|v| write!(f, "rx_rate_idx: {}, ", v));
212         self.signal.map(|v| write!(f, "signal: {}, ", v));
213         self.frame.as_ref().map(|v| write!(f, "frame: {:?}, ", &v));
214         self.freq.map(|v| write!(f, "freq: {}, ", v));
215         self.tx_info.as_ref().map(|v| write!(f, "tx_info: {:?}, ", &v));
216         self.tx_info_flags.as_ref().map(|v| write!(f, "tx_info_flags: {:?}, ", &v));
217         write!(f, "}}")?;
218         Ok(())
219     }
220 }
221 
222 impl HwsimAttrSet {
223     /// Creates a new `HwsimAttrSetBuilder` with default settings, ready for configuring attributes.
224     ///
225     /// # Returns
226     ///
227     /// * A new `HwsimAttrSetBuilder` instance, initialized with default values.
228     ///
229     /// # Examples
230     ///
231     /// ```rust
232     /// let mut builder = HwsimAttrSetBuilder::builder();
233     /// builder.signal(42).cookie(32); // Example attribute configuration
234     /// let attr_set = builder.build();
235     /// ```
builder() -> HwsimAttrSetBuilder236     pub fn builder() -> HwsimAttrSetBuilder {
237         HwsimAttrSetBuilder::default()
238     }
239 
240     /// Parse and validates the attributes from a HwsimMsg command.
parse(attributes: &[u8]) -> anyhow::Result<HwsimAttrSet>241     pub fn parse(attributes: &[u8]) -> anyhow::Result<HwsimAttrSet> {
242         Self::parse_with_frame_transmitter(attributes, Option::None, Option::None)
243     }
244     /// Parse and validates the attributes from a HwsimMsg command.
245     /// Update frame and transmitter if provided.
parse_with_frame_transmitter( attributes: &[u8], frame: Option<&[u8]>, transmitter: Option<&[u8; 6]>, ) -> anyhow::Result<HwsimAttrSet>246     pub fn parse_with_frame_transmitter(
247         attributes: &[u8],
248         frame: Option<&[u8]>,
249         transmitter: Option<&[u8; 6]>,
250     ) -> anyhow::Result<HwsimAttrSet> {
251         let mut index: usize = 0;
252         let mut builder = HwsimAttrSet::builder();
253         while index < attributes.len() {
254             // Parse a generic netlink attribute to get the size
255             let nla_hdr =
256                 NlAttrHdr::decode_full(&attributes[index..index + 4]).context("NlAttrHdr")?;
257             let nla_len = nla_hdr.nla_len as usize;
258             // Now parse a single attribute at a time from the
259             // attributes to allow padding per attribute.
260             let hwsim_attr = HwsimAttr::decode_full(&attributes[index..index + nla_len])?;
261             match hwsim_attr.specialize().context("HwsimAttr")? {
262                 HwsimAttrAddrTransmitter(child) => {
263                     builder.transmitter(transmitter.unwrap_or(child.address()))
264                 }
265                 HwsimAttrAddrReceiver(child) => builder.receiver(&child.address),
266                 HwsimAttrFrame(child) => builder.frame(frame.unwrap_or(&child.data)),
267                 HwsimAttrFlags(child) => builder.flags(child.flags),
268                 HwsimAttrRxRate(child) => builder.rx_rate(child.rx_rate_idx),
269                 HwsimAttrSignal(child) => builder.signal(child.signal),
270                 HwsimAttrCookie(child) => builder.cookie(child.cookie),
271                 HwsimAttrFreq(child) => builder.freq(child.freq),
272                 HwsimAttrTxInfo(child) => builder.tx_info(&child.tx_rates),
273                 HwsimAttrTxInfoFlags(child) => builder.tx_info_flags(&child.tx_rate_flags),
274                 _ => {
275                     return Err(anyhow!(
276                         "Invalid attribute message: {:?}",
277                         hwsim_attr.nla_type as u32
278                     ))
279                 }
280             };
281             // Manually step through the attribute bytes aligning as
282             // we go because netlink aligns each attribute which isn't
283             // a feature of PDL parser.
284             index += nla_align(nla_len);
285         }
286         builder.build()
287     }
288 }
289 
290 #[cfg(test)]
291 mod tests {
292     use super::*;
293     use anyhow::Context;
294     use anyhow::Error;
295     use netsim_packets::ieee80211::parse_mac_address;
296     use netsim_packets::mac80211_hwsim::{HwsimCmd, HwsimMsg};
297 
298     // Validate `HwsimAttrSet` attribute parsing from byte vector.
299     #[test]
test_attr_set_parse()300     fn test_attr_set_parse() {
301         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame.csv");
302         let hwsim_msg = HwsimMsg::decode_full(&packet).unwrap();
303         assert_eq!(hwsim_msg.hwsim_hdr().hwsim_cmd, HwsimCmd::Frame);
304         let attrs = HwsimAttrSet::parse(hwsim_msg.attributes()).unwrap();
305 
306         // Validate each attribute parsed
307         assert_eq!(attrs.transmitter, MacAddress::try_from(11670786u64).ok());
308         assert!(attrs.receiver.is_none());
309         assert!(attrs.frame.is_some());
310         assert_eq!(attrs.flags, Some(2));
311         assert!(attrs.rx_rate_idx.is_none());
312         assert!(attrs.signal.is_none());
313         assert_eq!(attrs.cookie, Some(201));
314         assert_eq!(attrs.freq, Some(2422));
315         assert!(attrs.tx_info.is_some());
316     }
317 
318     // Validate the contents of the `attributes` bytes constructed by
319     // the Builder by matching with the bytes containing the input
320     // attributes. Confirms attribute order, packet format and
321     // padding.
322     #[test]
test_attr_set_attributes()323     fn test_attr_set_attributes() {
324         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame.csv");
325         let hwsim_msg = HwsimMsg::decode_full(&packet).unwrap();
326         assert_eq!(hwsim_msg.hwsim_hdr().hwsim_cmd, HwsimCmd::Frame);
327         let attrs = HwsimAttrSet::parse(hwsim_msg.attributes()).unwrap();
328         assert_eq!(&attrs.attributes, hwsim_msg.attributes());
329     }
330 
331     /// Validate changing frame and transmitter during the parse.
332     /// 1. Check if reinserting the same values results in identical bytes.
333     /// 2. Insert modified values, parse to bytes, and parse back again to check
334     ///    if the round trip values are identical.
335     #[test]
test_attr_set_parse_with_frame_transmitter() -> Result<(), Error>336     fn test_attr_set_parse_with_frame_transmitter() -> Result<(), Error> {
337         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame.csv");
338         let hwsim_msg = HwsimMsg::decode_full(&packet)?;
339         assert_eq!(hwsim_msg.hwsim_hdr().hwsim_cmd, HwsimCmd::Frame);
340         let attrs = HwsimAttrSet::parse(hwsim_msg.attributes())?;
341         let transmitter: [u8; 6] = attrs.transmitter.context("transmitter")?.into();
342         let mod_attrs = HwsimAttrSet::parse_with_frame_transmitter(
343             hwsim_msg.attributes(),
344             attrs.frame.as_deref(),
345             Some(&transmitter),
346         )?;
347 
348         assert_eq!(attrs.attributes, mod_attrs.attributes);
349 
350         // Change frame and transmitter.
351         let mod_frame = Some(vec![0, 1, 2, 3]);
352         let mod_transmitter: Option<[u8; 6]> =
353             Some(parse_mac_address("00:0b:85:71:20:ce").context("transmitter")?.into());
354 
355         let mod_attrs = HwsimAttrSet::parse_with_frame_transmitter(
356             &attrs.attributes,
357             mod_frame.as_deref(),
358             mod_transmitter.as_ref(),
359         )?;
360 
361         let parsed_attrs = HwsimAttrSet::parse(&mod_attrs.attributes)?;
362         assert_eq!(parsed_attrs.transmitter, mod_transmitter.map(|t| MacAddress::from(&t)));
363         assert_eq!(parsed_attrs.frame, mod_frame);
364         Ok(())
365     }
366 
367     #[test]
test_hwsim_attr_set_display()368     fn test_hwsim_attr_set_display() {
369         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame.csv");
370         let hwsim_msg = HwsimMsg::decode_full(&packet).unwrap();
371         let attrs = HwsimAttrSet::parse(hwsim_msg.attributes()).unwrap();
372 
373         let fmt_attrs = format!("{}", attrs);
374         assert!(fmt_attrs.contains("transmitter: 02:15:b2:00:00:00"));
375         assert!(fmt_attrs.contains("cookie: 201"));
376     }
377 }
378