From: Johannes Berg In a new test framework for hwsim I'm working on, tests can modify the frame as it passes through the wmediumd APIs. If then the original frame is reported on the monitor interface, things get a bit confusing. Overwrite the frame that will be reported to the monitor with the frame reported for RX if both transmitter and cookie attributes are present (wmediumd doesn't set them). Also add a HWSIM_ATTR_NO_MONITOR flag to allow a frame to be dropped entirely from monitor report, e.g. in case it was never delivered to any peer. Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.h | 5 +- .../wireless/virtual/mac80211_hwsim_main.c | 52 ++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.h b/drivers/net/wireless/virtual/mac80211_hwsim.h index a022cd5c0f1c..1d2fd06c585a 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.h +++ b/drivers/net/wireless/virtual/mac80211_hwsim.h @@ -3,7 +3,7 @@ * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 * Copyright (c) 2008, Jouni Malinen * Copyright (c) 2011, Javier Lopez - * Copyright (C) 2020, 2022-2025 Intel Corporation + * Copyright (C) 2020, 2022-2026 Intel Corporation */ #ifndef __MAC80211_HWSIM_H @@ -162,6 +162,8 @@ enum hwsim_commands { * each radio instead of for the wiphy. * @HWSIM_ATTR_SUPPORT_NAN_DEVICE: support NAN Device virtual interface (flag) * @HWSIM_ATTR_SUPPORT_BACKGROUND_RADAR: background radar/CAC support (flag) + * @HWSIM_ATTR_NO_MONITOR: skip monitor report for this TX status, e.g. in case + * the frame was never reported to any receiver (flag) * @__HWSIM_ATTR_MAX: enum limit */ enum hwsim_attrs { @@ -197,6 +199,7 @@ enum hwsim_attrs { HWSIM_ATTR_MULTI_RADIO, HWSIM_ATTR_SUPPORT_NAN_DEVICE, HWSIM_ATTR_SUPPORT_BACKGROUND_RADAR, + HWSIM_ATTR_NO_MONITOR, __HWSIM_ATTR_MAX, }; #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c index 4e73b9c7fdab..fca4bf823ef4 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c @@ -895,6 +895,7 @@ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { [HWSIM_ATTR_MULTI_RADIO] = { .type = NLA_FLAG }, [HWSIM_ATTR_SUPPORT_NAN_DEVICE] = { .type = NLA_FLAG }, [HWSIM_ATTR_SUPPORT_BACKGROUND_RADAR] = { .type = NLA_FLAG }, + [HWSIM_ATTR_NO_MONITOR] = { .type = NLA_FLAG }, }; #if IS_REACHABLE(CONFIG_VIRTIO) @@ -6393,6 +6394,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, int i; unsigned long flags; bool found = false; + bool no_monitor; u32 freq; if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] || @@ -6405,6 +6407,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, src = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]); ret_skb_cookie = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]); + no_monitor = nla_get_flag(info->attrs[HWSIM_ATTR_NO_MONITOR]); data2 = get_hwsim_data_ref_from_addr(src); if (!data2) @@ -6441,7 +6444,9 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, txi = IEEE80211_SKB_CB(skb); freq = (uintptr_t)txi->rate_driver_data[1]; - mac80211_hwsim_monitor_rx(data2->hw, skb, freq); + + if (!no_monitor) + mac80211_hwsim_monitor_rx(data2->hw, skb, freq); /* Tx info received because the frame was broadcasted on user space, so we get all the necessary info: tx attempts and skb control buff */ @@ -6537,6 +6542,51 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, goto out; } + /* look for the skb matching the cookie passed back from user */ + if (info->attrs[HWSIM_ATTR_COOKIE] && + info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]) { + u64 cookie = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]); + struct sk_buff *orig_skb, *found = NULL; + struct mac80211_hwsim_data *txdata; + struct ieee80211_tx_info *txi; + const u8 *transmitter; + unsigned long flags; + + transmitter = nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); + txdata = get_hwsim_data_ref_from_addr(transmitter); + if (!txdata || txdata->netgroup != data2->netgroup) + goto out; + + spin_lock_irqsave(&txdata->pending.lock, flags); + skb_queue_walk(&txdata->pending, orig_skb) { + uintptr_t skb_cookie; + + txi = IEEE80211_SKB_CB(orig_skb); + skb_cookie = (uintptr_t)txi->rate_driver_data[0]; + + if (skb_cookie == cookie) { + found = orig_skb; + break; + } + } + + /* that's weird */ + if (!found) { + spin_unlock_irqrestore(&txdata->pending.lock, flags); + goto out; + } + + if (frame_data_len > found->len && + pskb_expand_head(found, 0, frame_data_len - found->len, + GFP_ATOMIC)) { + spin_unlock_irqrestore(&txdata->pending.lock, flags); + goto out; + } + skb_trim(found, 0); + skb_put_data(found, frame_data, frame_data_len); + spin_unlock_irqrestore(&txdata->pending.lock, flags); + } + /* check if radio is configured properly */ if ((data2->idle && !data2->tmp_chan) || !data2->started) -- 2.55.0