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 5c9713659ecf..9f895ad718e9 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) @@ -6394,6 +6395,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] || @@ -6406,6 +6408,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) @@ -6442,7 +6445,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 */ @@ -6538,6 +6543,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)