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