diff options
Diffstat (limited to 'rust/daemon/src/wifi/frame.rs')
-rw-r--r-- | rust/daemon/src/wifi/frame.rs | 194 |
1 files changed, 39 insertions, 155 deletions
diff --git a/rust/daemon/src/wifi/frame.rs b/rust/daemon/src/wifi/frame.rs index 4b8f462e..1ec89044 100644 --- a/rust/daemon/src/wifi/frame.rs +++ b/rust/daemon/src/wifi/frame.rs @@ -12,175 +12,59 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::ieee80211::Ieee80211; -use super::packets::mac80211_hwsim::HwsimAttrChild::*; -use super::packets::mac80211_hwsim::{HwsimAttr, HwsimMsg, HwsimMsgHdr, TxRate, TxRateFlag}; -use super::packets::netlink::{NlAttrHdr, NlMsgHdr}; +use super::ieee80211::{Ieee80211, MacAddress}; +use super::packets::mac80211_hwsim::{ + HwsimAttr, HwsimCmd, HwsimMsg, HwsimMsgHdr, TxRate, TxRateFlag, +}; +use crate::wifi::hwsim_attr_set::HwsimAttrSet; use anyhow::{anyhow, Context}; use log::{info, warn}; -use std::mem; -// Decode the hwsim Frame. -// -// HWSIM_CMD_FRAME is used to send/receive a broadcasted frame from/to -// kernel/user space, uses these attributes: -// -// HWSIM_ATTR_ADDR_TRANSMITTER, -// HWSIM_ATTR_ADDR_RECEIVER, -// HWSIM_ATTR_FRAME, -// HWSIM_ATTR_FLAGS, -// HWSIM_ATTR_RX_RATE, -// HWSIM_ATTR_SIGNAL, -// HWSIM_ATTR_COOKIE, -// HWSIM_ATTR_FREQ (optional) -// HWSIM_ATTR_TX_INFO (new use) -// HWSIM_ATTR_TX_INFO_FLAGS (new use) - -const NLA_ALIGNTO: usize = 4; - -fn nla_align(len: usize) -> usize { - len.wrapping_add(NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1) -} - -#[derive(Default)] -struct FrameBuilder { - transmitter: Option<[u8; 6]>, - receiver: Option<[u8; 6]>, - data: Option<Vec<u8>>, - flags: Option<u32>, - rx_rate_idx: Option<u32>, - signal: Option<u32>, - cookie: Option<u64>, - freq: Option<u32>, - tx_rates: Option<Vec<TxRate>>, - tx_rate_flags: Option<Vec<TxRateFlag>>, -} +/// Parser for the hwsim Frame command (HWSIM_CMD_FRAME). +/// +/// The Frame command is sent by the kernel's mac80211_hwsim subsystem +/// and contains the IEEE 802.11 frame along with hwsim attributes. +/// +/// This module parses the required and optional hwsim attributes and +/// returns errors if any required attributes are missing. +// The Frame struct contains parsed attributes along with the raw and +// parsed 802.11 frame in `data` and `ieee80211.` #[derive(Debug)] pub struct Frame { - transmitter: Option<[u8; 6]>, - receiver: Option<[u8; 6]>, - pub data: Vec<u8>, - pub ieee80211_hdr: Option<Ieee80211>, - pub flags: Option<u32>, - rx_rate_idx: Option<u32>, + pub transmitter: MacAddress, + pub flags: u32, + pub tx_info: Vec<TxRate>, + pub cookie: u64, pub signal: Option<u32>, - cookie: Option<u64>, pub freq: Option<u32>, - tx_rates: Option<Vec<TxRate>>, - tx_rate_flags: Option<Vec<TxRateFlag>>, -} - -fn anymsg(attr: &str) -> anyhow::Error { - anyhow!("hwsim Frame missing {} attribute", attr) -} - -impl FrameBuilder { - fn transmitter(&mut self, transmitter: &[u8; 6]) -> &mut Self { - self.transmitter = Some(*transmitter); - self - } - - fn receiver(&mut self, receiver: &[u8; 6]) -> &mut Self { - self.receiver = Some(*receiver); - self - } - - fn frame(&mut self, data: &[u8]) -> &mut Self { - self.data = Some(data.to_vec()); - self - } - - fn flags(&mut self, flags: u32) -> &mut Self { - self.flags = Some(flags); - self - } - - fn rx_rate(&mut self, rx_rate_idx: u32) -> &mut Self { - self.rx_rate_idx = Some(rx_rate_idx); - self - } - - fn signal(&mut self, signal: u32) -> &mut Self { - self.signal = Some(signal); - self - } - - fn cookie(&mut self, cookie: u64) -> &mut Self { - self.cookie = Some(cookie); - self - } - - fn freq(&mut self, freq: u32) -> &mut Self { - self.freq = Some(freq); - self - } - - fn tx_rates(&mut self, tx_rates: &[TxRate]) -> &mut Self { - self.tx_rates = Some(tx_rates.to_vec()); - self - } - - fn tx_rate_flags(&mut self, tx_rate_flags: &[TxRateFlag]) -> &mut Self { - self.tx_rate_flags = Some(tx_rate_flags.to_vec()); - self - } - - fn build(mut self) -> anyhow::Result<Frame> { - let data = self.data.ok_or(anymsg("frame"))?; - let ieee80211_hdr = Ieee80211::parse(&data).ok(); - Ok(Frame { - transmitter: self.transmitter, - receiver: self.receiver, - cookie: self.cookie, - flags: self.flags, - rx_rate_idx: self.rx_rate_idx, - signal: self.signal, - data, - ieee80211_hdr, - freq: self.freq, - tx_rates: self.tx_rates, - tx_rate_flags: self.tx_rate_flags, - }) - } + pub data: Vec<u8>, + pub ieee80211: Ieee80211, } impl Frame { - fn builder() -> FrameBuilder { - FrameBuilder::default() - } - // Builds and validates the Frame from the attributes in the // packet. Called when a hwsim packet with HwsimCmd::Frame is // found. - pub fn new(attributes: &[u8]) -> anyhow::Result<Frame> { - let mut index: usize = 0; - let mut builder = Frame::builder(); - while (index < attributes.len()) { - // Parse a generic netlink attribute to get the size - let nla = NlAttrHdr::parse(&attributes[index..index + 4]).unwrap(); - let nla_len = nla.nla_len as usize; - let hwsim_attr = HwsimAttr::parse(&attributes[index..index + nla_len])?; - match hwsim_attr.specialize() { - HwsimAttrAddrTransmitter(child) => builder.transmitter(child.get_address()), - HwsimAttrAddrReceiver(child) => builder.receiver(child.get_address()), - HwsimAttrFrame(child) => builder.frame(child.get_data()), - HwsimAttrFlags(child) => builder.flags(child.get_flags()), - HwsimAttrRxRate(child) => builder.rx_rate(child.get_rx_rate_idx()), - HwsimAttrSignal(child) => builder.signal(child.get_signal()), - HwsimAttrCookie(child) => builder.cookie(child.get_cookie()), - HwsimAttrFreq(child) => builder.freq(child.get_freq()), - HwsimAttrTxInfo(child) => builder.tx_rates(child.get_tx_rates()), - HwsimAttrTxInfoFlags(child) => builder.tx_rate_flags(child.get_tx_rate_flags()), - _ => { - return Err(anyhow!( - "Invalid attribute in frame: {:?}", - hwsim_attr.get_nla_type() as u32 - )) - } - }; - index += nla_align(nla_len); + pub fn parse(msg: &HwsimMsg) -> anyhow::Result<Frame> { + // Only expected to be called with HwsimCmd::Frame + if (msg.hwsim_hdr.hwsim_cmd != HwsimCmd::Frame) { + panic!("Invalid hwsim_cmd"); } - builder.build() + let attrs = HwsimAttrSet::parse(&msg.attributes).context("HwsimAttrSet")?; + let frame = attrs.frame.clone().context("Frame")?; + let ieee80211 = Ieee80211::parse(&frame).context("Ieee80211")?; + // Required attributes are unwrapped and return an error if + // they are not present. + Ok(Frame { + transmitter: attrs.transmitter.context("transmitter")?, + flags: attrs.flags.context("flags")?, + tx_info: attrs.tx_info.clone().context("tx_info")?, + cookie: attrs.cookie.context("cookie")?, + signal: attrs.signal, + freq: attrs.freq, + data: frame, + ieee80211, + }) } } |