This contains the following commits: ``` git log --oneline v6.12.52...v6.12.61 -- drivers/net/wireless/ net/mac80211/ net/wireless/ a1eb56723b32 wifi: ath12k: correctly handle mcast packets for clients c0a9c2c1b7b9 wifi: mac80211: use wiphy_hrtimer_work for csa.switch_work d4caee32a9f8 wifi: cfg80211: add an hrtimer based delayed work item 6455948c8aab wifi: mac80211: reject address change while connecting 80dc5a2ce5b7 wifi: ath11k: Clear affinity hint before calling ath11k_pcic_free_irq() in error path acd24d509227 wifi: mac80211: skip rate verification for not captured PSDUs 53cf801b8555 wifi: ath11k: zero init info->status in wmi_process_mgmt_tx_comp() e8fa86b0bd96 wifi: mac80211_hwsim: Limit destroy_on_close radio removal to netgroup 77d4afd6c78b Revert "wifi: ath10k: avoid unnecessary wait for service ready message" 07d862c7de3d wifi: ath12k: Increase DP_REO_CMD_RING_SIZE to 256 522734fc807c wifi: mac80211: Track NAN interface start/stop 8db790c2491e wifi: ath10k: Fix connection after GTK rekeying 72f1984246e6 wifi: rtw89: renew a completion for each H2C command waiting C2H event 336da4414300 wifi: rtw89: obtain RX path from ppdu status IE00 da91687f01f4 wifi: mt76: mt7996: fix memory leak on mt7996_mcu_sta_key_tlv error a534dd44b70e wifi: mt76: mt76_eeprom_override to int aa5ed215cfe8 wifi: mt76: mt7996: Temporarily disable EPCS efe2ef24feab wifi: mt76: mt7921: Add 160MHz beamformee capability for mt7922 device 5de410dfb4d9 wifi: mac80211: Fix HE capabilities element check f157d1cb2cdc wifi: iwlwifi: fw: Add ASUS to PPAG and TAS list c9df78e84e85 wifi: mac80211: Fix 6 GHz Band capabilities element advertisement in lower bands 958234997dd5 wifi: rtw89: fix BSSID comparison for non-transmitted BSSID ca18975c4de2 wifi: rtw89: wow: remove notify during WoWLAN net-detect bc1ca06998c1 wifi: rtw88: sdio: use indirect IO for device registers before power-on 8ebef59d0294 wifi: rtw89: print just once for unknown C2H events 5596a90c8952 wifi: mac80211: fix key tailroom accounting leak 23b8682f05ec wifi: mac80211: don't mark keys for inactive links as uploaded e3373f10c6a6 wifi: ath11k: avoid bit operation on key flags 50f50dd024b4 wifi: ath11k: add support for MU EDCA 2a6cd5951ba8 wifi: ath12k: free skb during idr cleanup callback 775e37df2acc wifi: ath11k: Add missing platform IDs for quirk table c4840991ee4c wifi: ath10k: Fix memory leak on unsupported WMI command a6eed58249e7 wifi: brcmfmac: fix crash while sending Action Frames in standalone AP Mode 57100b87c778 wifi: ath12k: fix read pointer after free in ath12k_mac_assign_vif_to_vdev() 4a63523d3541 wifi: cfg80211: Add missing lock in cfg80211_check_and_end_cac() e9fd43b799d2 wifi: rtw89: avoid possible TX wait initialization race b419093e5e42 wifi: mt76: mt7921u: Add VID/PID for Netgear A7500 feb1774aaf85 wifi: mt76: mt7925u: Add VID/PID for Netgear A9000 bd3ac455a88d wifi: ath11k: HAL SRNG: don't deinitialize and re-initialize again 8055133a9f64 wifi: rtw89: avoid circular locking dependency in ser_state_run() 1c873416758f wifi: mac80211: fix Rx packet handling when pubsta information is not available 6e7d9fa61d7d wifi: ath10k: avoid unnecessary wait for service ready message 8d4f6ab4c53e wifi: ath12k: fix wrong logging ID used for CE fc00890c55e3 wifi: mt76: mt7915: fix mt7981 pre-calibration e18c4e6ba36c wifi: mt76: mt7996: Convert mt7996_wed_rro_addr to LE f481404a9826 wifi: mt76: mt7996: Fix RX packets configuration for primary WED device 57519239c76c wifi: mt76: fix potential memory leak in mt76_wmac_probe() 27c8e2e4b56f wifi: iwlwifi: Remove redundant header files 605402433eb8 wifi: mwifiex: send world regulatory domain to driver ``` The removed patch was added upstream. Link: https://github.com/openwrt/openwrt/pull/21134 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
310 lines
9.3 KiB
Diff
310 lines
9.3 KiB
Diff
From: Felix Fietkau <nbd@nbd.name>
|
|
Date: Wed, 17 Jul 2024 15:43:52 +0200
|
|
Subject: [PATCH] wifi: cfg80211: add option for vif allowed radios
|
|
|
|
This allows users to prevent a vif from affecting radios other than the
|
|
configured ones. This can be useful in cases where e.g. an AP is running
|
|
on one radio, and triggering a scan on another radio should not disturb it.
|
|
|
|
Changing the allowed radios list for a vif is supported, but only while
|
|
it is down.
|
|
|
|
While it is possible to achieve the same by always explicitly specifying
|
|
a frequency list for scan requests and ensuring that the wrong channel/band
|
|
is never accidentally set on an unrelated interface, this change makes
|
|
multi-radio wiphy setups a lot easier to deal with for CLI users.
|
|
|
|
By itself, this patch only enforces the radio mask for scanning requests
|
|
and remain-on-channel. Follow-up changes build on this to limit configured
|
|
frequencies.
|
|
|
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
---
|
|
|
|
--- a/include/net/cfg80211.h
|
|
+++ b/include/net/cfg80211.h
|
|
@@ -6352,6 +6352,7 @@ enum ieee80211_ap_reg_power {
|
|
* entered.
|
|
* @links.cac_time_ms: CAC time in ms
|
|
* @valid_links: bitmap describing what elements of @links are valid
|
|
+ * @radio_mask: Bitmask of radios that this interface is allowed to operate on.
|
|
*/
|
|
struct wireless_dev {
|
|
struct wiphy *wiphy;
|
|
@@ -6464,6 +6465,8 @@ struct wireless_dev {
|
|
unsigned int cac_time_ms;
|
|
} links[IEEE80211_MLD_MAX_NUM_LINKS];
|
|
u16 valid_links;
|
|
+
|
|
+ u32 radio_mask;
|
|
};
|
|
|
|
static inline const u8 *wdev_address(struct wireless_dev *wdev)
|
|
@@ -6650,6 +6653,17 @@ bool cfg80211_radio_chandef_valid(const
|
|
const struct cfg80211_chan_def *chandef);
|
|
|
|
/**
|
|
+ * cfg80211_wdev_channel_allowed - Check if the wdev may use the channel
|
|
+ *
|
|
+ * @wdev: the wireless device
|
|
+ * @chan: channel to check
|
|
+ *
|
|
+ * Return: whether or not the wdev may use the channel
|
|
+ */
|
|
+bool cfg80211_wdev_channel_allowed(struct wireless_dev *wdev,
|
|
+ struct ieee80211_channel *chan);
|
|
+
|
|
+/**
|
|
* ieee80211_get_response_rate - get basic rate for a given rate
|
|
*
|
|
* @sband: the band to look for rates in
|
|
--- a/include/uapi/linux/nl80211.h
|
|
+++ b/include/uapi/linux/nl80211.h
|
|
@@ -2868,6 +2868,9 @@ enum nl80211_commands {
|
|
* nested item, it contains attributes defined in
|
|
* &enum nl80211_if_combination_attrs.
|
|
*
|
|
+ * @NL80211_ATTR_VIF_RADIO_MASK: Bitmask of allowed radios (u32).
|
|
+ * A value of 0 means all radios.
|
|
+ *
|
|
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
|
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
|
* @__NL80211_ATTR_AFTER_LAST: internal use
|
|
@@ -3416,6 +3419,8 @@ enum nl80211_attrs {
|
|
NL80211_ATTR_WIPHY_RADIOS,
|
|
NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS,
|
|
|
|
+ NL80211_ATTR_VIF_RADIO_MASK,
|
|
+
|
|
/* add attributes here, update the policy in nl80211.c */
|
|
|
|
__NL80211_ATTR_AFTER_LAST,
|
|
--- a/net/wireless/nl80211.c
|
|
+++ b/net/wireless/nl80211.c
|
|
@@ -832,6 +832,7 @@ static const struct nla_policy nl80211_p
|
|
[NL80211_ATTR_MLO_TTLM_DLINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
|
|
[NL80211_ATTR_MLO_TTLM_ULINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
|
|
[NL80211_ATTR_ASSOC_SPP_AMSDU] = { .type = NLA_FLAG },
|
|
+ [NL80211_ATTR_VIF_RADIO_MASK] = { .type = NLA_U32 },
|
|
};
|
|
|
|
/* policy for the key attributes */
|
|
@@ -4003,7 +4004,8 @@ static int nl80211_send_iface(struct sk_
|
|
nla_put_u32(msg, NL80211_ATTR_GENERATION,
|
|
rdev->devlist_generation ^
|
|
(cfg80211_rdev_list_generation << 2)) ||
|
|
- nla_put_u8(msg, NL80211_ATTR_4ADDR, wdev->use_4addr))
|
|
+ nla_put_u8(msg, NL80211_ATTR_4ADDR, wdev->use_4addr) ||
|
|
+ nla_put_u32(msg, NL80211_ATTR_VIF_RADIO_MASK, wdev->radio_mask))
|
|
goto nla_put_failure;
|
|
|
|
if (rdev->ops->get_channel && !wdev->valid_links) {
|
|
@@ -4324,6 +4326,29 @@ static int nl80211_valid_4addr(struct cf
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
+static int nl80211_parse_vif_radio_mask(struct genl_info *info,
|
|
+ u32 *radio_mask)
|
|
+{
|
|
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
+ struct nlattr *attr = info->attrs[NL80211_ATTR_VIF_RADIO_MASK];
|
|
+ u32 mask, allowed;
|
|
+
|
|
+ if (!attr) {
|
|
+ *radio_mask = 0;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ allowed = BIT(rdev->wiphy.n_radio) - 1;
|
|
+ mask = nla_get_u32(attr);
|
|
+ if (mask & ~allowed)
|
|
+ return -EINVAL;
|
|
+ if (!mask)
|
|
+ mask = allowed;
|
|
+ *radio_mask = mask;
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
|
|
{
|
|
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
@@ -4331,6 +4356,8 @@ static int nl80211_set_interface(struct
|
|
int err;
|
|
enum nl80211_iftype otype, ntype;
|
|
struct net_device *dev = info->user_ptr[1];
|
|
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
+ u32 radio_mask = 0;
|
|
bool change = false;
|
|
|
|
memset(¶ms, 0, sizeof(params));
|
|
@@ -4344,8 +4371,6 @@ static int nl80211_set_interface(struct
|
|
}
|
|
|
|
if (info->attrs[NL80211_ATTR_MESH_ID]) {
|
|
- struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
-
|
|
if (ntype != NL80211_IFTYPE_MESH_POINT)
|
|
return -EINVAL;
|
|
if (otype != NL80211_IFTYPE_MESH_POINT)
|
|
@@ -4376,6 +4401,12 @@ static int nl80211_set_interface(struct
|
|
if (err > 0)
|
|
change = true;
|
|
|
|
+ err = nl80211_parse_vif_radio_mask(info, &radio_mask);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ if (err && netif_running(dev))
|
|
+ return -EBUSY;
|
|
+
|
|
if (change)
|
|
err = cfg80211_change_iface(rdev, dev, ntype, ¶ms);
|
|
else
|
|
@@ -4384,11 +4415,11 @@ static int nl80211_set_interface(struct
|
|
if (!err && params.use_4addr != -1)
|
|
dev->ieee80211_ptr->use_4addr = params.use_4addr;
|
|
|
|
- if (change && !err) {
|
|
- struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
+ if (radio_mask)
|
|
+ wdev->radio_mask = radio_mask;
|
|
|
|
+ if (change && !err)
|
|
nl80211_notify_iface(rdev, wdev, NL80211_CMD_SET_INTERFACE);
|
|
- }
|
|
|
|
return err;
|
|
}
|
|
@@ -4399,6 +4430,7 @@ static int _nl80211_new_interface(struct
|
|
struct vif_params params;
|
|
struct wireless_dev *wdev;
|
|
struct sk_buff *msg;
|
|
+ u32 radio_mask;
|
|
int err;
|
|
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
|
|
|
|
@@ -4436,6 +4468,10 @@ static int _nl80211_new_interface(struct
|
|
if (err < 0)
|
|
return err;
|
|
|
|
+ err = nl80211_parse_vif_radio_mask(info, &radio_mask);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
if (!msg)
|
|
return -ENOMEM;
|
|
@@ -4477,6 +4513,9 @@ static int _nl80211_new_interface(struct
|
|
break;
|
|
}
|
|
|
|
+ if (radio_mask)
|
|
+ wdev->radio_mask = radio_mask;
|
|
+
|
|
if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
|
|
rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) {
|
|
nlmsg_free(msg);
|
|
@@ -9192,6 +9231,9 @@ static bool cfg80211_off_channel_oper_al
|
|
|
|
lockdep_assert_wiphy(wdev->wiphy);
|
|
|
|
+ if (!cfg80211_wdev_channel_allowed(wdev, chan))
|
|
+ return false;
|
|
+
|
|
if (!cfg80211_beaconing_iface_active(wdev))
|
|
return true;
|
|
|
|
@@ -9404,7 +9446,8 @@ static int nl80211_trigger_scan(struct s
|
|
}
|
|
|
|
/* ignore disabled channels */
|
|
- if (chan->flags & IEEE80211_CHAN_DISABLED)
|
|
+ if (chan->flags & IEEE80211_CHAN_DISABLED ||
|
|
+ !cfg80211_wdev_channel_allowed(wdev, chan))
|
|
continue;
|
|
|
|
request->channels[i] = chan;
|
|
@@ -9424,7 +9467,8 @@ static int nl80211_trigger_scan(struct s
|
|
|
|
chan = &wiphy->bands[band]->channels[j];
|
|
|
|
- if (chan->flags & IEEE80211_CHAN_DISABLED)
|
|
+ if (chan->flags & IEEE80211_CHAN_DISABLED ||
|
|
+ !cfg80211_wdev_channel_allowed(wdev, chan))
|
|
continue;
|
|
|
|
request->channels[i] = chan;
|
|
--- a/net/wireless/scan.c
|
|
+++ b/net/wireless/scan.c
|
|
@@ -953,7 +953,8 @@ static int cfg80211_scan_6ghz(struct cfg
|
|
struct ieee80211_channel *chan =
|
|
ieee80211_get_channel(&rdev->wiphy, ap->center_freq);
|
|
|
|
- if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
|
|
+ if (!chan || chan->flags & IEEE80211_CHAN_DISABLED ||
|
|
+ !cfg80211_wdev_channel_allowed(rdev_req->wdev, chan))
|
|
continue;
|
|
|
|
for (i = 0; i < rdev_req->n_channels; i++) {
|
|
@@ -3513,9 +3514,12 @@ int cfg80211_wext_siwscan(struct net_dev
|
|
continue;
|
|
|
|
for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
|
|
+ struct ieee80211_channel *chan;
|
|
+
|
|
/* ignore disabled channels */
|
|
- if (wiphy->bands[band]->channels[j].flags &
|
|
- IEEE80211_CHAN_DISABLED)
|
|
+ chan = &wiphy->bands[band]->channels[j];
|
|
+ if (chan->flags & IEEE80211_CHAN_DISABLED ||
|
|
+ !cfg80211_wdev_channel_allowed(creq->wdev, chan))
|
|
continue;
|
|
|
|
/* If we have a wireless request structure and the
|
|
--- a/net/wireless/util.c
|
|
+++ b/net/wireless/util.c
|
|
@@ -2970,3 +2970,32 @@ bool cfg80211_radio_chandef_valid(const
|
|
return true;
|
|
}
|
|
EXPORT_SYMBOL(cfg80211_radio_chandef_valid);
|
|
+
|
|
+bool cfg80211_wdev_channel_allowed(struct wireless_dev *wdev,
|
|
+ struct ieee80211_channel *chan)
|
|
+{
|
|
+ struct wiphy *wiphy = wdev->wiphy;
|
|
+ const struct wiphy_radio *radio;
|
|
+ struct cfg80211_chan_def chandef;
|
|
+ u32 radio_mask;
|
|
+ int i;
|
|
+
|
|
+ radio_mask = wdev->radio_mask;
|
|
+ if (!wiphy->n_radio || radio_mask == BIT(wiphy->n_radio) - 1)
|
|
+ return true;
|
|
+
|
|
+ cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20);
|
|
+ for (i = 0; i < wiphy->n_radio; i++) {
|
|
+ if (!(radio_mask & BIT(i)))
|
|
+ continue;
|
|
+
|
|
+ radio = &wiphy->radio[i];
|
|
+ if (!cfg80211_radio_chandef_valid(radio, &chandef))
|
|
+ continue;
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+EXPORT_SYMBOL(cfg80211_wdev_channel_allowed);
|
|
--- a/net/wireless/core.c
|
|
+++ b/net/wireless/core.c
|
|
@@ -1431,6 +1431,8 @@ void cfg80211_init_wdev(struct wireless_
|
|
/* allow mac80211 to determine the timeout */
|
|
wdev->ps_timeout = -1;
|
|
|
|
+ wdev->radio_mask = BIT(wdev->wiphy->n_radio) - 1;
|
|
+
|
|
if ((wdev->iftype == NL80211_IFTYPE_STATION ||
|
|
wdev->iftype == NL80211_IFTYPE_P2P_CLIENT ||
|
|
wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
|