Aside from various small improvements/cleanups, not much:

- cfg80211/mac80211: S1G and UHR improvements
  - hwsim: incumbent signal report test support
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEpeA8sTs3M8SN2hR410qiO8sPaAAFAmm7sb4ACgkQ10qiO8sP
 aAD+iQ/+IYWmM1Z/Iu6eZZx/VPrc4Xnj/8UgbalyjetyLRYFNEvawFSdutqZ23uI
 FO7vYbzGXMtAlt7fjmxVKMiN4aoX+rISRjG5cnH1qPpeVO8w9fnOZyqmNUFJFboN
 ibpr4dqPIS2qZDKegvOa9JO+8KkkPerPWl608eOzXPxoZaZAMnXOhWuV4cWdvuTT
 vEnL+Ma4ckkOV6QdBFazYaxAyTt3Mpqj5ULodixtKPMdgB3P+6mAVipp/icE5R1P
 R/Vd7Fn+0r7wb/4+1S6DcCBvT6V6Ui94bIRF9DB5LGG/9iLPrGYRD52qQpetzXzA
 Si238bs7qi/6t6Q5tfzK1LZVnzZXTUqcWGS6ba4JiMxrLTAK1AEmcLved6A48ywt
 YH9zImLRBRMSANbH27BoWvijT5YZGMetH06cTdFmZ8MMGoYV7CWBxVOaIroH7WMx
 exMnWEcX6PUVMtlIR4FTGwX/nalGbvnBtoMv9ei3NRb2Dkart8OFT6vIDfy6TBnD
 BzAUE3pDAW3I7ukbLQGJ3mmanZpHtF/Xgfr5Y9EbZHPjtC08l7cwdd2zn0n3Q2qu
 JGlzZiut6sJTfnRESbUvJ6fnCMdGARpQxq6p2At3njJW0sncvyV9WFKh4A+ReaDr
 PQ24fgapG5PNEISevO+/FV1z2qZ0+IbHSmcH+BIoktBnPUBLZFo=
 =cLVw
 -----END PGP SIGNATURE-----

Merge tag 'wireless-next-2026-03-19' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next

Johannes Berg says:

====================
Aside from various small improvements/cleanups, not much:
 - cfg80211/mac80211: S1G and UHR improvements
 - hwsim: incumbent signal report test support

* tag 'wireless-next-2026-03-19' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (31 commits)
  qtnfmac: use alloc_netdev macro for single queue devices
  wifi: libertas: don't kill URBs in interrupt context
  wifi: libertas: use USB anchors for tracking in-flight URBs
  wifi: nl80211: use int for band coming from netlink
  wifi: rsi_91x_usb: do not pause rfkill polling when stopping mac80211
  wifi: mac80211: fix STA link removal during link removal
  wifi: nl80211: reject S1G/60G with HT chantype
  wifi: ieee80211: fix definition of EHT-MCS 15 in MRU
  wifi: cfg80211: check non-S1G width with S1G chandef
  wifi: cfg80211: restrict cfg80211_chandef_create() to only HT-based bands
  wifi: mac80211: don't use cfg80211_chandef_create() for default chandef
  wifi: mac80211: Remove deleted sta links in ieee80211_ml_reconf_work()
  wifi: b43: use register definitions in nphy_op_software_rfkill
  wifi: cfg80211: split control freq check from chandef check
  wifi: mac80211: always use full chanctx compatible check
  wifi: mac80211: refactor chandef tracing macros
  wifi: mac80211: validate HE 6 GHz operation when EHT is used
  wifi: nl80211: split out UHR operation information
  wifi: mwifiex: drop redundant device reference
  wifi: rt2x00: drop redundant device reference
  ...
====================

Link: https://patch.msgid.link/20260319082439.79875-3-johannes@sipsolutions.net
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni 2026-03-19 15:30:19 +01:00
commit 9ac76f3d0b
65 changed files with 733 additions and 680 deletions

View File

@ -6288,10 +6288,10 @@ static int ath11k_mac_mgmt_action_frame_fill_elem_data(struct ath11k_vif *arvif,
lockdep_assert_held(&ar->conf_mutex);
/* make sure category field is present */
if (skb->len < IEEE80211_MIN_ACTION_SIZE)
if (skb->len < IEEE80211_MIN_ACTION_SIZE(category))
return -EINVAL;
remaining_len = skb->len - IEEE80211_MIN_ACTION_SIZE;
remaining_len = skb->len - IEEE80211_MIN_ACTION_SIZE(category);
has_protected = ieee80211_has_protected(hdr->frame_control);
/* In case of SW crypto and hdr protected (PMF), packet will already be encrypted,

View File

@ -9119,10 +9119,10 @@ static int ath12k_mac_mgmt_action_frame_fill_elem_data(struct ath12k_link_vif *a
lockdep_assert_wiphy(wiphy);
/* make sure category field is present */
if (skb->len < IEEE80211_MIN_ACTION_SIZE)
if (skb->len < IEEE80211_MIN_ACTION_SIZE(category))
return -EINVAL;
remaining_len = skb->len - IEEE80211_MIN_ACTION_SIZE;
remaining_len = skb->len - IEEE80211_MIN_ACTION_SIZE(category);
has_protected = ieee80211_has_protected(hdr->frame_control);
/* In case of SW crypto and hdr protected (PMF), packet will already be encrypted,

View File

@ -104,7 +104,7 @@ static bool ath12k_is_addba_resp_action_code(struct ieee80211_mgmt *mgmt)
if (mgmt->u.action.category != WLAN_CATEGORY_BACK)
return false;
if (mgmt->u.action.u.addba_resp.action_code != WLAN_ACTION_ADDBA_RESP)
if (mgmt->u.action.action_code != WLAN_ACTION_ADDBA_RESP)
return false;
return true;

View File

@ -2440,13 +2440,11 @@ static int at76_probe(struct usb_interface *interface,
struct mib_fw_version *fwv;
int board_type = (int)id->driver_info;
udev = usb_get_dev(interface_to_usbdev(interface));
udev = interface_to_usbdev(interface);
fwv = kmalloc_obj(*fwv);
if (!fwv) {
ret = -ENOMEM;
goto exit;
}
if (!fwv)
return -ENOMEM;
/* Load firmware into kernel memory */
fwe = at76_load_firmware(udev, board_type);
@ -2534,8 +2532,7 @@ static int at76_probe(struct usb_interface *interface,
exit:
kfree(fwv);
if (ret < 0)
usb_put_dev(udev);
return ret;
}
@ -2552,7 +2549,6 @@ static void at76_disconnect(struct usb_interface *interface)
wiphy_info(priv->hw->wiphy, "disconnecting\n");
at76_delete_device(priv);
usb_put_dev(interface_to_usbdev(interface));
dev_info(&interface->dev, "disconnected\n");
}

View File

