diff options
author | Bill Schilit <schilit@google.com> | 2023-12-28 05:01:16 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2023-12-28 05:01:16 +0000 |
commit | c7582a7f1ab43ed850e66ac014e14bbca2ecafac (patch) | |
tree | 80552476ffc7eb26b5650381ddd53a2deffd80e0 | |
parent | 3fc3d5d14d809df1c73faf38f6b5404c781fdbfa (diff) | |
parent | c7a500e8588ca29f9ffa85e330af229cf27a0686 (diff) | |
download | netsim-c7582a7f1ab43ed850e66ac014e14bbca2ecafac.tar.gz |
Merge "Add wifi packet process and reorganize hwsim attributes to be used from multiple commands." into main
-rw-r--r-- | rust/daemon/src/echip/wifi.rs | 5 | ||||
-rw-r--r-- | rust/daemon/src/wifi/frame.rs | 194 | ||||
-rw-r--r-- | rust/daemon/src/wifi/hwsim_attr_set.rs | 178 | ||||
-rw-r--r-- | rust/daemon/src/wifi/ieee80211.rs | 37 | ||||
-rw-r--r-- | rust/daemon/src/wifi/medium.rs | 75 | ||||
-rw-r--r-- | rust/daemon/src/wifi/mod.rs | 1 |
6 files changed, 314 insertions, 176 deletions
diff --git a/rust/daemon/src/echip/wifi.rs b/rust/daemon/src/echip/wifi.rs index 2dba81a..c2cc1f6 100644 --- a/rust/daemon/src/echip/wifi.rs +++ b/rust/daemon/src/echip/wifi.rs @@ -16,7 +16,7 @@ use crate::devices::chip::ChipIdentifier; use crate::echip::{EmulatedChip, SharedEmulatedChip}; use crate::ffi::ffi_wifi; use crate::wifi::medium; -use log::info; +use log::{info, warn}; use netsim_proto::common::ChipKind as ProtoChipKind; use netsim_proto::config::WiFi as WiFiConfig; use netsim_proto::model::chip::Radio; @@ -36,6 +36,9 @@ pub struct Wifi { impl EmulatedChip for Wifi { fn handle_request(&self, packet: &[u8]) { + if let Err(e) = medium::process(self.chip_id, packet) { + warn!("Error medium::process {}", e); + } if crate::config::get_dev() { let _ = medium::parse_hwsim_cmd(packet); } diff --git a/rust/daemon/src/wifi/frame.rs b/rust/daemon/src/wifi/frame.rs index 4b8f462..1ec8904 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, + }) } } diff --git a/rust/daemon/src/wifi/hwsim_attr_set.rs b/rust/daemon/src/wifi/hwsim_attr_set.rs new file mode 100644 index 0000000..2cb6507 --- /dev/null +++ b/rust/daemon/src/wifi/hwsim_attr_set.rs @@ -0,0 +1,178 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::ieee80211::MacAddress; +use super::packets::mac80211_hwsim::HwsimAttrChild::*; +use super::packets::mac80211_hwsim::{HwsimAttr, HwsimMsg, HwsimMsgHdr, TxRate, TxRateFlag}; +use super::packets::netlink::{NlAttrHdr, NlMsgHdr}; +use anyhow::{anyhow, Context}; +use log::{info, warn}; + +// Decode the hwsim attributes into a set. +// +// Hwsim attributes are used to exchange data between kernel's +// mac80211_hwsim subsystem and this user space process and include: +// +// 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 HwsimAttrSetBuilder { + transmitter: Option<MacAddress>, + receiver: Option<MacAddress>, + frame: Option<Vec<u8>>, + flags: Option<u32>, + rx_rate_idx: Option<u32>, + signal: Option<u32>, + cookie: Option<u64>, + freq: Option<u32>, + tx_info: Option<Vec<TxRate>>, + tx_rate_flags: Option<Vec<TxRateFlag>>, +} + +#[derive(Debug)] +pub struct HwsimAttrSet { + pub transmitter: Option<MacAddress>, + pub receiver: Option<MacAddress>, + pub frame: Option<Vec<u8>>, + pub flags: Option<u32>, + pub rx_rate_idx: Option<u32>, + pub signal: Option<u32>, + pub cookie: Option<u64>, + pub freq: Option<u32>, + pub tx_info: Option<Vec<TxRate>>, + pub tx_rate_flags: Option<Vec<TxRateFlag>>, +} + +impl HwsimAttrSetBuilder { + fn transmitter(&mut self, transmitter: &[u8; 6]) -> &mut Self { + self.transmitter = Some(MacAddress::from(transmitter)); + self + } + + fn receiver(&mut self, receiver: &[u8; 6]) -> &mut Self { + self.receiver = Some(MacAddress::from(receiver)); + self + } + + fn frame(&mut self, frame: &[u8]) -> &mut Self { + self.frame = Some(frame.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_info(&mut self, tx_info: &[TxRate]) -> &mut Self { + self.tx_info = Some(tx_info.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<HwsimAttrSet> { + Ok(HwsimAttrSet { + transmitter: self.transmitter, + receiver: self.receiver, + cookie: self.cookie, + flags: self.flags, + rx_rate_idx: self.rx_rate_idx, + signal: self.signal, + frame: self.frame, + freq: self.freq, + tx_info: self.tx_info, + tx_rate_flags: self.tx_rate_flags, + }) + } +} + +impl HwsimAttrSet { + fn builder() -> HwsimAttrSetBuilder { + HwsimAttrSetBuilder::default() + } + + // Builds and validates the attributes in the command. + pub fn parse(attributes: &[u8]) -> anyhow::Result<HwsimAttrSet> { + let mut index: usize = 0; + let mut builder = HwsimAttrSet::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_info(child.get_tx_rates()), + HwsimAttrTxInfoFlags(child) => builder.tx_rate_flags(child.get_tx_rate_flags()), + _ => { + return Err(anyhow!( + "Invalid attribute message: {:?}", + hwsim_attr.get_nla_type() as u32 + )) + } + }; + // Manually step through the attribute bytes aligning as + // we go because netlink aligns each attribute which isn't + // a feature of PDL parser. + index += nla_align(nla_len); + } + builder.build() + } +} diff --git a/rust/daemon/src/wifi/ieee80211.rs b/rust/daemon/src/wifi/ieee80211.rs index 7e501b8..54f5301 100644 --- a/rust/daemon/src/wifi/ieee80211.rs +++ b/rust/daemon/src/wifi/ieee80211.rs @@ -25,8 +25,20 @@ impl fmt::Display for MacAddress { let bytes = u64::to_le_bytes(self.0); write!( f, - "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", - bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0], + "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], + ) + } +} + +impl fmt::Display for Ieee80211 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{{ds: {}, src: {}, dst: {}}}", + self.get_ds(), + self.get_source(), + self.get_destination() ) } } @@ -66,6 +78,17 @@ impl Ieee80211 { && self.ieee80211.stype == (ManagementSubType::ProbeReq as u8) } + pub fn get_ds(&self) -> String { + match self.specialize() { + Ieee80211Child::Ieee80211ToAp(hdr) => "ToAp", + Ieee80211Child::Ieee80211FromAp(hdr) => "FromAp", + Ieee80211Child::Ieee80211Ibss(hdr) => "Ibss", + Ieee80211Child::Ieee80211Wds(hdr) => "Wds", + _ => panic!("unexpected specialized header"), + } + .to_string() + } + pub fn get_source(&self) -> MacAddress { match self.specialize() { Ieee80211Child::Ieee80211ToAp(hdr) => hdr.get_source(), @@ -75,6 +98,16 @@ impl Ieee80211 { _ => panic!("unexpected specialized header"), } } + + pub fn get_destination(&self) -> MacAddress { + match self.specialize() { + Ieee80211Child::Ieee80211ToAp(hdr) => hdr.get_destination(), + Ieee80211Child::Ieee80211FromAp(hdr) => hdr.get_destination(), + Ieee80211Child::Ieee80211Ibss(hdr) => hdr.get_destination(), + Ieee80211Child::Ieee80211Wds(hdr) => hdr.get_destination(), + _ => panic!("unexpected specialized header"), + } + } } fn parse_mac_address(s: &str) -> Option<MacAddress> { diff --git a/rust/daemon/src/wifi/medium.rs b/rust/daemon/src/wifi/medium.rs index 11454df..ddaa563 100644 --- a/rust/daemon/src/wifi/medium.rs +++ b/rust/daemon/src/wifi/medium.rs @@ -14,15 +14,11 @@ use super::packets::mac80211_hwsim::{HwsimAttr, HwsimCmd, HwsimMsg, HwsimMsgHdr}; use super::packets::netlink::{NlAttrHdr, NlMsgHdr}; +use crate::devices::chip::ChipIdentifier; use crate::wifi::frame::Frame; +use crate::wifi::hwsim_attr_set::HwsimAttrSet; use anyhow::{anyhow, Context}; -use log::{info, warn}; - -const NLA_ALIGNTO: usize = 4; - -fn nla_align(len: usize) -> usize { - len.wrapping_add(NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1) -} +use log::{debug, info, warn}; #[derive(Debug)] pub enum HwsimCmdEnum { @@ -37,16 +33,59 @@ pub enum HwsimCmdEnum { DelMacAddr, } -pub fn parse_hwsim_cmd(packet: &[u8]) -> anyhow::Result<HwsimCmdEnum> { - match HwsimMsg::parse(packet) { - Ok(hwsim_msg) => match (hwsim_msg.hwsim_hdr.hwsim_cmd) { - HwsimCmd::Frame => { - let frame = Frame::new(&hwsim_msg.attributes)?; - Ok(HwsimCmdEnum::Frame(Box::new(frame))) +/// Process commands from the kernel's mac80211_hwsim subsystem. +/// +/// This is the processing that will be implemented: +/// +/// * The source MacAddress in 802.11 frames is re-mapped to a globally +/// unique MacAddress because resumed Emulator AVDs appear with the +/// same address. +/// +/// * 802.11 multicast frames are re-broadcast to connected stations. +/// +pub fn process(chip_id: ChipIdentifier, packet: &[u8]) -> anyhow::Result<()> { + let hwsim_msg = HwsimMsg::parse(packet)?; + match (hwsim_msg.hwsim_hdr.hwsim_cmd) { + HwsimCmd::Frame => { + let frame = Frame::parse(&hwsim_msg)?; + info!( + "Frame chip {}, addr {}, flags {}, cookie {:?}, ieee80211 {}", + chip_id, frame.transmitter, frame.flags, frame.cookie, frame.ieee80211 + ); + } + HwsimCmd::AddMacAddr => { + let attr_set = HwsimAttrSet::parse(&hwsim_msg.attributes)?; + if let (Some(addr), Some(hwaddr)) = (attr_set.transmitter, attr_set.receiver) { + info!("ADD_MAC_ADDR transmitter {:?} receiver {:?}", hwaddr, addr); + } else { + warn!("ADD_MAC_ADDR missing transmitter or receiver"); + } + } + HwsimCmd::DelMacAddr => { + let attr_set = HwsimAttrSet::parse(&hwsim_msg.attributes)?; + if let (Some(addr), Some(hwaddr)) = (attr_set.transmitter, attr_set.receiver) { + info!("DEL_MAC_ADDR transmitter {:?} receiver {:?}", hwaddr, addr); + } else { + warn!("DEL_MAC_ADDR missing transmitter or receiver"); } - _ => Err(anyhow!("Unknown HwsimkMsg cmd={:?}", hwsim_msg.hwsim_hdr.hwsim_cmd)), - }, - Err(e) => Err(anyhow!("Unable to parse netlink message! {:?}", e)), + } + _ => { + info!("Another command found {:?}", hwsim_msg); + } + } + Ok(()) +} + +// TODO: move code below here into test module usable from CMake + +pub fn parse_hwsim_cmd(packet: &[u8]) -> anyhow::Result<HwsimCmdEnum> { + let hwsim_msg = HwsimMsg::parse(packet)?; + match (hwsim_msg.hwsim_hdr.hwsim_cmd) { + HwsimCmd::Frame => { + let frame = Frame::parse(&hwsim_msg)?; + Ok(HwsimCmdEnum::Frame(Box::new(frame))) + } + _ => Err(anyhow!("Unknown HwsimMsg cmd={:?}", hwsim_msg.hwsim_hdr.hwsim_cmd)), } } @@ -72,7 +111,7 @@ pub fn test_parse_hwsim_cmd() { 16, 255, 255, 57, 216, 0, 0, 8, 0, 5, 0, 1, 0, 0, 0, 8, 0, 6, 0, 206, 255, 255, 255, 8, 0, 19, 0, 143, 9, 0, 0, ]; - assert!(parse_hwsim_cmd(&packet2).is_ok()); + assert!(parse_hwsim_cmd(&packet2).is_err()); // missing cookie attribute let packet3: Vec<u8> = vec![ @@ -93,7 +132,7 @@ pub fn test_parse_hwsim_cmd() { 0, 0, 2, 90, 3, 36, 1, 0, 0, 0, 0, 8, 0, 5, 0, 1, 0, 0, 0, 8, 0, 6, 0, 206, 255, 255, 255, 8, 0, 19, 0, 143, 9, 0, 0, ]; - assert!(parse_hwsim_cmd(&packet3).is_ok()); + assert!(parse_hwsim_cmd(&packet3).is_err()); // HwsimkMsg cmd=TxInfoFrame packet let packet3: Vec<u8> = vec![ diff --git a/rust/daemon/src/wifi/mod.rs b/rust/daemon/src/wifi/mod.rs index 8891cce..80842a8 100644 --- a/rust/daemon/src/wifi/mod.rs +++ b/rust/daemon/src/wifi/mod.rs @@ -18,6 +18,7 @@ #![allow(unused)] pub(crate) mod frame; +pub(crate) mod hwsim_attr_set; pub(crate) mod ieee80211; pub(crate) mod medium; pub(crate) mod packets; |