@ -6566,19 +6566,19 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
b43_radio_mask(dev, 0x09, ~0x2);
b43_radio_write(dev, 0x204D, 0);
b43_radio_write(dev, 0x2053, 0);
b43_radio_write(dev, 0x2058, 0);
b43_radio_write(dev, 0x205E, 0);
b43_radio_mask(dev, 0x2062, ~0xF0);
b43_radio_write(dev, 0x2064, 0);
b43_radio_write(dev, B2056_TX0 | B2056_TX_PADA_BOOST_TUNE, 0);
b43_radio_write(dev, B2056_TX0 | B2056_TX_PADG_BOOST_TUNE, 0);
b43_radio_write(dev, B2056_TX0 | B2056_TX_PGAA_BOOST_TUNE, 0);
b43_radio_write(dev, B2056_TX0 | B2056_TX_PGAG_BOOST_TUNE, 0);
b43_radio_mask(dev, B2056_TX0 | B2056_TX_MIXA_BOOST_TUNE, ~0xF0);
b43_radio_write(dev, B2056_TX0 | B2056_TX_MIXG_BOOST_TUNE, 0);
b43_radio_write(dev, 0x304D, 0);
b43_radio_write(dev, 0x3053, 0);
b43_radio_write(dev, 0x3058, 0);
b43_radio_write(dev, 0x305E, 0);
b43_radio_mask(dev, 0x3062, ~0xF0);
b43_radio_write(dev, 0x3064, 0);
b43_radio_write(dev, B2056_TX1 | B2056_TX_PADA_BOOST_TUNE, 0);
b43_radio_write(dev, B2056_TX1 | B2056_TX_PADG_BOOST_TUNE, 0);
b43_radio_write(dev, B2056_TX1 | B2056_TX_PGAA_BOOST_TUNE, 0);
b43_radio_write(dev, B2056_TX1 | B2056_TX_PGAG_BOOST_TUNE, 0);
b43_radio_mask(dev, B2056_TX1 | B2056_TX_MIXA_BOOST_TUNE, ~0xF0);
b43_radio_write(dev, B2056_TX1 | B2056_TX_MIXG_BOOST_TUNE, 0);
}
} else {
if (phy->rev >= 19) {

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2025 Intel Corporation
* Copyright (C) 2025-2026 Intel Corporation
*/
#include "mld.h"
@ -116,9 +116,9 @@ static bool iwl_mld_is_skb_match(struct sk_buff *skb, u8 *addr, u8 dialog_token)
u8 skb_dialog_token;
if (ieee80211_is_timing_measurement(skb))
skb_dialog_token = mgmt->u.action.u.wnm_timing_msr.dialog_token;
skb_dialog_token = mgmt->u.action.wnm_timing_msr.dialog_token;
else
skb_dialog_token = mgmt->u.action.u.ftm.dialog_token;
skb_dialog_token = mgmt->u.action.ftm.dialog_token;
if ((ether_addr_equal(mgmt->sa, addr) ||
ether_addr_equal(mgmt->da, addr)) &&

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2015-2017 Intel Deutschland GmbH
* Copyright (C) 2018-2025 Intel Corporation
* Copyright (C) 2018-2026 Intel Corporation
*/
#include <linux/etherdevice.h>
#include <linux/math64.h>
@ -1409,8 +1409,7 @@ void iwl_mvm_ftm_lc_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
struct iwl_mvm_loc_entry *entry;
const u8 *ies, *lci, *civic, *msr_ie;
size_t ies_len, lci_len = 0, civic_len = 0;
size_t baselen = IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.ftm);
size_t baselen = IEEE80211_MIN_ACTION_SIZE(ftm);
static const u8 rprt_type_lci = IEEE80211_SPCT_MSR_RPRT_TYPE_LCI;
static const u8 rprt_type_civic = IEEE80211_SPCT_MSR_RPRT_TYPE_CIVIC;
@ -1419,7 +1418,7 @@ void iwl_mvm_ftm_lc_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
lockdep_assert_held(&mvm->mutex);
ies = mgmt->u.action.u.ftm.variable;
ies = mgmt->u.action.ftm.variable;
ies_len = len - baselen;
msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len,

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2022 Intel Corporation
* Copyright (C) 2022, 2026 Intel Corporation
*/
#include "mvm.h"
@ -18,9 +18,9 @@ static bool iwl_mvm_is_skb_match(struct sk_buff *skb, u8 *addr, u8 dialog_token)
u8 skb_dialog_token;
if (ieee80211_is_timing_measurement(skb))
skb_dialog_token = mgmt->u.action.u.wnm_timing_msr.dialog_token;
skb_dialog_token = mgmt->u.action.wnm_timing_msr.dialog_token;
else
skb_dialog_token = mgmt->u.action.u.ftm.dialog_token;
skb_dialog_token = mgmt->u.action.ftm.dialog_token;
if ((ether_addr_equal(mgmt->sa, addr) ||
ether_addr_equal(mgmt->da, addr)) &&

View File

@ -114,8 +114,8 @@ static void if_usb_write_bulk_callback(struct urb *urb)
static void if_usb_free(struct if_usb_card *cardp)
{
/* Unlink tx & rx urb */
usb_kill_urb(cardp->tx_urb);
usb_kill_urb(cardp->rx_urb);
usb_kill_anchored_urbs(&cardp->tx_submitted);
usb_kill_anchored_urbs(&cardp->rx_submitted);
usb_free_urb(cardp->tx_urb);
cardp->tx_urb = NULL;
@ -221,6 +221,9 @@ static int if_usb_probe(struct usb_interface *intf,
udev->descriptor.bDeviceSubClass,
udev->descriptor.bDeviceProtocol);
init_usb_anchor(&cardp->rx_submitted);
init_usb_anchor(&cardp->tx_submitted);
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
if (usb_endpoint_is_bulk_in(endpoint)) {
@ -276,7 +279,6 @@ static int if_usb_probe(struct usb_interface *intf,
cardp->boot2_version = udev->descriptor.bcdDevice;
usb_get_dev(udev);
usb_set_intfdata(intf, cardp);
r = lbs_get_firmware_async(priv, &udev->dev, cardp->model,
@ -287,7 +289,6 @@ static int if_usb_probe(struct usb_interface *intf,
return 0;
err_get_fw:
usb_put_dev(udev);
lbs_remove_card(priv);
err_add_card:
if_usb_reset_device(cardp);
@ -321,7 +322,6 @@ static void if_usb_disconnect(struct usb_interface *intf)
kfree(cardp);
usb_set_intfdata(intf, NULL);
usb_put_dev(interface_to_usbdev(intf));
}
/**
@ -426,7 +426,12 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb
goto tx_ret;
}
usb_kill_urb(cardp->tx_urb);
/* check if there are pending URBs */
if (!usb_anchor_empty(&cardp->tx_submitted)) {
lbs_deb_usbd(&cardp->udev->dev, "%s failed: pending URB\n", __func__);
ret = -EBUSY;
goto tx_ret;
}
usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
usb_sndbulkpipe(cardp->udev,
@ -435,8 +440,10 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb
cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
usb_anchor_urb(cardp->tx_urb, &cardp->tx_submitted);
if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
usb_unanchor_urb(cardp->tx_urb);
} else {
lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n");
ret = 0;
@ -467,8 +474,10 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
cardp);
lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
usb_anchor_urb(cardp->rx_urb, &cardp->rx_submitted);
if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
usb_unanchor_urb(cardp->rx_urb);
kfree_skb(skb);
cardp->rx_skb = NULL;
ret = -1;
@ -838,8 +847,8 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
}
/* Cancel any pending usb business */
usb_kill_urb(cardp->rx_urb);
usb_kill_urb(cardp->tx_urb);
usb_kill_anchored_urbs(&cardp->rx_submitted);
usb_kill_anchored_urbs(&cardp->tx_submitted);
cardp->fwlastblksent = 0;
cardp->fwdnldover = 0;
@ -869,8 +878,8 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
if (cardp->bootcmdresp == BOOT_CMD_RESP_NOT_SUPPORTED) {
/* Return to normal operation */
ret = -EOPNOTSUPP;
usb_kill_urb(cardp->rx_urb);
usb_kill_urb(cardp->tx_urb);
usb_kill_anchored_urbs(&cardp->rx_submitted);
usb_kill_anchored_urbs(&cardp->tx_submitted);
if (if_usb_submit_rx_urb(cardp) < 0)
ret = -EIO;
goto done;
@ -900,7 +909,7 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
wait_event_interruptible(cardp->fw_wq, cardp->surprise_removed || cardp->fwdnldover);
timer_delete_sync(&cardp->fw_timeout);
usb_kill_urb(cardp->rx_urb);
usb_kill_anchored_urbs(&cardp->rx_submitted);
if (!cardp->fwdnldover) {
pr_info("failed to load fw, resetting device!\n");
@ -960,8 +969,8 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
goto out;
/* Unlink tx & rx urb */
usb_kill_urb(cardp->tx_urb);
usb_kill_urb(cardp->rx_urb);
usb_kill_anchored_urbs(&cardp->tx_submitted);
usb_kill_anchored_urbs(&cardp->rx_submitted);
out:
return ret;

View File

@ -48,6 +48,9 @@ struct if_usb_card {
struct urb *rx_urb, *tx_urb;
struct lbs_private *priv;
struct usb_anchor rx_submitted;
struct usb_anchor tx_submitted;
struct sk_buff *rx_skb;
uint8_t ep_in;

View File

@ -223,7 +223,6 @@ static int if_usb_probe(struct usb_interface *intf,
if (!priv)
goto dealloc;
usb_get_dev(udev);
usb_set_intfdata(intf, cardp);
return 0;
@ -258,7 +257,6 @@ static void if_usb_disconnect(struct usb_interface *intf)
kfree(cardp);
usb_set_intfdata(intf, NULL);
usb_put_dev(interface_to_usbdev(intf));
lbtf_deb_leave(LBTF_DEB_MAIN);
}

View File

@ -755,16 +755,12 @@ mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv,
switch (action_code) {
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
/* See the layout of 'struct ieee80211_mgmt'. */
extra = sizeof(mgmt->u.action.u.tdls_discover_resp) +
sizeof(mgmt->u.action.category);
extra = IEEE80211_MIN_ACTION_SIZE(tdls_discover_resp) - 24;
skb_put(skb, extra);
mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
mgmt->u.action.u.tdls_discover_resp.action_code =
WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
mgmt->u.action.u.tdls_discover_resp.dialog_token =
dialog_token;
mgmt->u.action.u.tdls_discover_resp.capability =
cpu_to_le16(capab);
mgmt->u.action.action_code = WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
mgmt->u.action.tdls_discover_resp.dialog_token = dialog_token;
mgmt->u.action.tdls_discover_resp.capability = cpu_to_le16(capab);
/* move back for addr4 */
memmove(pos + ETH_ALEN, &mgmt->u.action, extra);
/* init address 4 */

View File

@ -520,8 +520,6 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
return ret;
}
usb_get_dev(udev);
return 0;
}
@ -666,8 +664,6 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
mwifiex_dbg(adapter, FATAL,
"%s: removing card\n", __func__);
mwifiex_remove_card(adapter);
usb_put_dev(interface_to_usbdev(intf));
}
static void mwifiex_usb_coredump(struct device *dev)

View File

@ -1985,9 +1985,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,
*/
if (unlikely(ieee80211_is_action(wh->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ &&
mgmt->u.action.action_code == WLAN_ACTION_ADDBA_REQ &&
priv->ap_fw)) {
u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
u16 capab = le16_to_cpu(mgmt->u.action.addba_req.capab);
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
index = mwl8k_tid_queue_mapping(tid);
}

View File

@ -413,10 +413,10 @@ mt76_connac2_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi,
u32 val;
if (ieee80211_is_action(fc) &&
skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 + 1 + 2 &&
skb->len >= IEEE80211_MIN_ACTION_SIZE(addba_req.capab) &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {
u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
mgmt->u.action.action_code == WLAN_ACTION_ADDBA_REQ) {
u16 capab = le16_to_cpu(mgmt->u.action.addba_req.capab);
txwi[5] |= cpu_to_le32(MT_TXD5_ADD_BA);
tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK;

View File

@ -668,9 +668,9 @@ mt7925_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi,
u32 val;
if (ieee80211_is_action(fc) &&
skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 &&
skb->len >= IEEE80211_MIN_ACTION_SIZE(action_code) &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ)
mgmt->u.action.action_code == WLAN_ACTION_ADDBA_REQ)
tid = MT_TX_ADDBA;
else if (ieee80211_is_mgmt(hdr->frame_control))
tid = MT_TX_NORMAL;

View File

@ -800,9 +800,9 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
u32 val;
if (ieee80211_is_action(fc) &&
skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 &&
skb->len >= IEEE80211_MIN_ACTION_SIZE(action_code) &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {
mgmt->u.action.action_code == WLAN_ACTION_ADDBA_REQ) {
if (is_mt7990(&dev->mt76))
txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TID_ADDBA, tid));
else

View File

@ -452,8 +452,8 @@ int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif,
void *qdev_vif;
int ret;
dev = alloc_netdev_mqs(sizeof(struct qtnf_vif *), name,
name_assign_type, ether_setup, 1, 1);
dev = alloc_netdev(sizeof(struct qtnf_vif *), name,
name_assign_type, ether_setup);
if (!dev)
return -ENOMEM;

View File

@ -802,14 +802,12 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
struct rt2x00_dev *rt2x00dev;
int retval;
usb_dev = usb_get_dev(usb_dev);
usb_reset_device(usb_dev);
hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
if (!hw) {
rt2x00_probe_err("Failed to allocate hardware\n");
retval = -ENOMEM;
goto exit_put_device;
return -ENOMEM;
}
usb_set_intfdata(usb_intf, hw);
@ -851,10 +849,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
exit_free_device:
ieee80211_free_hw(hw);
exit_put_device:
usb_put_dev(usb_dev);
usb_set_intfdata(usb_intf, NULL);
return retval;
@ -873,11 +867,7 @@ void rt2x00usb_disconnect(struct usb_interface *usb_intf)
rt2x00usb_free_reg(rt2x00dev);
ieee80211_free_hw(hw);
/*
* Free the USB device data.
*/
usb_set_intfdata(usb_intf, NULL);
usb_put_dev(interface_to_usbdev(usb_intf));
}
EXPORT_SYMBOL_GPL(rt2x00usb_disconnect);

View File

@ -5146,10 +5146,10 @@ static void rtl8xxxu_dump_action(struct device *dev,
if (!(rtl8xxxu_debug & RTL8XXXU_DEBUG_ACTION))
return;
switch (mgmt->u.action.u.addba_resp.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_ACTION_ADDBA_RESP:
cap = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
timeout = le16_to_cpu(mgmt->u.action.u.addba_resp.timeout);
cap = le16_to_cpu(mgmt->u.action.addba_resp.capab);
timeout = le16_to_cpu(mgmt->u.action.addba_resp.timeout);
dev_info(dev, "WLAN_ACTION_ADDBA_RESP: "
"timeout %i, tid %02x, buf_size %02x, policy %02x, "
"status %02x\n",
@ -5157,11 +5157,11 @@ static void rtl8xxxu_dump_action(struct device *dev,
(cap & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2,
(cap & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6,
(cap >> 1) & 0x1,
le16_to_cpu(mgmt->u.action.u.addba_resp.status));
le16_to_cpu(mgmt->u.action.addba_resp.status));
break;
case WLAN_ACTION_ADDBA_REQ:
cap = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
cap = le16_to_cpu(mgmt->u.action.addba_req.capab);
timeout = le16_to_cpu(mgmt->u.action.addba_req.timeout);
dev_info(dev, "WLAN_ACTION_ADDBA_REQ: "
"timeout %i, tid %02x, buf_size %02x, policy %02x\n",
timeout,
@ -5171,7 +5171,7 @@ static void rtl8xxxu_dump_action(struct device *dev,
break;
default:
dev_info(dev, "action frame %02x\n",
mgmt->u.action.u.addba_resp.action_code);
mgmt->u.action.action_code);
break;
}
}

View File

@ -1409,7 +1409,7 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
sta_entry =
(struct rtl_sta_info *)sta->drv_priv;
capab =
le16_to_cpu(mgmt->u.action.u.addba_req.capab);
le16_to_cpu(mgmt->u.action.addba_req.capab);
tid = (capab &
IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
if (tid >= MAX_TID_COUNT) {
@ -2392,35 +2392,35 @@ static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw,
struct sk_buff *skb;
struct ieee80211_mgmt *action_frame;
/* 27 = header + category + action + smps mode */
skb = dev_alloc_skb(27 + hw->extra_tx_headroom);
skb = dev_alloc_skb(IEEE80211_MIN_ACTION_SIZE(ht_smps) +
hw->extra_tx_headroom);
if (!skb)
return NULL;
skb_reserve(skb, hw->extra_tx_headroom);
action_frame = skb_put_zero(skb, 27);
action_frame = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE(ht_smps));
memcpy(action_frame->da, da, ETH_ALEN);
memcpy(action_frame->sa, rtlefuse->dev_addr, ETH_ALEN);
memcpy(action_frame->bssid, bssid, ETH_ALEN);
action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
action_frame->u.action.category = WLAN_CATEGORY_HT;
action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS;
action_frame->u.action.action_code = WLAN_HT_ACTION_SMPS;
switch (smps) {
case IEEE80211_SMPS_AUTOMATIC:/* 0 */
case IEEE80211_SMPS_NUM_MODES:/* 4 */
WARN_ON(1);
fallthrough;
case IEEE80211_SMPS_OFF:/* 1 */ /*MIMO_PS_NOLIMIT*/
action_frame->u.action.u.ht_smps.smps_control =
action_frame->u.action.ht_smps.smps_control =
WLAN_HT_SMPS_CONTROL_DISABLED;/* 0 */
break;
case IEEE80211_SMPS_STATIC:/* 2 */ /*MIMO_PS_STATIC*/
action_frame->u.action.u.ht_smps.smps_control =
action_frame->u.action.ht_smps.smps_control =
WLAN_HT_SMPS_CONTROL_STATIC;/* 1 */
break;
case IEEE80211_SMPS_DYNAMIC:/* 3 */ /*MIMO_PS_DYNAMIC*/
action_frame->u.action.u.ht_smps.smps_control =
action_frame->u.action.ht_smps.smps_control =
WLAN_HT_SMPS_CONTROL_DYNAMIC;/* 3 */
break;
}
@ -2519,25 +2519,25 @@ struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw,
struct ieee80211_mgmt *action_frame;
u16 params;
/* 27 = header + category + action + smps mode */
skb = dev_alloc_skb(34 + hw->extra_tx_headroom);
skb = dev_alloc_skb(IEEE80211_MIN_ACTION_SIZE(delba) +
hw->extra_tx_headroom);
if (!skb)
return NULL;
skb_reserve(skb, hw->extra_tx_headroom);
action_frame = skb_put_zero(skb, 34);
action_frame = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE(delba));
memcpy(action_frame->sa, sa, ETH_ALEN);
memcpy(action_frame->da, rtlefuse->dev_addr, ETH_ALEN);
memcpy(action_frame->bssid, bssid, ETH_ALEN);
action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
action_frame->u.action.category = WLAN_CATEGORY_BACK;
action_frame->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
action_frame->u.action.action_code = WLAN_ACTION_DELBA;
params = (u16)(1 << 11); /* bit 11 initiator */
params |= (u16)(tid << 12); /* bit 15:12 TID number */
action_frame->u.action.u.delba.params = cpu_to_le16(params);
action_frame->u.action.u.delba.reason_code =
action_frame->u.action.delba.params = cpu_to_le16(params);
action_frame->u.action.delba.reason_code =
cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
return skb;

View File

@ -507,7 +507,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
if (ieee80211_is_action(fc)) {
struct ieee80211_mgmt *action_frame =
(struct ieee80211_mgmt *)skb->data;
if (action_frame->u.action.u.ht_smps.action ==
if (action_frame->u.action.action_code ==
WLAN_HT_ACTION_SMPS) {
dev_kfree_skb(skb);
goto tx_status_ok;

View File

@ -325,6 +325,22 @@ void rsi_mac80211_detach(struct rsi_hw *adapter)
}
EXPORT_SYMBOL_GPL(rsi_mac80211_detach);
/**
* rsi_mac80211_rfkill_exit() - This function is used to stop rfkill polling
* when the device is removed.
* @adapter: Pointer to the adapter structure.
*
* Return: None.
*/
void rsi_mac80211_rfkill_exit(struct rsi_hw *adapter)
{
struct ieee80211_hw *hw = adapter->hw;
if (hw)
wiphy_rfkill_stop_polling(hw->wiphy);
}
EXPORT_SYMBOL_GPL(rsi_mac80211_rfkill_exit);
/**
* rsi_indicate_tx_status() - This function indicates the transmit status.
* @adapter: Pointer to the adapter structure.
@ -422,7 +438,6 @@ static void rsi_mac80211_stop(struct ieee80211_hw *hw, bool suspend)
rsi_dbg(ERR_ZONE, "===> Interface DOWN <===\n");
mutex_lock(&common->mutex);
common->iface_down = true;
wiphy_rfkill_stop_polling(hw->wiphy);
/* Block all rx frames */
rsi_send_rx_filter_frame(common, 0xffff);

View File

@ -877,6 +877,8 @@ static void rsi_disconnect(struct usb_interface *pfunction)
if (!adapter)
return;
rsi_mac80211_rfkill_exit(adapter);
rsi_mac80211_detach(adapter);
if (IS_ENABLED(CONFIG_RSI_COEX) && adapter->priv->coex_mode > 1 &&

View File

@ -79,6 +79,7 @@ static inline int rsi_kill_thread(struct rsi_thread *handle)
}
void rsi_mac80211_detach(struct rsi_hw *hw);
void rsi_mac80211_rfkill_exit(struct rsi_hw *hw);
u16 rsi_get_connected_channel(struct ieee80211_vif *vif);
struct rsi_hw *rsi_91x_init(u16 oper_mode);
void rsi_91x_deinit(struct rsi_hw *adapter);

View File

@ -21,14 +21,14 @@ static void wfx_rx_handle_ba(struct wfx_vif *wvif, struct ieee80211_mgmt *mgmt)
if (wfx_api_older_than(wvif->wdev, 3, 6))
return;
switch (mgmt->u.action.u.addba_req.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_ACTION_ADDBA_REQ:
params = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
params = le16_to_cpu(mgmt->u.action.addba_req.capab);
tid = (params & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
ieee80211_start_rx_ba_session_offl(vif, mgmt->sa, tid);
break;
case WLAN_ACTION_DELBA:
params = le16_to_cpu(mgmt->u.action.u.delba.params);
params = le16_to_cpu(mgmt->u.action.delba.params);
tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
ieee80211_stop_rx_ba_session_offl(vif, mgmt->sa, tid);
break;
@ -80,7 +80,7 @@ void wfx_rx_cb(struct wfx_vif *wvif, const struct wfx_hif_ind_rx *arg, struct sk
*/
if (ieee80211_is_action(frame->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
skb->len > IEEE80211_MIN_ACTION_SIZE) {
skb->len > IEEE80211_MIN_ACTION_SIZE(action_code)) {
wfx_rx_handle_ba(wvif, mgmt);
goto drop;
}

View File

@ -36,6 +36,8 @@
#include <linux/virtio.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include "mac80211_hwsim.h"
#define WARN_QUEUE 100
@ -1203,6 +1205,65 @@ static const struct file_operations hwsim_background_cac_ops = {
.llseek = default_llseek,
};
struct hwsim_chanctx_iter_arg {
struct ieee80211_chanctx_conf *conf;
u32 freq_mhz;
};
static void hwsim_6ghz_chanctx_iter(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *conf,
void *data)
{
struct hwsim_chanctx_iter_arg *arg = data;
if (conf->def.chan &&
conf->def.chan->band == NL80211_BAND_6GHZ &&
conf->def.chan->center_freq == arg->freq_mhz)
arg->conf = conf;
}
static ssize_t hwsim_simulate_incumbent_signal_write(struct file *file,
const char __user *ubuf,
size_t len, loff_t *ppos)
{
struct mac80211_hwsim_data *data = file->private_data;
struct hwsim_chanctx_iter_arg arg = {};
u32 bitmap;
char buf[64];
if (!len || len > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, ubuf, len))
return -EFAULT;
buf[len] = '\0';
if (sscanf(buf, "%u %i", &arg.freq_mhz, &bitmap) != 2)
return -EINVAL;
if (!arg.freq_mhz)
return -EINVAL;
ieee80211_iter_chan_contexts_atomic(data->hw,
hwsim_6ghz_chanctx_iter,
&arg);
if (!arg.conf)
return -EINVAL;
cfg80211_incumbent_signal_notify(data->hw->wiphy,
&arg.conf->def,
bitmap,
GFP_KERNEL);
return len;
}
static const struct file_operations hwsim_simulate_incumbent_signal_fops = {
.open = simple_open,
.write = hwsim_simulate_incumbent_signal_write,
};
static int hwsim_fops_group_read(void *dat, u64 *val)
{
struct mac80211_hwsim_data *data = dat;
@ -5950,6 +6011,9 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
debugfs_create_file("dfs_background_cac", 0200,
data->debugfs,
data, &hwsim_background_cac_ops);
debugfs_create_file("simulate_incumbent_signal_interference", 0200,
data->debugfs,
data, &hwsim_simulate_incumbent_signal_fops);
if (param->pmsr_capa) {
data->pmsr_capa = *param->pmsr_capa;

View File

@ -251,8 +251,8 @@ struct ieee80211_eht_operation_info {
#define IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF 0x40
#define IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK 0x07
#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_80MHZ 0x08
#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ 0x30
#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_80MHZ 0x10
#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ 0x20
#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_320MHZ 0x40
#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK 0x78
#define IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP 0x80

View File

@ -281,6 +281,9 @@ enum ieee80211_back_actioncode {
WLAN_ACTION_ADDBA_REQ = 0,
WLAN_ACTION_ADDBA_RESP = 1,
WLAN_ACTION_DELBA = 2,
WLAN_ACTION_NDP_ADDBA_REQ = 128,
WLAN_ACTION_NDP_ADDBA_RESP = 129,
WLAN_ACTION_NDP_DELBA = 130,
};
/* BACK (block-ack) parties */

View File

@ -12,8 +12,8 @@
#define IEEE80211_UHR_OPER_PARAMS_DPS_ENA 0x0001
#define IEEE80211_UHR_OPER_PARAMS_NPCA_ENA 0x0002
#define IEEE80211_UHR_OPER_PARAMS_DBE_ENA 0x0004
#define IEEE80211_UHR_OPER_PARAMS_PEDCA_ENA 0x0008
#define IEEE80211_UHR_OPER_PARAMS_PEDCA_ENA 0x0004
#define IEEE80211_UHR_OPER_PARAMS_DBE_ENA 0x0008
struct ieee80211_uhr_operation {
__le16 params;

View File

@ -1046,31 +1046,28 @@ struct ieee80211_mgmt {
} __packed probe_resp;
struct {
u8 category;
u8 action_code;
union {
struct {
u8 action_code;
u8 dialog_token;
u8 status_code;
u8 variable[];
} __packed wme_action;
struct{
u8 action_code;
u8 no_fixed_fields[0];
u8 variable[];
} __packed chan_switch;
struct{
u8 action_code;
struct ieee80211_ext_chansw_ie data;
u8 variable[];
} __packed ext_chan_switch;
struct{
u8 action_code;
u8 dialog_token;
u8 element_id;
u8 length;
struct ieee80211_msrment_ie msr_elem;
} __packed measurement;
struct{
u8 action_code;
u8 dialog_token;
__le16 capab;
__le16 timeout;
@ -1079,7 +1076,6 @@ struct ieee80211_mgmt {
u8 variable[];
} __packed addba_req;
struct{
u8 action_code;
u8 dialog_token;
__le16 status;
__le16 capab;
@ -1088,54 +1084,45 @@ struct ieee80211_mgmt {
u8 variable[];
} __packed addba_resp;
struct{
u8 action_code;
__le16 params;
__le16 reason_code;
} __packed delba;
struct {
u8 action_code;
u8 no_fixed_fields[0];
u8 variable[];
} __packed self_prot;
struct{
u8 action_code;
u8 no_fixed_fields[0];
u8 variable[];
} __packed mesh_action;
struct {
u8 action;
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
} __packed sa_query;
struct {
u8 action;
u8 smps_control;
} __packed ht_smps;
struct {
u8 action_code;
u8 chanwidth;
} __packed ht_notify_cw;
struct {
u8 action_code;
u8 dialog_token;
__le16 capability;
u8 variable[];
} __packed tdls_discover_resp;
struct {
u8 action_code;
u8 operating_mode;
} __packed vht_opmode_notif;
struct {
u8 action_code;
u8 membership[WLAN_MEMBERSHIP_LEN];
u8 position[WLAN_USER_POSITION_LEN];
} __packed vht_group_notif;
struct {
u8 action_code;
u8 dialog_token;
u8 tpc_elem_id;
u8 tpc_elem_length;
struct ieee80211_tpc_report_ie tpc;
} __packed tpc_report;
struct {
u8 action_code;
u8 dialog_token;
u8 follow_up;
u8 tod[6];
@ -1145,11 +1132,10 @@ struct ieee80211_mgmt {
u8 variable[];
} __packed ftm;
struct {
u8 action_code;
u8 no_fixed_fields[0];
u8 variable[];
} __packed s1g;
struct {
u8 action_code;
u8 dialog_token;
u8 follow_up;
u32 tod;
@ -1158,41 +1144,37 @@ struct ieee80211_mgmt {
u8 max_toa_error;
} __packed wnm_timing_msr;
struct {
u8 action_code;
u8 dialog_token;
u8 variable[];
} __packed ttlm_req;
struct {
u8 action_code;
u8 dialog_token;
__le16 status_code;
u8 variable[];
} __packed ttlm_res;
struct {
u8 action_code;
u8 no_fixed_fields[0];
/* no variable fields either */
} __packed ttlm_tear_down;
struct {
u8 action_code;
u8 dialog_token;
u8 variable[];
} __packed ml_reconf_req;
struct {
u8 action_code;
u8 dialog_token;
u8 count;
u8 variable[];
} __packed ml_reconf_resp;
struct {
u8 action_code;
u8 no_fixed_fields[0];
u8 variable[];
} __packed epcs;
struct {
u8 action_code;
u8 dialog_token;
u8 control;
u8 variable[];
} __packed eml_omn;
} u;
};
} __packed action;
DECLARE_FLEX_ARRAY(u8, body); /* Generic frame body */
} u;
@ -1210,8 +1192,7 @@ struct ieee80211_mgmt {
#define BSS_MEMBERSHIP_SELECTOR_MIN BSS_MEMBERSHIP_SELECTOR_UHR_PHY
/* mgmt header + 1 byte category code */
#define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u)
#define IEEE80211_MIN_ACTION_SIZE(type) offsetofend(struct ieee80211_mgmt, u.action.type)
/* Management MIC information element (IEEE 802.11w) for CMAC */
@ -1501,6 +1482,8 @@ enum ieee80211_statuscode {
WLAN_STATUS_REJECT_DSE_BAND = 96,
WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99,
WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103,
/* 802.11ah */
WLAN_STATUS_REJECTED_NDP_BLOCK_ACK_SUGGESTED = 109,
/* 802.11ai */
WLAN_STATUS_FILS_AUTHENTICATION_FAILURE = 112,
WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER = 113,
@ -2391,7 +2374,7 @@ static inline bool ieee80211_is_bufferable_mmpdu(struct sk_buff *skb)
if (!ieee80211_is_action(fc))
return false;
if (skb->len < offsetofend(typeof(*mgmt), u.action.u.ftm.action_code))
if (skb->len < IEEE80211_MIN_ACTION_SIZE(action_code))
return true;
/* action frame - additionally check for non-bufferable FTM */
@ -2400,8 +2383,8 @@ static inline bool ieee80211_is_bufferable_mmpdu(struct sk_buff *skb)
mgmt->u.action.category != WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION)
return true;
if (mgmt->u.action.u.ftm.action_code == WLAN_PUB_ACTION_FTM_REQUEST ||
mgmt->u.action.u.ftm.action_code == WLAN_PUB_ACTION_FTM_RESPONSE)
if (mgmt->u.action.action_code == WLAN_PUB_ACTION_FTM_REQUEST ||
mgmt->u.action.action_code == WLAN_PUB_ACTION_FTM_RESPONSE)
return false;
return true;
@ -2451,7 +2434,7 @@ static inline bool _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
*/
static inline bool ieee80211_is_robust_mgmt_frame(struct sk_buff *skb)
{
if (skb->len < IEEE80211_MIN_ACTION_SIZE)
if (skb->len < IEEE80211_MIN_ACTION_SIZE(category))
return false;
return _ieee80211_is_robust_mgmt_frame((void *)skb->data);
}
@ -2467,7 +2450,7 @@ static inline bool ieee80211_is_public_action(struct ieee80211_hdr *hdr,
{
struct ieee80211_mgmt *mgmt = (void *)hdr;
if (len < IEEE80211_MIN_ACTION_SIZE)
if (len < IEEE80211_MIN_ACTION_SIZE(category))
return false;
if (!ieee80211_is_action(hdr->frame_control))
return false;
@ -2485,13 +2468,14 @@ static inline bool ieee80211_is_public_action(struct ieee80211_hdr *hdr,
static inline bool
ieee80211_is_protected_dual_of_public_action(struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt = (void *)skb->data;
u8 action;
if (!ieee80211_is_public_action((void *)skb->data, skb->len) ||
skb->len < IEEE80211_MIN_ACTION_SIZE + 1)
skb->len < IEEE80211_MIN_ACTION_SIZE(action_code))
return false;
action = *(u8 *)(skb->data + IEEE80211_MIN_ACTION_SIZE);
action = mgmt->u.action.action_code;
return action != WLAN_PUB_ACTION_20_40_BSS_COEX &&
action != WLAN_PUB_ACTION_DSE_REG_LOC_ANN &&
@ -2530,7 +2514,7 @@ static inline bool _ieee80211_is_group_privacy_action(struct ieee80211_hdr *hdr)
*/
static inline bool ieee80211_is_group_privacy_action(struct sk_buff *skb)
{
if (skb->len < IEEE80211_MIN_ACTION_SIZE)
if (skb->len < IEEE80211_MIN_ACTION_SIZE(category))
return false;
return _ieee80211_is_group_privacy_action((void *)skb->data);
}
@ -2626,8 +2610,7 @@ static inline bool ieee80211_action_contains_tpc(struct sk_buff *skb)
if (!ieee80211_is_action(mgmt->frame_control))
return false;
if (skb->len < IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.tpc_report))
if (skb->len < IEEE80211_MIN_ACTION_SIZE(tpc_report))
return false;
/*
@ -2646,12 +2629,11 @@ static inline bool ieee80211_action_contains_tpc(struct sk_buff *skb)
return false;
/* both spectrum mgmt and link measurement have same action code */
if (mgmt->u.action.u.tpc_report.action_code !=
WLAN_ACTION_SPCT_TPC_RPRT)
if (mgmt->u.action.action_code != WLAN_ACTION_SPCT_TPC_RPRT)
return false;
if (mgmt->u.action.u.tpc_report.tpc_elem_id != WLAN_EID_TPC_REPORT ||
mgmt->u.action.u.tpc_report.tpc_elem_length !=
if (mgmt->u.action.tpc_report.tpc_elem_id != WLAN_EID_TPC_REPORT ||
mgmt->u.action.tpc_report.tpc_elem_length !=
sizeof(struct ieee80211_tpc_report_ie))
return false;
@ -2667,16 +2649,15 @@ static inline bool ieee80211_is_timing_measurement(struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt = (void *)skb->data;
if (skb->len < IEEE80211_MIN_ACTION_SIZE)
if (skb->len < IEEE80211_MIN_ACTION_SIZE(wnm_timing_msr))
return false;
if (!ieee80211_is_action(mgmt->frame_control))
return false;
if (mgmt->u.action.category == WLAN_CATEGORY_WNM_UNPROTECTED &&
mgmt->u.action.u.wnm_timing_msr.action_code ==
WLAN_UNPROTECTED_WNM_ACTION_TIMING_MEASUREMENT_RESPONSE &&
skb->len >= offsetofend(typeof(*mgmt), u.action.u.wnm_timing_msr))
mgmt->u.action.action_code ==
WLAN_UNPROTECTED_WNM_ACTION_TIMING_MEASUREMENT_RESPONSE)
return true;
return false;
@ -2691,15 +2672,13 @@ static inline bool ieee80211_is_ftm(struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt = (void *)skb->data;
if (skb->len < IEEE80211_MIN_ACTION_SIZE(ftm))
return false;
if (!ieee80211_is_public_action((void *)mgmt, skb->len))
return false;
if (mgmt->u.action.u.ftm.action_code ==
WLAN_PUB_ACTION_FTM_RESPONSE &&
skb->len >= offsetofend(typeof(*mgmt), u.action.u.ftm))
return true;
return false;
return mgmt->u.action.action_code == WLAN_PUB_ACTION_FTM_RESPONSE;
}
struct element {

View File

@ -2913,6 +2913,9 @@ struct ieee80211_txq {
* HW flag so drivers can opt in according to their own control, e.g. in
* testing.
*
* @IEEE80211_HW_SUPPORTS_NDP_BLOCKACK: HW can transmit/receive S1G NDP
* BlockAck frames.
*
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/
enum ieee80211_hw_flags {
@ -2973,6 +2976,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_DISALLOW_PUNCTURING,
IEEE80211_HW_HANDLES_QUIET_CSA,
IEEE80211_HW_STRICT,
IEEE80211_HW_SUPPORTS_NDP_BLOCKACK,
/* keep last, obviously */
NUM_IEEE80211_HW_FLAGS

View File

@ -3001,6 +3001,10 @@ enum nl80211_commands {
* interference detection is not performed on these sub-channels, their
* corresponding bits are consistently set to zero.
*
* @NL80211_ATTR_UHR_OPERATION: Full UHR Operation element, as it appears in
* association response etc., since it's abridged in the beacon. Used
* for START_AP etc.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@ -3576,6 +3580,8 @@ enum nl80211_attrs {
NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP,
NL80211_ATTR_UHR_OPERATION,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,

View File

@ -9,7 +9,7 @@
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2007-2010, Intel Corporation
* Copyright(c) 2015-2017 Intel Deutschland GmbH
* Copyright (C) 2018-2025 Intel Corporation
* Copyright (C) 2018-2026 Intel Corporation
*/
/**
@ -94,7 +94,8 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
/* check if this is a self generated aggregation halt */
if (initiator == WLAN_BACK_RECIPIENT && tx)
ieee80211_send_delba(sta->sdata, sta->sta.addr,
tid, WLAN_BACK_RECIPIENT, reason);
tid, WLAN_BACK_RECIPIENT, reason,
ieee80211_s1g_use_ndp_ba(sta->sdata, sta));
/*
* return here in case tid_rx is not assigned - which will happen if
@ -240,6 +241,7 @@ static void ieee80211_send_addba_resp(struct sta_info *sta, u8 *da, u16 tid,
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
bool amsdu = ieee80211_hw_check(&local->hw, SUPPORTS_AMSDU_IN_AMPDU);
bool use_ndp = ieee80211_s1g_use_ndp_ba(sdata, sta);
u16 capab;
skb = dev_alloc_skb(sizeof(*mgmt) +
@ -251,19 +253,21 @@ static void ieee80211_send_addba_resp(struct sta_info *sta, u8 *da, u16 tid,
skb_reserve(skb, local->hw.extra_tx_headroom);
mgmt = ieee80211_mgmt_ba(skb, da, sdata);
skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
skb_put(skb, 2 + sizeof(mgmt->u.action.addba_resp));
mgmt->u.action.category = WLAN_CATEGORY_BACK;
mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
mgmt->u.action.action_code = use_ndp ?
WLAN_ACTION_NDP_ADDBA_RESP : WLAN_ACTION_ADDBA_RESP;
mgmt->u.action.addba_resp.dialog_token = dialog_token;
capab = u16_encode_bits(amsdu, IEEE80211_ADDBA_PARAM_AMSDU_MASK);
capab |= u16_encode_bits(policy, IEEE80211_ADDBA_PARAM_POLICY_MASK);
capab |= u16_encode_bits(tid, IEEE80211_ADDBA_PARAM_TID_MASK);
capab |= u16_encode_bits(buf_size, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
mgmt->u.action.addba_resp.capab = cpu_to_le16(capab);
mgmt->u.action.addba_resp.timeout = cpu_to_le16(timeout);
mgmt->u.action.addba_resp.status = cpu_to_le16(status);
if (sta->sta.valid_links || sta->sta.deflink.he_cap.has_he)
ieee80211_add_addbaext(skb, req_addba_ext_data, buf_size);
@ -275,6 +279,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
u8 dialog_token, u16 timeout,
u16 start_seq_num, u16 ba_policy, u16 tid,
u16 buf_size, bool tx, bool auto_seq,
bool req_ndp,
const u8 addba_ext_data)
{
struct ieee80211_local *local = sta->sdata->local;
@ -300,6 +305,18 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
goto end;
}
if (tx && ieee80211_s1g_use_ndp_ba(sta->sdata, sta) && !req_ndp) {
/*
* According to IEEE 802.11-2024: Inform S1G originator
* ADDBA rejected as NDP BlockAck is preferred
*/
status = WLAN_STATUS_REJECTED_NDP_BLOCK_ACK_SUGGESTED;
ht_dbg(sta->sdata,
"Rejecting AddBA Req from %pM tid %u - require NDP BlockAck\n",
sta->sta.addr, tid);
goto end;
}
if (!sta->sta.valid_links &&
!sta->sta.deflink.ht_cap.ht_supported &&
!sta->sta.deflink.he_cap.has_he &&
@ -473,31 +490,33 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
struct ieee80211_mgmt *mgmt,
size_t len)
{
bool req_ndp = mgmt->u.action.action_code == WLAN_ACTION_NDP_ADDBA_REQ;
u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num;
u8 dialog_token, addba_ext_data;
/* extract session parameters from addba request frame */
dialog_token = mgmt->u.action.u.addba_req.dialog_token;
timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
dialog_token = mgmt->u.action.addba_req.dialog_token;
timeout = le16_to_cpu(mgmt->u.action.addba_req.timeout);
start_seq_num =
le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
le16_to_cpu(mgmt->u.action.addba_req.start_seq_num) >> 4;
capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
capab = le16_to_cpu(mgmt->u.action.addba_req.capab);
ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
addba_ext_data =
ieee80211_retrieve_addba_ext_data(sta,
mgmt->u.action.u.addba_req.variable,
mgmt->u.action.addba_req.variable,
len -
offsetof(typeof(*mgmt),
u.action.u.addba_req.variable),
u.action.addba_req.variable),
&buf_size);
__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
start_seq_num, ba_policy, tid,
buf_size, true, false, addba_ext_data);
buf_size, true, false,
req_ndp, addba_ext_data);
}
void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif,

View File

@ -9,7 +9,7 @@
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2007-2010, Intel Corporation
* Copyright(c) 2015-2017 Intel Deutschland GmbH
* Copyright (C) 2018 - 2024 Intel Corporation
* Copyright (C) 2018-2026 Intel Corporation
*/
#include <linux/ieee80211.h>
@ -60,7 +60,7 @@
static void ieee80211_send_addba_request(struct sta_info *sta, u16 tid,
u8 dialog_token, u16 start_seq_num,
u16 agg_size, u16 timeout)
u16 agg_size, u16 timeout, bool ndp)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
@ -68,7 +68,7 @@ static void ieee80211_send_addba_request(struct sta_info *sta, u16 tid,
struct ieee80211_mgmt *mgmt;
u16 capab;
skb = dev_alloc_skb(sizeof(*mgmt) +
skb = dev_alloc_skb(IEEE80211_MIN_ACTION_SIZE(addba_req) +
2 + sizeof(struct ieee80211_addba_ext_ie) +
local->hw.extra_tx_headroom);
if (!skb)
@ -77,21 +77,22 @@ static void ieee80211_send_addba_request(struct sta_info *sta, u16 tid,
skb_reserve(skb, local->hw.extra_tx_headroom);
mgmt = ieee80211_mgmt_ba(skb, sta->sta.addr, sdata);
skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
skb_put(skb, 2 + sizeof(mgmt->u.action.addba_req));
mgmt->u.action.category = WLAN_CATEGORY_BACK;
mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
mgmt->u.action.action_code = ndp ?
WLAN_ACTION_NDP_ADDBA_REQ : WLAN_ACTION_ADDBA_REQ;
mgmt->u.action.u.addba_req.dialog_token = dialog_token;
mgmt->u.action.addba_req.dialog_token = dialog_token;
capab = IEEE80211_ADDBA_PARAM_AMSDU_MASK;
capab |= IEEE80211_ADDBA_PARAM_POLICY_MASK;
capab |= u16_encode_bits(tid, IEEE80211_ADDBA_PARAM_TID_MASK);
capab |= u16_encode_bits(agg_size, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
mgmt->u.action.addba_req.capab = cpu_to_le16(capab);
mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
mgmt->u.action.u.addba_req.start_seq_num =
mgmt->u.action.addba_req.timeout = cpu_to_le16(timeout);
mgmt->u.action.addba_req.start_seq_num =
cpu_to_le16(start_seq_num << 4);
if (sta->sta.deflink.he_cap.has_he)
@ -484,7 +485,8 @@ static void ieee80211_send_addba_with_timeout(struct sta_info *sta,
/* send AddBA request */
ieee80211_send_addba_request(sta, tid, tid_tx->dialog_token,
tid_tx->ssn, buf_size, tid_tx->timeout);
tid_tx->ssn, buf_size, tid_tx->timeout,
tid_tx->ndp);
WARN_ON(test_and_set_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state));
}
@ -521,6 +523,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
*/
synchronize_net();
tid_tx->ndp = ieee80211_s1g_use_ndp_ba(sdata, sta);
params.ssn = sta->tid_seq[tid] >> 4;
ret = drv_ampdu_action(local, sdata, &params);
tid_tx->ssn = params.ssn;
@ -940,7 +943,9 @@ void ieee80211_stop_tx_ba_cb(struct sta_info *sta, int tid,
if (send_delba)
ieee80211_send_delba(sdata, sta->sta.addr, tid,
WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
WLAN_BACK_INITIATOR,
WLAN_REASON_QSTA_NOT_USE,
tid_tx->ndp);
}
void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
@ -978,15 +983,15 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
lockdep_assert_wiphy(sta->local->hw.wiphy);
capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
capab = le16_to_cpu(mgmt->u.action.addba_resp.capab);
amsdu = capab & IEEE80211_ADDBA_PARAM_AMSDU_MASK;
tid = u16_get_bits(capab, IEEE80211_ADDBA_PARAM_TID_MASK);
buf_size = u16_get_bits(capab, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
ieee80211_retrieve_addba_ext_data(sta,
mgmt->u.action.u.addba_resp.variable,
mgmt->u.action.addba_resp.variable,
len - offsetof(typeof(*mgmt),
u.action.u.addba_resp.variable),
u.action.addba_resp.variable),
&buf_size);
buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes);
@ -999,7 +1004,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
if (!tid_tx)
return;
if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) {
if (mgmt->u.action.addba_resp.dialog_token != tid_tx->dialog_token) {
ht_dbg(sta->sdata, "wrong addBA response token, %pM tid %d\n",
sta->sta.addr, tid);
return;
@ -1029,7 +1034,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
* is set to 0, the Buffer Size subfield is set to a value
* of at least 1.
*/
if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
if (le16_to_cpu(mgmt->u.action.addba_resp.status)
== WLAN_STATUS_SUCCESS && buf_size) {
if (test_and_set_bit(HT_AGG_STATE_RESPONSE_RECEIVED,
&tid_tx->state)) {
@ -1046,7 +1051,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
sta->ampdu_mlme.addba_req_num[tid] = 0;
tid_tx->timeout =
le16_to_cpu(mgmt->u.action.u.addba_resp.timeout);
le16_to_cpu(mgmt->u.action.addba_resp.timeout);
if (tid_tx->timeout) {
mod_timer(&tid_tx->session_timer,

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* mac80211 - channel management
* Copyright 2020 - 2025 Intel Corporation
* Copyright 2020-2026 Intel Corporation
*/
#include <linux/nl80211.h>
@ -239,24 +239,45 @@ ieee80211_chanreq_compatible(const struct ieee80211_chan_req *a,
return tmp;
}
/*
* When checking for compatible, check against all the links using
* the chanctx (except the one passed that might be changing) to
* allow changes to the AP's bandwidth for wider bandwidth OFDMA
* purposes, which wouldn't be treated as compatible by checking
* against the chanctx's oper/ap chandefs.
*/
static const struct ieee80211_chan_req *
ieee80211_chanctx_compatible(struct ieee80211_chanctx *ctx,
_ieee80211_chanctx_compatible(struct ieee80211_local *local,
struct ieee80211_link_data *skip_link,
struct ieee80211_chanctx *ctx,
const struct ieee80211_chan_req *req,
struct ieee80211_chan_req *tmp)
{
const struct ieee80211_chan_req *ret = req;
struct ieee80211_chanctx_user_iter iter;
lockdep_assert_wiphy(local->hw.wiphy);
for_each_chanctx_user_all(local, ctx, &iter) {
if (iter.link && iter.link == skip_link)
continue;
ret = ieee80211_chanreq_compatible(ret, iter.chanreq, tmp);
if (!ret)
return NULL;
}
*tmp = *ret;
return tmp;
}
static const struct ieee80211_chan_req *
ieee80211_chanctx_compatible(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
const struct ieee80211_chan_req *req,
struct ieee80211_chan_req *tmp)
{
const struct ieee80211_chan_req *ret;
struct ieee80211_chan_req tmp2;
*tmp = (struct ieee80211_chan_req){
.oper = ctx->conf.def,
.ap = ctx->conf.ap,
};
ret = ieee80211_chanreq_compatible(tmp, req, &tmp2);
if (!ret)
return NULL;
*tmp = *ret;
return tmp;
return _ieee80211_chanctx_compatible(local, NULL, ctx, req, tmp);
}
static const struct ieee80211_chan_req *
@ -756,7 +777,8 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
continue;
compat = ieee80211_chanctx_compatible(ctx, chanreq, &tmp);
compat = ieee80211_chanctx_compatible(local, ctx, chanreq,
&tmp);
if (!compat)
continue;
@ -2128,40 +2150,6 @@ int ieee80211_link_use_reserved_context(struct ieee80211_link_data *link)
return 0;
}
/*
* This is similar to ieee80211_chanctx_compatible(), but rechecks
* against all the links actually using it (except the one that's
* passed, since that one is changing).
* This is done in order to allow changes to the AP's bandwidth for
* wider bandwidth OFDMA purposes, which wouldn't be treated as
* compatible by ieee80211_chanctx_recheck() but is OK if the link
* requesting the update is the only one using it.
*/
static const struct ieee80211_chan_req *
ieee80211_chanctx_recheck(struct ieee80211_local *local,
struct ieee80211_link_data *skip_link,
struct ieee80211_chanctx *ctx,
const struct ieee80211_chan_req *req,
struct ieee80211_chan_req *tmp)
{
const struct ieee80211_chan_req *ret = req;
struct ieee80211_chanctx_user_iter iter;
lockdep_assert_wiphy(local->hw.wiphy);
for_each_chanctx_user_all(local, ctx, &iter) {
if (iter.link == skip_link)
continue;
ret = ieee80211_chanreq_compatible(ret, iter.chanreq, tmp);
if (!ret)
return NULL;
}
*tmp = *ret;
return tmp;
}
int ieee80211_link_change_chanreq(struct ieee80211_link_data *link,
const struct ieee80211_chan_req *chanreq,
u64 *changed)
@ -2198,7 +2186,7 @@ int ieee80211_link_change_chanreq(struct ieee80211_link_data *link,
ctx = container_of(conf, struct ieee80211_chanctx, conf);
compat = ieee80211_chanctx_recheck(local, link, ctx, chanreq, &tmp);
compat = _ieee80211_chanctx_compatible(local, link, ctx, chanreq, &tmp);
if (!compat)
return -EINVAL;

View File

@ -490,6 +490,7 @@ static const char *hw_flag_names[] = {
FLAG(DISALLOW_PUNCTURING),
FLAG(HANDLES_QUIET_CSA),
FLAG(STRICT),
FLAG(SUPPORTS_NDP_BLOCKACK),
#undef FLAG
};

View File

@ -108,7 +108,7 @@ static void
ieee80211_send_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *req, int opt_len)
{
int len = offsetofend(struct ieee80211_mgmt, u.action.u.eml_omn);
int len = IEEE80211_MIN_ACTION_SIZE(eml_omn);
struct ieee80211_local *local = sdata->local;
struct ieee80211_mgmt *mgmt;
struct sk_buff *skb;
@ -127,16 +127,15 @@ ieee80211_send_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT;
mgmt->u.action.u.eml_omn.action_code =
WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF;
mgmt->u.action.u.eml_omn.dialog_token =
req->u.action.u.eml_omn.dialog_token;
mgmt->u.action.u.eml_omn.control = req->u.action.u.eml_omn.control &
mgmt->u.action.action_code = WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF;
mgmt->u.action.eml_omn.dialog_token =
req->u.action.eml_omn.dialog_token;
mgmt->u.action.eml_omn.control = req->u.action.eml_omn.control &
~(IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE |
IEEE80211_EML_CTRL_INDEV_COEX_ACT);
/* Copy optional fields from the received notification frame */
memcpy(mgmt->u.action.u.eml_omn.variable,
req->u.action.u.eml_omn.variable, opt_len);
memcpy(mgmt->u.action.eml_omn.variable,
req->u.action.eml_omn.variable, opt_len);
ieee80211_tx_skb(sdata, skb);
}
@ -144,14 +143,14 @@ ieee80211_send_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
int len = offsetofend(struct ieee80211_mgmt, u.action.u.eml_omn);
int len = IEEE80211_MIN_ACTION_SIZE(eml_omn);
enum nl80211_iftype type = ieee80211_vif_type_p2p(&sdata->vif);
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
const struct wiphy_iftype_ext_capab *ift_ext_capa;
struct ieee80211_mgmt *mgmt = (void *)skb->data;
struct ieee80211_local *local = sdata->local;
u8 control = mgmt->u.action.u.eml_omn.control;
u8 *ptr = mgmt->u.action.u.eml_omn.variable;
u8 control = mgmt->u.action.eml_omn.control;
u8 *ptr = mgmt->u.action.eml_omn.variable;
struct ieee80211_eml_params eml_params = {
.link_id = status->link_id,
.control = control,

View File

@ -9,7 +9,7 @@
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2007-2010, Intel Corporation
* Copyright 2017 Intel Deutschland GmbH
* Copyright(c) 2020-2025 Intel Corporation
* Copyright(c) 2020-2026 Intel Corporation
*/
#include <linux/ieee80211.h>
@ -379,7 +379,7 @@ void ieee80211_ba_session_work(struct wiphy *wiphy, struct wiphy_work *work)
sta->ampdu_mlme.tid_rx_manage_offl))
__ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid,
IEEE80211_MAX_AMPDU_BUF_HT,
false, true, 0);
false, true, false, 0);
if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS,
sta->ampdu_mlme.tid_rx_manage_offl))
@ -455,29 +455,32 @@ void ieee80211_ba_session_work(struct wiphy *wiphy, struct wiphy_work *work)
void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
const u8 *da, u16 tid,
u16 initiator, u16 reason_code)
u16 initiator, u16 reason_code,
bool use_ndp)
{
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u16 params;
skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
skb = dev_alloc_skb(IEEE80211_MIN_ACTION_SIZE(delba) +
local->hw.extra_tx_headroom);
if (!skb)
return;
skb_reserve(skb, local->hw.extra_tx_headroom);
mgmt = ieee80211_mgmt_ba(skb, da, sdata);
skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba));
skb_put(skb, 2 + sizeof(mgmt->u.action.delba));
mgmt->u.action.category = WLAN_CATEGORY_BACK;
mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
mgmt->u.action.action_code = use_ndp ?
WLAN_ACTION_NDP_DELBA : WLAN_ACTION_DELBA;
params = (u16)(initiator << 11); /* bit 11 initiator */
params |= (u16)(tid << 12); /* bit 15:12 TID number */
mgmt->u.action.u.delba.params = cpu_to_le16(params);
mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
mgmt->u.action.delba.params = cpu_to_le16(params);
mgmt->u.action.delba.reason_code = cpu_to_le16(reason_code);
ieee80211_tx_skb(sdata, skb);
}
@ -489,14 +492,14 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
u16 tid, params;
u16 initiator;
params = le16_to_cpu(mgmt->u.action.u.delba.params);
params = le16_to_cpu(mgmt->u.action.delba.params);
tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11;
ht_dbg_ratelimited(sdata, "delba from %pM (%s) tid %d reason code %d\n",
mgmt->sa, initiator ? "initiator" : "recipient",
tid,
le16_to_cpu(mgmt->u.action.u.delba.reason_code));
le16_to_cpu(mgmt->u.action.delba.reason_code));
if (initiator == WLAN_BACK_INITIATOR)
__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0,
@ -530,20 +533,20 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
struct ieee80211_tx_info *info;
u8 status_link_id = link_id < 0 ? 0 : link_id;
/* 27 = header + category + action + smps mode */
skb = dev_alloc_skb(27 + local->hw.extra_tx_headroom);
skb = dev_alloc_skb(IEEE80211_MIN_ACTION_SIZE(ht_smps) +
local->hw.extra_tx_headroom);
if (!skb)
return -ENOMEM;
skb_reserve(skb, local->hw.extra_tx_headroom);
action_frame = skb_put(skb, 27);
action_frame = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE(ht_smps));
memcpy(action_frame->da, da, ETH_ALEN);
memcpy(action_frame->sa, sdata->dev->dev_addr, ETH_ALEN);
memcpy(action_frame->bssid, bssid, ETH_ALEN);
action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
action_frame->u.action.category = WLAN_CATEGORY_HT;
action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS;
action_frame->u.action.action_code = WLAN_HT_ACTION_SMPS;
switch (smps) {
case IEEE80211_SMPS_AUTOMATIC:
case IEEE80211_SMPS_NUM_MODES:
@ -551,15 +554,15 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
smps = IEEE80211_SMPS_OFF;
fallthrough;
case IEEE80211_SMPS_OFF:
action_frame->u.action.u.ht_smps.smps_control =
action_frame->u.action.ht_smps.smps_control =
WLAN_HT_SMPS_CONTROL_DISABLED;
break;
case IEEE80211_SMPS_STATIC:
action_frame->u.action.u.ht_smps.smps_control =
action_frame->u.action.ht_smps.smps_control =
WLAN_HT_SMPS_CONTROL_STATIC;
break;
case IEEE80211_SMPS_DYNAMIC:
action_frame->u.action.u.ht_smps.smps_control =
action_frame->u.action.ht_smps.smps_control =
WLAN_HT_SMPS_CONTROL_DYNAMIC;
break;
}

View File

@ -9,7 +9,7 @@
* Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* Copyright(c) 2018-2025 Intel Corporation
* Copyright(c) 2018-2026 Intel Corporation
*/
#include <linux/delay.h>
@ -888,19 +888,11 @@ ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata,
struct ieee80211_rx_status *rx_status,
struct ieee802_11_elems *elems)
{
int required_len;
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
if (len < IEEE80211_MIN_ACTION_SIZE(chan_switch))
return;
/* CSA is the only action we handle for now */
if (mgmt->u.action.u.measurement.action_code !=
WLAN_ACTION_SPCT_CHL_SWITCH)
return;
required_len = IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.chan_switch);
if (len < required_len)
if (mgmt->u.action.action_code != WLAN_ACTION_SPCT_CHL_SWITCH)
return;
if (!sdata->vif.bss_conf.csa_active)
@ -1613,12 +1605,12 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
case WLAN_CATEGORY_SPECTRUM_MGMT:
ies_len = skb->len -
offsetof(struct ieee80211_mgmt,
u.action.u.chan_switch.variable);
u.action.chan_switch.variable);
if (ies_len < 0)
break;
elems = ieee802_11_parse_elems(mgmt->u.action.u.chan_switch.variable,
elems = ieee802_11_parse_elems(mgmt->u.action.chan_switch.variable,
ies_len,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,

View File

@ -2190,7 +2190,8 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
struct link_sta_info *link_sta);
void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
const u8 *da, u16 tid,
u16 initiator, u16 reason_code);
u16 initiator, u16 reason_code,
bool use_ndp);
int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps, const u8 *da,
const u8 *bssid, int link_id);
@ -2206,6 +2207,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
u8 dialog_token, u16 timeout,
u16 start_seq_num, u16 ba_policy, u16 tid,
u16 buf_size, bool tx, bool auto_seq,
bool req_ndp,
const u8 addba_ext_data);
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
enum ieee80211_agg_stop_reason reason);
@ -2331,6 +2333,8 @@ void ieee80211_s1g_status_twt_action(struct ieee80211_sub_if_data *sdata,
void ieee80211_s1g_cap_to_sta_s1g_cap(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_s1g_cap *s1g_cap_ie,
struct link_sta_info *link_sta);
bool ieee80211_s1g_use_ndp_ba(const struct ieee80211_sub_if_data *sdata,
const struct sta_info *sta);
/* Spectrum management */
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,

View File

@ -1579,16 +1579,19 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
sta = sta_info_get_bss(sdata, mgmt->sa);
if (sta) {
switch (mgmt->u.action.u.addba_req.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_ACTION_ADDBA_REQ:
case WLAN_ACTION_NDP_ADDBA_REQ:
ieee80211_process_addba_request(local, sta,
mgmt, len);
break;
case WLAN_ACTION_ADDBA_RESP:
case WLAN_ACTION_NDP_ADDBA_RESP:
ieee80211_process_addba_resp(local, sta,
mgmt, len);
break;
case WLAN_ACTION_DELBA:
case WLAN_ACTION_NDP_DELBA:
ieee80211_process_delba(sdata, sta,
mgmt, len);
break;
@ -1599,9 +1602,9 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
}
} else if (ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_HT) {
switch (mgmt->u.action.u.ht_smps.action) {
switch (mgmt->u.action.action_code) {
case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: {
u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth;
u8 chanwidth = mgmt->u.action.ht_notify_cw.chanwidth;
struct ieee80211_rx_status *status;
struct link_sta_info *link_sta;
struct sta_info *sta;
@ -1628,7 +1631,7 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
}
} else if (ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_VHT) {
switch (mgmt->u.action.u.vht_group_notif.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_VHT_ACTION_OPMODE_NOTIF: {
struct ieee80211_rx_status *status;
enum nl80211_band band;
@ -1637,7 +1640,7 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
status = IEEE80211_SKB_RXCB(skb);
band = status->band;
opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode;
opmode = mgmt->u.action.vht_opmode_notif.operating_mode;
sta = sta_info_get_bss(sdata, mgmt->sa);
@ -1658,7 +1661,7 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
}
} else if (ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_S1G) {
switch (mgmt->u.action.u.s1g.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_S1G_TWT_TEARDOWN:
case WLAN_S1G_TWT_SETUP:
ieee80211_s1g_rx_twt_action(sdata, skb);
@ -1669,7 +1672,7 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
} else if (ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_PROTECTED_EHT) {
if (sdata->vif.type == NL80211_IFTYPE_AP) {
switch (mgmt->u.action.u.eml_omn.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF:
ieee80211_rx_eml_op_mode_notif(sdata, skb);
break;
@ -1677,7 +1680,7 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
break;
}
} else if (sdata->vif.type == NL80211_IFTYPE_STATION) {
switch (mgmt->u.action.u.ttlm_req.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_PROTECTED_EHT_ACTION_TTLM_REQ:
ieee80211_process_neg_ttlm_req(sdata, mgmt,
skb->len);
@ -1765,7 +1768,7 @@ static void ieee80211_iface_process_status(struct ieee80211_sub_if_data *sdata,
if (ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_S1G) {
switch (mgmt->u.action.u.s1g.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_S1G_TWT_TEARDOWN:
case WLAN_S1G_TWT_SETUP:
ieee80211_s1g_status_twt_action(sdata, skb);

View File

@ -1118,6 +1118,19 @@ ieee80211_ifcomb_check(const struct ieee80211_iface_combination *c, int n_comb)
return true;
}
static void ieee80211_create_default_chandef(struct cfg80211_chan_def *chandef,
struct ieee80211_channel *chan)
{
*chandef = (struct cfg80211_chan_def) {
.chan = chan,
.width = chan->band == NL80211_BAND_S1GHZ ?
NL80211_CHAN_WIDTH_1 :
NL80211_CHAN_WIDTH_20_NOHT,
.center_freq1 = chan->center_freq,
.freq1_offset = chan->freq_offset,
};
}
int ieee80211_register_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
@ -1261,9 +1274,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
/* if none found then use the first anyway */
if (i == sband->n_channels)
i = 0;
cfg80211_chandef_create(&dflt_chandef,
&sband->channels[i],
NL80211_CHAN_NO_HT);
ieee80211_create_default_chandef(&dflt_chandef,
&sband->channels[i]);
/* init channel we're on */
local->monitor_chanreq.oper = dflt_chandef;
if (local->emulate_chanctx) {

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2008, 2009 open80211s Ltd.
* Copyright (C) 2018 - 2025 Intel Corporation
* Copyright (C) 2018-2026 Intel Corporation
* Authors: Luis Carlos Cobo <luisca@cozybit.com>
* Javier Cardona <javier@cozybit.com>
*/
@ -19,8 +19,7 @@ static struct kmem_cache *rm_cache;
bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
{
return (mgmt->u.action.u.mesh_action.action_code ==
WLAN_MESH_ACTION_HWMP_PATH_SELECTION);
return mgmt->u.action.action_code == WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
}
void ieee80211s_init(void)
@ -1618,13 +1617,12 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
size_t baselen;
u8 *pos;
if (mgmt->u.action.u.measurement.action_code !=
WLAN_ACTION_SPCT_CHL_SWITCH)
if (mgmt->u.action.action_code != WLAN_ACTION_SPCT_CHL_SWITCH)
return;
pos = mgmt->u.action.u.chan_switch.variable;
pos = mgmt->u.action.chan_switch.variable;
baselen = offsetof(struct ieee80211_mgmt,
u.action.u.chan_switch.variable);
u.action.chan_switch.variable);
elems = ieee802_11_parse_elems(pos, len - baselen,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
@ -1670,7 +1668,7 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
{
switch (mgmt->u.action.category) {
case WLAN_CATEGORY_SELF_PROTECTED:
switch (mgmt->u.action.u.self_prot.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_SP_MESH_PEERING_OPEN:
case WLAN_SP_MESH_PEERING_CLOSE:
case WLAN_SP_MESH_PEERING_CONFIRM:

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2008, 2009 open80211s Ltd.
* Copyright (C) 2019, 2021-2023, 2025 Intel Corporation
* Copyright (C) 2019, 2021-2023, 2025-2026 Intel Corporation
* Author: Luis Carlos Cobo <luisca@cozybit.com>
*/
@ -105,12 +105,11 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
u32 lifetime, u32 metric, u32 preq_id,
struct ieee80211_sub_if_data *sdata)
{
int hdr_len = IEEE80211_MIN_ACTION_SIZE(mesh_action);
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos, ie_len;
int hdr_len = offsetofend(struct ieee80211_mgmt,
u.action.u.mesh_action);
skb = dev_alloc_skb(local->tx_headroom +
hdr_len +
@ -127,8 +126,7 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
/* BSSID == SA */
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
mgmt->u.action.u.mesh_action.action_code =
WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
mgmt->u.action.action_code = WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
switch (action) {
case MPATH_PREQ:
@ -237,13 +235,12 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
u8 ttl, const u8 *target, u32 target_sn,
u16 target_rcode, const u8 *ra)
{
int hdr_len = IEEE80211_MIN_ACTION_SIZE(mesh_action);
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_mgmt *mgmt;
u8 *pos, ie_len;
int hdr_len = offsetofend(struct ieee80211_mgmt,
u.action.u.mesh_action);
if (time_before(jiffies, ifmsh->next_perr))
return -EAGAIN;
@ -265,8 +262,7 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
/* BSSID == SA */
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
mgmt->u.action.u.mesh_action.action_code =
WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
mgmt->u.action.action_code = WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
ie_len = 15;
pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_PERR;
@ -938,7 +934,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta;
/* need action_code */
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
if (len < IEEE80211_MIN_ACTION_SIZE(mesh_action))
return;
rcu_read_lock();
@ -949,8 +945,8 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
}
rcu_read_unlock();
baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
elems = ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
baselen = mgmt->u.action.mesh_action.variable - (u8 *)mgmt;
elems = ieee802_11_parse_elems(mgmt->u.action.mesh_action.variable,
len - baselen,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2008, 2009 open80211s Ltd.
* Copyright (C) 2019, 2021-2025 Intel Corporation
* Copyright (C) 2019, 2021-2026 Intel Corporation
* Author: Luis Carlos Cobo <luisca@cozybit.com>
*/
#include <linux/gfp.h>
@ -13,7 +13,7 @@
#include "rate.h"
#include "mesh.h"
#define PLINK_CNF_AID(mgmt) ((mgmt)->u.action.u.self_prot.variable + 2)
#define PLINK_CNF_AID(mgmt) ((mgmt)->u.action.self_prot.variable + 2)
#define PLINK_GET_LLID(p) (p + 2)
#define PLINK_GET_PLID(p) (p + 4)
@ -215,6 +215,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
enum ieee80211_self_protected_actioncode action,
u8 *da, u16 llid, u16 plid, u16 reason)
{
int hdr_len = IEEE80211_MIN_ACTION_SIZE(self_prot);
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct ieee80211_tx_info *info;
@ -223,7 +224,6 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
u16 peering_proto = 0;
u8 *pos, ie_len = 4;
u8 ie_len_he_cap, ie_len_eht_cap;
int hdr_len = offsetofend(struct ieee80211_mgmt, u.action.u.self_prot);
int err = -ENOMEM;
ie_len_he_cap = ieee80211_ie_len_he_cap(sdata);
@ -260,7 +260,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
mgmt->u.action.category = WLAN_CATEGORY_SELF_PROTECTED;
mgmt->u.action.u.self_prot.action_code = action;
mgmt->u.action.action_code = action;
if (action != WLAN_SP_MESH_PEERING_CLOSE) {
struct ieee80211_supported_band *sband;
@ -1141,7 +1141,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
return;
}
ftype = mgmt->u.action.u.self_prot.action_code;
ftype = mgmt->u.action.action_code;
if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
(ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
(ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
@ -1224,8 +1224,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
size_t baselen;
u8 *baseaddr;
/* need action_code, aux */
if (len < IEEE80211_MIN_ACTION_SIZE + 3)
/* need aux */
if (len < IEEE80211_MIN_ACTION_SIZE(self_prot) + 1)
return;
if (sdata->u.mesh.user_mpm)
@ -1238,10 +1238,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
return;
}
baseaddr = mgmt->u.action.u.self_prot.variable;
baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
if (mgmt->u.action.u.self_prot.action_code ==
WLAN_SP_MESH_PEERING_CONFIRM) {
baseaddr = mgmt->u.action.self_prot.variable;
baselen = mgmt->u.action.self_prot.variable - (u8 *)mgmt;
if (mgmt->u.action.action_code == WLAN_SP_MESH_PEERING_CONFIRM) {
baseaddr += 4;
baselen += 4;

View File

@ -216,6 +216,24 @@ ieee80211_determine_ap_chan(struct ieee80211_sub_if_data *sdata,
return IEEE80211_CONN_MODE_LEGACY;
}
if (eht_oper && ieee80211_hw_check(&sdata->local->hw, STRICT)) {
struct cfg80211_chan_def he_chandef = *chandef;
if (!ieee80211_chandef_he_6ghz_oper(sdata->local,
he_oper, NULL,
&he_chandef)) {
sdata_info(sdata,
"bad HE operation in EHT AP\n");
return IEEE80211_CONN_MODE_LEGACY;
}
if (!cfg80211_chandef_compatible(chandef,
&he_chandef)) {
sdata_info(sdata, "HE/EHT incompatible\n");
return IEEE80211_CONN_MODE_LEGACY;
}
}
if (mode <= IEEE80211_CONN_MODE_EHT)
return mode;
goto check_uhr;
@ -6721,7 +6739,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
sdata_info(sdata,
"RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n",
reassoc ? "Rea" : "A", assoc_data->ap_addr,
capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
capab_info, status_code, aid);
ifmgd->broken_ap = false;
@ -7058,6 +7076,7 @@ static void ieee80211_ml_reconf_work(struct wiphy *wiphy,
container_of(work, struct ieee80211_sub_if_data,
u.mgd.ml_reconf_work.work);
u16 new_valid_links, new_active_links, new_dormant_links;
struct sta_info *sta;
int ret;
if (!sdata->u.mgd.removed_links)
@ -7093,6 +7112,16 @@ static void ieee80211_ml_reconf_work(struct wiphy *wiphy,
}
}
sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);
if (sta) {
unsigned long removed_links = sdata->u.mgd.removed_links;
unsigned int link_id;
for_each_set_bit(link_id, &removed_links,
IEEE80211_MLD_MAX_NUM_LINKS)
ieee80211_sta_remove_link(sta, link_id);
}
new_dormant_links = sdata->vif.dormant_links & ~sdata->u.mgd.removed_links;
ret = ieee80211_vif_set_links(sdata, new_valid_links,
@ -7957,7 +7986,7 @@ ieee80211_send_neg_ttlm_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct ieee80211_mgmt *mgmt;
struct sk_buff *skb;
int hdr_len = offsetofend(struct ieee80211_mgmt, u.action.u.ttlm_req);
int hdr_len = IEEE80211_MIN_ACTION_SIZE(ttlm_req);
int ttlm_max_len = 2 + 1 + sizeof(struct ieee80211_ttlm_elem) + 1 +
2 * 2 * IEEE80211_TTLM_NUM_TIDS;
@ -7974,9 +8003,8 @@ ieee80211_send_neg_ttlm_req(struct ieee80211_sub_if_data *sdata,
memcpy(mgmt->bssid, sdata->vif.cfg.ap_addr, ETH_ALEN);
mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT;
mgmt->u.action.u.ttlm_req.action_code =
WLAN_PROTECTED_EHT_ACTION_TTLM_REQ;
mgmt->u.action.u.ttlm_req.dialog_token = dialog_token;
mgmt->u.action.action_code = WLAN_PROTECTED_EHT_ACTION_TTLM_REQ;
mgmt->u.action.ttlm_req.dialog_token = dialog_token;
ieee80211_neg_ttlm_add_suggested_map(skb, neg_ttlm);
ieee80211_tx_skb(sdata, skb);
}
@ -8026,7 +8054,7 @@ ieee80211_send_neg_ttlm_res(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct ieee80211_mgmt *mgmt;
struct sk_buff *skb;
int hdr_len = offsetofend(struct ieee80211_mgmt, u.action.u.ttlm_res);
int hdr_len = IEEE80211_MIN_ACTION_SIZE(ttlm_res);
int ttlm_max_len = 2 + 1 + sizeof(struct ieee80211_ttlm_elem) + 1 +
2 * 2 * IEEE80211_TTLM_NUM_TIDS;
u16 status_code;
@ -8044,9 +8072,8 @@ ieee80211_send_neg_ttlm_res(struct ieee80211_sub_if_data *sdata,
memcpy(mgmt->bssid, sdata->vif.cfg.ap_addr, ETH_ALEN);
mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT;
mgmt->u.action.u.ttlm_res.action_code =
WLAN_PROTECTED_EHT_ACTION_TTLM_RES;
mgmt->u.action.u.ttlm_res.dialog_token = dialog_token;
mgmt->u.action.action_code = WLAN_PROTECTED_EHT_ACTION_TTLM_RES;
mgmt->u.action.ttlm_res.dialog_token = dialog_token;
switch (ttlm_res) {
default:
WARN_ON(1);
@ -8063,7 +8090,7 @@ ieee80211_send_neg_ttlm_res(struct ieee80211_sub_if_data *sdata,
break;
}
mgmt->u.action.u.ttlm_res.status_code = cpu_to_le16(status_code);
mgmt->u.action.ttlm_res.status_code = cpu_to_le16(status_code);
ieee80211_tx_skb(sdata, skb);
}
@ -8163,10 +8190,9 @@ void ieee80211_process_neg_ttlm_req(struct ieee80211_sub_if_data *sdata,
if (!ieee80211_vif_is_mld(&sdata->vif))
return;
dialog_token = mgmt->u.action.u.ttlm_req.dialog_token;
ies_len = len - offsetof(struct ieee80211_mgmt,
u.action.u.ttlm_req.variable);
elems = ieee802_11_parse_elems(mgmt->u.action.u.ttlm_req.variable,
dialog_token = mgmt->u.action.ttlm_req.dialog_token;
ies_len = len - IEEE80211_MIN_ACTION_SIZE(ttlm_req);
elems = ieee802_11_parse_elems(mgmt->u.action.ttlm_req.variable,
ies_len,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
@ -8217,8 +8243,7 @@ void ieee80211_process_neg_ttlm_res(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len)
{
if (!ieee80211_vif_is_mld(&sdata->vif) ||
mgmt->u.action.u.ttlm_req.dialog_token !=
sdata->u.mgd.dialog_token_alloc)
mgmt->u.action.ttlm_res.dialog_token != sdata->u.mgd.dialog_token_alloc)
return;
wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
@ -8232,7 +8257,7 @@ void ieee80211_process_neg_ttlm_res(struct ieee80211_sub_if_data *sdata,
* This can be better implemented in the future, to handle request
* rejections.
*/
if (le16_to_cpu(mgmt->u.action.u.ttlm_res.status_code) != WLAN_STATUS_SUCCESS)
if (le16_to_cpu(mgmt->u.action.ttlm_res.status_code) != WLAN_STATUS_SUCCESS)
__ieee80211_disconnect(sdata);
}
@ -8265,12 +8290,11 @@ static void ieee80211_teardown_ttlm_work(struct wiphy *wiphy,
void ieee80211_send_teardown_neg_ttlm(struct ieee80211_vif *vif)
{
int frame_len = IEEE80211_MIN_ACTION_SIZE(ttlm_tear_down);
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_local *local = sdata->local;
struct ieee80211_mgmt *mgmt;
struct sk_buff *skb;
int frame_len = offsetofend(struct ieee80211_mgmt,
u.action.u.ttlm_tear_down);
struct ieee80211_tx_info *info;
skb = dev_alloc_skb(local->hw.extra_tx_headroom + frame_len);
@ -8286,8 +8310,7 @@ void ieee80211_send_teardown_neg_ttlm(struct ieee80211_vif *vif)
memcpy(mgmt->bssid, sdata->vif.cfg.ap_addr, ETH_ALEN);
mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT;
mgmt->u.action.u.ttlm_tear_down.action_code =
WLAN_PROTECTED_EHT_ACTION_TTLM_TEARDOWN;
mgmt->u.action.action_code = WLAN_PROTECTED_EHT_ACTION_TTLM_TEARDOWN;
info = IEEE80211_SKB_CB(skb);
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
@ -8370,13 +8393,13 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
case WLAN_CATEGORY_SPECTRUM_MGMT:
ies_len = skb->len -
offsetof(struct ieee80211_mgmt,
u.action.u.chan_switch.variable);
u.action.chan_switch.variable);
if (ies_len < 0)
break;
/* CSA IE cannot be overridden, no need for BSSID */
elems = ieee802_11_parse_elems(mgmt->u.action.u.chan_switch.variable,
elems = ieee802_11_parse_elems(mgmt->u.action.chan_switch.variable,
ies_len,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
@ -8398,7 +8421,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
case WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION:
ies_len = skb->len -
offsetof(struct ieee80211_mgmt,
u.action.u.ext_chan_switch.variable);
u.action.ext_chan_switch.variable);
if (ies_len < 0)
break;
@ -8407,7 +8430,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
* extended CSA IE can't be overridden, no need for
* BSSID
*/
elems = ieee802_11_parse_elems(mgmt->u.action.u.ext_chan_switch.variable,
elems = ieee802_11_parse_elems(mgmt->u.action.ext_chan_switch.variable,
ies_len,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
@ -8424,7 +8447,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
/* for the handling code pretend it was an IE */
elems->ext_chansw_ie =
&mgmt->u.action.u.ext_chan_switch.data;
&mgmt->u.action.ext_chan_switch.data;
ieee80211_sta_process_chanswitch(link,
rx_status->mactime,
@ -10426,25 +10449,25 @@ void ieee80211_process_ml_reconf_resp(struct ieee80211_sub_if_data *sdata,
u8 *pos;
if (!ieee80211_vif_is_mld(&sdata->vif) ||
len < offsetofend(typeof(*mgmt), u.action.u.ml_reconf_resp) ||
mgmt->u.action.u.ml_reconf_resp.dialog_token !=
sdata->u.mgd.reconf.dialog_token ||
len < IEEE80211_MIN_ACTION_SIZE(ml_reconf_resp) ||
mgmt->u.action.ml_reconf_resp.dialog_token !=
sdata->u.mgd.reconf.dialog_token ||
!sta_changed_links)
return;
pos = mgmt->u.action.u.ml_reconf_resp.variable;
len -= offsetofend(typeof(*mgmt), u.action.u.ml_reconf_resp);
pos = mgmt->u.action.ml_reconf_resp.variable;
len -= offsetofend(typeof(*mgmt), u.action.ml_reconf_resp);
/* each status duple is 3 octets */
if (len < mgmt->u.action.u.ml_reconf_resp.count * 3) {
if (len < mgmt->u.action.ml_reconf_resp.count * 3) {
sdata_info(sdata,
"mlo: reconf: unexpected len=%zu, count=%u\n",
len, mgmt->u.action.u.ml_reconf_resp.count);
len, mgmt->u.action.ml_reconf_resp.count);
goto disconnect;
}
link_mask = sta_changed_links;
for (i = 0; i < mgmt->u.action.u.ml_reconf_resp.count; i++) {
for (i = 0; i < mgmt->u.action.ml_reconf_resp.count; i++) {
u16 status = get_unaligned_le16(pos + 1);
link_id = *pos;
@ -10729,8 +10752,7 @@ ieee80211_build_ml_reconf_req(struct ieee80211_sub_if_data *sdata,
return NULL;
skb_reserve(skb, local->hw.extra_tx_headroom);
mgmt = skb_put_zero(skb, offsetofend(struct ieee80211_mgmt,
u.action.u.ml_reconf_req));
mgmt = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE(ml_reconf_req));
/* Add the MAC header */
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
@ -10741,12 +10763,11 @@ ieee80211_build_ml_reconf_req(struct ieee80211_sub_if_data *sdata,
/* Add the action frame fixed fields */
mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT;
mgmt->u.action.u.ml_reconf_req.action_code =
WLAN_PROTECTED_EHT_ACTION_LINK_RECONFIG_REQ;
mgmt->u.action.action_code = WLAN_PROTECTED_EHT_ACTION_LINK_RECONFIG_REQ;
/* allocate a dialog token and store it */
sdata->u.mgd.reconf.dialog_token = ++sdata->u.mgd.dialog_token_alloc;
mgmt->u.action.u.ml_reconf_req.dialog_token =
mgmt->u.action.ml_reconf_req.dialog_token =
sdata->u.mgd.reconf.dialog_token;
/* Add the ML reconfiguration element and the common information */
@ -11116,11 +11137,10 @@ static bool ieee80211_mgd_epcs_supp(struct ieee80211_sub_if_data *sdata)
int ieee80211_mgd_set_epcs(struct ieee80211_sub_if_data *sdata, bool enable)
{
int frame_len = IEEE80211_MIN_ACTION_SIZE(epcs) + (enable ? 1 : 0);
struct ieee80211_local *local = sdata->local;
struct ieee80211_mgmt *mgmt;
struct sk_buff *skb;
int frame_len = offsetofend(struct ieee80211_mgmt,
u.action.u.epcs) + (enable ? 1 : 0);
if (!ieee80211_mgd_epcs_supp(sdata))
return -EINVAL;
@ -11149,15 +11169,15 @@ int ieee80211_mgd_set_epcs(struct ieee80211_sub_if_data *sdata, bool enable)
mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT;
if (enable) {
u8 *pos = mgmt->u.action.u.epcs.variable;
u8 *pos = mgmt->u.action.epcs.variable;
mgmt->u.action.u.epcs.action_code =
mgmt->u.action.action_code =
WLAN_PROTECTED_EHT_ACTION_EPCS_ENABLE_REQ;
*pos = ++sdata->u.mgd.dialog_token_alloc;
sdata->u.mgd.epcs.dialog_token = *pos;
} else {
mgmt->u.action.u.epcs.action_code =
mgmt->u.action.action_code =
WLAN_PROTECTED_EHT_ACTION_EPCS_ENABLE_TEARDOWN;
ieee80211_epcs_teardown(sdata);
@ -11246,7 +11266,7 @@ void ieee80211_process_epcs_ena_resp(struct ieee80211_sub_if_data *sdata,
return;
/* Handle dialog token and status code */
pos = mgmt->u.action.u.epcs.variable;
pos = mgmt->u.action.epcs.variable;
dialog_token = *pos;
status_code = get_unaligned_le16(pos + 1);
@ -11268,8 +11288,7 @@ void ieee80211_process_epcs_ena_resp(struct ieee80211_sub_if_data *sdata,
return;
pos += IEEE80211_EPCS_ENA_RESP_BODY_LEN;
ies_len = len - offsetof(struct ieee80211_mgmt,
u.action.u.epcs.variable) -
ies_len = len - IEEE80211_MIN_ACTION_SIZE(epcs) -
IEEE80211_EPCS_ENA_RESP_BODY_LEN;
elems = ieee802_11_parse_elems(pos, ies_len,

View File

@ -274,7 +274,7 @@ static void ieee80211_handle_mu_mimo_mon(struct ieee80211_sub_if_data *sdata,
if (!sdata)
return;
BUILD_BUG_ON(sizeof(action) != IEEE80211_MIN_ACTION_SIZE + 1);
BUILD_BUG_ON(sizeof(action) != IEEE80211_MIN_ACTION_SIZE(action_code));
if (skb->len < rtap_space + sizeof(action) +
VHT_MUMIMO_GROUPS_DATA_LEN)
@ -1162,7 +1162,7 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
u8 category;
/* make sure category field is present */
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE(category))
return RX_DROP_U_RUNT_ACTION;
mgmt = (struct ieee80211_mgmt *)hdr;
@ -1475,7 +1475,9 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
!test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg))
ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid,
WLAN_BACK_RECIPIENT,
WLAN_REASON_QSTA_REQUIRE_SETUP);
WLAN_REASON_QSTA_REQUIRE_SETUP,
ieee80211_s1g_use_ndp_ba(rx->sdata,
rx->sta));
goto dont_reorder;
}
@ -3372,7 +3374,9 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
!test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg))
ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid,
WLAN_BACK_RECIPIENT,
WLAN_REASON_QSTA_REQUIRE_SETUP);
WLAN_REASON_QSTA_REQUIRE_SETUP,
ieee80211_s1g_use_ndp_ba(rx->sdata,
rx->sta));
tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]);
if (!tid_agg_rx)
@ -3422,7 +3426,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
return;
}
if (len < 24 + 1 + sizeof(resp->u.action.u.sa_query)) {
if (len < IEEE80211_MIN_ACTION_SIZE(sa_query)) {
/* Too short SA Query request frame */
return;
}
@ -3432,17 +3436,16 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
return;
skb_reserve(skb, local->hw.extra_tx_headroom);
resp = skb_put_zero(skb, 24);
resp = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE(sa_query));
memcpy(resp->da, sdata->vif.cfg.ap_addr, ETH_ALEN);
memcpy(resp->sa, sdata->vif.addr, ETH_ALEN);
memcpy(resp->bssid, sdata->vif.cfg.ap_addr, ETH_ALEN);
resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query));
resp->u.action.category = WLAN_CATEGORY_SA_QUERY;
resp->u.action.u.sa_query.action = WLAN_ACTION_SA_QUERY_RESPONSE;
memcpy(resp->u.action.u.sa_query.trans_id,
mgmt->u.action.u.sa_query.trans_id,
resp->u.action.action_code = WLAN_ACTION_SA_QUERY_RESPONSE;
memcpy(resp->u.action.sa_query.trans_id,
mgmt->u.action.sa_query.trans_id,
WLAN_SA_QUERY_TR_ID_LEN);
ieee80211_tx_skb(sdata, skb);
@ -3516,7 +3519,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
/* drop too small action frames */
if (ieee80211_is_action(mgmt->frame_control) &&
rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
rx->skb->len < IEEE80211_MIN_ACTION_SIZE(category))
return RX_DROP_U_RUNT_ACTION;
/* Drop non-broadcast Beacon frames */
@ -3565,29 +3568,28 @@ ieee80211_process_rx_twt_action(struct ieee80211_rx_data *rx)
if (!rx->sta)
return false;
switch (mgmt->u.action.u.s1g.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_S1G_TWT_SETUP: {
struct ieee80211_twt_setup *twt;
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE +
1 + /* action code */
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE(action_code) +
sizeof(struct ieee80211_twt_setup) +
2 /* TWT req_type agrt */)
break;
twt = (void *)mgmt->u.action.u.s1g.variable;
twt = (void *)mgmt->u.action.s1g.variable;
if (twt->element_id != WLAN_EID_S1G_TWT)
break;
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE +
4 + /* action code + token + tlv */
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE(action_code) +
3 + /* token + tlv */
twt->length)
break;
return true; /* queue the frame */
}
case WLAN_S1G_TWT_TEARDOWN:
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE + 2)
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE(action_code) + 1)
break;
return true; /* queue the frame */
@ -3632,10 +3634,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
break;
/* verify action & smps_control/chanwidth are present */
if (len < IEEE80211_MIN_ACTION_SIZE + 2)
if (len < IEEE80211_MIN_ACTION_SIZE(ht_smps))
goto invalid;
switch (mgmt->u.action.u.ht_smps.action) {
switch (mgmt->u.action.action_code) {
case WLAN_HT_ACTION_SMPS: {
struct ieee80211_supported_band *sband;
enum ieee80211_smps_mode smps_mode;
@ -3646,7 +3648,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
goto handled;
/* convert to HT capability */
switch (mgmt->u.action.u.ht_smps.smps_control) {
switch (mgmt->u.action.ht_smps.smps_control) {
case WLAN_HT_SMPS_CONTROL_DISABLED:
smps_mode = IEEE80211_SMPS_OFF;
break;
@ -3679,7 +3681,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
goto handled;
}
case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: {
u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth;
u8 chanwidth = mgmt->u.action.ht_notify_cw.chanwidth;
if (chanwidth != IEEE80211_HT_CHANWIDTH_20MHZ &&
chanwidth != IEEE80211_HT_CHANWIDTH_ANY)
@ -3699,7 +3701,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
break;
case WLAN_CATEGORY_PUBLIC:
case WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION:
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
if (len < IEEE80211_MIN_ACTION_SIZE(action_code))
goto invalid;
if (sdata->vif.type != NL80211_IFTYPE_STATION)
break;
@ -3707,11 +3709,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
break;
if (!ether_addr_equal(mgmt->bssid, sdata->deflink.u.mgd.bssid))
break;
if (mgmt->u.action.u.ext_chan_switch.action_code !=
if (mgmt->u.action.action_code !=
WLAN_PUB_ACTION_EXT_CHANSW_ANN)
break;
if (len < offsetof(struct ieee80211_mgmt,
u.action.u.ext_chan_switch.variable))
if (len < IEEE80211_MIN_ACTION_SIZE(ext_chan_switch))
goto invalid;
goto queue;
case WLAN_CATEGORY_VHT:
@ -3723,18 +3724,18 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
break;
/* verify action code is present */
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
if (len < IEEE80211_MIN_ACTION_SIZE(action_code))
goto invalid;
switch (mgmt->u.action.u.vht_opmode_notif.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_VHT_ACTION_OPMODE_NOTIF: {
/* verify opmode is present */
if (len < IEEE80211_MIN_ACTION_SIZE + 2)
if (len < IEEE80211_MIN_ACTION_SIZE(vht_opmode_notif))
goto invalid;
goto queue;
}
case WLAN_VHT_ACTION_GROUPID_MGMT: {
if (len < IEEE80211_MIN_ACTION_SIZE + 25)
if (len < IEEE80211_MIN_ACTION_SIZE(vht_group_notif))
goto invalid;
goto queue;
}
@ -3751,23 +3752,23 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
break;
/* verify action_code is present */
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
if (len < IEEE80211_MIN_ACTION_SIZE(action_code))
break;
switch (mgmt->u.action.u.addba_req.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_ACTION_ADDBA_REQ:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.addba_req)))
case WLAN_ACTION_NDP_ADDBA_REQ:
if (len < IEEE80211_MIN_ACTION_SIZE(addba_req))
goto invalid;
break;
case WLAN_ACTION_ADDBA_RESP:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.addba_resp)))
case WLAN_ACTION_NDP_ADDBA_RESP:
if (len < IEEE80211_MIN_ACTION_SIZE(addba_resp))
goto invalid;
break;
case WLAN_ACTION_DELBA:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.delba)))
case WLAN_ACTION_NDP_DELBA:
if (len < IEEE80211_MIN_ACTION_SIZE(delba))
goto invalid;
break;
default:
@ -3777,16 +3778,15 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
goto queue;
case WLAN_CATEGORY_SPECTRUM_MGMT:
/* verify action_code is present */
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
if (len < IEEE80211_MIN_ACTION_SIZE(action_code))
break;
switch (mgmt->u.action.u.measurement.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_ACTION_SPCT_MSR_REQ:
if (status->band != NL80211_BAND_5GHZ)
break;
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.measurement)))
if (len < IEEE80211_MIN_ACTION_SIZE(measurement))
break;
if (sdata->vif.type != NL80211_IFTYPE_STATION)
@ -3796,8 +3796,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
goto handled;
case WLAN_ACTION_SPCT_CHL_SWITCH: {
u8 *bssid;
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.chan_switch)))
if (len < IEEE80211_MIN_ACTION_SIZE(chan_switch))
break;
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
@ -3822,11 +3821,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
}
break;
case WLAN_CATEGORY_SELF_PROTECTED:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.self_prot.action_code)))
if (len < IEEE80211_MIN_ACTION_SIZE(self_prot))
break;
switch (mgmt->u.action.u.self_prot.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_SP_MESH_PEERING_OPEN:
case WLAN_SP_MESH_PEERING_CLOSE:
case WLAN_SP_MESH_PEERING_CONFIRM:
@ -3844,8 +3842,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
}
break;
case WLAN_CATEGORY_MESH_ACTION:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.mesh_action.action_code)))
if (len < IEEE80211_MIN_ACTION_SIZE(action_code))
break;
if (!ieee80211_vif_is_mesh(&sdata->vif))
@ -3855,11 +3852,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
break;
goto queue;
case WLAN_CATEGORY_S1G:
if (len < offsetofend(typeof(*mgmt),
u.action.u.s1g.action_code))
if (len < IEEE80211_MIN_ACTION_SIZE(action_code))
break;
switch (mgmt->u.action.u.s1g.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_S1G_TWT_SETUP:
case WLAN_S1G_TWT_TEARDOWN:
if (ieee80211_process_rx_twt_action(rx))
@ -3870,33 +3866,29 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
}
break;
case WLAN_CATEGORY_PROTECTED_EHT:
if (len < offsetofend(typeof(*mgmt),
u.action.u.ttlm_req.action_code))
if (len < IEEE80211_MIN_ACTION_SIZE(action_code))
break;
switch (mgmt->u.action.u.ttlm_req.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_PROTECTED_EHT_ACTION_TTLM_REQ:
if (sdata->vif.type != NL80211_IFTYPE_STATION)
break;
if (len < offsetofend(typeof(*mgmt),
u.action.u.ttlm_req))
if (len < IEEE80211_MIN_ACTION_SIZE(ttlm_req))
goto invalid;
goto queue;
case WLAN_PROTECTED_EHT_ACTION_TTLM_RES:
if (sdata->vif.type != NL80211_IFTYPE_STATION)
break;
if (len < offsetofend(typeof(*mgmt),
u.action.u.ttlm_res))
if (len < IEEE80211_MIN_ACTION_SIZE(ttlm_res))
goto invalid;
goto queue;
case WLAN_PROTECTED_EHT_ACTION_TTLM_TEARDOWN:
if (sdata->vif.type != NL80211_IFTYPE_STATION)
break;
if (len < offsetofend(typeof(*mgmt),
u.action.u.ttlm_tear_down))
if (len < IEEE80211_MIN_ACTION_SIZE(ttlm_tear_down))
goto invalid;
goto queue;
case WLAN_PROTECTED_EHT_ACTION_LINK_RECONFIG_RESP:
@ -3906,34 +3898,29 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
/* The reconfiguration response action frame must
* least one 'Status Duple' entry (3 octets)
*/
if (len <
offsetofend(typeof(*mgmt),
u.action.u.ml_reconf_resp) + 3)
if (len < IEEE80211_MIN_ACTION_SIZE(ml_reconf_resp) + 3)
goto invalid;
goto queue;
case WLAN_PROTECTED_EHT_ACTION_EPCS_ENABLE_RESP:
if (sdata->vif.type != NL80211_IFTYPE_STATION)
break;
if (len < offsetofend(typeof(*mgmt),
u.action.u.epcs) +
IEEE80211_EPCS_ENA_RESP_BODY_LEN)
if (len < IEEE80211_MIN_ACTION_SIZE(epcs) +
IEEE80211_EPCS_ENA_RESP_BODY_LEN)
goto invalid;
goto queue;
case WLAN_PROTECTED_EHT_ACTION_EPCS_ENABLE_TEARDOWN:
if (sdata->vif.type != NL80211_IFTYPE_STATION)
break;
if (len < offsetofend(typeof(*mgmt),
u.action.u.epcs))
if (len < IEEE80211_MIN_ACTION_SIZE(epcs))
goto invalid;
goto queue;
case WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF:
if (sdata->vif.type != NL80211_IFTYPE_AP)
break;
if (len < offsetofend(typeof(*mgmt),
u.action.u.eml_omn))
if (len < IEEE80211_MIN_ACTION_SIZE(eml_omn))
goto invalid;
goto queue;
default:
@ -4015,11 +4002,10 @@ ieee80211_rx_h_action_post_userspace(struct ieee80211_rx_data *rx)
switch (mgmt->u.action.category) {
case WLAN_CATEGORY_SA_QUERY:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.sa_query)))
if (len < IEEE80211_MIN_ACTION_SIZE(sa_query))
break;
switch (mgmt->u.action.u.sa_query.action) {
switch (mgmt->u.action.action_code) {
case WLAN_ACTION_SA_QUERY_REQUEST:
if (sdata->vif.type != NL80211_IFTYPE_STATION)
break;

View File

@ -2,7 +2,7 @@
/*
* S1G handling
* Copyright(c) 2020 Adapt-IP
* Copyright (C) 2023 Intel Corporation
* Copyright (C) 2023, 2026 Intel Corporation
*/
#include <linux/ieee80211.h>
#include <net/mac80211.h>
@ -27,14 +27,14 @@ bool ieee80211_s1g_is_twt_setup(struct sk_buff *skb)
if (likely(mgmt->u.action.category != WLAN_CATEGORY_S1G))
return false;
return mgmt->u.action.u.s1g.action_code == WLAN_S1G_TWT_SETUP;
return mgmt->u.action.action_code == WLAN_S1G_TWT_SETUP;
}
static void
ieee80211_s1g_send_twt_setup(struct ieee80211_sub_if_data *sdata, const u8 *da,
const u8 *bssid, struct ieee80211_twt_setup *twt)
{
int len = IEEE80211_MIN_ACTION_SIZE + 4 + twt->length;
int len = IEEE80211_MIN_ACTION_SIZE(s1g) + 3 + twt->length;
struct ieee80211_local *local = sdata->local;
struct ieee80211_mgmt *mgmt;
struct sk_buff *skb;
@ -52,8 +52,8 @@ ieee80211_s1g_send_twt_setup(struct ieee80211_sub_if_data *sdata, const u8 *da,
memcpy(mgmt->bssid, bssid, ETH_ALEN);
mgmt->u.action.category = WLAN_CATEGORY_S1G;
mgmt->u.action.u.s1g.action_code = WLAN_S1G_TWT_SETUP;
memcpy(mgmt->u.action.u.s1g.variable, twt, 3 + twt->length);
mgmt->u.action.action_code = WLAN_S1G_TWT_SETUP;
memcpy(mgmt->u.action.s1g.variable, twt, 3 + twt->length);
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
IEEE80211_TX_INTFL_MLME_CONN_TX |
@ -71,12 +71,12 @@ ieee80211_s1g_send_twt_teardown(struct ieee80211_sub_if_data *sdata,
u8 *id;
skb = dev_alloc_skb(local->hw.extra_tx_headroom +
IEEE80211_MIN_ACTION_SIZE + 2);
IEEE80211_MIN_ACTION_SIZE(s1g) + 1);
if (!skb)
return;
skb_reserve(skb, local->hw.extra_tx_headroom);
mgmt = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE + 2);
mgmt = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE(s1g) + 1);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
memcpy(mgmt->da, da, ETH_ALEN);
@ -84,8 +84,8 @@ ieee80211_s1g_send_twt_teardown(struct ieee80211_sub_if_data *sdata,
memcpy(mgmt->bssid, bssid, ETH_ALEN);
mgmt->u.action.category = WLAN_CATEGORY_S1G;
mgmt->u.action.u.s1g.action_code = WLAN_S1G_TWT_TEARDOWN;
id = (u8 *)mgmt->u.action.u.s1g.variable;
mgmt->u.action.action_code = WLAN_S1G_TWT_TEARDOWN;
id = (u8 *)mgmt->u.action.s1g.variable;
*id = flowid;
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
@ -98,7 +98,7 @@ ieee80211_s1g_rx_twt_setup(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt = (void *)skb->data;
struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.u.s1g.variable;
struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.s1g.variable;
struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
twt_agrt->req_type &= cpu_to_le16(~IEEE80211_TWT_REQTYPE_REQUEST);
@ -128,7 +128,7 @@ ieee80211_s1g_rx_twt_teardown(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
drv_twt_teardown_request(sdata->local, sdata, &sta->sta,
mgmt->u.action.u.s1g.variable[0]);
mgmt->u.action.s1g.variable[0]);
}
static void
@ -136,7 +136,7 @@ ieee80211_s1g_tx_twt_setup_fail(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.u.s1g.variable;
struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.s1g.variable;
struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
u8 flowid = le16_get_bits(twt_agrt->req_type,
IEEE80211_TWT_REQTYPE_FLOWID);
@ -160,7 +160,7 @@ void ieee80211_s1g_rx_twt_action(struct ieee80211_sub_if_data *sdata,
if (!sta)
return;
switch (mgmt->u.action.u.s1g.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_S1G_TWT_SETUP:
ieee80211_s1g_rx_twt_setup(sdata, sta, skb);
break;
@ -185,7 +185,7 @@ void ieee80211_s1g_status_twt_action(struct ieee80211_sub_if_data *sdata,
if (!sta)
return;
switch (mgmt->u.action.u.s1g.action_code) {
switch (mgmt->u.action.action_code) {
case WLAN_S1G_TWT_SETUP:
/* process failed twt setup frames */
ieee80211_s1g_tx_twt_setup_fail(sdata, sta, skb);
@ -220,3 +220,11 @@ void ieee80211_s1g_cap_to_sta_s1g_cap(struct ieee80211_sub_if_data *sdata,
ieee80211_sta_recalc_aggregates(&link_sta->sta->sta);
}
bool ieee80211_s1g_use_ndp_ba(const struct ieee80211_sub_if_data *sdata,
const struct sta_info *sta)
{
return sdata->vif.cfg.s1g &&
ieee80211_hw_check(&sdata->local->hw, SUPPORTS_NDP_BLOCKACK) &&
(sta && sta->sta.deflink.s1g_cap.s1g);
}

View File

@ -9,7 +9,7 @@
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2007-2008, Intel Corporation
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
* Copyright (C) 2018, 2020, 2022-2024 Intel Corporation
* Copyright (C) 2018, 2020, 2022-2024, 2026 Intel Corporation
*/
#include <linux/ieee80211.h>
@ -409,35 +409,30 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da
struct sk_buff *skb;
struct ieee80211_mgmt *msr_report;
skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom +
sizeof(struct ieee80211_msrment_ie));
skb = dev_alloc_skb(IEEE80211_MIN_ACTION_SIZE(measurement) +
local->hw.extra_tx_headroom);
if (!skb)
return;
skb_reserve(skb, local->hw.extra_tx_headroom);
msr_report = skb_put_zero(skb, 24);
msr_report = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE(measurement));
memcpy(msr_report->da, da, ETH_ALEN);
memcpy(msr_report->sa, sdata->vif.addr, ETH_ALEN);
memcpy(msr_report->bssid, bssid, ETH_ALEN);
msr_report->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement));
msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
msr_report->u.action.u.measurement.action_code =
WLAN_ACTION_SPCT_MSR_RPRT;
msr_report->u.action.u.measurement.dialog_token = dialog_token;
msr_report->u.action.action_code = WLAN_ACTION_SPCT_MSR_RPRT;
msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT;
msr_report->u.action.u.measurement.length =
msr_report->u.action.measurement.dialog_token = dialog_token;
msr_report->u.action.measurement.element_id = WLAN_EID_MEASURE_REPORT;
msr_report->u.action.measurement.length =
sizeof(struct ieee80211_msrment_ie);
memset(&msr_report->u.action.u.measurement.msr_elem, 0,
sizeof(struct ieee80211_msrment_ie));
msr_report->u.action.u.measurement.msr_elem.token = request_ie->token;
msr_report->u.action.u.measurement.msr_elem.mode |=
msr_report->u.action.measurement.msr_elem.token = request_ie->token;
msr_report->u.action.measurement.msr_elem.mode |=
IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED;
msr_report->u.action.u.measurement.msr_elem.type = request_ie->type;
msr_report->u.action.measurement.msr_elem.type = request_ie->type;
ieee80211_tx_skb(sdata, skb);
}
@ -454,7 +449,7 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
* TODO: Answer basic measurement as unmeasured
*/
ieee80211_send_refuse_measurement_request(sdata,
&mgmt->u.action.u.measurement.msr_elem,
&mgmt->u.action.measurement.msr_elem,
mgmt->sa, mgmt->bssid,
mgmt->u.action.u.measurement.dialog_token);
mgmt->u.action.measurement.dialog_token);
}

View File

@ -171,6 +171,7 @@ struct sta_info;
* @bar_pending: BAR needs to be re-sent
* @amsdu: support A-MSDU within A-MDPU
* @ssn: starting sequence number of the session
* @ndp: this session is using NDP Block ACKs
*
* This structure's lifetime is managed by RCU, assignments to
* the array holding it must hold the aggregation mutex.
@ -199,6 +200,7 @@ struct tid_ampdu_tx {
u16 failed_bar_ssn;
bool bar_pending;
bool amsdu;
bool ndp;
u8 tid;
};
@ -510,7 +512,6 @@ struct ieee80211_fragment_cache {
* during finalize
* @debugfs_dir: debug filesystem directory dentry
* @pub: public (driver visible) link STA data
* TODO Move other link params from sta_info as required for MLD operation
*/
struct link_sta_info {
u8 addr[ETH_ALEN];

View File

@ -6,7 +6,7 @@
* Copyright 2014, Intel Corporation
* Copyright 2014 Intel Mobile Communications GmbH
* Copyright 2015 - 2016 Intel Deutschland GmbH
* Copyright (C) 2019, 2021-2025 Intel Corporation
* Copyright (C) 2019, 2021-2026 Intel Corporation
*/
#include <linux/ieee80211.h>
@ -879,28 +879,23 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_mgmt *mgmt;
mgmt = skb_put_zero(skb, 24);
if (action_code != WLAN_PUB_ACTION_TDLS_DISCOVER_RES)
return -EINVAL;
mgmt = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE(tdls_discover_resp));
memcpy(mgmt->da, peer, ETH_ALEN);
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
memcpy(mgmt->bssid, link->u.mgd.bssid, ETH_ALEN);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
switch (action_code) {
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
mgmt->u.action.u.tdls_discover_resp.action_code =
WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
mgmt->u.action.u.tdls_discover_resp.dialog_token =
dialog_token;
mgmt->u.action.u.tdls_discover_resp.capability =
cpu_to_le16(ieee80211_get_tdls_sta_capab(link,
status_code));
break;
default:
return -EINVAL;
}
mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
mgmt->u.action.action_code = WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
mgmt->u.action.tdls_discover_resp.dialog_token = dialog_token;
mgmt->u.action.tdls_discover_resp.capability =
cpu_to_le16(ieee80211_get_tdls_sta_capab(link,
status_code));
return 0;
}

View File

@ -2,7 +2,7 @@
/*
* Portions of this file
* Copyright(c) 2016-2017 Intel Deutschland GmbH
* Copyright (C) 2018 - 2024 Intel Corporation
* Copyright (C) 2018-2024, 2026 Intel Corporation
*/
#if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ)
@ -37,64 +37,46 @@
#define VIF_PR_FMT " vif:%s(%d%s)"
#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
#define CHANDEF_ENTRY __field(u32, control_freq) \
__field(u32, freq_offset) \
__field(u32, chan_width) \
__field(u32, center_freq1) \
__field(u32, freq1_offset) \
__field(u32, center_freq2)
#define CHANDEF_ASSIGN(c) \
__entry->control_freq = (c) ? ((c)->chan ? (c)->chan->center_freq : 0) : 0; \
__entry->freq_offset = (c) ? ((c)->chan ? (c)->chan->freq_offset : 0) : 0; \
__entry->chan_width = (c) ? (c)->width : 0; \
__entry->center_freq1 = (c) ? (c)->center_freq1 : 0; \
__entry->freq1_offset = (c) ? (c)->freq1_offset : 0; \
__entry->center_freq2 = (c) ? (c)->center_freq2 : 0;
#define CHANDEF_PR_FMT " chandef(%d.%03d MHz,width:%d,center: %d.%03d/%d MHz)"
#define CHANDEF_PR_ARG __entry->control_freq, __entry->freq_offset, __entry->chan_width, \
__entry->center_freq1, __entry->freq1_offset, __entry->center_freq2
#define __CHANDEF_ENTRY(n) \
__field(u32, n##control_freq) \
__field(u32, n##freq_offset) \
__field(u32, n##chan_width) \
__field(u32, n##center_freq1) \
__field(u32, n##freq1_offset) \
__field(u32, n##center_freq2) \
__field(u16, n##punctured)
#define __CHANDEF_ASSIGN(n, c) \
__entry->n##control_freq = (c) && (c)->chan ? \
(c)->chan->center_freq : 0; \
__entry->n##freq_offset = (c) && (c)->chan ? \
(c)->chan->freq_offset : 0; \
__entry->n##chan_width = (c) ? (c)->width : 0; \
__entry->n##center_freq1 = (c) ? (c)->center_freq1 : 0; \
__entry->n##freq1_offset = (c) ? (c)->freq1_offset : 0; \
__entry->n##center_freq2 = (c) ? (c)->center_freq2 : 0; \
__entry->n##punctured = (c) ? (c)->punctured : 0;
#define __CHANDEF_PR_FMT(n) \
" " #n "(%d.%03d MHz,width:%d,center: %d.%03d/%d MHz, punct:0x%x)"
#define __CHANDEF_PR_ARG(n) \
__entry->n##control_freq, __entry->n##freq_offset, \
__entry->n##chan_width, __entry->n##center_freq1, \
__entry->n##freq1_offset, __entry->n##center_freq2, \
__entry->n##punctured
#define MIN_CHANDEF_ENTRY \
__field(u32, min_control_freq) \
__field(u32, min_freq_offset) \
__field(u32, min_chan_width) \
__field(u32, min_center_freq1) \
__field(u32, min_freq1_offset) \
__field(u32, min_center_freq2)
#define CHANDEF_ENTRY __CHANDEF_ENTRY()
#define CHANDEF_ASSIGN(c) __CHANDEF_ASSIGN(, c)
#define CHANDEF_PR_FMT __CHANDEF_PR_FMT(chandef)
#define CHANDEF_PR_ARG __CHANDEF_PR_ARG()
#define MIN_CHANDEF_ASSIGN(c) \
__entry->min_control_freq = (c)->chan ? (c)->chan->center_freq : 0; \
__entry->min_freq_offset = (c)->chan ? (c)->chan->freq_offset : 0; \
__entry->min_chan_width = (c)->width; \
__entry->min_center_freq1 = (c)->center_freq1; \
__entry->min_freq1_offset = (c)->freq1_offset; \
__entry->min_center_freq2 = (c)->center_freq2;
#define MIN_CHANDEF_PR_FMT " mindef(%d.%03d MHz,width:%d,center: %d.%03d/%d MHz)"
#define MIN_CHANDEF_PR_ARG __entry->min_control_freq, __entry->min_freq_offset, \
__entry->min_chan_width, \
__entry->min_center_freq1, __entry->min_freq1_offset, \
__entry->min_center_freq2
#define MIN_CHANDEF_ENTRY __CHANDEF_ENTRY(min)
#define MIN_CHANDEF_ASSIGN(c) __CHANDEF_ASSIGN(min, c)
#define MIN_CHANDEF_PR_FMT __CHANDEF_PR_FMT(mindef)
#define MIN_CHANDEF_PR_ARG __CHANDEF_PR_ARG(min)
#define AP_CHANDEF_ENTRY \
__field(u32, ap_control_freq) \
__field(u32, ap_freq_offset) \
__field(u32, ap_chan_width) \
__field(u32, ap_center_freq1) \
__field(u32, ap_freq1_offset) \
__field(u32, ap_center_freq2)
#define AP_CHANDEF_ASSIGN(c) \
__entry->ap_control_freq = (c)->chan ? (c)->chan->center_freq : 0;\
__entry->ap_freq_offset = (c)->chan ? (c)->chan->freq_offset : 0;\
__entry->ap_chan_width = (c)->chan ? (c)->width : 0; \
__entry->ap_center_freq1 = (c)->chan ? (c)->center_freq1 : 0; \
__entry->ap_freq1_offset = (c)->chan ? (c)->freq1_offset : 0; \
__entry->ap_center_freq2 = (c)->chan ? (c)->center_freq2 : 0;
#define AP_CHANDEF_PR_FMT " ap(%d.%03d MHz,width:%d,center: %d.%03d/%d MHz)"
#define AP_CHANDEF_PR_ARG __entry->ap_control_freq, __entry->ap_freq_offset, \
__entry->ap_chan_width, \
__entry->ap_center_freq1, __entry->ap_freq1_offset, \
__entry->ap_center_freq2
#define AP_CHANDEF_ENTRY __CHANDEF_ENTRY(ap)
#define AP_CHANDEF_ASSIGN(c) __CHANDEF_ASSIGN(ap, c)
#define AP_CHANDEF_PR_FMT __CHANDEF_PR_FMT(ap)
#define AP_CHANDEF_PR_ARG __CHANDEF_PR_ARG(ap)
#define CHANCTX_ENTRY CHANDEF_ENTRY \
MIN_CHANDEF_ENTRY \

View File

@ -3766,12 +3766,11 @@ void ieee80211_chandef_downgrade(struct cfg80211_chan_def *c,
int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
struct cfg80211_csa_settings *csa_settings)
{
int hdr_len = IEEE80211_MIN_ACTION_SIZE(chan_switch);
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
struct ieee80211_local *local = sdata->local;
int freq;
int hdr_len = offsetofend(struct ieee80211_mgmt,
u.action.u.chan_switch);
u8 *pos;
if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
@ -3800,7 +3799,7 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
}
mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH;
mgmt->u.action.action_code = WLAN_ACTION_SPCT_CHL_SWITCH;
pos = skb_put(skb, 5);
*pos++ = WLAN_EID_CHANNEL_SWITCH; /* EID */
*pos++ = 3; /* IE length */

View File

@ -4,7 +4,7 @@
*
* Portions of this file
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH
* Copyright (C) 2018 - 2024 Intel Corporation
* Copyright (C) 2018-2026 Intel Corporation
*/
#include <linux/ieee80211.h>
@ -723,17 +723,17 @@ void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata,
if (!link_conf->mu_mimo_owner)
return;
if (!memcmp(mgmt->u.action.u.vht_group_notif.position,
if (!memcmp(mgmt->u.action.vht_group_notif.position,
link_conf->mu_group.position, WLAN_USER_POSITION_LEN) &&
!memcmp(mgmt->u.action.u.vht_group_notif.membership,
!memcmp(mgmt->u.action.vht_group_notif.membership,
link_conf->mu_group.membership, WLAN_MEMBERSHIP_LEN))
return;
memcpy(link_conf->mu_group.membership,
mgmt->u.action.u.vht_group_notif.membership,
mgmt->u.action.vht_group_notif.membership,
WLAN_MEMBERSHIP_LEN);
memcpy(link_conf->mu_group.position,
mgmt->u.action.u.vht_group_notif.position,
mgmt->u.action.vht_group_notif.position,
WLAN_USER_POSITION_LEN);
ieee80211_link_info_change_notify(sdata, link,

View File

@ -6,7 +6,7 @@
*
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2018-2025 Intel Corporation
* Copyright 2018-2026 Intel Corporation
*/
#include <linux/export.h>
@ -29,9 +29,11 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
*chandef = (struct cfg80211_chan_def) {
.chan = chan,
.freq1_offset = chan->freq_offset,
};
WARN_ON(chan->band == NL80211_BAND_60GHZ ||
chan->band == NL80211_BAND_S1GHZ);
switch (chan_type) {
case NL80211_CHAN_NO_HT:
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
@ -339,6 +341,58 @@ static bool cfg80211_valid_center_freq(u32 center,
return (center - bw / 2 - 5945) % step == 0;
}
static bool
cfg80211_chandef_valid_control_freq(const struct cfg80211_chan_def *chandef,
u32 control_freq)
{
switch (chandef->width) {
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_1:
case NL80211_CHAN_WIDTH_2:
case NL80211_CHAN_WIDTH_4:
case NL80211_CHAN_WIDTH_8:
case NL80211_CHAN_WIDTH_16:
/* checked separately */
break;
case NL80211_CHAN_WIDTH_320:
if (chandef->center_freq1 == control_freq + 150 ||
chandef->center_freq1 == control_freq + 130 ||
chandef->center_freq1 == control_freq + 110 ||
chandef->center_freq1 == control_freq + 90 ||
chandef->center_freq1 == control_freq - 90 ||
chandef->center_freq1 == control_freq - 110 ||
chandef->center_freq1 == control_freq - 130 ||
chandef->center_freq1 == control_freq - 150)
break;
fallthrough;
case NL80211_CHAN_WIDTH_160:
if (chandef->center_freq1 == control_freq + 70 ||
chandef->center_freq1 == control_freq + 50 ||
chandef->center_freq1 == control_freq - 50 ||
chandef->center_freq1 == control_freq - 70)
break;
fallthrough;
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_80:
if (chandef->center_freq1 == control_freq + 30 ||
chandef->center_freq1 == control_freq - 30)
break;
fallthrough;
case NL80211_CHAN_WIDTH_40:
if (chandef->center_freq1 == control_freq + 10 ||
chandef->center_freq1 == control_freq - 10)
break;
fallthrough;
default:
return false;
}
return true;
}
bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
{
u32 control_freq, control_freq_khz, start_khz, end_khz;
@ -351,6 +405,14 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
control_freq = chandef->chan->center_freq;
if (cfg80211_chandef_is_s1g(chandef) &&
chandef->width != NL80211_CHAN_WIDTH_1 &&
chandef->width != NL80211_CHAN_WIDTH_2 &&
chandef->width != NL80211_CHAN_WIDTH_4 &&
chandef->width != NL80211_CHAN_WIDTH_8 &&
chandef->width != NL80211_CHAN_WIDTH_16)
return false;
switch (chandef->width) {
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
@ -393,50 +455,8 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
break;
}
switch (chandef->width) {
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_1:
case NL80211_CHAN_WIDTH_2:
case NL80211_CHAN_WIDTH_4:
case NL80211_CHAN_WIDTH_8:
case NL80211_CHAN_WIDTH_16:
/* all checked above */
break;
case NL80211_CHAN_WIDTH_320:
if (chandef->center_freq1 == control_freq + 150 ||
chandef->center_freq1 == control_freq + 130 ||
chandef->center_freq1 == control_freq + 110 ||
chandef->center_freq1 == control_freq + 90 ||
chandef->center_freq1 == control_freq - 90 ||
chandef->center_freq1 == control_freq - 110 ||
chandef->center_freq1 == control_freq - 130 ||
chandef->center_freq1 == control_freq - 150)
break;
fallthrough;
case NL80211_CHAN_WIDTH_160:
if (chandef->center_freq1 == control_freq + 70 ||
chandef->center_freq1 == control_freq + 50 ||
chandef->center_freq1 == control_freq - 50 ||
chandef->center_freq1 == control_freq - 70)
break;
fallthrough;
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_80:
if (chandef->center_freq1 == control_freq + 30 ||
chandef->center_freq1 == control_freq - 30)
break;
fallthrough;
case NL80211_CHAN_WIDTH_40:
if (chandef->center_freq1 == control_freq + 10 ||
chandef->center_freq1 == control_freq - 10)
break;
fallthrough;
default:
if (!cfg80211_chandef_valid_control_freq(chandef, control_freq))
return false;
}
if (!cfg80211_valid_center_freq(chandef->center_freq1, chandef->width))
return false;

View File

@ -339,7 +339,20 @@ static int validate_uhr_capa(const struct nlattr *attr,
const u8 *data = nla_data(attr);
unsigned int len = nla_len(attr);
return ieee80211_uhr_capa_size_ok(data, len, false);
if (!ieee80211_uhr_capa_size_ok(data, len, false))
return -EINVAL;
return 0;
}
static int validate_uhr_operation(const struct nlattr *attr,
struct netlink_ext_ack *extack)
{
const u8 *data = nla_data(attr);
unsigned int len = nla_len(attr);
if (!ieee80211_uhr_oper_size_ok(data, len, false))
return -EINVAL;
return 0;
}
/* policy for the attributes */
@ -947,6 +960,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_UHR_CAPABILITY] =
NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_uhr_capa, 255),
[NL80211_ATTR_DISABLE_UHR] = { .type = NLA_FLAG },
[NL80211_ATTR_UHR_OPERATION] =
NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_uhr_operation),
};
/* policy for the key attributes */
@ -3619,6 +3634,9 @@ static int _nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
case NL80211_CHAN_HT20:
case NL80211_CHAN_HT40PLUS:
case NL80211_CHAN_HT40MINUS:
if (chandef->chan->band == NL80211_BAND_60GHZ ||
chandef->chan->band == NL80211_BAND_S1GHZ)
return -EINVAL;
cfg80211_chandef_create(chandef, chandef->chan,
chantype);
/* user input for center_freq is incorrect */
@ -5825,7 +5843,7 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
*/
BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
nla_for_each_nested(tx_rates, attrs[attr], rem) {
enum nl80211_band band = nla_type(tx_rates);
int band = nla_type(tx_rates);
int err;
if (band < 0 || band >= NUM_NL80211_BANDS)
@ -6499,16 +6517,6 @@ static int nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
return -EINVAL;
}
cap = cfg80211_find_ext_elem(WLAN_EID_EXT_UHR_OPER, ies, ies_len);
if (cap) {
if (!cap->datalen)
return -EINVAL;
params->uhr_oper = (void *)(cap->data + 1);
if (!ieee80211_uhr_oper_size_ok((const u8 *)params->uhr_oper,
cap->datalen - 1, true))
return -EINVAL;
}
return 0;
}
@ -6950,6 +6958,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
if (err)
goto out;
if (info->attrs[NL80211_ATTR_UHR_OPERATION])
params->uhr_oper = nla_data(info->attrs[NL80211_ATTR_UHR_OPERATION]);
err = nl80211_validate_ap_phy_operation(params);
if (err)
goto out;
@ -10694,7 +10705,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
nla_for_each_nested(attr,
info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
tmp) {
enum nl80211_band band = nla_type(attr);
int band = nla_type(attr);
if (band < 0 || band >= NUM_NL80211_BANDS) {
err = -EINVAL;

View File

@ -1,17 +1,6 @@
// SPDX-License-Identifier: ISC
/*
* Copyright (C) 2017 Rafał Miłecki <rafal@milecki.pl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/of.h>

View File

@ -1,17 +1,9 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
/*
* Radiotap parser
*
* Copyright 2007 Andy Green <andy@warmcat.com>
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See COPYING for more details.
*/
#include <linux/kernel.h>

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: ISC
/*
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
@ -6,18 +7,6 @@
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2017 Intel Deutschland GmbH
* Copyright (C) 2018 - 2026 Intel Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: ISC */
#ifndef __NET_WIRELESS_REG_H
#define __NET_WIRELESS_REG_H
@ -6,18 +7,6 @@
/*
* Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
* Copyright (C) 2019, 2023 Intel Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum ieee80211_regd_source {

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/module.h>
#ifndef __CHECKER__

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* This file implement the Wireless Extensions core API.
*
@ -5,8 +6,6 @@
* Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright (C) 2024 Intel Corporation
*
* (As all part of the Linux kernel, this file is GPL)
*/
#include <linux/kernel.h>
#include <linux/netdevice.h>

View File

@ -1,11 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
/*
* This file implement the Wireless Extensions priv API.
*
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
* Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
*
* (As all part of the Linux kernel, this file is GPL)
*/
#include <linux/slab.h>
#include <linux/wireless.h>

View File

@ -1,10 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
* This file implement the Wireless Extensions proc API.
*
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
* Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
*
* (As all part of the Linux kernel, this file is GPL)
*/
/*