Initial commit
Some checks failed
Build Kernel / Build all affected Kernels (push) Has been cancelled
Build all core packages / Build all core packages for selected target (push) Has been cancelled
Build and Push prebuilt tools container / Build and Push all prebuilt containers (push) Has been cancelled
Build Toolchains / Build Toolchains for each target (push) Has been cancelled
Build host tools / Build host tools for linux and macos based systems (push) Has been cancelled
Coverity scan build / Coverity x86/64 build (push) Has been cancelled
Some checks failed
Build Kernel / Build all affected Kernels (push) Has been cancelled
Build all core packages / Build all core packages for selected target (push) Has been cancelled
Build and Push prebuilt tools container / Build and Push all prebuilt containers (push) Has been cancelled
Build Toolchains / Build Toolchains for each target (push) Has been cancelled
Build host tools / Build host tools for linux and macos based systems (push) Has been cancelled
Coverity scan build / Coverity x86/64 build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 27 Oct 2014 00:00:00 +0100
|
||||
Subject: [PATCH] mac80211: preseve AP mode keys across STA reconnect
|
||||
|
||||
Used for AP+STA support in OpenWrt - preserve AP mode keys across STA reconnect
|
||||
---
|
||||
net/mac80211/cfg.c | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -1649,12 +1649,6 @@ static int ieee80211_stop_ap(struct wiph
|
||||
|
||||
__sta_info_flush(sdata, true, link_id);
|
||||
|
||||
- ieee80211_remove_link_keys(link, &keys);
|
||||
- if (!list_empty(&keys)) {
|
||||
- synchronize_net();
|
||||
- ieee80211_free_key_list(local, &keys);
|
||||
- }
|
||||
-
|
||||
link_conf->enable_beacon = false;
|
||||
sdata->beacon_rate_set = false;
|
||||
sdata->vif.cfg.ssid_len = 0;
|
||||
@@ -0,0 +1,52 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 11 Dec 2014 00:00:00 +0100
|
||||
Subject: [PATCH] cfg80211: add support for changing the device mac address via
|
||||
sysfs
|
||||
|
||||
---
|
||||
net/wireless/sysfs.c | 27 ++++++++++++++++++++++-----
|
||||
1 file changed, 22 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/net/wireless/sysfs.c
|
||||
+++ b/net/wireless/sysfs.c
|
||||
@@ -24,18 +24,35 @@ static inline struct cfg80211_registered
|
||||
return container_of(dev, struct cfg80211_registered_device, wiphy.dev);
|
||||
}
|
||||
|
||||
-#define SHOW_FMT(name, fmt, member) \
|
||||
+#define SHOW_FMT(name, fmt, member, mode) \
|
||||
static ssize_t name ## _show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \
|
||||
} \
|
||||
-static DEVICE_ATTR_RO(name)
|
||||
+static DEVICE_ATTR_##mode(name)
|
||||
|
||||
-SHOW_FMT(index, "%d", wiphy_idx);
|
||||
-SHOW_FMT(macaddress, "%pM", wiphy.perm_addr);
|
||||
-SHOW_FMT(address_mask, "%pM", wiphy.addr_mask);
|
||||
+static ssize_t macaddress_store(struct device *dev,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t len)
|
||||
+{
|
||||
+ u8 mac[ETH_ALEN];
|
||||
+
|
||||
+ if (!mac_pton(buf, mac))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n')
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ memcpy(dev_to_rdev(dev)->wiphy.perm_addr, mac, ETH_ALEN);
|
||||
+
|
||||
+ return strnlen(buf, len);
|
||||
+}
|
||||
+
|
||||
+SHOW_FMT(index, "%d", wiphy_idx, RO);
|
||||
+SHOW_FMT(macaddress, "%pM", wiphy.perm_addr, RW);
|
||||
+SHOW_FMT(address_mask, "%pM", wiphy.addr_mask, RO);
|
||||
|
||||
static ssize_t name_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
@@ -0,0 +1,27 @@
|
||||
--- a/net/mac80211/main.c
|
||||
+++ b/net/mac80211/main.c
|
||||
@@ -1581,24 +1581,6 @@ int ieee80211_register_hw(struct ieee802
|
||||
|
||||
ieee80211_check_wbrf_support(local);
|
||||
|
||||
- rtnl_lock();
|
||||
- wiphy_lock(hw->wiphy);
|
||||
-
|
||||
- /* add one default STA interface if supported */
|
||||
- if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) &&
|
||||
- !ieee80211_hw_check(hw, NO_AUTO_VIF)) {
|
||||
- struct vif_params params = {0};
|
||||
-
|
||||
- result = ieee80211_if_add(local, "wlan%d", NET_NAME_ENUM, NULL,
|
||||
- NL80211_IFTYPE_STATION, ¶ms);
|
||||
- if (result)
|
||||
- wiphy_warn(local->hw.wiphy,
|
||||
- "Failed to add default virtual iface\n");
|
||||
- }
|
||||
-
|
||||
- wiphy_unlock(hw->wiphy);
|
||||
- rtnl_unlock();
|
||||
-
|
||||
#ifdef CONFIG_INET
|
||||
local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
|
||||
result = register_inetaddr_notifier(&local->ifa_notifier);
|
||||
19
package/kernel/mac80211/patches/subsys/210-ap_scan.patch
Normal file
19
package/kernel/mac80211/patches/subsys/210-ap_scan.patch
Normal file
@@ -0,0 +1,19 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 3 Oct 2012 00:00:00 +0200
|
||||
Subject: [PATCH] mac80211: allow scans in access point mode (for site survey)
|
||||
|
||||
---
|
||||
net/mac80211/cfg.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -2863,6 +2863,8 @@ static int ieee80211_scan(struct wiphy *
|
||||
*/
|
||||
fallthrough;
|
||||
case NL80211_IFTYPE_AP:
|
||||
+ /* skip check */
|
||||
+ break;
|
||||
/*
|
||||
* If the scan has been forced (and the driver supports
|
||||
* forcing), don't care about being beaconing already.
|
||||
@@ -0,0 +1,40 @@
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Mon, 24 Feb 2020 00:00:00 +0100
|
||||
Subject: [PATCH] mac80211: Allow IBSS mode and different beacon intervals
|
||||
|
||||
ath10k-ct supports the combination to select IBSS (ADHOC) mode and
|
||||
different beacon intervals together. mac80211 does not like this
|
||||
combination, but Ben says this is ok, so remove this check.
|
||||
|
||||
ath10k-ct starting with version 5.2 allows the combination of
|
||||
NL80211_IFTYPE_ADHOC and beacon_int_min_gcd in ath10k_10x_ct_if_comb
|
||||
which triggers this warning. Ben told me that this is not a big problem
|
||||
and we should ignore this.
|
||||
---
|
||||
net/wireless/core.c | 15 ---------------
|
||||
1 file changed, 15 deletions(-)
|
||||
|
||||
--- a/net/wireless/core.c
|
||||
+++ b/net/wireless/core.c
|
||||
@@ -654,21 +654,6 @@ static int wiphy_verify_combinations(str
|
||||
c->limits[j].max > 1))
|
||||
return -EINVAL;
|
||||
|
||||
- /*
|
||||
- * This isn't well-defined right now. If you have an
|
||||
- * IBSS interface, then its beacon interval may change
|
||||
- * by joining other networks, and nothing prevents it
|
||||
- * from doing that.
|
||||
- * So technically we probably shouldn't even allow AP
|
||||
- * and IBSS in the same interface, but it seems that
|
||||
- * some drivers support that, possibly only with fixed
|
||||
- * beacon intervals for IBSS.
|
||||
- */
|
||||
- if (WARN_ON(types & BIT(NL80211_IFTYPE_ADHOC) &&
|
||||
- c->beacon_int_min_gcd)) {
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
cnt += c->limits[j].max;
|
||||
/*
|
||||
* Don't advertise an unsupported type
|
||||
@@ -0,0 +1,34 @@
|
||||
From: David Bauer <mail@david-bauer.net>
|
||||
Date: Thu, 30 Nov 2023 07:32:52 +0100
|
||||
Subject: [PATCH] mac80211: avoid crashing on invalid band info
|
||||
|
||||
Frequent crashes have been observed on MT7916 based platforms. While the
|
||||
root of these crashes are currently unknown, they happen when decoding
|
||||
rate information of connected STAs in AP mode. The rate-information is
|
||||
associated with a band which is not available on the PHY.
|
||||
|
||||
Check for this condition in order to avoid crashing the whole system.
|
||||
This patch should be removed once the roout cause has been found and
|
||||
fixed.
|
||||
|
||||
Link: https://github.com/freifunk-gluon/gluon/issues/2980
|
||||
|
||||
Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -2439,6 +2439,13 @@ static void sta_stats_decode_rate(struct
|
||||
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
|
||||
+ if (!sband) {
|
||||
+ wiphy_warn(local->hw.wiphy,
|
||||
+ "Invalid band %d\n",
|
||||
+ band);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
if (WARN_ON_ONCE(!sband->bitrates))
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
From b478e06a16a8baa00c5ecc87c1d636981f2206d5 Mon Sep 17 00:00:00 2001
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Tue, 29 Oct 2019 10:25:25 +0100
|
||||
Subject: [PATCH] mac80211: sta: randomize BA session dialog token allocator
|
||||
|
||||
We currently always start the dialog token generator at zero,
|
||||
so the first dialog token we use is always 1. This would be
|
||||
OK if we had a perfect guarantee that we always do a proper
|
||||
deauth/re-auth handshake, but in IBSS mode this doesn't always
|
||||
happen properly.
|
||||
|
||||
To make problems with block ack (aggregation) sessions getting
|
||||
stuck less likely, randomize the dialog token so if we start a
|
||||
new session but the peer still has old state for us, it can
|
||||
better detect this.
|
||||
|
||||
This is really just a workaround to make things a bit more
|
||||
robust than they are now - a better fix would be to do a full
|
||||
authentication handshake in IBSS mode upon having discovered a
|
||||
new station, and on the receiver resetting the state (removing
|
||||
and re-adding the station) on receiving the authentication
|
||||
packet.
|
||||
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
net/mac80211/sta_info.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -565,6 +565,7 @@ __sta_info_alloc(struct ieee80211_sub_if
|
||||
spin_lock_init(&sta->ps_lock);
|
||||
INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames);
|
||||
wiphy_work_init(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
|
||||
+ sta->ampdu_mlme.dialog_token_allocator = get_random_u32_below(U8_MAX);
|
||||
#ifdef CPTCFG_MAC80211_MESH
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
sta->mesh = kzalloc(sizeof(*sta->mesh), gfp);
|
||||
@@ -0,0 +1,21 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 28 Apr 2021 21:03:13 +0200
|
||||
Subject: [PATCH] mac80211: minstrel_ht: fix MINSTREL_FRAC macro
|
||||
|
||||
Add missing braces to avoid issues with e.g. using additions in the
|
||||
div expression
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rc80211_minstrel_ht.h
|
||||
+++ b/net/mac80211/rc80211_minstrel_ht.h
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
/* scaled fraction values */
|
||||
#define MINSTREL_SCALE 12
|
||||
-#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
|
||||
+#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / (div))
|
||||
#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
|
||||
|
||||
#define EWMA_LEVEL 96 /* ewma weighting factor [/EWMA_DIV] */
|
||||
@@ -0,0 +1,30 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 6 Feb 2021 16:08:01 +0100
|
||||
Subject: [PATCH] mac80211: minstrel_ht: reduce fluctuations in rate
|
||||
probability stats
|
||||
|
||||
In some scenarios when there is a lot of fluctuation in packet error rates,
|
||||
rate switching can be amplified when the statistics get skewed by time slots
|
||||
with very few tries.
|
||||
Make the input data to the moving average more smooth by adding the
|
||||
success/attempts count from the last stats window as well. This has the
|
||||
advantage of smoothing the data without introducing any extra lag to sampling
|
||||
rates.
|
||||
This significantly improves rate stability on a strong test link subjected to
|
||||
periodic noise bursts generated with a SDR
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||
@@ -769,7 +769,8 @@ minstrel_ht_calc_rate_stats(struct minst
|
||||
unsigned int cur_prob;
|
||||
|
||||
if (unlikely(mrs->attempts > 0)) {
|
||||
- cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
|
||||
+ cur_prob = MINSTREL_FRAC(mrs->success + mrs->last_success,
|
||||
+ mrs->attempts + mrs->last_attempts);
|
||||
minstrel_filter_avg_add(&mrs->prob_avg,
|
||||
&mrs->prob_avg_1, cur_prob);
|
||||
mrs->att_hist += mrs->attempts;
|
||||
@@ -0,0 +1,151 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 6 Feb 2021 16:33:14 +0100
|
||||
Subject: [PATCH] mac80211: minstrel_ht: rework rate downgrade code and
|
||||
max_prob rate selection
|
||||
|
||||
The current fallback code for fast rate switching on potentially failing rates
|
||||
is triggering too often if there is some strong noise on the channel. This can
|
||||
lead to wild fluctuations in the rate selection.
|
||||
Additionally, switching down to max_prob_rate can create a significant gap down
|
||||
in throughput, especially when using only 2 spatial streams, because max_prob_rate
|
||||
is limited to using fewer streams than the max_tp rates.
|
||||
In order to improve throughput without reducing reliability too much, use the
|
||||
rate downgrade code for the max_prob_rate only, and allow the non-downgraded
|
||||
max_prob_rate to use as many spatial streams as the max_tp rates
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||
@@ -580,6 +580,14 @@ minstrel_ht_set_best_prob_rate(struct mi
|
||||
int cur_tp_avg, cur_group, cur_idx;
|
||||
int max_gpr_group, max_gpr_idx;
|
||||
int max_gpr_tp_avg, max_gpr_prob;
|
||||
+ int min_dur;
|
||||
+
|
||||
+ min_dur = max(minstrel_get_duration(mi->max_tp_rate[0]),
|
||||
+ minstrel_get_duration(mi->max_tp_rate[1]));
|
||||
+
|
||||
+ /* make the rate at least 18% slower than max tp rates */
|
||||
+ if (minstrel_get_duration(index) <= min_dur * 19 / 16)
|
||||
+ return;
|
||||
|
||||
cur_group = MI_RATE_GROUP(index);
|
||||
cur_idx = MI_RATE_IDX(index);
|
||||
@@ -601,11 +609,6 @@ minstrel_ht_set_best_prob_rate(struct mi
|
||||
!minstrel_ht_is_legacy_group(max_tp_group))
|
||||
return;
|
||||
|
||||
- /* skip rates faster than max tp rate with lower prob */
|
||||
- if (minstrel_get_duration(mi->max_tp_rate[0]) > minstrel_get_duration(index) &&
|
||||
- mrs->prob_avg < max_tp_prob)
|
||||
- return;
|
||||
-
|
||||
max_gpr_group = MI_RATE_GROUP(mg->max_group_prob_rate);
|
||||
max_gpr_idx = MI_RATE_IDX(mg->max_group_prob_rate);
|
||||
max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg;
|
||||
@@ -663,40 +666,6 @@ minstrel_ht_assign_best_tp_rates(struct
|
||||
|
||||
}
|
||||
|
||||
-/*
|
||||
- * Try to increase robustness of max_prob rate by decrease number of
|
||||
- * streams if possible.
|
||||
- */
|
||||
-static inline void
|
||||
-minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
|
||||
-{
|
||||
- struct minstrel_mcs_group_data *mg;
|
||||
- int tmp_max_streams, group, tmp_idx, tmp_prob;
|
||||
- int tmp_tp = 0;
|
||||
-
|
||||
- if (!mi->sta->deflink.ht_cap.ht_supported)
|
||||
- return;
|
||||
-
|
||||
- group = MI_RATE_GROUP(mi->max_tp_rate[0]);
|
||||
- tmp_max_streams = minstrel_mcs_groups[group].streams;
|
||||
- for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
|
||||
- mg = &mi->groups[group];
|
||||
- if (!mi->supported[group] || group == MINSTREL_CCK_GROUP)
|
||||
- continue;
|
||||
-
|
||||
- tmp_idx = MI_RATE_IDX(mg->max_group_prob_rate);
|
||||
- tmp_prob = mi->groups[group].rates[tmp_idx].prob_avg;
|
||||
-
|
||||
- if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) &&
|
||||
- (minstrel_mcs_groups[group].streams < tmp_max_streams)) {
|
||||
- mi->max_prob_rate = mg->max_group_prob_rate;
|
||||
- tmp_tp = minstrel_ht_get_tp_avg(mi, group,
|
||||
- tmp_idx,
|
||||
- tmp_prob);
|
||||
- }
|
||||
- }
|
||||
-}
|
||||
-
|
||||
static u16
|
||||
__minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi,
|
||||
enum minstrel_sample_type type)
|
||||
@@ -1176,8 +1145,6 @@ minstrel_ht_update_stats(struct minstrel
|
||||
|
||||
mi->max_prob_rate = tmp_max_prob_rate;
|
||||
|
||||
- /* Try to increase robustness of max_prob_rate*/
|
||||
- minstrel_ht_prob_rate_reduce_streams(mi);
|
||||
minstrel_ht_refill_sample_rates(mi);
|
||||
|
||||
#ifdef CPTCFG_MAC80211_DEBUGFS
|
||||
@@ -1256,7 +1223,7 @@ minstrel_ht_ri_txstat_valid(struct minst
|
||||
}
|
||||
|
||||
static void
|
||||
-minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary)
|
||||
+minstrel_downgrade_prob_rate(struct minstrel_ht_sta *mi, u16 *idx)
|
||||
{
|
||||
int group, orig_group;
|
||||
|
||||
@@ -1271,11 +1238,7 @@ minstrel_downgrade_rate(struct minstrel_
|
||||
minstrel_mcs_groups[orig_group].streams)
|
||||
continue;
|
||||
|
||||
- if (primary)
|
||||
- *idx = mi->groups[group].max_group_tp_rate[0];
|
||||
- else
|
||||
- *idx = mi->groups[group].max_group_tp_rate[1];
|
||||
- break;
|
||||
+ *idx = mi->groups[group].max_group_prob_rate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1286,7 +1249,7 @@ minstrel_ht_tx_status(void *priv, struct
|
||||
struct ieee80211_tx_info *info = st->info;
|
||||
struct minstrel_ht_sta *mi = priv_sta;
|
||||
struct ieee80211_tx_rate *ar = info->status.rates;
|
||||
- struct minstrel_rate_stats *rate, *rate2;
|
||||
+ struct minstrel_rate_stats *rate;
|
||||
struct minstrel_priv *mp = priv;
|
||||
u32 update_interval = mp->update_interval;
|
||||
bool last, update = false;
|
||||
@@ -1354,18 +1317,13 @@ minstrel_ht_tx_status(void *priv, struct
|
||||
/*
|
||||
* check for sudden death of spatial multiplexing,
|
||||
* downgrade to a lower number of streams if necessary.
|
||||
+ * only do this for the max_prob_rate to prevent spurious
|
||||
+ * rate fluctuations when the link changes suddenly
|
||||
*/
|
||||
- rate = minstrel_get_ratestats(mi, mi->max_tp_rate[0]);
|
||||
+ rate = minstrel_get_ratestats(mi, mi->max_prob_rate);
|
||||
if (rate->attempts > 30 &&
|
||||
rate->success < rate->attempts / 4) {
|
||||
- minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true);
|
||||
- update = true;
|
||||
- }
|
||||
-
|
||||
- rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]);
|
||||
- if (rate2->attempts > 30 &&
|
||||
- rate2->success < rate2->attempts / 4) {
|
||||
- minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false);
|
||||
+ minstrel_downgrade_prob_rate(mi, &mi->max_prob_rate);
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sun, 26 Jun 2022 11:43:25 +0200
|
||||
Subject: [PATCH] mac80211: increase quantum for airtime scheduler
|
||||
|
||||
Given the typical AQL budget and queue length, a quantum of 256 with the
|
||||
default station weight often requires iterating over all queues frequently,
|
||||
until one of them becomes eligible.
|
||||
Improve performance by using 8 times station weight as scheduler quantum
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -103,6 +103,8 @@ ieee80211_sta_keep_active(struct sta_inf
|
||||
return time_before_eq(jiffies, sta->airtime[ac].last_active + HZ / 10);
|
||||
}
|
||||
|
||||
+#define AIRTIME_QUANTUM_SHIFT 3
|
||||
+
|
||||
struct ieee80211_bss {
|
||||
u32 device_ts_beacon, device_ts_presp;
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -4081,7 +4081,7 @@ struct ieee80211_txq *ieee80211_next_txq
|
||||
|
||||
if (deficit < 0)
|
||||
sta->airtime[txqi->txq.ac].deficit +=
|
||||
- sta->airtime_weight;
|
||||
+ sta->airtime_weight << AIRTIME_QUANTUM_SHIFT;
|
||||
|
||||
if (deficit < 0 || !aql_check) {
|
||||
list_move_tail(&txqi->schedule_order,
|
||||
@@ -4224,7 +4224,8 @@ bool ieee80211_txq_may_transmit(struct i
|
||||
}
|
||||
sta = container_of(iter->txq.sta, struct sta_info, sta);
|
||||
if (ieee80211_sta_deficit(sta, ac) < 0)
|
||||
- sta->airtime[ac].deficit += sta->airtime_weight;
|
||||
+ sta->airtime[ac].deficit += sta->airtime_weight <<
|
||||
+ AIRTIME_QUANTUM_SHIFT;
|
||||
list_move_tail(&iter->schedule_order, &local->active_txqs[ac]);
|
||||
}
|
||||
|
||||
@@ -4232,7 +4233,7 @@ bool ieee80211_txq_may_transmit(struct i
|
||||
if (sta->airtime[ac].deficit >= 0)
|
||||
goto out;
|
||||
|
||||
- sta->airtime[ac].deficit += sta->airtime_weight;
|
||||
+ sta->airtime[ac].deficit += sta->airtime_weight << AIRTIME_QUANTUM_SHIFT;
|
||||
list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
|
||||
spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 14 Sep 2023 13:17:16 +0200
|
||||
Subject: [PATCH] cfg80211: allow grace period for DFS available after beacon
|
||||
shutdown
|
||||
|
||||
Fixes reconfiguring an AP on a DFS channel in non-ETSI regdomain
|
||||
|
||||
Fixes: b35a51c7dd25 ("cfg80211: Make pre-CAC results valid only for ETSI domain")
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -187,6 +187,8 @@ enum ieee80211_channel_flags {
|
||||
* @dfs_state: current state of this channel. Only relevant if radar is required
|
||||
* on this channel.
|
||||
* @dfs_state_entered: timestamp (jiffies) when the dfs state was entered.
|
||||
+ * @dfs_state_last_available: timestamp (jiffies) of the last time when the
|
||||
+ * channel was available.
|
||||
* @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels.
|
||||
* @psd: power spectral density (in dBm)
|
||||
*/
|
||||
@@ -204,6 +206,7 @@ struct ieee80211_channel {
|
||||
int orig_mag, orig_mpwr;
|
||||
enum nl80211_dfs_state dfs_state;
|
||||
unsigned long dfs_state_entered;
|
||||
+ unsigned long dfs_state_last_available;
|
||||
unsigned int dfs_cac_ms;
|
||||
s8 psd;
|
||||
};
|
||||
--- a/net/wireless/ap.c
|
||||
+++ b/net/wireless/ap.c
|
||||
@@ -30,6 +30,9 @@ static int ___cfg80211_stop_ap(struct cf
|
||||
if (!wdev->links[link_id].ap.beacon_interval)
|
||||
return -ENOENT;
|
||||
|
||||
+ cfg80211_update_last_available(wdev->wiphy,
|
||||
+ &wdev->links[link_id].ap.chandef);
|
||||
+
|
||||
err = rdev_stop_ap(rdev, dev, link_id);
|
||||
if (!err) {
|
||||
wdev->conn_owner_nlportid = 0;
|
||||
@@ -41,9 +44,6 @@ static int ___cfg80211_stop_ap(struct cf
|
||||
if (notify)
|
||||
nl80211_send_ap_stopped(wdev, link_id);
|
||||
|
||||
- /* Should we apply the grace period during beaconing interface
|
||||
- * shutdown also?
|
||||
- */
|
||||
cfg80211_sched_dfs_chan_update(rdev);
|
||||
}
|
||||
|
||||
--- a/net/wireless/chan.c
|
||||
+++ b/net/wireless/chan.c
|
||||
@@ -598,6 +598,8 @@ static void cfg80211_set_chans_dfs_state
|
||||
|
||||
c->dfs_state = dfs_state;
|
||||
c->dfs_state_entered = jiffies;
|
||||
+ if (dfs_state == NL80211_DFS_AVAILABLE)
|
||||
+ c->dfs_state_last_available = jiffies;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1087,6 +1089,49 @@ static bool cfg80211_get_chans_dfs_avail
|
||||
return true;
|
||||
}
|
||||
|
||||
+static void
|
||||
+__cfg80211_update_last_available(struct wiphy *wiphy,
|
||||
+ u32 center_freq,
|
||||
+ u32 bandwidth)
|
||||
+{
|
||||
+ struct ieee80211_channel *c;
|
||||
+ u32 freq, start_freq, end_freq;
|
||||
+
|
||||
+ start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
|
||||
+ end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
|
||||
+
|
||||
+ /*
|
||||
+ * Check entire range of channels for the bandwidth.
|
||||
+ * If any channel in between is disabled or has not
|
||||
+ * had gone through CAC return false
|
||||
+ */
|
||||
+ for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
|
||||
+ c = ieee80211_get_channel_khz(wiphy, freq);
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ c->dfs_state_last_available = jiffies;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void cfg80211_update_last_available(struct wiphy *wiphy,
|
||||
+ const struct cfg80211_chan_def *chandef)
|
||||
+{
|
||||
+ int width;
|
||||
+
|
||||
+ width = cfg80211_chandef_get_width(chandef);
|
||||
+ if (width < 0)
|
||||
+ return;
|
||||
+
|
||||
+ __cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq1),
|
||||
+ width);
|
||||
+ if (chandef->width != NL80211_CHAN_WIDTH_80P80)
|
||||
+ return;
|
||||
+
|
||||
+ __cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq2),
|
||||
+ width);
|
||||
+}
|
||||
+
|
||||
static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
|
||||
const struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
--- a/net/wireless/core.h
|
||||
+++ b/net/wireless/core.h
|
||||
@@ -467,6 +467,8 @@ void cfg80211_set_dfs_state(struct wiphy
|
||||
enum nl80211_dfs_state dfs_state);
|
||||
|
||||
void cfg80211_dfs_channels_update_work(struct work_struct *work);
|
||||
+void cfg80211_update_last_available(struct wiphy *wiphy,
|
||||
+ const struct cfg80211_chan_def *chandef);
|
||||
|
||||
void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev);
|
||||
|
||||
--- a/net/wireless/mlme.c
|
||||
+++ b/net/wireless/mlme.c
|
||||
@@ -1037,6 +1037,8 @@ void cfg80211_dfs_channels_update_work(s
|
||||
if (c->dfs_state == NL80211_DFS_UNAVAILABLE) {
|
||||
time_dfs_update = IEEE80211_DFS_MIN_NOP_TIME_MS;
|
||||
radar_event = NL80211_RADAR_NOP_FINISHED;
|
||||
+ timeout = c->dfs_state_entered +
|
||||
+ msecs_to_jiffies(time_dfs_update);
|
||||
} else {
|
||||
if (regulatory_pre_cac_allowed(wiphy) ||
|
||||
cfg80211_any_wiphy_oper_chan(wiphy, c))
|
||||
@@ -1044,11 +1046,10 @@ void cfg80211_dfs_channels_update_work(s
|
||||
|
||||
time_dfs_update = REG_PRE_CAC_EXPIRY_GRACE_MS;
|
||||
radar_event = NL80211_RADAR_PRE_CAC_EXPIRED;
|
||||
+ timeout = c->dfs_state_last_available +
|
||||
+ msecs_to_jiffies(time_dfs_update);
|
||||
}
|
||||
|
||||
- timeout = c->dfs_state_entered +
|
||||
- msecs_to_jiffies(time_dfs_update);
|
||||
-
|
||||
if (time_after_eq(jiffies, timeout)) {
|
||||
c->dfs_state = NL80211_DFS_USABLE;
|
||||
c->dfs_state_entered = jiffies;
|
||||
@@ -0,0 +1,293 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 9 Feb 2024 19:43:40 +0100
|
||||
Subject: [PATCH] mac80211: add AQL support for broadcast packets
|
||||
|
||||
Excessive broadcast traffic with little competing unicast traffic can easily
|
||||
flood hardware queues, leading to throughput issues. Additionally, filling
|
||||
the hardware queues with too many packets breaks FQ for broadcast data.
|
||||
Fix this by enabling AQL for broadcast packets.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -3423,6 +3423,7 @@ enum wiphy_params_flags {
|
||||
/* The per TXQ device queue limit in airtime */
|
||||
#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L 5000
|
||||
#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H 12000
|
||||
+#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_BC 50000
|
||||
|
||||
/* The per interface airtime threshold to switch to lower queue limit */
|
||||
#define IEEE80211_AQL_THRESHOLD 24000
|
||||
--- a/net/mac80211/debugfs.c
|
||||
+++ b/net/mac80211/debugfs.c
|
||||
@@ -215,11 +215,13 @@ static ssize_t aql_pending_read(struct f
|
||||
"VI %u us\n"
|
||||
"BE %u us\n"
|
||||
"BK %u us\n"
|
||||
+ "BC/MC %u us\n"
|
||||
"total %u us\n",
|
||||
atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VO]),
|
||||
atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VI]),
|
||||
atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BE]),
|
||||
atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BK]),
|
||||
+ atomic_read(&local->aql_bc_pending_airtime),
|
||||
atomic_read(&local->aql_total_pending_airtime));
|
||||
return simple_read_from_buffer(user_buf, count, ppos,
|
||||
buf, len);
|
||||
@@ -245,7 +247,8 @@ static ssize_t aql_txq_limit_read(struct
|
||||
"VO %u %u\n"
|
||||
"VI %u %u\n"
|
||||
"BE %u %u\n"
|
||||
- "BK %u %u\n",
|
||||
+ "BK %u %u\n"
|
||||
+ "BC/MC %u\n",
|
||||
local->aql_txq_limit_low[IEEE80211_AC_VO],
|
||||
local->aql_txq_limit_high[IEEE80211_AC_VO],
|
||||
local->aql_txq_limit_low[IEEE80211_AC_VI],
|
||||
@@ -253,7 +256,8 @@ static ssize_t aql_txq_limit_read(struct
|
||||
local->aql_txq_limit_low[IEEE80211_AC_BE],
|
||||
local->aql_txq_limit_high[IEEE80211_AC_BE],
|
||||
local->aql_txq_limit_low[IEEE80211_AC_BK],
|
||||
- local->aql_txq_limit_high[IEEE80211_AC_BK]);
|
||||
+ local->aql_txq_limit_high[IEEE80211_AC_BK],
|
||||
+ local->aql_txq_limit_bc);
|
||||
return simple_read_from_buffer(user_buf, count, ppos,
|
||||
buf, len);
|
||||
}
|
||||
@@ -279,6 +283,11 @@ static ssize_t aql_txq_limit_write(struc
|
||||
else
|
||||
buf[count] = '\0';
|
||||
|
||||
+ if (sscanf(buf, "mcast %u", &q_limit_low) == 1) {
|
||||
+ local->aql_txq_limit_bc = q_limit_low;
|
||||
+ return count;
|
||||
+ }
|
||||
+
|
||||
if (sscanf(buf, "%u %u %u", &ac, &q_limit_low, &q_limit_high) != 3)
|
||||
return -EINVAL;
|
||||
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1351,10 +1351,12 @@ struct ieee80211_local {
|
||||
spinlock_t handle_wake_tx_queue_lock;
|
||||
|
||||
u16 airtime_flags;
|
||||
+ u32 aql_txq_limit_bc;
|
||||
u32 aql_txq_limit_low[IEEE80211_NUM_ACS];
|
||||
u32 aql_txq_limit_high[IEEE80211_NUM_ACS];
|
||||
u32 aql_threshold;
|
||||
atomic_t aql_total_pending_airtime;
|
||||
+ atomic_t aql_bc_pending_airtime;
|
||||
atomic_t aql_ac_pending_airtime[IEEE80211_NUM_ACS];
|
||||
|
||||
const struct ieee80211_ops *ops;
|
||||
--- a/net/mac80211/main.c
|
||||
+++ b/net/mac80211/main.c
|
||||
@@ -952,6 +952,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
|
||||
spin_lock_init(&local->rx_path_lock);
|
||||
spin_lock_init(&local->queue_stop_reason_lock);
|
||||
|
||||
+ local->aql_txq_limit_bc = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_BC;
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
INIT_LIST_HEAD(&local->active_txqs[i]);
|
||||
spin_lock_init(&local->active_txq_lock[i]);
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -2353,13 +2353,28 @@ EXPORT_SYMBOL(ieee80211_sta_recalc_aggre
|
||||
|
||||
void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
|
||||
struct sta_info *sta, u8 ac,
|
||||
- u16 tx_airtime, bool tx_completed)
|
||||
+ u16 tx_airtime, bool tx_completed,
|
||||
+ bool mcast)
|
||||
{
|
||||
int tx_pending;
|
||||
|
||||
if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
|
||||
return;
|
||||
|
||||
+ if (mcast) {
|
||||
+ if (!tx_completed) {
|
||||
+ atomic_add(tx_airtime, &local->aql_bc_pending_airtime);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ tx_pending = atomic_sub_return(tx_airtime,
|
||||
+ &local->aql_bc_pending_airtime);
|
||||
+ if (tx_pending < 0)
|
||||
+ atomic_cmpxchg(&local->aql_bc_pending_airtime,
|
||||
+ tx_pending, 0);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (!tx_completed) {
|
||||
if (sta)
|
||||
atomic_add(tx_airtime,
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -2554,7 +2554,7 @@ static u16 ieee80211_store_ack_skb(struc
|
||||
|
||||
spin_lock_irqsave(&local->ack_status_lock, flags);
|
||||
id = idr_alloc(&local->ack_status_frames, ack_skb,
|
||||
- 1, 0x2000, GFP_ATOMIC);
|
||||
+ 1, 0x1000, GFP_ATOMIC);
|
||||
spin_unlock_irqrestore(&local->ack_status_lock, flags);
|
||||
|
||||
if (id >= 0) {
|
||||
@@ -3982,20 +3982,20 @@ begin:
|
||||
encap_out:
|
||||
info->control.vif = vif;
|
||||
|
||||
- if (tx.sta &&
|
||||
- wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
|
||||
- bool ampdu = txq->ac != IEEE80211_AC_VO;
|
||||
+ if (wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
|
||||
+ bool ampdu = txq->sta && txq->ac != IEEE80211_AC_VO;
|
||||
u32 airtime;
|
||||
|
||||
airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta,
|
||||
skb->len, ampdu);
|
||||
- if (airtime) {
|
||||
- airtime = ieee80211_info_set_tx_time_est(info, airtime);
|
||||
- ieee80211_sta_update_pending_airtime(local, tx.sta,
|
||||
- txq->ac,
|
||||
- airtime,
|
||||
- false);
|
||||
- }
|
||||
+ if (!airtime)
|
||||
+ return skb;
|
||||
+
|
||||
+ airtime = ieee80211_info_set_tx_time_est(info, airtime);
|
||||
+ info->tx_time_mc = !tx.sta;
|
||||
+ ieee80211_sta_update_pending_airtime(local, tx.sta, txq->ac,
|
||||
+ airtime, false,
|
||||
+ info->tx_time_mc);
|
||||
}
|
||||
|
||||
return skb;
|
||||
@@ -4047,6 +4047,7 @@ struct ieee80211_txq *ieee80211_next_txq
|
||||
struct ieee80211_txq *ret = NULL;
|
||||
struct txq_info *txqi = NULL, *head = NULL;
|
||||
bool found_eligible_txq = false;
|
||||
+ bool aql_check;
|
||||
|
||||
spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
|
||||
@@ -4070,26 +4071,26 @@ struct ieee80211_txq *ieee80211_next_txq
|
||||
if (!head)
|
||||
head = txqi;
|
||||
|
||||
+ aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
|
||||
+ if (aql_check)
|
||||
+ found_eligible_txq = true;
|
||||
+
|
||||
if (txqi->txq.sta) {
|
||||
struct sta_info *sta = container_of(txqi->txq.sta,
|
||||
struct sta_info, sta);
|
||||
- bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
|
||||
- s32 deficit = ieee80211_sta_deficit(sta, txqi->txq.ac);
|
||||
-
|
||||
- if (aql_check)
|
||||
- found_eligible_txq = true;
|
||||
-
|
||||
- if (deficit < 0)
|
||||
+ if (ieee80211_sta_deficit(sta, txqi->txq.ac) < 0) {
|
||||
sta->airtime[txqi->txq.ac].deficit +=
|
||||
sta->airtime_weight << AIRTIME_QUANTUM_SHIFT;
|
||||
-
|
||||
- if (deficit < 0 || !aql_check) {
|
||||
- list_move_tail(&txqi->schedule_order,
|
||||
- &local->active_txqs[txqi->txq.ac]);
|
||||
- goto begin;
|
||||
+ aql_check = false;
|
||||
}
|
||||
}
|
||||
|
||||
+ if (!aql_check) {
|
||||
+ list_move_tail(&txqi->schedule_order,
|
||||
+ &local->active_txqs[txqi->txq.ac]);
|
||||
+ goto begin;
|
||||
+ }
|
||||
+
|
||||
if (txqi->schedule_round == local->schedule_round[ac])
|
||||
goto out;
|
||||
|
||||
@@ -4154,7 +4155,8 @@ bool ieee80211_txq_airtime_check(struct
|
||||
return true;
|
||||
|
||||
if (!txq->sta)
|
||||
- return true;
|
||||
+ return atomic_read(&local->aql_bc_pending_airtime) <
|
||||
+ local->aql_txq_limit_bc;
|
||||
|
||||
if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
|
||||
return true;
|
||||
@@ -4203,15 +4205,15 @@ bool ieee80211_txq_may_transmit(struct i
|
||||
|
||||
spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
|
||||
- if (!txqi->txq.sta)
|
||||
- goto out;
|
||||
-
|
||||
if (list_empty(&txqi->schedule_order))
|
||||
goto out;
|
||||
|
||||
if (!ieee80211_txq_schedule_airtime_check(local, ac))
|
||||
goto out;
|
||||
|
||||
+ if (!txqi->txq.sta)
|
||||
+ goto out;
|
||||
+
|
||||
list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
|
||||
schedule_order) {
|
||||
if (iter == txqi)
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -1222,8 +1222,8 @@ struct ieee80211_tx_info {
|
||||
status_data_idr:1,
|
||||
status_data:13,
|
||||
hw_queue:4,
|
||||
+ tx_time_mc:1,
|
||||
tx_time_est:10;
|
||||
- /* 1 free bit */
|
||||
|
||||
union {
|
||||
struct {
|
||||
--- a/net/mac80211/sta_info.h
|
||||
+++ b/net/mac80211/sta_info.h
|
||||
@@ -147,7 +147,8 @@ struct airtime_info {
|
||||
|
||||
void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
|
||||
struct sta_info *sta, u8 ac,
|
||||
- u16 tx_airtime, bool tx_completed);
|
||||
+ u16 tx_airtime, bool tx_completed,
|
||||
+ bool mcast);
|
||||
|
||||
struct sta_info;
|
||||
|
||||
--- a/net/mac80211/status.c
|
||||
+++ b/net/mac80211/status.c
|
||||
@@ -734,7 +734,7 @@ static void ieee80211_report_used_skb(st
|
||||
ieee80211_sta_update_pending_airtime(local, sta,
|
||||
skb_get_queue_mapping(skb),
|
||||
tx_time_est,
|
||||
- true);
|
||||
+ true, info->tx_time_mc);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
@@ -1158,10 +1158,11 @@ void ieee80211_tx_status_ext(struct ieee
|
||||
/* Do this here to avoid the expensive lookup of the sta
|
||||
* in ieee80211_report_used_skb().
|
||||
*/
|
||||
+ bool mcast = IEEE80211_SKB_CB(skb)->tx_time_mc;
|
||||
ieee80211_sta_update_pending_airtime(local, sta,
|
||||
skb_get_queue_mapping(skb),
|
||||
tx_time_est,
|
||||
- true);
|
||||
+ true, mcast);
|
||||
ieee80211_info_set_tx_time_est(IEEE80211_SKB_CB(skb), 0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 2 Oct 2024 11:45:35 +0200
|
||||
Subject: [PATCH] wifi: mac80211: do not pass a stopped vif to the driver in
|
||||
.get_txpower
|
||||
|
||||
Avoid potentially crashing in the driver because of uninitialized private data
|
||||
|
||||
Fixes: 5b3dc42b1b0d ("mac80211: add support for driver tx power reporting")
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -3134,7 +3134,8 @@ static int ieee80211_get_tx_power(struct
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
|
||||
- if (local->ops->get_txpower)
|
||||
+ if (local->ops->get_txpower &&
|
||||
+ (sdata->flags & IEEE80211_SDATA_IN_DRIVER))
|
||||
return drv_get_txpower(local, sdata, dbm);
|
||||
|
||||
if (local->emulate_chanctx)
|
||||
@@ -0,0 +1,233 @@
|
||||
From: Ming Yen Hsieh <mingyen.hsieh@mediatek.com>
|
||||
Date: Wed, 4 Sep 2024 19:12:56 +0800
|
||||
Subject: [PATCH] wifi: mac80211: introduce EHT rate support in AQL airtime
|
||||
|
||||
Add definitions related to EHT mode and airtime calculation
|
||||
according to the 802.11BE_D4.0.
|
||||
|
||||
Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
|
||||
Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
|
||||
Signed-off-by: Deren Wu <deren.wu@mediatek.com>
|
||||
Signed-off-by: Quan Zhou <quan.zhou@mediatek.com>
|
||||
Signed-off-by: Ming Yen Hsieh <mingyen.hsieh@mediatek.com>
|
||||
Link: https://patch.msgid.link/20240904111256.11734-1-mingyen.hsieh@mediatek.com
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/airtime.c
|
||||
+++ b/net/mac80211/airtime.c
|
||||
@@ -55,10 +55,21 @@
|
||||
#define HE_DURATION_S(shift, streams, gi, bps) \
|
||||
(HE_DURATION(streams, gi, bps) >> shift)
|
||||
|
||||
+/* gi in HE/EHT is identical. It matches enum nl80211_eht_gi as well */
|
||||
+#define EHT_GI_08 HE_GI_08
|
||||
+#define EHT_GI_16 HE_GI_16
|
||||
+#define EHT_GI_32 HE_GI_32
|
||||
+
|
||||
+#define EHT_DURATION(streams, gi, bps) \
|
||||
+ HE_DURATION(streams, gi, bps)
|
||||
+#define EHT_DURATION_S(shift, streams, gi, bps) \
|
||||
+ HE_DURATION_S(shift, streams, gi, bps)
|
||||
+
|
||||
#define BW_20 0
|
||||
#define BW_40 1
|
||||
#define BW_80 2
|
||||
#define BW_160 3
|
||||
+#define BW_320 4
|
||||
|
||||
/*
|
||||
* Define group sort order: HT40 -> SGI -> #streams
|
||||
@@ -68,17 +79,26 @@
|
||||
#define IEEE80211_VHT_STREAM_GROUPS 8 /* BW(=4) * SGI(=2) */
|
||||
|
||||
#define IEEE80211_HE_MAX_STREAMS 8
|
||||
+#define IEEE80211_HE_STREAM_GROUPS 12 /* BW(=4) * GI(=3) */
|
||||
+
|
||||
+#define IEEE80211_EHT_MAX_STREAMS 8
|
||||
+#define IEEE80211_EHT_STREAM_GROUPS 15 /* BW(=5) * GI(=3) */
|
||||
|
||||
#define IEEE80211_HT_GROUPS_NB (IEEE80211_MAX_STREAMS * \
|
||||
IEEE80211_HT_STREAM_GROUPS)
|
||||
#define IEEE80211_VHT_GROUPS_NB (IEEE80211_MAX_STREAMS * \
|
||||
IEEE80211_VHT_STREAM_GROUPS)
|
||||
+#define IEEE80211_HE_GROUPS_NB (IEEE80211_HE_MAX_STREAMS * \
|
||||
+ IEEE80211_HE_STREAM_GROUPS)
|
||||
+#define IEEE80211_EHT_GROUPS_NB (IEEE80211_EHT_MAX_STREAMS * \
|
||||
+ IEEE80211_EHT_STREAM_GROUPS)
|
||||
|
||||
#define IEEE80211_HT_GROUP_0 0
|
||||
#define IEEE80211_VHT_GROUP_0 (IEEE80211_HT_GROUP_0 + IEEE80211_HT_GROUPS_NB)
|
||||
#define IEEE80211_HE_GROUP_0 (IEEE80211_VHT_GROUP_0 + IEEE80211_VHT_GROUPS_NB)
|
||||
+#define IEEE80211_EHT_GROUP_0 (IEEE80211_HE_GROUP_0 + IEEE80211_HE_GROUPS_NB)
|
||||
|
||||
-#define MCS_GROUP_RATES 12
|
||||
+#define MCS_GROUP_RATES 14
|
||||
|
||||
#define HT_GROUP_IDX(_streams, _sgi, _ht40) \
|
||||
IEEE80211_HT_GROUP_0 + \
|
||||
@@ -203,6 +223,69 @@
|
||||
#define HE_GROUP(_streams, _gi, _bw) \
|
||||
__HE_GROUP(_streams, _gi, _bw, \
|
||||
HE_GROUP_SHIFT(_streams, _gi, _bw))
|
||||
+
|
||||
+#define EHT_BW2VBPS(_bw, r5, r4, r3, r2, r1) \
|
||||
+ ((_bw) == BW_320 ? r5 : BW2VBPS(_bw, r4, r3, r2, r1))
|
||||
+
|
||||
+#define EHT_GROUP_IDX(_streams, _gi, _bw) \
|
||||
+ (IEEE80211_EHT_GROUP_0 + \
|
||||
+ IEEE80211_EHT_MAX_STREAMS * 3 * (_bw) + \
|
||||
+ IEEE80211_EHT_MAX_STREAMS * (_gi) + \
|
||||
+ (_streams) - 1)
|
||||
+
|
||||
+#define __EHT_GROUP(_streams, _gi, _bw, _s) \
|
||||
+ [EHT_GROUP_IDX(_streams, _gi, _bw)] = { \
|
||||
+ .shift = _s, \
|
||||
+ .duration = { \
|
||||
+ EHT_DURATION_S(_s, _streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 1960, 980, 490, 234, 117)), \
|
||||
+ EHT_DURATION_S(_s, _streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 3920, 1960, 980, 468, 234)), \
|
||||
+ EHT_DURATION_S(_s, _streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 5880, 2937, 1470, 702, 351)), \
|
||||
+ EHT_DURATION_S(_s, _streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 7840, 3920, 1960, 936, 468)), \
|
||||
+ EHT_DURATION_S(_s, _streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 11760, 5880, 2940, 1404, 702)), \
|
||||
+ EHT_DURATION_S(_s, _streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 15680, 7840, 3920, 1872, 936)), \
|
||||
+ EHT_DURATION_S(_s, _streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 17640, 8820, 4410, 2106, 1053)), \
|
||||
+ EHT_DURATION_S(_s, _streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 19600, 9800, 4900, 2340, 1170)), \
|
||||
+ EHT_DURATION_S(_s, _streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 23520, 11760, 5880, 2808, 1404)), \
|
||||
+ EHT_DURATION_S(_s, _streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 26133, 13066, 6533, 3120, 1560)), \
|
||||
+ EHT_DURATION_S(_s, _streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 29400, 14700, 7350, 3510, 1755)), \
|
||||
+ EHT_DURATION_S(_s, _streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 32666, 16333, 8166, 3900, 1950)), \
|
||||
+ EHT_DURATION_S(_s, _streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 35280, 17640, 8820, 4212, 2106)), \
|
||||
+ EHT_DURATION_S(_s, _streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 39200, 19600, 9800, 4680, 2340)) \
|
||||
+ } \
|
||||
+}
|
||||
+
|
||||
+#define EHT_GROUP_SHIFT(_streams, _gi, _bw) \
|
||||
+ GROUP_SHIFT(EHT_DURATION(_streams, _gi, \
|
||||
+ EHT_BW2VBPS(_bw, 1960, 980, 490, 234, 117)))
|
||||
+
|
||||
+#define EHT_GROUP(_streams, _gi, _bw) \
|
||||
+ __EHT_GROUP(_streams, _gi, _bw, \
|
||||
+ EHT_GROUP_SHIFT(_streams, _gi, _bw))
|
||||
+
|
||||
+#define EHT_GROUP_RANGE(_gi, _bw) \
|
||||
+ EHT_GROUP(1, _gi, _bw), \
|
||||
+ EHT_GROUP(2, _gi, _bw), \
|
||||
+ EHT_GROUP(3, _gi, _bw), \
|
||||
+ EHT_GROUP(4, _gi, _bw), \
|
||||
+ EHT_GROUP(5, _gi, _bw), \
|
||||
+ EHT_GROUP(6, _gi, _bw), \
|
||||
+ EHT_GROUP(7, _gi, _bw), \
|
||||
+ EHT_GROUP(8, _gi, _bw)
|
||||
+
|
||||
struct mcs_group {
|
||||
u8 shift;
|
||||
u16 duration[MCS_GROUP_RATES];
|
||||
@@ -376,6 +459,26 @@ static const struct mcs_group airtime_mc
|
||||
HE_GROUP(6, HE_GI_32, BW_160),
|
||||
HE_GROUP(7, HE_GI_32, BW_160),
|
||||
HE_GROUP(8, HE_GI_32, BW_160),
|
||||
+
|
||||
+ EHT_GROUP_RANGE(EHT_GI_08, BW_20),
|
||||
+ EHT_GROUP_RANGE(EHT_GI_16, BW_20),
|
||||
+ EHT_GROUP_RANGE(EHT_GI_32, BW_20),
|
||||
+
|
||||
+ EHT_GROUP_RANGE(EHT_GI_08, BW_40),
|
||||
+ EHT_GROUP_RANGE(EHT_GI_16, BW_40),
|
||||
+ EHT_GROUP_RANGE(EHT_GI_32, BW_40),
|
||||
+
|
||||
+ EHT_GROUP_RANGE(EHT_GI_08, BW_80),
|
||||
+ EHT_GROUP_RANGE(EHT_GI_16, BW_80),
|
||||
+ EHT_GROUP_RANGE(EHT_GI_32, BW_80),
|
||||
+
|
||||
+ EHT_GROUP_RANGE(EHT_GI_08, BW_160),
|
||||
+ EHT_GROUP_RANGE(EHT_GI_16, BW_160),
|
||||
+ EHT_GROUP_RANGE(EHT_GI_32, BW_160),
|
||||
+
|
||||
+ EHT_GROUP_RANGE(EHT_GI_08, BW_320),
|
||||
+ EHT_GROUP_RANGE(EHT_GI_16, BW_320),
|
||||
+ EHT_GROUP_RANGE(EHT_GI_32, BW_320),
|
||||
};
|
||||
|
||||
static u32
|
||||
@@ -422,6 +525,9 @@ static u32 ieee80211_get_rate_duration(s
|
||||
case RATE_INFO_BW_160:
|
||||
bw = BW_160;
|
||||
break;
|
||||
+ case RATE_INFO_BW_320:
|
||||
+ bw = BW_320;
|
||||
+ break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
@@ -443,14 +549,27 @@ static u32 ieee80211_get_rate_duration(s
|
||||
idx = status->rate_idx;
|
||||
group = HE_GROUP_IDX(streams, status->he_gi, bw);
|
||||
break;
|
||||
+ case RX_ENC_EHT:
|
||||
+ streams = status->nss;
|
||||
+ idx = status->rate_idx;
|
||||
+ group = EHT_GROUP_IDX(streams, status->eht.gi, bw);
|
||||
+ break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
- if (WARN_ON_ONCE((status->encoding != RX_ENC_HE && streams > 4) ||
|
||||
- (status->encoding == RX_ENC_HE && streams > 8)))
|
||||
- return 0;
|
||||
+ switch (status->encoding) {
|
||||
+ case RX_ENC_EHT:
|
||||
+ case RX_ENC_HE:
|
||||
+ if (WARN_ON_ONCE(streams > 8))
|
||||
+ return 0;
|
||||
+ break;
|
||||
+ default:
|
||||
+ if (WARN_ON_ONCE(streams > 4))
|
||||
+ return 0;
|
||||
+ break;
|
||||
+ }
|
||||
|
||||
if (idx >= MCS_GROUP_RATES)
|
||||
return 0;
|
||||
@@ -517,7 +636,9 @@ static bool ieee80211_fill_rate_info(str
|
||||
stat->nss = ri->nss;
|
||||
stat->rate_idx = ri->mcs;
|
||||
|
||||
- if (ri->flags & RATE_INFO_FLAGS_HE_MCS)
|
||||
+ if (ri->flags & RATE_INFO_FLAGS_EHT_MCS)
|
||||
+ stat->encoding = RX_ENC_EHT;
|
||||
+ else if (ri->flags & RATE_INFO_FLAGS_HE_MCS)
|
||||
stat->encoding = RX_ENC_HE;
|
||||
else if (ri->flags & RATE_INFO_FLAGS_VHT_MCS)
|
||||
stat->encoding = RX_ENC_VHT;
|
||||
@@ -529,7 +650,14 @@ static bool ieee80211_fill_rate_info(str
|
||||
if (ri->flags & RATE_INFO_FLAGS_SHORT_GI)
|
||||
stat->enc_flags |= RX_ENC_FLAG_SHORT_GI;
|
||||
|
||||
- stat->he_gi = ri->he_gi;
|
||||
+ switch (stat->encoding) {
|
||||
+ case RX_ENC_EHT:
|
||||
+ stat->eht.gi = ri->eht_gi;
|
||||
+ break;
|
||||
+ default:
|
||||
+ stat->he_gi = ri->he_gi;
|
||||
+ break;
|
||||
+ }
|
||||
|
||||
if (stat->encoding != RX_ENC_LEGACY)
|
||||
return true;
|
||||
@@ -0,0 +1,122 @@
|
||||
From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
|
||||
Date: Tue, 17 Sep 2024 19:32:39 +0530
|
||||
Subject: [PATCH] wifi: cfg80211: check radio iface combination for multi radio
|
||||
per wiphy
|
||||
|
||||
Currently, wiphy_verify_combinations() fails for the multi-radio per wiphy
|
||||
due to the condition check on new global interface combination that DFS
|
||||
only works on one channel. In a multi-radio scenario, new global interface
|
||||
combination encompasses the capabilities of all radio combinations, so it
|
||||
supports more than one channel with DFS. For multi-radio per wiphy,
|
||||
interface combination verification needs to be performed for radio specific
|
||||
interface combinations. This is necessary as the new global interface
|
||||
combination combines the capabilities of all radio combinations.
|
||||
|
||||
Fixes: a01b1e9f9955 ("wifi: mac80211: add support for DFS with multiple radios")
|
||||
Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
|
||||
---
|
||||
|
||||
--- a/net/wireless/core.c
|
||||
+++ b/net/wireless/core.c
|
||||
@@ -599,16 +599,20 @@ use_default_name:
|
||||
}
|
||||
EXPORT_SYMBOL(wiphy_new_nm);
|
||||
|
||||
-static int wiphy_verify_combinations(struct wiphy *wiphy)
|
||||
+static
|
||||
+int wiphy_verify_iface_combinations(struct wiphy *wiphy,
|
||||
+ const struct ieee80211_iface_combination *iface_comb,
|
||||
+ int n_iface_comb,
|
||||
+ bool combined_radio)
|
||||
{
|
||||
const struct ieee80211_iface_combination *c;
|
||||
int i, j;
|
||||
|
||||
- for (i = 0; i < wiphy->n_iface_combinations; i++) {
|
||||
+ for (i = 0; i < n_iface_comb; i++) {
|
||||
u32 cnt = 0;
|
||||
u16 all_iftypes = 0;
|
||||
|
||||
- c = &wiphy->iface_combinations[i];
|
||||
+ c = &iface_comb[i];
|
||||
|
||||
/*
|
||||
* Combinations with just one interface aren't real,
|
||||
@@ -621,9 +625,13 @@ static int wiphy_verify_combinations(str
|
||||
if (WARN_ON(!c->num_different_channels))
|
||||
return -EINVAL;
|
||||
|
||||
- /* DFS only works on one channel. */
|
||||
- if (WARN_ON(c->radar_detect_widths &&
|
||||
- (c->num_different_channels > 1)))
|
||||
+ /* DFS only works on one channel. Avoid this check
|
||||
+ * for multi-radio global combination, since it hold
|
||||
+ * the capabilities of all radio combinations.
|
||||
+ */
|
||||
+ if (!combined_radio &&
|
||||
+ WARN_ON(c->radar_detect_widths &&
|
||||
+ c->num_different_channels > 1))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON(!c->n_limits))
|
||||
@@ -644,13 +652,21 @@ static int wiphy_verify_combinations(str
|
||||
if (WARN_ON(wiphy->software_iftypes & types))
|
||||
return -EINVAL;
|
||||
|
||||
- /* Only a single P2P_DEVICE can be allowed */
|
||||
- if (WARN_ON(types & BIT(NL80211_IFTYPE_P2P_DEVICE) &&
|
||||
+ /* Only a single P2P_DEVICE can be allowed, avoid this
|
||||
+ * check for multi-radio global combination, since it
|
||||
+ * hold the capabilities of all radio combinations.
|
||||
+ */
|
||||
+ if (!combined_radio &&
|
||||
+ WARN_ON(types & BIT(NL80211_IFTYPE_P2P_DEVICE) &&
|
||||
c->limits[j].max > 1))
|
||||
return -EINVAL;
|
||||
|
||||
- /* Only a single NAN can be allowed */
|
||||
- if (WARN_ON(types & BIT(NL80211_IFTYPE_NAN) &&
|
||||
+ /* Only a single NAN can be allowed, avoid this
|
||||
+ * check for multi-radio global combination, since it
|
||||
+ * hold the capabilities of all radio combinations.
|
||||
+ */
|
||||
+ if (!combined_radio &&
|
||||
+ WARN_ON(types & BIT(NL80211_IFTYPE_NAN) &&
|
||||
c->limits[j].max > 1))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -674,6 +690,34 @@ static int wiphy_verify_combinations(str
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int wiphy_verify_combinations(struct wiphy *wiphy)
|
||||
+{
|
||||
+ int i, ret;
|
||||
+ bool combined_radio = false;
|
||||
+
|
||||
+ if (wiphy->n_radio) {
|
||||
+ for (i = 0; i < wiphy->n_radio; i++) {
|
||||
+ const struct wiphy_radio *radio = &wiphy->radio[i];
|
||||
+
|
||||
+ ret = wiphy_verify_iface_combinations(wiphy,
|
||||
+ radio->iface_combinations,
|
||||
+ radio->n_iface_combinations,
|
||||
+ false);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ combined_radio = true;
|
||||
+ }
|
||||
+
|
||||
+ ret = wiphy_verify_iface_combinations(wiphy,
|
||||
+ wiphy->iface_combinations,
|
||||
+ wiphy->n_iface_combinations,
|
||||
+ combined_radio);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
int wiphy_register(struct wiphy *wiphy)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
@@ -0,0 +1,64 @@
|
||||
From: Issam Hamdi <ih@simonwunderlich.de>
|
||||
Date: Fri, 16 Aug 2024 16:24:18 +0200
|
||||
Subject: [PATCH] wifi: cfg80211: Set correct chandef when starting CAC
|
||||
|
||||
When starting CAC in a mode other than AP mode, it return a
|
||||
"WARNING: CPU: 0 PID: 63 at cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211]"
|
||||
caused by the chandef.chan being null at the end of CAC.
|
||||
|
||||
Solution: Ensure the channel definition is set for the different modes
|
||||
when starting CAC to avoid getting a NULL 'chan' at the end of CAC.
|
||||
|
||||
Call Trace:
|
||||
? show_regs.part.0+0x14/0x16
|
||||
? __warn+0x67/0xc0
|
||||
? cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211]
|
||||
? report_bug+0xa7/0x130
|
||||
? exc_overflow+0x30/0x30
|
||||
? handle_bug+0x27/0x50
|
||||
? exc_invalid_op+0x18/0x60
|
||||
? handle_exception+0xf6/0xf6
|
||||
? exc_overflow+0x30/0x30
|
||||
? cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211]
|
||||
? exc_overflow+0x30/0x30
|
||||
? cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211]
|
||||
? regulatory_propagate_dfs_state.cold+0x1b/0x4c [cfg80211]
|
||||
? cfg80211_propagate_cac_done_wk+0x1a/0x30 [cfg80211]
|
||||
? process_one_work+0x165/0x280
|
||||
? worker_thread+0x120/0x3f0
|
||||
? kthread+0xc2/0xf0
|
||||
? process_one_work+0x280/0x280
|
||||
? kthread_complete_and_exit+0x20/0x20
|
||||
? ret_from_fork+0x19/0x24
|
||||
|
||||
Reported-by: Kretschmer Mathias <mathias.kretschmer@fit.fraunhofer.de>
|
||||
Signed-off-by: Issam Hamdi <ih@simonwunderlich.de>
|
||||
Link: https://patch.msgid.link/20240816142418.3381951-1-ih@simonwunderlich.de
|
||||
[shorten subject, remove OCB, reorder cases to match previous list]
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -10144,7 +10144,20 @@ static int nl80211_start_radar_detection
|
||||
|
||||
err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms);
|
||||
if (!err) {
|
||||
- wdev->links[0].ap.chandef = chandef;
|
||||
+ switch (wdev->iftype) {
|
||||
+ case NL80211_IFTYPE_AP:
|
||||
+ case NL80211_IFTYPE_P2P_GO:
|
||||
+ wdev->links[0].ap.chandef = chandef;
|
||||
+ break;
|
||||
+ case NL80211_IFTYPE_ADHOC:
|
||||
+ wdev->u.ibss.chandef = chandef;
|
||||
+ break;
|
||||
+ case NL80211_IFTYPE_MESH_POINT:
|
||||
+ wdev->u.mesh.chandef = chandef;
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
wdev->cac_started = true;
|
||||
wdev->cac_start_time = jiffies;
|
||||
wdev->cac_time_ms = cac_time_ms;
|
||||
@@ -0,0 +1,136 @@
|
||||
From: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Date: Fri, 6 Sep 2024 12:14:19 +0530
|
||||
Subject: [PATCH] Revert "wifi: mac80211: move radar detect work to sdata"
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This reverts commit ce9e660ef32e ("wifi: mac80211: move radar detect work to sdata").
|
||||
|
||||
To enable radar detection with MLO, it’s essential to handle it on a
|
||||
per-link basis. This is because when using MLO, multiple links may already
|
||||
be active and beaconing. In this scenario, another link should be able to
|
||||
initiate a radar detection. Also, if underlying links are associated with
|
||||
different hardware devices but grouped together for MLO, they could
|
||||
potentially start radar detection simultaneously. Therefore, it makes
|
||||
sense to manage radar detection settings separately for each link by moving
|
||||
them back to a per-link data structure.
|
||||
|
||||
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Link: https://patch.msgid.link/20240906064426.2101315-2-quic_adisi@quicinc.com
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -1658,7 +1658,7 @@ static int ieee80211_stop_ap(struct wiph
|
||||
|
||||
if (sdata->wdev.cac_started) {
|
||||
chandef = link_conf->chanreq.oper;
|
||||
- wiphy_delayed_work_cancel(wiphy, &sdata->dfs_cac_timer_work);
|
||||
+ wiphy_delayed_work_cancel(wiphy, &link->dfs_cac_timer_work);
|
||||
cfg80211_cac_event(sdata->dev, &chandef,
|
||||
NL80211_RADAR_CAC_ABORTED,
|
||||
GFP_KERNEL);
|
||||
@@ -3482,7 +3482,7 @@ static int ieee80211_start_radar_detecti
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
|
||||
- wiphy_delayed_work_queue(wiphy, &sdata->dfs_cac_timer_work,
|
||||
+ wiphy_delayed_work_queue(wiphy, &sdata->deflink.dfs_cac_timer_work,
|
||||
msecs_to_jiffies(cac_time_ms));
|
||||
|
||||
out_unlock:
|
||||
@@ -3499,7 +3499,7 @@ static void ieee80211_end_cac(struct wip
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
wiphy_delayed_work_cancel(wiphy,
|
||||
- &sdata->dfs_cac_timer_work);
|
||||
+ &sdata->deflink.dfs_cac_timer_work);
|
||||
|
||||
if (sdata->wdev.cac_started) {
|
||||
ieee80211_link_release_channel(&sdata->deflink);
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1069,6 +1069,7 @@ struct ieee80211_link_data {
|
||||
int ap_power_level; /* in dBm */
|
||||
|
||||
bool radar_required;
|
||||
+ struct wiphy_delayed_work dfs_cac_timer_work;
|
||||
|
||||
union {
|
||||
struct ieee80211_link_data_managed mgd;
|
||||
@@ -1167,8 +1168,6 @@ struct ieee80211_sub_if_data {
|
||||
struct ieee80211_link_data deflink;
|
||||
struct ieee80211_link_data __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
|
||||
|
||||
- struct wiphy_delayed_work dfs_cac_timer_work;
|
||||
-
|
||||
/* for ieee80211_set_active_links_async() */
|
||||
struct wiphy_work activate_links_work;
|
||||
u16 desired_active_links;
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -551,7 +551,7 @@ static void ieee80211_do_stop(struct iee
|
||||
wiphy_work_cancel(local->hw.wiphy,
|
||||
&sdata->deflink.color_change_finalize_work);
|
||||
wiphy_delayed_work_cancel(local->hw.wiphy,
|
||||
- &sdata->dfs_cac_timer_work);
|
||||
+ &sdata->deflink.dfs_cac_timer_work);
|
||||
|
||||
if (sdata->wdev.cac_started) {
|
||||
chandef = sdata->vif.bss_conf.chanreq.oper;
|
||||
@@ -1744,8 +1744,6 @@ static void ieee80211_setup_sdata(struct
|
||||
wiphy_work_init(&sdata->work, ieee80211_iface_work);
|
||||
wiphy_work_init(&sdata->activate_links_work,
|
||||
ieee80211_activate_links_work);
|
||||
- wiphy_delayed_work_init(&sdata->dfs_cac_timer_work,
|
||||
- ieee80211_dfs_cac_timer_work);
|
||||
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
--- a/net/mac80211/link.c
|
||||
+++ b/net/mac80211/link.c
|
||||
@@ -45,6 +45,8 @@ void ieee80211_link_init(struct ieee8021
|
||||
ieee80211_color_collision_detection_work);
|
||||
INIT_LIST_HEAD(&link->assigned_chanctx_list);
|
||||
INIT_LIST_HEAD(&link->reserved_chanctx_list);
|
||||
+ wiphy_delayed_work_init(&link->dfs_cac_timer_work,
|
||||
+ ieee80211_dfs_cac_timer_work);
|
||||
|
||||
if (!deflink) {
|
||||
switch (sdata->vif.type) {
|
||||
--- a/net/mac80211/mlme.c
|
||||
+++ b/net/mac80211/mlme.c
|
||||
@@ -3031,15 +3031,16 @@ void ieee80211_dynamic_ps_timer(struct t
|
||||
|
||||
void ieee80211_dfs_cac_timer_work(struct wiphy *wiphy, struct wiphy_work *work)
|
||||
{
|
||||
- struct ieee80211_sub_if_data *sdata =
|
||||
- container_of(work, struct ieee80211_sub_if_data,
|
||||
+ struct ieee80211_link_data *link =
|
||||
+ container_of(work, struct ieee80211_link_data,
|
||||
dfs_cac_timer_work.work);
|
||||
- struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chanreq.oper;
|
||||
+ struct cfg80211_chan_def chandef = link->conf->chanreq.oper;
|
||||
+ struct ieee80211_sub_if_data *sdata = link->sdata;
|
||||
|
||||
lockdep_assert_wiphy(sdata->local->hw.wiphy);
|
||||
|
||||
if (sdata->wdev.cac_started) {
|
||||
- ieee80211_link_release_channel(&sdata->deflink);
|
||||
+ ieee80211_link_release_channel(link);
|
||||
cfg80211_cac_event(sdata->dev, &chandef,
|
||||
NL80211_RADAR_CAC_FINISHED,
|
||||
GFP_KERNEL);
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -3460,7 +3460,7 @@ void ieee80211_dfs_cac_cancel(struct iee
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
wiphy_delayed_work_cancel(local->hw.wiphy,
|
||||
- &sdata->dfs_cac_timer_work);
|
||||
+ &sdata->deflink.dfs_cac_timer_work);
|
||||
|
||||
if (sdata->wdev.cac_started) {
|
||||
chandef = sdata->vif.bss_conf.chanreq.oper;
|
||||
@@ -0,0 +1,50 @@
|
||||
From: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Date: Fri, 6 Sep 2024 12:14:20 +0530
|
||||
Subject: [PATCH] wifi: mac80211: remove label usage in
|
||||
ieee80211_start_radar_detection()
|
||||
|
||||
After locks rework [1], ieee80211_start_radar_detection() function is no
|
||||
longer acquiring any lock as such explicitly. Hence, it is not unlocking
|
||||
anything as well. However, label "out_unlock" is still used which creates
|
||||
confusion. Also, now there is no need of goto label as such.
|
||||
|
||||
Get rid of the goto logic and use direct return statements.
|
||||
|
||||
[1]: https://lore.kernel.org/all/20230828135928.b1c6efffe9ad.I4aec875e25abc9ef0b5ad1e70b5747fd483fbd3c@changeid/
|
||||
|
||||
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Link: https://patch.msgid.link/20240906064426.2101315-3-quic_adisi@quicinc.com
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -3468,10 +3468,8 @@ static int ieee80211_start_radar_detecti
|
||||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
- if (!list_empty(&local->roc_list) || local->scanning) {
|
||||
- err = -EBUSY;
|
||||
- goto out_unlock;
|
||||
- }
|
||||
+ if (!list_empty(&local->roc_list) || local->scanning)
|
||||
+ return -EBUSY;
|
||||
|
||||
/* whatever, but channel contexts should not complain about that one */
|
||||
sdata->deflink.smps_mode = IEEE80211_SMPS_OFF;
|
||||
@@ -3480,13 +3478,12 @@ static int ieee80211_start_radar_detecti
|
||||
err = ieee80211_link_use_channel(&sdata->deflink, &chanreq,
|
||||
IEEE80211_CHANCTX_SHARED);
|
||||
if (err)
|
||||
- goto out_unlock;
|
||||
+ return err;
|
||||
|
||||
wiphy_delayed_work_queue(wiphy, &sdata->deflink.dfs_cac_timer_work,
|
||||
msecs_to_jiffies(cac_time_ms));
|
||||
|
||||
- out_unlock:
|
||||
- return err;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static void ieee80211_end_cac(struct wiphy *wiphy,
|
||||
@@ -0,0 +1,42 @@
|
||||
From: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Date: Fri, 6 Sep 2024 12:14:21 +0530
|
||||
Subject: [PATCH] wifi: trace: unlink rdev_end_cac trace event from
|
||||
wiphy_netdev_evt class
|
||||
|
||||
rdev_end_cac trace event is linked with wiphy_netdev_evt event class.
|
||||
There is no option to pass link ID currently to wiphy_netdev_evt class.
|
||||
A subsequent change would pass link ID to rdev_end_cac event and hence
|
||||
it can no longer derive the event class from wiphy_netdev_evt.
|
||||
|
||||
Therefore, unlink rdev_end_cac event from wiphy_netdev_evt and define it's
|
||||
own independent trace event. Link ID would be passed in subsequent change.
|
||||
|
||||
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Link: https://patch.msgid.link/20240906064426.2101315-4-quic_adisi@quicinc.com
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/wireless/trace.h
|
||||
+++ b/net/wireless/trace.h
|
||||
@@ -805,9 +805,18 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_flus
|
||||
TP_ARGS(wiphy, netdev)
|
||||
);
|
||||
|
||||
-DEFINE_EVENT(wiphy_netdev_evt, rdev_end_cac,
|
||||
- TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
|
||||
- TP_ARGS(wiphy, netdev)
|
||||
+TRACE_EVENT(rdev_end_cac,
|
||||
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
|
||||
+ TP_ARGS(wiphy, netdev),
|
||||
+ TP_STRUCT__entry(
|
||||
+ WIPHY_ENTRY
|
||||
+ NETDEV_ENTRY
|
||||
+ ),
|
||||
+ TP_fast_assign(
|
||||
+ WIPHY_ASSIGN;
|
||||
+ NETDEV_ASSIGN;
|
||||
+ ),
|
||||
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(station_add_change,
|
||||
@@ -0,0 +1,309 @@
|
||||
From: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Date: Fri, 6 Sep 2024 12:14:22 +0530
|
||||
Subject: [PATCH] wifi: cfg80211: move DFS related members to links[] in
|
||||
wireless_dev
|
||||
|
||||
A few members related to DFS handling are currently under per wireless
|
||||
device data structure. However, in order to support DFS with MLO, there is
|
||||
a need to have them on a per-link manner.
|
||||
|
||||
Hence, as a preliminary step, move members cac_started, cac_start_time
|
||||
and cac_time_ms to be on a per-link basis.
|
||||
|
||||
Since currently, link ID is not known at all places, use default value of
|
||||
0 for now.
|
||||
|
||||
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Link: https://patch.msgid.link/20240906064426.2101315-5-quic_adisi@quicinc.com
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/11h.c
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/11h.c
|
||||
@@ -117,7 +117,7 @@ void mwifiex_dfs_cac_work_queue(struct w
|
||||
dfs_cac_work);
|
||||
|
||||
chandef = priv->dfs_chandef;
|
||||
- if (priv->wdev.cac_started) {
|
||||
+ if (priv->wdev.links[0].cac_started) {
|
||||
mwifiex_dbg(priv->adapter, MSG,
|
||||
"CAC timer finished; No radar detected\n");
|
||||
cfg80211_cac_event(priv->netdev, &chandef,
|
||||
@@ -174,7 +174,7 @@ int mwifiex_stop_radar_detection(struct
|
||||
*/
|
||||
void mwifiex_abort_cac(struct mwifiex_private *priv)
|
||||
{
|
||||
- if (priv->wdev.cac_started) {
|
||||
+ if (priv->wdev.links[0].cac_started) {
|
||||
if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef))
|
||||
mwifiex_dbg(priv->adapter, ERROR,
|
||||
"failed to stop CAC in FW\n");
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
|
||||
@@ -1880,7 +1880,7 @@ mwifiex_cfg80211_del_station(struct wiph
|
||||
struct mwifiex_sta_node *sta_node;
|
||||
u8 deauth_mac[ETH_ALEN];
|
||||
|
||||
- if (!priv->bss_started && priv->wdev.cac_started) {
|
||||
+ if (!priv->bss_started && priv->wdev.links[0].cac_started) {
|
||||
mwifiex_dbg(priv->adapter, INFO, "%s: abort CAC!\n", __func__);
|
||||
mwifiex_abort_cac(priv);
|
||||
}
|
||||
@@ -3978,7 +3978,7 @@ mwifiex_cfg80211_channel_switch(struct w
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
- if (priv->wdev.cac_started)
|
||||
+ if (priv->wdev.links[0].cac_started)
|
||||
return -EBUSY;
|
||||
|
||||
if (cfg80211_chandef_identical(¶ms->chandef,
|
||||
--- a/drivers/net/wireless/quantenna/qtnfmac/event.c
|
||||
+++ b/drivers/net/wireless/quantenna/qtnfmac/event.c
|
||||
@@ -520,21 +520,21 @@ static int qtnf_event_handle_radar(struc
|
||||
cfg80211_radar_event(wiphy, &chandef, GFP_KERNEL);
|
||||
break;
|
||||
case QLINK_RADAR_CAC_FINISHED:
|
||||
- if (!vif->wdev.cac_started)
|
||||
+ if (!vif->wdev.links[0].cac_started)
|
||||
break;
|
||||
|
||||
cfg80211_cac_event(vif->netdev, &chandef,
|
||||
NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
|
||||
break;
|
||||
case QLINK_RADAR_CAC_ABORTED:
|
||||
- if (!vif->wdev.cac_started)
|
||||
+ if (!vif->wdev.links[0].cac_started)
|
||||
break;
|
||||
|
||||
cfg80211_cac_event(vif->netdev, &chandef,
|
||||
NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
|
||||
break;
|
||||
case QLINK_RADAR_CAC_STARTED:
|
||||
- if (vif->wdev.cac_started)
|
||||
+ if (vif->wdev.links[0].cac_started)
|
||||
break;
|
||||
|
||||
if (!wiphy_ext_feature_isset(wiphy,
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -6198,9 +6198,6 @@ enum ieee80211_ap_reg_power {
|
||||
* @address: The address for this device, valid only if @netdev is %NULL
|
||||
* @is_running: true if this is a non-netdev device that has been started, e.g.
|
||||
* the P2P Device.
|
||||
- * @cac_started: true if DFS channel availability check has been started
|
||||
- * @cac_start_time: timestamp (jiffies) when the dfs state was entered.
|
||||
- * @cac_time_ms: CAC time in ms
|
||||
* @ps: powersave mode is enabled
|
||||
* @ps_timeout: dynamic powersave timeout
|
||||
* @ap_unexpected_nlportid: (private) netlink port ID of application
|
||||
@@ -6224,6 +6221,11 @@ enum ieee80211_ap_reg_power {
|
||||
* unprotected beacon report
|
||||
* @links: array of %IEEE80211_MLD_MAX_NUM_LINKS elements containing @addr
|
||||
* @ap and @client for each link
|
||||
+ * @links[].cac_started: true if DFS channel availability check has been
|
||||
+ * started
|
||||
+ * @links[].cac_start_time: timestamp (jiffies) when the dfs state was
|
||||
+ * entered.
|
||||
+ * @links[].cac_time_ms: CAC time in ms
|
||||
* @valid_links: bitmap describing what elements of @links are valid
|
||||
*/
|
||||
struct wireless_dev {
|
||||
@@ -6265,11 +6267,6 @@ struct wireless_dev {
|
||||
u32 owner_nlportid;
|
||||
bool nl_owner_dead;
|
||||
|
||||
- /* FIXME: need to rework radar detection for MLO */
|
||||
- bool cac_started;
|
||||
- unsigned long cac_start_time;
|
||||
- unsigned int cac_time_ms;
|
||||
-
|
||||
#ifdef CPTCFG_CFG80211_WEXT
|
||||
/* wext data */
|
||||
struct {
|
||||
@@ -6336,6 +6333,10 @@ struct wireless_dev {
|
||||
struct cfg80211_internal_bss *current_bss;
|
||||
} client;
|
||||
};
|
||||
+
|
||||
+ bool cac_started;
|
||||
+ unsigned long cac_start_time;
|
||||
+ unsigned int cac_time_ms;
|
||||
} links[IEEE80211_MLD_MAX_NUM_LINKS];
|
||||
u16 valid_links;
|
||||
};
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -1656,7 +1656,7 @@ static int ieee80211_stop_ap(struct wiph
|
||||
ieee80211_link_info_change_notify(sdata, link,
|
||||
BSS_CHANGED_BEACON_ENABLED);
|
||||
|
||||
- if (sdata->wdev.cac_started) {
|
||||
+ if (sdata->wdev.links[0].cac_started) {
|
||||
chandef = link_conf->chanreq.oper;
|
||||
wiphy_delayed_work_cancel(wiphy, &link->dfs_cac_timer_work);
|
||||
cfg80211_cac_event(sdata->dev, &chandef,
|
||||
@@ -3498,9 +3498,9 @@ static void ieee80211_end_cac(struct wip
|
||||
wiphy_delayed_work_cancel(wiphy,
|
||||
&sdata->deflink.dfs_cac_timer_work);
|
||||
|
||||
- if (sdata->wdev.cac_started) {
|
||||
+ if (sdata->wdev.links[0].cac_started) {
|
||||
ieee80211_link_release_channel(&sdata->deflink);
|
||||
- sdata->wdev.cac_started = false;
|
||||
+ sdata->wdev.links[0].cac_started = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3955,7 +3955,7 @@ __ieee80211_channel_switch(struct wiphy
|
||||
if (!list_empty(&local->roc_list) || local->scanning)
|
||||
return -EBUSY;
|
||||
|
||||
- if (sdata->wdev.cac_started)
|
||||
+ if (sdata->wdev.links[0].cac_started)
|
||||
return -EBUSY;
|
||||
|
||||
if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS))
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -553,7 +553,7 @@ static void ieee80211_do_stop(struct iee
|
||||
wiphy_delayed_work_cancel(local->hw.wiphy,
|
||||
&sdata->deflink.dfs_cac_timer_work);
|
||||
|
||||
- if (sdata->wdev.cac_started) {
|
||||
+ if (sdata->wdev.links[0].cac_started) {
|
||||
chandef = sdata->vif.bss_conf.chanreq.oper;
|
||||
WARN_ON(local->suspended);
|
||||
ieee80211_link_release_channel(&sdata->deflink);
|
||||
--- a/net/mac80211/mlme.c
|
||||
+++ b/net/mac80211/mlme.c
|
||||
@@ -3039,7 +3039,7 @@ void ieee80211_dfs_cac_timer_work(struct
|
||||
|
||||
lockdep_assert_wiphy(sdata->local->hw.wiphy);
|
||||
|
||||
- if (sdata->wdev.cac_started) {
|
||||
+ if (sdata->wdev.links[0].cac_started) {
|
||||
ieee80211_link_release_channel(link);
|
||||
cfg80211_cac_event(sdata->dev, &chandef,
|
||||
NL80211_RADAR_CAC_FINISHED,
|
||||
--- a/net/mac80211/scan.c
|
||||
+++ b/net/mac80211/scan.c
|
||||
@@ -585,7 +585,7 @@ static bool __ieee80211_can_leave_ch(str
|
||||
return false;
|
||||
|
||||
list_for_each_entry(sdata_iter, &local->interfaces, list) {
|
||||
- if (sdata_iter->wdev.cac_started)
|
||||
+ if (sdata_iter->wdev.links[0].cac_started)
|
||||
return false;
|
||||
}
|
||||
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -3462,7 +3462,7 @@ void ieee80211_dfs_cac_cancel(struct iee
|
||||
wiphy_delayed_work_cancel(local->hw.wiphy,
|
||||
&sdata->deflink.dfs_cac_timer_work);
|
||||
|
||||
- if (sdata->wdev.cac_started) {
|
||||
+ if (sdata->wdev.links[0].cac_started) {
|
||||
chandef = sdata->vif.bss_conf.chanreq.oper;
|
||||
ieee80211_link_release_channel(&sdata->deflink);
|
||||
cfg80211_cac_event(sdata->dev,
|
||||
--- a/net/wireless/ibss.c
|
||||
+++ b/net/wireless/ibss.c
|
||||
@@ -94,7 +94,7 @@ int __cfg80211_join_ibss(struct cfg80211
|
||||
|
||||
lockdep_assert_held(&rdev->wiphy.mtx);
|
||||
|
||||
- if (wdev->cac_started)
|
||||
+ if (wdev->links[0].cac_started)
|
||||
return -EBUSY;
|
||||
|
||||
if (wdev->u.ibss.ssid_len)
|
||||
--- a/net/wireless/mesh.c
|
||||
+++ b/net/wireless/mesh.c
|
||||
@@ -127,7 +127,7 @@ int __cfg80211_join_mesh(struct cfg80211
|
||||
if (!rdev->ops->join_mesh)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
- if (wdev->cac_started)
|
||||
+ if (wdev->links[0].cac_started)
|
||||
return -EBUSY;
|
||||
|
||||
if (!setup->chandef.chan) {
|
||||
--- a/net/wireless/mlme.c
|
||||
+++ b/net/wireless/mlme.c
|
||||
@@ -1124,13 +1124,14 @@ void cfg80211_cac_event(struct net_devic
|
||||
|
||||
trace_cfg80211_cac_event(netdev, event);
|
||||
|
||||
- if (WARN_ON(!wdev->cac_started && event != NL80211_RADAR_CAC_STARTED))
|
||||
+ if (WARN_ON(!wdev->links[0].cac_started &&
|
||||
+ event != NL80211_RADAR_CAC_STARTED))
|
||||
return;
|
||||
|
||||
switch (event) {
|
||||
case NL80211_RADAR_CAC_FINISHED:
|
||||
- timeout = wdev->cac_start_time +
|
||||
- msecs_to_jiffies(wdev->cac_time_ms);
|
||||
+ timeout = wdev->links[0].cac_start_time +
|
||||
+ msecs_to_jiffies(wdev->links[0].cac_time_ms);
|
||||
WARN_ON(!time_after_eq(jiffies, timeout));
|
||||
cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
|
||||
memcpy(&rdev->cac_done_chandef, chandef,
|
||||
@@ -1139,10 +1140,10 @@ void cfg80211_cac_event(struct net_devic
|
||||
cfg80211_sched_dfs_chan_update(rdev);
|
||||
fallthrough;
|
||||
case NL80211_RADAR_CAC_ABORTED:
|
||||
- wdev->cac_started = false;
|
||||
+ wdev->links[0].cac_started = false;
|
||||
break;
|
||||
case NL80211_RADAR_CAC_STARTED:
|
||||
- wdev->cac_started = true;
|
||||
+ wdev->links[0].cac_started = true;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -6066,7 +6066,7 @@ static int nl80211_start_ap(struct sk_bu
|
||||
if (!rdev->ops->start_ap)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
- if (wdev->cac_started)
|
||||
+ if (wdev->links[0].cac_started)
|
||||
return -EBUSY;
|
||||
|
||||
if (wdev->links[link_id].ap.beacon_interval)
|
||||
@@ -10122,7 +10122,7 @@ static int nl80211_start_radar_detection
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
- if (cfg80211_beaconing_iface_active(wdev) || wdev->cac_started) {
|
||||
+ if (cfg80211_beaconing_iface_active(wdev) || wdev->links[0].cac_started) {
|
||||
err = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
@@ -10158,9 +10158,9 @@ static int nl80211_start_radar_detection
|
||||
default:
|
||||
break;
|
||||
}
|
||||
- wdev->cac_started = true;
|
||||
- wdev->cac_start_time = jiffies;
|
||||
- wdev->cac_time_ms = cac_time_ms;
|
||||
+ wdev->links[0].cac_started = true;
|
||||
+ wdev->links[0].cac_start_time = jiffies;
|
||||
+ wdev->links[0].cac_time_ms = cac_time_ms;
|
||||
}
|
||||
unlock:
|
||||
wiphy_unlock(wiphy);
|
||||
--- a/net/wireless/reg.c
|
||||
+++ b/net/wireless/reg.c
|
||||
@@ -4241,7 +4241,7 @@ static void cfg80211_check_and_end_cac(s
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
struct cfg80211_chan_def *chandef;
|
||||
|
||||
- if (!wdev->cac_started)
|
||||
+ if (!wdev->links[0].cac_started)
|
||||
continue;
|
||||
|
||||
/* FIXME: radar detection is tied to link 0 for now */
|
||||
@@ -0,0 +1,435 @@
|
||||
From: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Date: Fri, 6 Sep 2024 12:14:23 +0530
|
||||
Subject: [PATCH] wifi: cfg80211: handle DFS per link
|
||||
|
||||
Currently, during starting a radar detection, no link id information is
|
||||
parsed and passed down. In order to support starting radar detection
|
||||
during Multi Link Operation, it is required to pass link id as well.
|
||||
|
||||
Add changes to first parse and then pass link id in the start radar
|
||||
detection path.
|
||||
|
||||
Additionally, update notification APIs to allow drivers/mac80211 to
|
||||
pass the link ID.
|
||||
|
||||
However, everything is handled at link 0 only until all API's are ready to
|
||||
handle it per link.
|
||||
|
||||
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Link: https://patch.msgid.link/20240906064426.2101315-6-quic_adisi@quicinc.com
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/11h.c
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/11h.c
|
||||
@@ -122,7 +122,7 @@ void mwifiex_dfs_cac_work_queue(struct w
|
||||
"CAC timer finished; No radar detected\n");
|
||||
cfg80211_cac_event(priv->netdev, &chandef,
|
||||
NL80211_RADAR_CAC_FINISHED,
|
||||
- GFP_KERNEL);
|
||||
+ GFP_KERNEL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +182,8 @@ void mwifiex_abort_cac(struct mwifiex_pr
|
||||
"Aborting delayed work for CAC.\n");
|
||||
cancel_delayed_work_sync(&priv->dfs_cac_work);
|
||||
cfg80211_cac_event(priv->netdev, &priv->dfs_chandef,
|
||||
- NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
|
||||
+ NL80211_RADAR_CAC_ABORTED, GFP_KERNEL,
|
||||
+ 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +222,7 @@ int mwifiex_11h_handle_chanrpt_ready(str
|
||||
cfg80211_cac_event(priv->netdev,
|
||||
&priv->dfs_chandef,
|
||||
NL80211_RADAR_DETECTED,
|
||||
- GFP_KERNEL);
|
||||
+ GFP_KERNEL, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
|
||||
@@ -4145,7 +4145,7 @@ static int
|
||||
mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef,
|
||||
- u32 cac_time_ms)
|
||||
+ u32 cac_time_ms, int link_id)
|
||||
{
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||
struct mwifiex_radar_params radar_params;
|
||||
--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
|
||||
+++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
|
||||
@@ -837,7 +837,7 @@ static int qtnf_channel_switch(struct wi
|
||||
static int qtnf_start_radar_detection(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
struct cfg80211_chan_def *chandef,
|
||||
- u32 cac_time_ms)
|
||||
+ u32 cac_time_ms, int link_id)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
||||
int ret;
|
||||
--- a/drivers/net/wireless/quantenna/qtnfmac/event.c
|
||||
+++ b/drivers/net/wireless/quantenna/qtnfmac/event.c
|
||||
@@ -524,14 +524,14 @@ static int qtnf_event_handle_radar(struc
|
||||
break;
|
||||
|
||||
cfg80211_cac_event(vif->netdev, &chandef,
|
||||
- NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
|
||||
+ NL80211_RADAR_CAC_FINISHED, GFP_KERNEL, 0);
|
||||
break;
|
||||
case QLINK_RADAR_CAC_ABORTED:
|
||||
if (!vif->wdev.links[0].cac_started)
|
||||
break;
|
||||
|
||||
cfg80211_cac_event(vif->netdev, &chandef,
|
||||
- NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
|
||||
+ NL80211_RADAR_CAC_ABORTED, GFP_KERNEL, 0);
|
||||
break;
|
||||
case QLINK_RADAR_CAC_STARTED:
|
||||
if (vif->wdev.links[0].cac_started)
|
||||
@@ -542,7 +542,7 @@ static int qtnf_event_handle_radar(struc
|
||||
break;
|
||||
|
||||
cfg80211_cac_event(vif->netdev, &chandef,
|
||||
- NL80211_RADAR_CAC_STARTED, GFP_KERNEL);
|
||||
+ NL80211_RADAR_CAC_STARTED, GFP_KERNEL, 0);
|
||||
break;
|
||||
default:
|
||||
pr_warn("%s: unhandled radar event %u\n",
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -4841,9 +4841,9 @@ struct cfg80211_ops {
|
||||
int (*start_radar_detection)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef,
|
||||
- u32 cac_time_ms);
|
||||
+ u32 cac_time_ms, int link_id);
|
||||
void (*end_cac)(struct wiphy *wiphy,
|
||||
- struct net_device *dev);
|
||||
+ struct net_device *dev, unsigned int link_id);
|
||||
int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_update_ft_ies_params *ftie);
|
||||
int (*crit_proto_start)(struct wiphy *wiphy,
|
||||
@@ -8745,6 +8745,7 @@ void cfg80211_sta_opmode_change_notify(s
|
||||
* @chandef: chandef for the current channel
|
||||
* @event: type of event
|
||||
* @gfp: context flags
|
||||
+ * @link_id: valid link_id for MLO operation or 0 otherwise.
|
||||
*
|
||||
* This function is called when a Channel availability check (CAC) is finished
|
||||
* or aborted. This must be called to notify the completion of a CAC process,
|
||||
@@ -8752,7 +8753,8 @@ void cfg80211_sta_opmode_change_notify(s
|
||||
*/
|
||||
void cfg80211_cac_event(struct net_device *netdev,
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
- enum nl80211_radar_event event, gfp_t gfp);
|
||||
+ enum nl80211_radar_event event, gfp_t gfp,
|
||||
+ unsigned int link_id);
|
||||
|
||||
/**
|
||||
* cfg80211_background_cac_abort - Channel Availability Check offchan abort event
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -1661,7 +1661,7 @@ static int ieee80211_stop_ap(struct wiph
|
||||
wiphy_delayed_work_cancel(wiphy, &link->dfs_cac_timer_work);
|
||||
cfg80211_cac_event(sdata->dev, &chandef,
|
||||
NL80211_RADAR_CAC_ABORTED,
|
||||
- GFP_KERNEL);
|
||||
+ GFP_KERNEL, 0);
|
||||
}
|
||||
|
||||
drv_stop_ap(sdata->local, sdata, link_conf);
|
||||
@@ -3459,7 +3459,7 @@ static int ieee80211_set_bitrate_mask(st
|
||||
static int ieee80211_start_radar_detection(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef,
|
||||
- u32 cac_time_ms)
|
||||
+ u32 cac_time_ms, int link_id)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_chan_req chanreq = { .oper = *chandef };
|
||||
@@ -3487,7 +3487,7 @@ static int ieee80211_start_radar_detecti
|
||||
}
|
||||
|
||||
static void ieee80211_end_cac(struct wiphy *wiphy,
|
||||
- struct net_device *dev)
|
||||
+ struct net_device *dev, unsigned int link_id)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -559,7 +559,7 @@ static void ieee80211_do_stop(struct iee
|
||||
ieee80211_link_release_channel(&sdata->deflink);
|
||||
cfg80211_cac_event(sdata->dev, &chandef,
|
||||
NL80211_RADAR_CAC_ABORTED,
|
||||
- GFP_KERNEL);
|
||||
+ GFP_KERNEL, 0);
|
||||
}
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
||||
--- a/net/mac80211/mlme.c
|
||||
+++ b/net/mac80211/mlme.c
|
||||
@@ -3043,7 +3043,7 @@ void ieee80211_dfs_cac_timer_work(struct
|
||||
ieee80211_link_release_channel(link);
|
||||
cfg80211_cac_event(sdata->dev, &chandef,
|
||||
NL80211_RADAR_CAC_FINISHED,
|
||||
- GFP_KERNEL);
|
||||
+ GFP_KERNEL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -3468,7 +3468,7 @@ void ieee80211_dfs_cac_cancel(struct iee
|
||||
cfg80211_cac_event(sdata->dev,
|
||||
&chandef,
|
||||
NL80211_RADAR_CAC_ABORTED,
|
||||
- GFP_KERNEL);
|
||||
+ GFP_KERNEL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
--- a/net/wireless/mlme.c
|
||||
+++ b/net/wireless/mlme.c
|
||||
@@ -1111,18 +1111,19 @@ EXPORT_SYMBOL(__cfg80211_radar_event);
|
||||
|
||||
void cfg80211_cac_event(struct net_device *netdev,
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
- enum nl80211_radar_event event, gfp_t gfp)
|
||||
+ enum nl80211_radar_event event, gfp_t gfp,
|
||||
+ unsigned int link_id)
|
||||
{
|
||||
struct wireless_dev *wdev = netdev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
unsigned long timeout;
|
||||
|
||||
- /* not yet supported */
|
||||
- if (wdev->valid_links)
|
||||
+ if (WARN_ON(wdev->valid_links &&
|
||||
+ !(wdev->valid_links & BIT(link_id))))
|
||||
return;
|
||||
|
||||
- trace_cfg80211_cac_event(netdev, event);
|
||||
+ trace_cfg80211_cac_event(netdev, event, link_id);
|
||||
|
||||
if (WARN_ON(!wdev->links[0].cac_started &&
|
||||
event != NL80211_RADAR_CAC_STARTED))
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -10122,7 +10122,20 @@ static int nl80211_start_radar_detection
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
- if (cfg80211_beaconing_iface_active(wdev) || wdev->links[0].cac_started) {
|
||||
+ if (cfg80211_beaconing_iface_active(wdev)) {
|
||||
+ /* During MLO other link(s) can beacon, only the current link
|
||||
+ * can not already beacon
|
||||
+ */
|
||||
+ if (wdev->valid_links &&
|
||||
+ !wdev->links[0].ap.beacon_interval) {
|
||||
+ /* nothing */
|
||||
+ } else {
|
||||
+ err = -EBUSY;
|
||||
+ goto unlock;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (wdev->links[0].cac_started) {
|
||||
err = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
@@ -10142,7 +10155,8 @@ static int nl80211_start_radar_detection
|
||||
if (WARN_ON(!cac_time_ms))
|
||||
cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
|
||||
|
||||
- err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms);
|
||||
+ err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms,
|
||||
+ 0);
|
||||
if (!err) {
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
@@ -16512,10 +16526,10 @@ nl80211_set_ttlm(struct sk_buff *skb, st
|
||||
SELECTOR(__sel, NETDEV_UP_NOTMX, \
|
||||
NL80211_FLAG_NEED_NETDEV_UP | \
|
||||
NL80211_FLAG_NO_WIPHY_MTX) \
|
||||
- SELECTOR(__sel, NETDEV_UP_NOTMX_NOMLO, \
|
||||
+ SELECTOR(__sel, NETDEV_UP_NOTMX_MLO, \
|
||||
NL80211_FLAG_NEED_NETDEV_UP | \
|
||||
NL80211_FLAG_NO_WIPHY_MTX | \
|
||||
- NL80211_FLAG_MLO_UNSUPPORTED) \
|
||||
+ NL80211_FLAG_MLO_VALID_LINK_ID) \
|
||||
SELECTOR(__sel, NETDEV_UP_CLEAR, \
|
||||
NL80211_FLAG_NEED_NETDEV_UP | \
|
||||
NL80211_FLAG_CLEAR_SKB) \
|
||||
@@ -17410,7 +17424,7 @@ static const struct genl_small_ops nl802
|
||||
.flags = GENL_UNS_ADMIN_PERM,
|
||||
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP |
|
||||
NL80211_FLAG_NO_WIPHY_MTX |
|
||||
- NL80211_FLAG_MLO_UNSUPPORTED),
|
||||
+ NL80211_FLAG_MLO_VALID_LINK_ID),
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
|
||||
--- a/net/wireless/rdev-ops.h
|
||||
+++ b/net/wireless/rdev-ops.h
|
||||
@@ -1200,26 +1200,27 @@ static inline int
|
||||
rdev_start_radar_detection(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef,
|
||||
- u32 cac_time_ms)
|
||||
+ u32 cac_time_ms, int link_id)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
trace_rdev_start_radar_detection(&rdev->wiphy, dev, chandef,
|
||||
- cac_time_ms);
|
||||
+ cac_time_ms, link_id);
|
||||
if (rdev->ops->start_radar_detection)
|
||||
ret = rdev->ops->start_radar_detection(&rdev->wiphy, dev,
|
||||
- chandef, cac_time_ms);
|
||||
+ chandef, cac_time_ms,
|
||||
+ link_id);
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void
|
||||
rdev_end_cac(struct cfg80211_registered_device *rdev,
|
||||
- struct net_device *dev)
|
||||
+ struct net_device *dev, unsigned int link_id)
|
||||
{
|
||||
- trace_rdev_end_cac(&rdev->wiphy, dev);
|
||||
+ trace_rdev_end_cac(&rdev->wiphy, dev, link_id);
|
||||
if (rdev->ops->end_cac)
|
||||
- rdev->ops->end_cac(&rdev->wiphy, dev);
|
||||
+ rdev->ops->end_cac(&rdev->wiphy, dev, link_id);
|
||||
trace_rdev_return_void(&rdev->wiphy);
|
||||
}
|
||||
|
||||
--- a/net/wireless/reg.c
|
||||
+++ b/net/wireless/reg.c
|
||||
@@ -4229,6 +4229,8 @@ EXPORT_SYMBOL(regulatory_pre_cac_allowed
|
||||
static void cfg80211_check_and_end_cac(struct cfg80211_registered_device *rdev)
|
||||
{
|
||||
struct wireless_dev *wdev;
|
||||
+ unsigned int link_id;
|
||||
+
|
||||
/* If we finished CAC or received radar, we should end any
|
||||
* CAC running on the same channels.
|
||||
* the check !cfg80211_chandef_dfs_usable contain 2 options:
|
||||
@@ -4241,16 +4243,17 @@ static void cfg80211_check_and_end_cac(s
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
struct cfg80211_chan_def *chandef;
|
||||
|
||||
- if (!wdev->links[0].cac_started)
|
||||
- continue;
|
||||
+ for_each_valid_link(wdev, link_id) {
|
||||
+ if (!wdev->links[link_id].cac_started)
|
||||
+ continue;
|
||||
|
||||
- /* FIXME: radar detection is tied to link 0 for now */
|
||||
- chandef = wdev_chandef(wdev, 0);
|
||||
- if (!chandef)
|
||||
- continue;
|
||||
+ chandef = wdev_chandef(wdev, link_id);
|
||||
+ if (!chandef)
|
||||
+ continue;
|
||||
|
||||
- if (!cfg80211_chandef_dfs_usable(&rdev->wiphy, chandef))
|
||||
- rdev_end_cac(rdev, wdev->netdev);
|
||||
+ if (!cfg80211_chandef_dfs_usable(&rdev->wiphy, chandef))
|
||||
+ rdev_end_cac(rdev, wdev->netdev, link_id);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
--- a/net/wireless/trace.h
|
||||
+++ b/net/wireless/trace.h
|
||||
@@ -806,17 +806,21 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_flus
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_end_cac,
|
||||
- TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
|
||||
- TP_ARGS(wiphy, netdev),
|
||||
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
|
||||
+ unsigned int link_id),
|
||||
+ TP_ARGS(wiphy, netdev, link_id),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
NETDEV_ENTRY
|
||||
+ __field(unsigned int, link_id)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
NETDEV_ASSIGN;
|
||||
+ __entry->link_id = link_id;
|
||||
),
|
||||
- TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG)
|
||||
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id: %d",
|
||||
+ WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(station_add_change,
|
||||
@@ -2661,24 +2665,26 @@ TRACE_EVENT(rdev_external_auth,
|
||||
TRACE_EVENT(rdev_start_radar_detection,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
|
||||
struct cfg80211_chan_def *chandef,
|
||||
- u32 cac_time_ms),
|
||||
- TP_ARGS(wiphy, netdev, chandef, cac_time_ms),
|
||||
+ u32 cac_time_ms, int link_id),
|
||||
+ TP_ARGS(wiphy, netdev, chandef, cac_time_ms, link_id),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
NETDEV_ENTRY
|
||||
CHAN_DEF_ENTRY
|
||||
__field(u32, cac_time_ms)
|
||||
+ __field(int, link_id)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
NETDEV_ASSIGN;
|
||||
CHAN_DEF_ASSIGN(chandef);
|
||||
__entry->cac_time_ms = cac_time_ms;
|
||||
+ __entry->link_id = link_id;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT
|
||||
- ", cac_time_ms=%u",
|
||||
+ ", cac_time_ms=%u, link_id=%d",
|
||||
WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG,
|
||||
- __entry->cac_time_ms)
|
||||
+ __entry->cac_time_ms, __entry->link_id)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_set_mcast_rate,
|
||||
@@ -3492,18 +3498,21 @@ TRACE_EVENT(cfg80211_radar_event,
|
||||
);
|
||||
|
||||
TRACE_EVENT(cfg80211_cac_event,
|
||||
- TP_PROTO(struct net_device *netdev, enum nl80211_radar_event evt),
|
||||
- TP_ARGS(netdev, evt),
|
||||
+ TP_PROTO(struct net_device *netdev, enum nl80211_radar_event evt,
|
||||
+ unsigned int link_id),
|
||||
+ TP_ARGS(netdev, evt, link_id),
|
||||
TP_STRUCT__entry(
|
||||
NETDEV_ENTRY
|
||||
__field(enum nl80211_radar_event, evt)
|
||||
+ __field(unsigned int, link_id)
|
||||
),
|
||||
TP_fast_assign(
|
||||
NETDEV_ASSIGN;
|
||||
__entry->evt = evt;
|
||||
+ __entry->link_id = link_id;
|
||||
),
|
||||
- TP_printk(NETDEV_PR_FMT ", event: %d",
|
||||
- NETDEV_PR_ARG, __entry->evt)
|
||||
+ TP_printk(NETDEV_PR_FMT ", event: %d, link_id=%u",
|
||||
+ NETDEV_PR_ARG, __entry->evt, __entry->link_id)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(cfg80211_rx_evt,
|
||||
@@ -0,0 +1,134 @@
|
||||
From: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Date: Fri, 6 Sep 2024 12:14:24 +0530
|
||||
Subject: [PATCH] wifi: mac80211: handle DFS per link
|
||||
|
||||
In order to support DFS with MLO, handle the link ID now passed from
|
||||
cfg80211, adjust the code to do everything per link and call the
|
||||
notifications to cfg80211 correctly.
|
||||
|
||||
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Link: https://patch.msgid.link/20240906064426.2101315-7-quic_adisi@quicinc.com
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -3464,6 +3464,7 @@ static int ieee80211_start_radar_detecti
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_chan_req chanreq = { .oper = *chandef };
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
+ struct ieee80211_link_data *link_data;
|
||||
int err;
|
||||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
@@ -3471,16 +3472,20 @@ static int ieee80211_start_radar_detecti
|
||||
if (!list_empty(&local->roc_list) || local->scanning)
|
||||
return -EBUSY;
|
||||
|
||||
+ link_data = sdata_dereference(sdata->link[link_id], sdata);
|
||||
+ if (!link_data)
|
||||
+ return -ENOLINK;
|
||||
+
|
||||
/* whatever, but channel contexts should not complain about that one */
|
||||
- sdata->deflink.smps_mode = IEEE80211_SMPS_OFF;
|
||||
- sdata->deflink.needed_rx_chains = local->rx_chains;
|
||||
+ link_data->smps_mode = IEEE80211_SMPS_OFF;
|
||||
+ link_data->needed_rx_chains = local->rx_chains;
|
||||
|
||||
- err = ieee80211_link_use_channel(&sdata->deflink, &chanreq,
|
||||
+ err = ieee80211_link_use_channel(link_data, &chanreq,
|
||||
IEEE80211_CHANCTX_SHARED);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
- wiphy_delayed_work_queue(wiphy, &sdata->deflink.dfs_cac_timer_work,
|
||||
+ wiphy_delayed_work_queue(wiphy, &link_data->dfs_cac_timer_work,
|
||||
msecs_to_jiffies(cac_time_ms));
|
||||
|
||||
return 0;
|
||||
@@ -3491,16 +3496,21 @@ static void ieee80211_end_cac(struct wip
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
+ struct ieee80211_link_data *link_data;
|
||||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
+ link_data = sdata_dereference(sdata->link[link_id], sdata);
|
||||
+ if (!link_data)
|
||||
+ continue;
|
||||
+
|
||||
wiphy_delayed_work_cancel(wiphy,
|
||||
- &sdata->deflink.dfs_cac_timer_work);
|
||||
+ &link_data->dfs_cac_timer_work);
|
||||
|
||||
- if (sdata->wdev.links[0].cac_started) {
|
||||
- ieee80211_link_release_channel(&sdata->deflink);
|
||||
- sdata->wdev.links[0].cac_started = false;
|
||||
+ if (sdata->wdev.links[link_id].cac_started) {
|
||||
+ ieee80211_link_release_channel(link_data);
|
||||
+ sdata->wdev.links[link_id].cac_started = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
--- a/net/mac80211/link.c
|
||||
+++ b/net/mac80211/link.c
|
||||
@@ -77,6 +77,16 @@ void ieee80211_link_stop(struct ieee8021
|
||||
&link->color_change_finalize_work);
|
||||
wiphy_work_cancel(link->sdata->local->hw.wiphy,
|
||||
&link->csa.finalize_work);
|
||||
+
|
||||
+ if (link->sdata->wdev.links[link->link_id].cac_started) {
|
||||
+ wiphy_delayed_work_cancel(link->sdata->local->hw.wiphy,
|
||||
+ &link->dfs_cac_timer_work);
|
||||
+ cfg80211_cac_event(link->sdata->dev,
|
||||
+ &link->conf->chanreq.oper,
|
||||
+ NL80211_RADAR_CAC_ABORTED,
|
||||
+ GFP_KERNEL, link->link_id);
|
||||
+ }
|
||||
+
|
||||
ieee80211_link_release_channel(link);
|
||||
}
|
||||
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -3455,20 +3455,30 @@ void ieee80211_dfs_cac_cancel(struct iee
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct cfg80211_chan_def chandef;
|
||||
+ struct ieee80211_link_data *link;
|
||||
+ unsigned int link_id;
|
||||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
- wiphy_delayed_work_cancel(local->hw.wiphy,
|
||||
- &sdata->deflink.dfs_cac_timer_work);
|
||||
+ for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS;
|
||||
+ link_id++) {
|
||||
+ link = sdata_dereference(sdata->link[link_id],
|
||||
+ sdata);
|
||||
+ if (!link)
|
||||
+ continue;
|
||||
|
||||
- if (sdata->wdev.links[0].cac_started) {
|
||||
- chandef = sdata->vif.bss_conf.chanreq.oper;
|
||||
- ieee80211_link_release_channel(&sdata->deflink);
|
||||
- cfg80211_cac_event(sdata->dev,
|
||||
- &chandef,
|
||||
+ wiphy_delayed_work_cancel(local->hw.wiphy,
|
||||
+ &link->dfs_cac_timer_work);
|
||||
+
|
||||
+ if (!sdata->wdev.links[link_id].cac_started)
|
||||
+ continue;
|
||||
+
|
||||
+ chandef = link->conf->chanreq.oper;
|
||||
+ ieee80211_link_release_channel(link);
|
||||
+ cfg80211_cac_event(sdata->dev, &chandef,
|
||||
NL80211_RADAR_CAC_ABORTED,
|
||||
- GFP_KERNEL, 0);
|
||||
+ GFP_KERNEL, link_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
From: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Date: Fri, 6 Sep 2024 12:14:25 +0530
|
||||
Subject: [PATCH] wifi: cfg80211/mac80211: use proper link ID for DFS
|
||||
|
||||
Now that all APIs have support to handle DFS per link, use proper link ID
|
||||
instead of 0.
|
||||
|
||||
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Link: https://patch.msgid.link/20240906064426.2101315-8-quic_adisi@quicinc.com
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -1656,12 +1656,12 @@ static int ieee80211_stop_ap(struct wiph
|
||||
ieee80211_link_info_change_notify(sdata, link,
|
||||
BSS_CHANGED_BEACON_ENABLED);
|
||||
|
||||
- if (sdata->wdev.links[0].cac_started) {
|
||||
+ if (sdata->wdev.links[link_id].cac_started) {
|
||||
chandef = link_conf->chanreq.oper;
|
||||
wiphy_delayed_work_cancel(wiphy, &link->dfs_cac_timer_work);
|
||||
cfg80211_cac_event(sdata->dev, &chandef,
|
||||
NL80211_RADAR_CAC_ABORTED,
|
||||
- GFP_KERNEL, 0);
|
||||
+ GFP_KERNEL, link_id);
|
||||
}
|
||||
|
||||
drv_stop_ap(sdata->local, sdata, link_conf);
|
||||
@@ -3965,7 +3965,7 @@ __ieee80211_channel_switch(struct wiphy
|
||||
if (!list_empty(&local->roc_list) || local->scanning)
|
||||
return -EBUSY;
|
||||
|
||||
- if (sdata->wdev.links[0].cac_started)
|
||||
+ if (sdata->wdev.links[link_id].cac_started)
|
||||
return -EBUSY;
|
||||
|
||||
if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS))
|
||||
--- a/net/mac80211/mlme.c
|
||||
+++ b/net/mac80211/mlme.c
|
||||
@@ -3039,11 +3039,11 @@ void ieee80211_dfs_cac_timer_work(struct
|
||||
|
||||
lockdep_assert_wiphy(sdata->local->hw.wiphy);
|
||||
|
||||
- if (sdata->wdev.links[0].cac_started) {
|
||||
+ if (sdata->wdev.links[link->link_id].cac_started) {
|
||||
ieee80211_link_release_channel(link);
|
||||
cfg80211_cac_event(sdata->dev, &chandef,
|
||||
NL80211_RADAR_CAC_FINISHED,
|
||||
- GFP_KERNEL, 0);
|
||||
+ GFP_KERNEL, link->link_id);
|
||||
}
|
||||
}
|
||||
|
||||
--- a/net/mac80211/scan.c
|
||||
+++ b/net/mac80211/scan.c
|
||||
@@ -575,6 +575,7 @@ static bool __ieee80211_can_leave_ch(str
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_sub_if_data *sdata_iter;
|
||||
+ unsigned int link_id;
|
||||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
@@ -585,8 +586,9 @@ static bool __ieee80211_can_leave_ch(str
|
||||
return false;
|
||||
|
||||
list_for_each_entry(sdata_iter, &local->interfaces, list) {
|
||||
- if (sdata_iter->wdev.links[0].cac_started)
|
||||
- return false;
|
||||
+ for_each_valid_link(&sdata_iter->wdev, link_id)
|
||||
+ if (sdata_iter->wdev.links[link_id].cac_started)
|
||||
+ return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
--- a/net/wireless/mlme.c
|
||||
+++ b/net/wireless/mlme.c
|
||||
@@ -1125,14 +1125,14 @@ void cfg80211_cac_event(struct net_devic
|
||||
|
||||
trace_cfg80211_cac_event(netdev, event, link_id);
|
||||
|
||||
- if (WARN_ON(!wdev->links[0].cac_started &&
|
||||
+ if (WARN_ON(!wdev->links[link_id].cac_started &&
|
||||
event != NL80211_RADAR_CAC_STARTED))
|
||||
return;
|
||||
|
||||
switch (event) {
|
||||
case NL80211_RADAR_CAC_FINISHED:
|
||||
- timeout = wdev->links[0].cac_start_time +
|
||||
- msecs_to_jiffies(wdev->links[0].cac_time_ms);
|
||||
+ timeout = wdev->links[link_id].cac_start_time +
|
||||
+ msecs_to_jiffies(wdev->links[link_id].cac_time_ms);
|
||||
WARN_ON(!time_after_eq(jiffies, timeout));
|
||||
cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
|
||||
memcpy(&rdev->cac_done_chandef, chandef,
|
||||
@@ -1141,10 +1141,10 @@ void cfg80211_cac_event(struct net_devic
|
||||
cfg80211_sched_dfs_chan_update(rdev);
|
||||
fallthrough;
|
||||
case NL80211_RADAR_CAC_ABORTED:
|
||||
- wdev->links[0].cac_started = false;
|
||||
+ wdev->links[link_id].cac_started = false;
|
||||
break;
|
||||
case NL80211_RADAR_CAC_STARTED:
|
||||
- wdev->links[0].cac_started = true;
|
||||
+ wdev->links[link_id].cac_started = true;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -6066,7 +6066,7 @@ static int nl80211_start_ap(struct sk_bu
|
||||
if (!rdev->ops->start_ap)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
- if (wdev->links[0].cac_started)
|
||||
+ if (wdev->links[link_id].cac_started)
|
||||
return -EBUSY;
|
||||
|
||||
if (wdev->links[link_id].ap.beacon_interval)
|
||||
@@ -10073,6 +10073,7 @@ static int nl80211_start_radar_detection
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
+ int link_id = nl80211_link_id(info->attrs);
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_chan_def chandef;
|
||||
enum nl80211_dfs_regions dfs_region;
|
||||
@@ -10127,7 +10128,7 @@ static int nl80211_start_radar_detection
|
||||
* can not already beacon
|
||||
*/
|
||||
if (wdev->valid_links &&
|
||||
- !wdev->links[0].ap.beacon_interval) {
|
||||
+ !wdev->links[link_id].ap.beacon_interval) {
|
||||
/* nothing */
|
||||
} else {
|
||||
err = -EBUSY;
|
||||
@@ -10135,7 +10136,7 @@ static int nl80211_start_radar_detection
|
||||
}
|
||||
}
|
||||
|
||||
- if (wdev->links[0].cac_started) {
|
||||
+ if (wdev->links[link_id].cac_started) {
|
||||
err = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
@@ -10156,7 +10157,7 @@ static int nl80211_start_radar_detection
|
||||
cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
|
||||
|
||||
err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms,
|
||||
- 0);
|
||||
+ link_id);
|
||||
if (!err) {
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
@@ -10172,9 +10173,9 @@ static int nl80211_start_radar_detection
|
||||
default:
|
||||
break;
|
||||
}
|
||||
- wdev->links[0].cac_started = true;
|
||||
- wdev->links[0].cac_start_time = jiffies;
|
||||
- wdev->links[0].cac_time_ms = cac_time_ms;
|
||||
+ wdev->links[link_id].cac_started = true;
|
||||
+ wdev->links[link_id].cac_start_time = jiffies;
|
||||
+ wdev->links[link_id].cac_time_ms = cac_time_ms;
|
||||
}
|
||||
unlock:
|
||||
wiphy_unlock(wiphy);
|
||||
@@ -0,0 +1,360 @@
|
||||
From: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Date: Fri, 6 Sep 2024 12:14:26 +0530
|
||||
Subject: [PATCH] wifi: mac80211: handle ieee80211_radar_detected() for MLO
|
||||
|
||||
Currently DFS works under assumption there could be only one channel
|
||||
context in the hardware. Hence, drivers just calls the function
|
||||
ieee80211_radar_detected() passing the hardware structure. However, with
|
||||
MLO, this obviously will not work since number of channel contexts will be
|
||||
more than one and hence drivers would need to pass the channel information
|
||||
as well on which the radar is detected.
|
||||
|
||||
Also, when radar is detected in one of the links, other link's CAC should
|
||||
not be cancelled.
|
||||
|
||||
Hence, in order to support DFS with MLO, do the following changes -
|
||||
* Add channel context conf pointer as an argument to the function
|
||||
ieee80211_radar_detected(). During MLO, drivers would have to pass on
|
||||
which channel context conf radar is detected. Otherwise, drivers could
|
||||
just pass NULL.
|
||||
* ieee80211_radar_detected() will iterate over all channel contexts
|
||||
present and
|
||||
* if channel context conf is passed, only mark that as radar
|
||||
detected
|
||||
* if NULL is passed, then mark all channel contexts as radar
|
||||
detected
|
||||
* Then as usual, schedule the radar detected work.
|
||||
* In the worker, go over all the contexts again and for all such context
|
||||
which is marked with radar detected, cancel the ongoing CAC by calling
|
||||
ieee80211_dfs_cac_cancel() and then notify cfg80211 via
|
||||
cfg80211_radar_event().
|
||||
* To cancel the CAC, pass the channel context as well where radar is
|
||||
detected to ieee80211_dfs_cac_cancel(). This ensures that CAC is
|
||||
canceled only on the links using the provided context, leaving other
|
||||
links unaffected.
|
||||
|
||||
This would also help in scenarios where there is split phy 5 GHz radio,
|
||||
which is capable of DFS channels in both lower and upper band. In this
|
||||
case, simultaneous radars can be detected.
|
||||
|
||||
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||
Link: https://patch.msgid.link/20240906064426.2101315-9-quic_adisi@quicinc.com
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath10k/debug.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/debug.c
|
||||
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
+ * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@@ -1774,7 +1774,7 @@ static ssize_t ath10k_write_simulate_rad
|
||||
if (!arvif->is_started)
|
||||
return -EINVAL;
|
||||
|
||||
- ieee80211_radar_detected(ar->hw);
|
||||
+ ieee80211_radar_detected(ar->hw, NULL);
|
||||
|
||||
return count;
|
||||
}
|
||||
--- a/drivers/net/wireless/ath/ath10k/mac.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/mac.c
|
||||
@@ -1437,7 +1437,7 @@ static void ath10k_recalc_radar_detectio
|
||||
* by indicating that radar was detected.
|
||||
*/
|
||||
ath10k_warn(ar, "failed to start CAC: %d\n", ret);
|
||||
- ieee80211_radar_detected(ar->hw);
|
||||
+ ieee80211_radar_detected(ar->hw, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath10k/wmi.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
|
||||
@@ -3990,7 +3990,7 @@ static void ath10k_radar_detected(struct
|
||||
if (ar->dfs_block_radar_events)
|
||||
ath10k_info(ar, "DFS Radar detected, but ignored as requested\n");
|
||||
else
|
||||
- ieee80211_radar_detected(ar->hw);
|
||||
+ ieee80211_radar_detected(ar->hw, NULL);
|
||||
}
|
||||
|
||||
static void ath10k_radar_confirmation_work(struct work_struct *work)
|
||||
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
||||
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
||||
@@ -8358,7 +8358,7 @@ ath11k_wmi_pdev_dfs_radar_detected_event
|
||||
if (ar->dfs_block_radar_events)
|
||||
ath11k_info(ab, "DFS Radar detected, but ignored as requested\n");
|
||||
else
|
||||
- ieee80211_radar_detected(ar->hw);
|
||||
+ ieee80211_radar_detected(ar->hw, NULL);
|
||||
|
||||
exit:
|
||||
rcu_read_unlock();
|
||||
--- a/drivers/net/wireless/ath/ath12k/wmi.c
|
||||
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
|
||||
@@ -6789,7 +6789,7 @@ ath12k_wmi_pdev_dfs_radar_detected_event
|
||||
if (ar->dfs_block_radar_events)
|
||||
ath12k_info(ab, "DFS Radar detected, but ignored as requested\n");
|
||||
else
|
||||
- ieee80211_radar_detected(ath12k_ar_to_hw(ar));
|
||||
+ ieee80211_radar_detected(ath12k_ar_to_hw(ar), NULL);
|
||||
|
||||
exit:
|
||||
rcu_read_unlock();
|
||||
--- a/drivers/net/wireless/ath/ath9k/dfs.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/dfs.c
|
||||
@@ -280,7 +280,7 @@ ath9k_dfs_process_radar_pulse(struct ath
|
||||
if (!pd->add_pulse(pd, pe, NULL))
|
||||
return;
|
||||
DFS_STAT_INC(sc, radar_detected);
|
||||
- ieee80211_radar_detected(sc->hw);
|
||||
+ ieee80211_radar_detected(sc->hw, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
--- a/drivers/net/wireless/ath/ath9k/dfs_debug.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c
|
||||
@@ -116,7 +116,7 @@ static ssize_t write_file_simulate_radar
|
||||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
|
||||
- ieee80211_radar_detected(sc->hw);
|
||||
+ ieee80211_radar_detected(sc->hw, NULL);
|
||||
|
||||
return count;
|
||||
}
|
||||
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
|
||||
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
|
||||
@@ -394,7 +394,7 @@ mt7615_mcu_rx_radar_detected(struct mt76
|
||||
if (mt76_phy_dfs_state(mphy) < MT_DFS_STATE_CAC)
|
||||
return;
|
||||
|
||||
- ieee80211_radar_detected(mphy->hw);
|
||||
+ ieee80211_radar_detected(mphy->hw, NULL);
|
||||
dev->hw_pattern++;
|
||||
}
|
||||
|
||||
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
|
||||
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
|
||||
@@ -630,7 +630,7 @@ static void mt76x02_dfs_tasklet(struct t
|
||||
radar_detected = mt76x02_dfs_check_detection(dev);
|
||||
if (radar_detected) {
|
||||
/* sw detector rx radar pattern */
|
||||
- ieee80211_radar_detected(dev->mt76.hw);
|
||||
+ ieee80211_radar_detected(dev->mt76.hw, NULL);
|
||||
mt76x02_dfs_detector_reset(dev);
|
||||
|
||||
return;
|
||||
@@ -658,7 +658,7 @@ static void mt76x02_dfs_tasklet(struct t
|
||||
|
||||
/* hw detector rx radar pattern */
|
||||
dfs_pd->stats[i].hw_pattern++;
|
||||
- ieee80211_radar_detected(dev->mt76.hw);
|
||||
+ ieee80211_radar_detected(dev->mt76.hw, NULL);
|
||||
mt76x02_dfs_detector_reset(dev);
|
||||
|
||||
return;
|
||||
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
|
||||
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
|
||||
@@ -293,7 +293,7 @@ mt7915_mcu_rx_radar_detected(struct mt79
|
||||
&dev->rdd2_chandef,
|
||||
GFP_ATOMIC);
|
||||
else
|
||||
- ieee80211_radar_detected(mphy->hw);
|
||||
+ ieee80211_radar_detected(mphy->hw, NULL);
|
||||
dev->hw_pattern++;
|
||||
}
|
||||
|
||||
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
|
||||
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
|
||||
@@ -371,7 +371,7 @@ mt7996_mcu_rx_radar_detected(struct mt79
|
||||
&dev->rdd2_chandef,
|
||||
GFP_ATOMIC);
|
||||
else
|
||||
- ieee80211_radar_detected(mphy->hw);
|
||||
+ ieee80211_radar_detected(mphy->hw, NULL);
|
||||
dev->hw_pattern++;
|
||||
}
|
||||
|
||||
--- a/drivers/net/wireless/ti/wl18xx/event.c
|
||||
+++ b/drivers/net/wireless/ti/wl18xx/event.c
|
||||
@@ -142,7 +142,7 @@ int wl18xx_process_mailbox_events(struct
|
||||
wl18xx_radar_type_decode(mbox->radar_type));
|
||||
|
||||
if (!wl->radar_debug_mode)
|
||||
- ieee80211_radar_detected(wl->hw);
|
||||
+ ieee80211_radar_detected(wl->hw, NULL);
|
||||
}
|
||||
|
||||
if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
|
||||
--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
|
||||
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
|
||||
@@ -1146,7 +1146,7 @@ static int hwsim_write_simulate_radar(vo
|
||||
{
|
||||
struct mac80211_hwsim_data *data = dat;
|
||||
|
||||
- ieee80211_radar_detected(data->hw);
|
||||
+ ieee80211_radar_detected(data->hw, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -6717,8 +6717,11 @@ void ieee80211_cqm_beacon_loss_notify(st
|
||||
* ieee80211_radar_detected - inform that a radar was detected
|
||||
*
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
+ * @chanctx_conf: Channel context on which radar is detected. Mandatory to
|
||||
+ * pass a valid pointer during MLO. For non-MLO %NULL can be passed
|
||||
*/
|
||||
-void ieee80211_radar_detected(struct ieee80211_hw *hw);
|
||||
+void ieee80211_radar_detected(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_chanctx_conf *chanctx_conf);
|
||||
|
||||
/**
|
||||
* ieee80211_chswitch_done - Complete channel switch process
|
||||
--- a/net/mac80211/chan.c
|
||||
+++ b/net/mac80211/chan.c
|
||||
@@ -681,6 +681,7 @@ ieee80211_alloc_chanctx(struct ieee80211
|
||||
ctx->mode = mode;
|
||||
ctx->conf.radar_enabled = false;
|
||||
ctx->conf.radio_idx = radio_idx;
|
||||
+ ctx->radar_detected = false;
|
||||
_ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
|
||||
|
||||
return ctx;
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -895,6 +895,8 @@ struct ieee80211_chanctx {
|
||||
struct ieee80211_chan_req req;
|
||||
|
||||
struct ieee80211_chanctx_conf conf;
|
||||
+
|
||||
+ bool radar_detected;
|
||||
};
|
||||
|
||||
struct mac80211_qos_map {
|
||||
@@ -2632,7 +2634,8 @@ void ieee80211_recalc_chanctx_min_def(st
|
||||
bool ieee80211_is_radar_required(struct ieee80211_local *local);
|
||||
|
||||
void ieee80211_dfs_cac_timer_work(struct wiphy *wiphy, struct wiphy_work *work);
|
||||
-void ieee80211_dfs_cac_cancel(struct ieee80211_local *local);
|
||||
+void ieee80211_dfs_cac_cancel(struct ieee80211_local *local,
|
||||
+ struct ieee80211_chanctx *chanctx);
|
||||
void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy,
|
||||
struct wiphy_work *work);
|
||||
int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
|
||||
--- a/net/mac80211/pm.c
|
||||
+++ b/net/mac80211/pm.c
|
||||
@@ -32,7 +32,7 @@ int __ieee80211_suspend(struct ieee80211
|
||||
|
||||
ieee80211_scan_cancel(local);
|
||||
|
||||
- ieee80211_dfs_cac_cancel(local);
|
||||
+ ieee80211_dfs_cac_cancel(local, NULL);
|
||||
|
||||
ieee80211_roc_purge(local, NULL);
|
||||
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -3451,11 +3451,16 @@ u64 ieee80211_calculate_rx_timestamp(str
|
||||
return ts;
|
||||
}
|
||||
|
||||
-void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
|
||||
+/* Cancel CAC for the interfaces under the specified @local. If @ctx is
|
||||
+ * also provided, only the interfaces using that ctx will be canceled.
|
||||
+ */
|
||||
+void ieee80211_dfs_cac_cancel(struct ieee80211_local *local,
|
||||
+ struct ieee80211_chanctx *ctx)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct cfg80211_chan_def chandef;
|
||||
struct ieee80211_link_data *link;
|
||||
+ struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
unsigned int link_id;
|
||||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
@@ -3468,6 +3473,11 @@ void ieee80211_dfs_cac_cancel(struct iee
|
||||
if (!link)
|
||||
continue;
|
||||
|
||||
+ chanctx_conf = sdata_dereference(link->conf->chanctx_conf,
|
||||
+ sdata);
|
||||
+ if (ctx && &ctx->conf != chanctx_conf)
|
||||
+ continue;
|
||||
+
|
||||
wiphy_delayed_work_cancel(local->hw.wiphy,
|
||||
&link->dfs_cac_timer_work);
|
||||
|
||||
@@ -3488,9 +3498,8 @@ void ieee80211_dfs_radar_detected_work(s
|
||||
{
|
||||
struct ieee80211_local *local =
|
||||
container_of(work, struct ieee80211_local, radar_detected_work);
|
||||
- struct cfg80211_chan_def chandef = local->hw.conf.chandef;
|
||||
+ struct cfg80211_chan_def chandef;
|
||||
struct ieee80211_chanctx *ctx;
|
||||
- int num_chanctx = 0;
|
||||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
@@ -3498,25 +3507,46 @@ void ieee80211_dfs_radar_detected_work(s
|
||||
if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER)
|
||||
continue;
|
||||
|
||||
- num_chanctx++;
|
||||
+ if (!ctx->radar_detected)
|
||||
+ continue;
|
||||
+
|
||||
+ ctx->radar_detected = false;
|
||||
+
|
||||
chandef = ctx->conf.def;
|
||||
+
|
||||
+ ieee80211_dfs_cac_cancel(local, ctx);
|
||||
+ cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);
|
||||
}
|
||||
+}
|
||||
|
||||
- ieee80211_dfs_cac_cancel(local);
|
||||
+static void
|
||||
+ieee80211_radar_mark_chan_ctx_iterator(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_chanctx_conf *chanctx_conf,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct ieee80211_chanctx *ctx =
|
||||
+ container_of(chanctx_conf, struct ieee80211_chanctx,
|
||||
+ conf);
|
||||
|
||||
- if (num_chanctx > 1)
|
||||
- /* XXX: multi-channel is not supported yet */
|
||||
- WARN_ON(1);
|
||||
- else
|
||||
- cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);
|
||||
+ if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER)
|
||||
+ return;
|
||||
+
|
||||
+ if (data && data != chanctx_conf)
|
||||
+ return;
|
||||
+
|
||||
+ ctx->radar_detected = true;
|
||||
}
|
||||
|
||||
-void ieee80211_radar_detected(struct ieee80211_hw *hw)
|
||||
+void ieee80211_radar_detected(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_chanctx_conf *chanctx_conf)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
trace_api_radar_detected(local);
|
||||
|
||||
+ ieee80211_iter_chan_contexts_atomic(hw, ieee80211_radar_mark_chan_ctx_iterator,
|
||||
+ chanctx_conf);
|
||||
+
|
||||
wiphy_work_queue(hw->wiphy, &local->radar_detected_work);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_radar_detected);
|
||||
@@ -0,0 +1,79 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sun, 6 Oct 2024 17:34:08 +0200
|
||||
Subject: [PATCH] wifi: mac80211: skip non-uploaded keys in ieee80211_iter_keys
|
||||
|
||||
Sync iterator conditions with ieee80211_iter_keys_rcu.
|
||||
|
||||
Fixes: 830af02f24fb ("mac80211: allow driver to iterate keys")
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/key.c
|
||||
+++ b/net/mac80211/key.c
|
||||
@@ -987,6 +987,26 @@ void ieee80211_reenable_keys(struct ieee
|
||||
}
|
||||
}
|
||||
|
||||
+static void
|
||||
+ieee80211_key_iter(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_vif *vif,
|
||||
+ struct ieee80211_key *key,
|
||||
+ void (*iter)(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_vif *vif,
|
||||
+ struct ieee80211_sta *sta,
|
||||
+ struct ieee80211_key_conf *key,
|
||||
+ void *data),
|
||||
+ void *iter_data)
|
||||
+{
|
||||
+ /* skip keys of station in removal process */
|
||||
+ if (key->sta && key->sta->removed)
|
||||
+ return;
|
||||
+ if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
|
||||
+ return;
|
||||
+ iter(hw, vif, key->sta ? &key->sta->sta : NULL,
|
||||
+ &key->conf, iter_data);
|
||||
+}
|
||||
+
|
||||
void ieee80211_iter_keys(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
void (*iter)(struct ieee80211_hw *hw,
|
||||
@@ -1005,16 +1025,13 @@ void ieee80211_iter_keys(struct ieee8021
|
||||
if (vif) {
|
||||
sdata = vif_to_sdata(vif);
|
||||
list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
|
||||
- iter(hw, &sdata->vif,
|
||||
- key->sta ? &key->sta->sta : NULL,
|
||||
- &key->conf, iter_data);
|
||||
+ ieee80211_key_iter(hw, vif, key, iter, iter_data);
|
||||
} else {
|
||||
list_for_each_entry(sdata, &local->interfaces, list)
|
||||
list_for_each_entry_safe(key, tmp,
|
||||
&sdata->key_list, list)
|
||||
- iter(hw, &sdata->vif,
|
||||
- key->sta ? &key->sta->sta : NULL,
|
||||
- &key->conf, iter_data);
|
||||
+ ieee80211_key_iter(hw, &sdata->vif, key,
|
||||
+ iter, iter_data);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_iter_keys);
|
||||
@@ -1031,17 +1048,8 @@ _ieee80211_iter_keys_rcu(struct ieee8021
|
||||
{
|
||||
struct ieee80211_key *key;
|
||||
|
||||
- list_for_each_entry_rcu(key, &sdata->key_list, list) {
|
||||
- /* skip keys of station in removal process */
|
||||
- if (key->sta && key->sta->removed)
|
||||
- continue;
|
||||
- if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
|
||||
- continue;
|
||||
-
|
||||
- iter(hw, &sdata->vif,
|
||||
- key->sta ? &key->sta->sta : NULL,
|
||||
- &key->conf, iter_data);
|
||||
- }
|
||||
+ list_for_each_entry_rcu(key, &sdata->key_list, list)
|
||||
+ ieee80211_key_iter(hw, &sdata->vif, key, iter, iter_data);
|
||||
}
|
||||
|
||||
void ieee80211_iter_keys_rcu(struct ieee80211_hw *hw,
|
||||
@@ -0,0 +1,309 @@
|
||||
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
|
||||
@@ -6227,6 +6227,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;
|
||||
@@ -6339,6 +6340,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)
|
||||
@@ -6525,6 +6528,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
|
||||
@@ -829,6 +829,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 */
|
||||
@@ -3996,7 +3997,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) {
|
||||
@@ -4312,6 +4314,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];
|
||||
@@ -4319,6 +4344,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));
|
||||
@@ -4332,8 +4359,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)
|
||||
@@ -4364,6 +4389,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
|
||||
@@ -4372,11 +4403,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;
|
||||
}
|
||||
@@ -4387,6 +4418,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;
|
||||
|
||||
@@ -4424,6 +4456,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;
|
||||
@@ -4465,6 +4501,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);
|
||||
@@ -9180,6 +9219,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;
|
||||
|
||||
@@ -9392,7 +9434,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;
|
||||
@@ -9412,7 +9455,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
|
||||
@@ -956,7 +956,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++) {
|
||||
@@ -3490,9 +3491,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
|
||||
@@ -2923,3 +2923,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
|
||||
@@ -1415,6 +1415,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)
|
||||
@@ -0,0 +1,79 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 26 Sep 2024 14:06:11 +0200
|
||||
Subject: [PATCH] wifi: mac80211: use vif radio mask to limit ibss scan
|
||||
frequencies
|
||||
|
||||
Reject frequencies not supported by any radio that the vif is allowed to use.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/scan.c
|
||||
+++ b/net/mac80211/scan.c
|
||||
@@ -1178,14 +1178,14 @@ int ieee80211_request_ibss_scan(struct i
|
||||
unsigned int n_channels)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
- int ret = -EBUSY, i, n_ch = 0;
|
||||
+ int i, n_ch = 0;
|
||||
enum nl80211_band band;
|
||||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
/* busy scanning */
|
||||
if (local->scan_req)
|
||||
- goto unlock;
|
||||
+ return -EBUSY;
|
||||
|
||||
/* fill internal scan request */
|
||||
if (!channels) {
|
||||
@@ -1202,7 +1202,9 @@ int ieee80211_request_ibss_scan(struct i
|
||||
&local->hw.wiphy->bands[band]->channels[i];
|
||||
|
||||
if (tmp_ch->flags & (IEEE80211_CHAN_NO_IR |
|
||||
- IEEE80211_CHAN_DISABLED))
|
||||
+ IEEE80211_CHAN_DISABLED) ||
|
||||
+ !cfg80211_wdev_channel_allowed(&sdata->wdev,
|
||||
+ tmp_ch))
|
||||
continue;
|
||||
|
||||
local->int_scan_req->channels[n_ch] = tmp_ch;
|
||||
@@ -1211,21 +1213,23 @@ int ieee80211_request_ibss_scan(struct i
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(n_ch == 0))
|
||||
- goto unlock;
|
||||
+ return -EINVAL;
|
||||
|
||||
local->int_scan_req->n_channels = n_ch;
|
||||
} else {
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
if (channels[i]->flags & (IEEE80211_CHAN_NO_IR |
|
||||
- IEEE80211_CHAN_DISABLED))
|
||||
+ IEEE80211_CHAN_DISABLED) ||
|
||||
+ !cfg80211_wdev_channel_allowed(&sdata->wdev,
|
||||
+ channels[i]))
|
||||
continue;
|
||||
|
||||
local->int_scan_req->channels[n_ch] = channels[i];
|
||||
n_ch++;
|
||||
}
|
||||
|
||||
- if (WARN_ON_ONCE(n_ch == 0))
|
||||
- goto unlock;
|
||||
+ if (n_ch == 0)
|
||||
+ return -EINVAL;
|
||||
|
||||
local->int_scan_req->n_channels = n_ch;
|
||||
}
|
||||
@@ -1235,9 +1239,7 @@ int ieee80211_request_ibss_scan(struct i
|
||||
memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
|
||||
local->int_scan_req->ssids[0].ssid_len = ssid_len;
|
||||
|
||||
- ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
|
||||
- unlock:
|
||||
- return ret;
|
||||
+ return __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
|
||||
}
|
||||
|
||||
void ieee80211_scan_cancel(struct ieee80211_local *local)
|
||||
@@ -0,0 +1,52 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 26 Sep 2024 14:07:50 +0200
|
||||
Subject: [PATCH] wifi: mac80211: use vif radio mask to limit creating chanctx
|
||||
|
||||
Reject frequencies not supported by any radio that the vif is allowed to use.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/chan.c
|
||||
+++ b/net/mac80211/chan.c
|
||||
@@ -1167,7 +1167,7 @@ ieee80211_replace_chanctx(struct ieee802
|
||||
static bool
|
||||
ieee80211_find_available_radio(struct ieee80211_local *local,
|
||||
const struct ieee80211_chan_req *chanreq,
|
||||
- int *radio_idx)
|
||||
+ u32 radio_mask, int *radio_idx)
|
||||
{
|
||||
struct wiphy *wiphy = local->hw.wiphy;
|
||||
const struct wiphy_radio *radio;
|
||||
@@ -1178,6 +1178,9 @@ ieee80211_find_available_radio(struct ie
|
||||
return true;
|
||||
|
||||
for (i = 0; i < wiphy->n_radio; i++) {
|
||||
+ if (!(radio_mask & BIT(i)))
|
||||
+ continue;
|
||||
+
|
||||
radio = &wiphy->radio[i];
|
||||
if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
|
||||
continue;
|
||||
@@ -1211,7 +1214,9 @@ int ieee80211_link_reserve_chanctx(struc
|
||||
new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
|
||||
if (!new_ctx) {
|
||||
if (ieee80211_can_create_new_chanctx(local, -1) &&
|
||||
- ieee80211_find_available_radio(local, chanreq, &radio_idx))
|
||||
+ ieee80211_find_available_radio(local, chanreq,
|
||||
+ sdata->wdev.radio_mask,
|
||||
+ &radio_idx))
|
||||
new_ctx = ieee80211_new_chanctx(local, chanreq, mode,
|
||||
false, radio_idx);
|
||||
else
|
||||
@@ -1881,7 +1886,9 @@ int _ieee80211_link_use_channel(struct i
|
||||
/* Note: context is now reserved */
|
||||
if (ctx)
|
||||
reserved = true;
|
||||
- else if (!ieee80211_find_available_radio(local, chanreq, &radio_idx))
|
||||
+ else if (!ieee80211_find_available_radio(local, chanreq,
|
||||
+ sdata->wdev.radio_mask,
|
||||
+ &radio_idx))
|
||||
ctx = ERR_PTR(-EBUSY);
|
||||
else
|
||||
ctx = ieee80211_new_chanctx(local, chanreq, mode,
|
||||
@@ -0,0 +1,67 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 17 Jul 2024 22:49:16 +0200
|
||||
Subject: [PATCH] wifi: mac80211: remove status->ampdu_delimiter_crc
|
||||
|
||||
This was never used by any driver, so remove it to free up some space.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -1448,8 +1448,6 @@ ieee80211_tx_info_clear_status(struct ie
|
||||
* @RX_FLAG_AMPDU_IS_LAST: this subframe is the last subframe of the A-MPDU
|
||||
* @RX_FLAG_AMPDU_DELIM_CRC_ERROR: A delimiter CRC error has been detected
|
||||
* on this subframe
|
||||
- * @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC
|
||||
- * is stored in the @ampdu_delimiter_crc field)
|
||||
* @RX_FLAG_MIC_STRIPPED: The mic was stripped of this packet. Decryption was
|
||||
* done by the hardware
|
||||
* @RX_FLAG_ONLY_MONITOR: Report frame only to monitor interfaces without
|
||||
@@ -1521,7 +1519,7 @@ enum mac80211_rx_flags {
|
||||
RX_FLAG_AMPDU_LAST_KNOWN = BIT(12),
|
||||
RX_FLAG_AMPDU_IS_LAST = BIT(13),
|
||||
RX_FLAG_AMPDU_DELIM_CRC_ERROR = BIT(14),
|
||||
- RX_FLAG_AMPDU_DELIM_CRC_KNOWN = BIT(15),
|
||||
+ /* one free bit at 15 */
|
||||
RX_FLAG_MACTIME = BIT(16) | BIT(17),
|
||||
RX_FLAG_MACTIME_PLCP_START = 1 << 16,
|
||||
RX_FLAG_MACTIME_START = 2 << 16,
|
||||
@@ -1618,7 +1616,6 @@ enum mac80211_rx_encoding {
|
||||
* @rx_flags: internal RX flags for mac80211
|
||||
* @ampdu_reference: A-MPDU reference number, must be a different value for
|
||||
* each A-MPDU but the same for each subframe within one A-MPDU
|
||||
- * @ampdu_delimiter_crc: A-MPDU delimiter CRC
|
||||
* @zero_length_psdu_type: radiotap type of the 0-length PSDU
|
||||
* @link_valid: if the link which is identified by @link_id is valid. This flag
|
||||
* is set only when connection is MLO.
|
||||
@@ -1656,7 +1653,6 @@ struct ieee80211_rx_status {
|
||||
s8 signal;
|
||||
u8 chains;
|
||||
s8 chain_signal[IEEE80211_MAX_CHAINS];
|
||||
- u8 ampdu_delimiter_crc;
|
||||
u8 zero_length_psdu_type;
|
||||
u8 link_valid:1, link_id:4;
|
||||
};
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -508,18 +508,13 @@ ieee80211_add_rx_radiotap_header(struct
|
||||
flags |= IEEE80211_RADIOTAP_AMPDU_IS_LAST;
|
||||
if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_ERROR)
|
||||
flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR;
|
||||
- if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
|
||||
- flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN;
|
||||
if (status->flag & RX_FLAG_AMPDU_EOF_BIT_KNOWN)
|
||||
flags |= IEEE80211_RADIOTAP_AMPDU_EOF_KNOWN;
|
||||
if (status->flag & RX_FLAG_AMPDU_EOF_BIT)
|
||||
flags |= IEEE80211_RADIOTAP_AMPDU_EOF;
|
||||
put_unaligned_le16(flags, pos);
|
||||
pos += 2;
|
||||
- if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
|
||||
- *pos++ = status->ampdu_delimiter_crc;
|
||||
- else
|
||||
- *pos++ = 0;
|
||||
+ *pos++ = 0;
|
||||
*pos++ = 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 26 Sep 2024 19:52:30 +0200
|
||||
Subject: [PATCH] wifi: cfg80211: pass net_device to .set_monitor_channel
|
||||
|
||||
Preparation for allowing multiple monitor interfaces with different channels
|
||||
on a multi-radio wiphy.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
|
||||
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
|
||||
@@ -1493,6 +1493,7 @@ out:
|
||||
}
|
||||
|
||||
static int wil_cfg80211_set_channel(struct wiphy *wiphy,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
--- a/drivers/net/wireless/marvell/libertas/cfg.c
|
||||
+++ b/drivers/net/wireless/marvell/libertas/cfg.c
|
||||
@@ -486,6 +486,7 @@ static int lbs_add_wps_enrollee_tlv(u8 *
|
||||
*/
|
||||
|
||||
static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct lbs_private *priv = wiphy_priv(wiphy);
|
||||
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
|
||||
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
|
||||
@@ -231,6 +231,7 @@ struct wilc_vif *wilc_get_wl_to_vif(stru
|
||||
}
|
||||
|
||||
static int set_channel(struct wiphy *wiphy,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct wilc *wl = wiphy_priv(wiphy);
|
||||
@@ -1424,7 +1425,7 @@ static int start_ap(struct wiphy *wiphy,
|
||||
struct wilc_vif *vif = netdev_priv(dev);
|
||||
int ret;
|
||||
|
||||
- ret = set_channel(wiphy, &settings->chandef);
|
||||
+ ret = set_channel(wiphy, dev, &settings->chandef);
|
||||
if (ret != 0)
|
||||
netdev_err(dev, "Error in setting channel\n");
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -4700,6 +4700,7 @@ struct cfg80211_ops {
|
||||
struct ieee80211_channel *chan);
|
||||
|
||||
int (*set_monitor_channel)(struct wiphy *wiphy,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
|
||||
int (*scan)(struct wiphy *wiphy,
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -879,6 +879,7 @@ static int ieee80211_get_station(struct
|
||||
}
|
||||
|
||||
static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
--- a/net/wireless/chan.c
|
||||
+++ b/net/wireless/chan.c
|
||||
@@ -1673,6 +1673,7 @@ bool cfg80211_reg_check_beaconing(struct
|
||||
EXPORT_SYMBOL(cfg80211_reg_check_beaconing);
|
||||
|
||||
int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
if (!rdev->ops->set_monitor_channel)
|
||||
@@ -1680,7 +1681,7 @@ int cfg80211_set_monitor_channel(struct
|
||||
if (!cfg80211_has_monitors_only(rdev))
|
||||
return -EBUSY;
|
||||
|
||||
- return rdev_set_monitor_channel(rdev, chandef);
|
||||
+ return rdev_set_monitor_channel(rdev, dev, chandef);
|
||||
}
|
||||
|
||||
bool cfg80211_any_usable_channels(struct wiphy *wiphy,
|
||||
--- a/net/wireless/core.h
|
||||
+++ b/net/wireless/core.h
|
||||
@@ -510,6 +510,7 @@ static inline unsigned int elapsed_jiffi
|
||||
}
|
||||
|
||||
int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
|
||||
int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -3562,7 +3562,7 @@ static int __nl80211_set_channel(struct
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
return cfg80211_set_mesh_channel(rdev, wdev, &chandef);
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
- return cfg80211_set_monitor_channel(rdev, &chandef);
|
||||
+ return cfg80211_set_monitor_channel(rdev, dev, &chandef);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
--- a/net/wireless/rdev-ops.h
|
||||
+++ b/net/wireless/rdev-ops.h
|
||||
@@ -445,11 +445,12 @@ rdev_libertas_set_mesh_channel(struct cf
|
||||
|
||||
static inline int
|
||||
rdev_set_monitor_channel(struct cfg80211_registered_device *rdev,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
int ret;
|
||||
- trace_rdev_set_monitor_channel(&rdev->wiphy, chandef);
|
||||
- ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chandef);
|
||||
+ trace_rdev_set_monitor_channel(&rdev->wiphy, dev, chandef);
|
||||
+ ret = rdev->ops->set_monitor_channel(&rdev->wiphy, dev, chandef);
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
--- a/net/wireless/trace.h
|
||||
+++ b/net/wireless/trace.h
|
||||
@@ -1318,19 +1318,21 @@ TRACE_EVENT(rdev_libertas_set_mesh_chann
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_set_monitor_channel,
|
||||
- TP_PROTO(struct wiphy *wiphy,
|
||||
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
|
||||
struct cfg80211_chan_def *chandef),
|
||||
- TP_ARGS(wiphy, chandef),
|
||||
+ TP_ARGS(wiphy, netdev, chandef),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
+ NETDEV_ENTRY
|
||||
CHAN_DEF_ENTRY
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
+ NETDEV_ASSIGN;
|
||||
CHAN_DEF_ASSIGN(chandef);
|
||||
),
|
||||
- TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
|
||||
- WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
|
||||
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT,
|
||||
+ WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_auth,
|
||||
--- a/net/wireless/wext-compat.c
|
||||
+++ b/net/wireless/wext-compat.c
|
||||
@@ -830,7 +830,7 @@ static int cfg80211_wext_siwfreq(struct
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
- ret = cfg80211_set_monitor_channel(rdev, &chandef);
|
||||
+ ret = cfg80211_set_monitor_channel(rdev, dev, &chandef);
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
freq = cfg80211_wext_freq(wextfreq);
|
||||
@@ -0,0 +1,337 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 30 Sep 2024 15:09:45 +0200
|
||||
Subject: [PATCH] wifi: mac80211: add flag to opt out of virtual monitor
|
||||
support
|
||||
|
||||
This is useful for multi-radio devices that are capable of monitoring on
|
||||
multiple channels simultanenously. When this flag is set, each monitor
|
||||
interface is passed to the driver individually and can have a configured
|
||||
channel.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -2679,6 +2679,11 @@ struct ieee80211_txq {
|
||||
* a virtual monitor interface when monitor interfaces are the only
|
||||
* active interfaces.
|
||||
*
|
||||
+ * @IEEE80211_HW_NO_VIRTUAL_MONITOR: The driver would like to be informed
|
||||
+ * of any monitor interface, as well as their configured channel.
|
||||
+ * This is useful for supporting multiple monitor interfaces on different
|
||||
+ * channels.
|
||||
+ *
|
||||
* @IEEE80211_HW_NO_AUTO_VIF: The driver would like for no wlanX to
|
||||
* be created. It is expected user-space will create vifs as
|
||||
* desired (and thus have them named as desired).
|
||||
@@ -2838,6 +2843,7 @@ enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_SUPPORTS_DYNAMIC_PS,
|
||||
IEEE80211_HW_MFP_CAPABLE,
|
||||
IEEE80211_HW_WANT_MONITOR_VIF,
|
||||
+ IEEE80211_HW_NO_VIRTUAL_MONITOR,
|
||||
IEEE80211_HW_NO_AUTO_VIF,
|
||||
IEEE80211_HW_SW_CRYPTO_CONTROL,
|
||||
IEEE80211_HW_SUPPORT_FAST_XMIT,
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -105,8 +105,11 @@ static int ieee80211_set_mon_options(str
|
||||
}
|
||||
|
||||
/* also validate MU-MIMO change */
|
||||
- monitor_sdata = wiphy_dereference(local->hw.wiphy,
|
||||
- local->monitor_sdata);
|
||||
+ if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
+ monitor_sdata = sdata;
|
||||
+ else
|
||||
+ monitor_sdata = wiphy_dereference(local->hw.wiphy,
|
||||
+ local->monitor_sdata);
|
||||
|
||||
if (!monitor_sdata &&
|
||||
(params->vht_mumimo_groups || params->vht_mumimo_follow_addr))
|
||||
@@ -114,7 +117,9 @@ static int ieee80211_set_mon_options(str
|
||||
|
||||
/* apply all changes now - no failures allowed */
|
||||
|
||||
- if (monitor_sdata && ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
|
||||
+ if (monitor_sdata &&
|
||||
+ (ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) ||
|
||||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)))
|
||||
ieee80211_set_mu_mimo_follow(monitor_sdata, params);
|
||||
|
||||
if (params->flags) {
|
||||
@@ -889,22 +894,25 @@ static int ieee80211_set_monitor_channel
|
||||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
- if (cfg80211_chandef_identical(&local->monitor_chanreq.oper,
|
||||
- &chanreq.oper))
|
||||
- return 0;
|
||||
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
+ if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
|
||||
+ if (cfg80211_chandef_identical(&local->monitor_chanreq.oper,
|
||||
+ &chanreq.oper))
|
||||
+ return 0;
|
||||
|
||||
- sdata = wiphy_dereference(local->hw.wiphy,
|
||||
- local->monitor_sdata);
|
||||
- if (!sdata)
|
||||
- goto done;
|
||||
+ sdata = wiphy_dereference(wiphy, local->monitor_sdata);
|
||||
+ if (!sdata)
|
||||
+ goto done;
|
||||
+ }
|
||||
|
||||
- if (cfg80211_chandef_identical(&sdata->vif.bss_conf.chanreq.oper,
|
||||
+ if (rcu_access_pointer(sdata->deflink.conf->chanctx_conf) &&
|
||||
+ cfg80211_chandef_identical(&sdata->vif.bss_conf.chanreq.oper,
|
||||
&chanreq.oper))
|
||||
return 0;
|
||||
|
||||
ieee80211_link_release_channel(&sdata->deflink);
|
||||
ret = ieee80211_link_use_channel(&sdata->deflink, &chanreq,
|
||||
- IEEE80211_CHANCTX_EXCLUSIVE);
|
||||
+ IEEE80211_CHANCTX_SHARED);
|
||||
if (ret)
|
||||
return ret;
|
||||
done:
|
||||
@@ -3049,7 +3057,8 @@ static int ieee80211_set_tx_power(struct
|
||||
if (wdev) {
|
||||
sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
|
||||
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
|
||||
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
|
||||
if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@@ -3097,7 +3106,8 @@ static int ieee80211_set_tx_power(struct
|
||||
}
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
|
||||
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
|
||||
has_monitor = true;
|
||||
continue;
|
||||
}
|
||||
@@ -3107,7 +3117,8 @@ static int ieee80211_set_tx_power(struct
|
||||
sdata->vif.bss_conf.txpower_type = txp_type;
|
||||
}
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
|
||||
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
continue;
|
||||
ieee80211_recalc_txpower(sdata, update_txp_type);
|
||||
}
|
||||
@@ -4299,7 +4310,8 @@ static int ieee80211_cfg_get_channel(str
|
||||
if (chanctx_conf) {
|
||||
*chandef = link->conf->chanreq.oper;
|
||||
ret = 0;
|
||||
- } else if (local->open_count > 0 &&
|
||||
+ } else if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
|
||||
+ local->open_count > 0 &&
|
||||
local->open_count == local->monitors &&
|
||||
sdata->vif.type == NL80211_IFTYPE_MONITOR) {
|
||||
*chandef = local->monitor_chanreq.oper;
|
||||
--- a/net/mac80211/chan.c
|
||||
+++ b/net/mac80211/chan.c
|
||||
@@ -337,6 +337,10 @@ ieee80211_get_chanctx_max_required_bw(st
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
case NL80211_IFTYPE_NAN:
|
||||
continue;
|
||||
+ case NL80211_IFTYPE_MONITOR:
|
||||
+ WARN_ON_ONCE(!ieee80211_hw_check(&local->hw,
|
||||
+ NO_VIRTUAL_MONITOR));
|
||||
+ fallthrough;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
case NL80211_IFTYPE_OCB:
|
||||
@@ -345,7 +349,6 @@ ieee80211_get_chanctx_max_required_bw(st
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
case NUM_NL80211_IFTYPES:
|
||||
- case NL80211_IFTYPE_MONITOR:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
WARN_ON_ONCE(1);
|
||||
@@ -954,6 +957,10 @@ void ieee80211_recalc_smps_chanctx(struc
|
||||
if (!link->sdata->u.mgd.associated)
|
||||
continue;
|
||||
break;
|
||||
+ case NL80211_IFTYPE_MONITOR:
|
||||
+ if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
+ continue;
|
||||
+ break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
@@ -966,6 +973,11 @@ void ieee80211_recalc_smps_chanctx(struc
|
||||
if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf)
|
||||
continue;
|
||||
|
||||
+ if (link->sdata->vif.type == NL80211_IFTYPE_MONITOR) {
|
||||
+ rx_chains_dynamic = rx_chains_static = local->rx_chains;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
switch (link->smps_mode) {
|
||||
default:
|
||||
WARN_ONCE(1, "Invalid SMPS mode %d\n",
|
||||
--- a/net/mac80211/debugfs.c
|
||||
+++ b/net/mac80211/debugfs.c
|
||||
@@ -465,6 +465,7 @@ static const char *hw_flag_names[] = {
|
||||
FLAG(SUPPORTS_DYNAMIC_PS),
|
||||
FLAG(MFP_CAPABLE),
|
||||
FLAG(WANT_MONITOR_VIF),
|
||||
+ FLAG(NO_VIRTUAL_MONITOR),
|
||||
FLAG(NO_AUTO_VIF),
|
||||
FLAG(SW_CRYPTO_CONTROL),
|
||||
FLAG(SUPPORT_FAST_XMIT),
|
||||
--- a/net/mac80211/driver-ops.c
|
||||
+++ b/net/mac80211/driver-ops.c
|
||||
@@ -65,6 +65,7 @@ int drv_add_interface(struct ieee80211_l
|
||||
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
|
||||
(sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
|
||||
!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))))
|
||||
return -EINVAL;
|
||||
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -279,8 +279,13 @@ static int _ieee80211_change_mac(struct
|
||||
ret = eth_mac_addr(sdata->dev, sa);
|
||||
|
||||
if (ret == 0) {
|
||||
- memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
|
||||
- ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
|
||||
+ if (check_dup) {
|
||||
+ memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
|
||||
+ ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
|
||||
+ } else {
|
||||
+ memset(sdata->vif.addr, 0, ETH_ALEN);
|
||||
+ memset(sdata->vif.bss_conf.addr, 0, ETH_ALEN);
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Regardless of eth_mac_addr() return we still want to add the
|
||||
@@ -699,9 +704,11 @@ static void ieee80211_do_stop(struct iee
|
||||
ieee80211_recalc_idle(local);
|
||||
ieee80211_recalc_offload(local);
|
||||
|
||||
- if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
|
||||
+ if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
break;
|
||||
|
||||
+ ieee80211_link_release_channel(&sdata->deflink);
|
||||
fallthrough;
|
||||
default:
|
||||
if (!going_down)
|
||||
@@ -1131,7 +1138,8 @@ int ieee80211_add_virtual_monitor(struct
|
||||
ASSERT_RTNL();
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
- if (local->monitor_sdata)
|
||||
+ if (local->monitor_sdata ||
|
||||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
return 0;
|
||||
|
||||
sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
|
||||
@@ -1193,6 +1201,9 @@ void ieee80211_del_virtual_monitor(struc
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
+ if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
+ return;
|
||||
+
|
||||
ASSERT_RTNL();
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
@@ -1328,7 +1339,8 @@ int ieee80211_do_open(struct wireless_de
|
||||
break;
|
||||
}
|
||||
|
||||
- if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
|
||||
+ if ((sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
|
||||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
|
||||
res = drv_add_interface(local, sdata);
|
||||
if (res)
|
||||
goto err_stop;
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -840,6 +840,9 @@ ieee80211_rx_monitor(struct ieee80211_lo
|
||||
bool last_monitor = list_is_last(&sdata->u.mntr.list,
|
||||
&local->mon_list);
|
||||
|
||||
+ if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
+ ieee80211_handle_mu_mimo_mon(sdata, origskb, rtap_space);
|
||||
+
|
||||
if (!monskb)
|
||||
monskb = ieee80211_make_monitor_skb(local, &origskb,
|
||||
rate, rtap_space,
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1763,7 +1763,8 @@ static bool __ieee80211_tx(struct ieee80
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
- if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
|
||||
+ if ((sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
|
||||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
|
||||
vif = &sdata->vif;
|
||||
break;
|
||||
}
|
||||
@@ -3952,7 +3953,8 @@ begin:
|
||||
|
||||
switch (tx.sdata->vif.type) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
- if (tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
|
||||
+ if ((tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
|
||||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
|
||||
vif = &tx.sdata->vif;
|
||||
break;
|
||||
}
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -754,7 +754,8 @@ static void __iterate_interfaces(struct
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
- if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
|
||||
+ if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
continue;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
@@ -1857,8 +1858,10 @@ int ieee80211_reconfig(struct ieee80211_
|
||||
}
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
+ continue;
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
- sdata->vif.type != NL80211_IFTYPE_MONITOR &&
|
||||
ieee80211_sdata_running(sdata)) {
|
||||
res = drv_add_interface(local, sdata);
|
||||
if (WARN_ON(res))
|
||||
@@ -1871,11 +1874,14 @@ int ieee80211_reconfig(struct ieee80211_
|
||||
*/
|
||||
if (res) {
|
||||
list_for_each_entry_continue_reverse(sdata, &local->interfaces,
|
||||
- list)
|
||||
+ list) {
|
||||
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
+ continue;
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
- sdata->vif.type != NL80211_IFTYPE_MONITOR &&
|
||||
ieee80211_sdata_running(sdata))
|
||||
drv_remove_interface(local, sdata);
|
||||
+ }
|
||||
ieee80211_handle_reconfig_failure(local);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 30 Sep 2024 17:04:09 +0200
|
||||
Subject: [PATCH] wifi: cfg80211: add monitor SKIP_TX flag
|
||||
|
||||
This can be used to indicate that the user is not interested in receiving
|
||||
locally sent packets on the monitor interface.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -2272,6 +2272,7 @@ static inline int cfg80211_get_station(s
|
||||
* @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering
|
||||
* @MONITOR_FLAG_COOK_FRAMES: report frames after processing
|
||||
* @MONITOR_FLAG_ACTIVE: active monitor, ACKs frames on its MAC address
|
||||
+ * @MONITOR_FLAG_SKIP_TX: do not pass locally transmitted frames
|
||||
*/
|
||||
enum monitor_flags {
|
||||
MONITOR_FLAG_CHANGED = BIT(__NL80211_MNTR_FLAG_INVALID),
|
||||
@@ -2281,6 +2282,7 @@ enum monitor_flags {
|
||||
MONITOR_FLAG_OTHER_BSS = BIT(NL80211_MNTR_FLAG_OTHER_BSS),
|
||||
MONITOR_FLAG_COOK_FRAMES = BIT(NL80211_MNTR_FLAG_COOK_FRAMES),
|
||||
MONITOR_FLAG_ACTIVE = BIT(NL80211_MNTR_FLAG_ACTIVE),
|
||||
+ MONITOR_FLAG_SKIP_TX = BIT(NL80211_MNTR_FLAG_SKIP_TX),
|
||||
};
|
||||
|
||||
/**
|
||||
--- a/include/uapi/linux/nl80211.h
|
||||
+++ b/include/uapi/linux/nl80211.h
|
||||
@@ -4703,6 +4703,7 @@ enum nl80211_survey_info {
|
||||
* overrides all other flags.
|
||||
* @NL80211_MNTR_FLAG_ACTIVE: use the configured MAC address
|
||||
* and ACK incoming unicast packets.
|
||||
+ * @NL80211_MNTR_FLAG_SKIP_TX: do not pass local tx packets
|
||||
*
|
||||
* @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
|
||||
* @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
|
||||
@@ -4715,6 +4716,7 @@ enum nl80211_mntr_flags {
|
||||
NL80211_MNTR_FLAG_OTHER_BSS,
|
||||
NL80211_MNTR_FLAG_COOK_FRAMES,
|
||||
NL80211_MNTR_FLAG_ACTIVE,
|
||||
+ NL80211_MNTR_FLAG_SKIP_TX,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_MNTR_FLAG_AFTER_LAST,
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -4201,6 +4201,7 @@ static const struct nla_policy mntr_flag
|
||||
[NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
|
||||
[NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
|
||||
[NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
|
||||
+ [NL80211_MNTR_FLAG_SKIP_TX] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
|
||||
@@ -0,0 +1,54 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 30 Sep 2024 17:05:18 +0200
|
||||
Subject: [PATCH] wifi: mac80211: add support for the monitor SKIP_TX flag
|
||||
|
||||
Do not pass locally sent packets to monitor interfaces with this flag set.
|
||||
Skip processing tx packets on the status call entirely if no monitor
|
||||
interfaces without this flag are present.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1374,7 +1374,7 @@ struct ieee80211_local {
|
||||
spinlock_t queue_stop_reason_lock;
|
||||
|
||||
int open_count;
|
||||
- int monitors, cooked_mntrs;
|
||||
+ int monitors, cooked_mntrs, tx_mntrs;
|
||||
/* number of interfaces with corresponding FIF_ flags */
|
||||
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll,
|
||||
fif_probe_req;
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -1094,6 +1094,8 @@ void ieee80211_adjust_monitor_flags(stru
|
||||
ADJUST(CONTROL, control);
|
||||
ADJUST(CONTROL, pspoll);
|
||||
ADJUST(OTHER_BSS, other_bss);
|
||||
+ if (!(flags & MONITOR_FLAG_SKIP_TX))
|
||||
+ local->tx_mntrs += offset;
|
||||
|
||||
#undef ADJUST
|
||||
}
|
||||
--- a/net/mac80211/status.c
|
||||
+++ b/net/mac80211/status.c
|
||||
@@ -927,6 +927,9 @@ void ieee80211_tx_monitor(struct ieee802
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
||||
+ if (sdata->u.mntr.flags & MONITOR_FLAG_SKIP_TX)
|
||||
+ continue;
|
||||
+
|
||||
if ((sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) &&
|
||||
!send_to_cooked)
|
||||
continue;
|
||||
@@ -1099,7 +1102,7 @@ static void __ieee80211_tx_status(struct
|
||||
* This is a bit racy but we can avoid a lot of work
|
||||
* with this test...
|
||||
*/
|
||||
- if (!local->monitors && (!send_to_cooked || !local->cooked_mntrs)) {
|
||||
+ if (!local->tx_mntrs && (!send_to_cooked || !local->cooked_mntrs)) {
|
||||
if (status->free_list)
|
||||
list_add_tail(&skb->list, status->free_list);
|
||||
else
|
||||
@@ -0,0 +1,94 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 2 Oct 2024 12:31:22 +0200
|
||||
Subject: [PATCH] wifi: mac80211: refactor ieee80211_rx_monitor
|
||||
|
||||
Rework the monitor mode interface iteration to get rid of the last_monitor
|
||||
condition. Preparation for further filtering received monitor packets.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -762,8 +762,8 @@ ieee80211_rx_monitor(struct ieee80211_lo
|
||||
struct ieee80211_rate *rate)
|
||||
{
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb);
|
||||
- struct ieee80211_sub_if_data *sdata;
|
||||
- struct sk_buff *monskb = NULL;
|
||||
+ struct ieee80211_sub_if_data *sdata, *prev_sdata = NULL;
|
||||
+ struct sk_buff *skb, *monskb = NULL;
|
||||
int present_fcs_len = 0;
|
||||
unsigned int rtap_space = 0;
|
||||
struct ieee80211_sub_if_data *monitor_sdata =
|
||||
@@ -837,8 +837,10 @@ ieee80211_rx_monitor(struct ieee80211_lo
|
||||
ieee80211_handle_mu_mimo_mon(monitor_sdata, origskb, rtap_space);
|
||||
|
||||
list_for_each_entry_rcu(sdata, &local->mon_list, u.mntr.list) {
|
||||
- bool last_monitor = list_is_last(&sdata->u.mntr.list,
|
||||
- &local->mon_list);
|
||||
+ if (!prev_sdata) {
|
||||
+ prev_sdata = sdata;
|
||||
+ continue;
|
||||
+ }
|
||||
|
||||
if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
ieee80211_handle_mu_mimo_mon(sdata, origskb, rtap_space);
|
||||
@@ -846,34 +848,34 @@ ieee80211_rx_monitor(struct ieee80211_lo
|
||||
if (!monskb)
|
||||
monskb = ieee80211_make_monitor_skb(local, &origskb,
|
||||
rate, rtap_space,
|
||||
- only_monitor &&
|
||||
- last_monitor);
|
||||
-
|
||||
- if (monskb) {
|
||||
- struct sk_buff *skb;
|
||||
+ false);
|
||||
+ if (!monskb)
|
||||
+ continue;
|
||||
|
||||
- if (last_monitor) {
|
||||
- skb = monskb;
|
||||
- monskb = NULL;
|
||||
- } else {
|
||||
- skb = skb_clone(monskb, GFP_ATOMIC);
|
||||
- }
|
||||
+ skb = skb_clone(monskb, GFP_ATOMIC);
|
||||
+ if (!skb)
|
||||
+ continue;
|
||||
+
|
||||
+ skb->dev = prev_sdata->dev;
|
||||
+ dev_sw_netstats_rx_add(skb->dev, skb->len);
|
||||
+ netif_receive_skb(skb);
|
||||
+ prev_sdata = sdata;
|
||||
+ }
|
||||
|
||||
- if (skb) {
|
||||
- skb->dev = sdata->dev;
|
||||
- dev_sw_netstats_rx_add(skb->dev, skb->len);
|
||||
- netif_receive_skb(skb);
|
||||
- }
|
||||
+ if (prev_sdata) {
|
||||
+ if (monskb)
|
||||
+ skb = monskb;
|
||||
+ else
|
||||
+ skb = ieee80211_make_monitor_skb(local, &origskb,
|
||||
+ rate, rtap_space,
|
||||
+ only_monitor);
|
||||
+ if (skb) {
|
||||
+ skb->dev = prev_sdata->dev;
|
||||
+ dev_sw_netstats_rx_add(skb->dev, skb->len);
|
||||
+ netif_receive_skb(skb);
|
||||
}
|
||||
-
|
||||
- if (last_monitor)
|
||||
- break;
|
||||
}
|
||||
|
||||
- /* this happens if last_monitor was erroneously false */
|
||||
- dev_kfree_skb(monskb);
|
||||
-
|
||||
- /* ditto */
|
||||
if (!origskb)
|
||||
return NULL;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 2 Oct 2024 12:35:13 +0200
|
||||
Subject: [PATCH] wifi: mac80211: filter on monitor interfaces based on
|
||||
configured channel
|
||||
|
||||
When a monitor interface has an assigned channel (only happens with the
|
||||
NO_VIRTUAL_MONITOR feature), only pass packets received on that channel.
|
||||
This is useful for monitoring on multiple channels at the same time using
|
||||
multiple monitor interfaces.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -837,6 +837,13 @@ ieee80211_rx_monitor(struct ieee80211_lo
|
||||
ieee80211_handle_mu_mimo_mon(monitor_sdata, origskb, rtap_space);
|
||||
|
||||
list_for_each_entry_rcu(sdata, &local->mon_list, u.mntr.list) {
|
||||
+ struct cfg80211_chan_def *chandef;
|
||||
+
|
||||
+ chandef = &sdata->vif.bss_conf.chanreq.oper;
|
||||
+ if (chandef->chan &&
|
||||
+ chandef->chan->center_freq != status->freq)
|
||||
+ continue;
|
||||
+
|
||||
if (!prev_sdata) {
|
||||
prev_sdata = sdata;
|
||||
continue;
|
||||
@@ -0,0 +1,64 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 7 Aug 2024 13:31:07 +0200
|
||||
Subject: [PATCH] wifi: cfg80211: report per wiphy radio antenna mask
|
||||
|
||||
With multi-radio devices, each radio typically gets a fixed set of antennas.
|
||||
In order to be able to disable specific antennas for some radios, user space
|
||||
needs to know which antenna mask bits are assigned to which radio.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -5443,6 +5443,8 @@ struct wiphy_radio_freq_range {
|
||||
* @iface_combinations: Valid interface combinations array, should not
|
||||
* list single interface types.
|
||||
* @n_iface_combinations: number of entries in @iface_combinations array.
|
||||
+ *
|
||||
+ * @antenna_mask: bitmask of antennas connected to this radio.
|
||||
*/
|
||||
struct wiphy_radio {
|
||||
const struct wiphy_radio_freq_range *freq_range;
|
||||
@@ -5450,6 +5452,8 @@ struct wiphy_radio {
|
||||
|
||||
const struct ieee80211_iface_combination *iface_combinations;
|
||||
int n_iface_combinations;
|
||||
+
|
||||
+ u32 antenna_mask;
|
||||
};
|
||||
|
||||
#define CFG80211_HW_TIMESTAMP_ALL_PEERS 0xffff
|
||||
--- a/include/uapi/linux/nl80211.h
|
||||
+++ b/include/uapi/linux/nl80211.h
|
||||
@@ -8038,6 +8038,8 @@ enum nl80211_ap_settings_flags {
|
||||
* @NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION: Supported interface
|
||||
* combination for this radio. Attribute may be present multiple times
|
||||
* and contains attributes defined in &enum nl80211_if_combination_attrs.
|
||||
+ * @NL80211_WIPHY_RADIO_ATTR_ANTENNA_MASK: bitmask (u32) of antennas
|
||||
+ * connected to this radio.
|
||||
*
|
||||
* @__NL80211_WIPHY_RADIO_ATTR_LAST: Internal
|
||||
* @NL80211_WIPHY_RADIO_ATTR_MAX: Highest attribute
|
||||
@@ -8048,6 +8050,7 @@ enum nl80211_wiphy_radio_attrs {
|
||||
NL80211_WIPHY_RADIO_ATTR_INDEX,
|
||||
NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE,
|
||||
NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION,
|
||||
+ NL80211_WIPHY_RADIO_ATTR_ANTENNA_MASK,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_WIPHY_RADIO_ATTR_LAST,
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -2431,6 +2431,11 @@ static int nl80211_put_radio(struct wiph
|
||||
if (nla_put_u32(msg, NL80211_WIPHY_RADIO_ATTR_INDEX, idx))
|
||||
goto nla_put_failure;
|
||||
|
||||
+ if (r->antenna_mask &&
|
||||
+ nla_put_u32(msg, NL80211_WIPHY_RADIO_ATTR_ANTENNA_MASK,
|
||||
+ r->antenna_mask))
|
||||
+ goto nla_put_failure;
|
||||
+
|
||||
for (i = 0; i < r->n_freq_range; i++) {
|
||||
const struct wiphy_radio_freq_range *range = &r->freq_range[i];
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 15 Nov 2024 12:28:43 +0100
|
||||
Subject: [PATCH] wifi: mac80211: fix vif addr when switching from monitor
|
||||
to station
|
||||
|
||||
Since adding support for opting out of virtual monitor support, a zero vif
|
||||
addr was used to indicate passive vs active monitor to the driver.
|
||||
This would break the vif->addr when changing the netdev mac address before
|
||||
switching the interface from monitor to sta mode.
|
||||
Fix the regression by adding a separate flag to indicate whether vif->addr
|
||||
is valid.
|
||||
|
||||
Reported-by: syzbot+9ea265d998de25ac6a46@syzkaller.appspotmail.com
|
||||
Fixes: 9d40f7e32774 ("wifi: mac80211: add flag to opt out of virtual monitor support")
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -1972,6 +1972,8 @@ enum ieee80211_neg_ttlm_res {
|
||||
* @neg_ttlm: negotiated TID to link mapping info.
|
||||
* see &struct ieee80211_neg_ttlm.
|
||||
* @addr: address of this interface
|
||||
+ * @addr_valid: indicates if the address is actively used. Set to false for
|
||||
+ * passive monitor interfaces, true in all other cases.
|
||||
* @p2p: indicates whether this AP or STA interface is a p2p
|
||||
* interface, i.e. a GO or p2p-sta respectively
|
||||
* @netdev_features: tx netdev features supported by the hardware for this
|
||||
@@ -2011,6 +2013,7 @@ struct ieee80211_vif {
|
||||
u16 valid_links, active_links, dormant_links, suspended_links;
|
||||
struct ieee80211_neg_ttlm neg_ttlm;
|
||||
u8 addr[ETH_ALEN] __aligned(2);
|
||||
+ bool addr_valid;
|
||||
bool p2p;
|
||||
|
||||
u8 cab_queue;
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -279,13 +279,8 @@ static int _ieee80211_change_mac(struct
|
||||
ret = eth_mac_addr(sdata->dev, sa);
|
||||
|
||||
if (ret == 0) {
|
||||
- if (check_dup) {
|
||||
- memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
|
||||
- ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
|
||||
- } else {
|
||||
- memset(sdata->vif.addr, 0, ETH_ALEN);
|
||||
- memset(sdata->vif.bss_conf.addr, 0, ETH_ALEN);
|
||||
- }
|
||||
+ memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
|
||||
+ ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
|
||||
}
|
||||
|
||||
/* Regardless of eth_mac_addr() return we still want to add the
|
||||
@@ -1324,6 +1319,8 @@ int ieee80211_do_open(struct wireless_de
|
||||
}
|
||||
}
|
||||
|
||||
+ sdata->vif.addr_valid = sdata->vif.type != NL80211_IFTYPE_MONITOR ||
|
||||
+ (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE);
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
/* no need to tell driver, but set carrier and chanctx */
|
||||
@@ -0,0 +1,32 @@
|
||||
From: Benjamin Lin <benjamin-jw.lin@mediatek.com>
|
||||
Date: Mon, 18 Nov 2024 16:07:22 +0800
|
||||
Subject: [PATCH] wifi: mac80211: fix incorrect timing to initialize
|
||||
station NSS capability
|
||||
|
||||
Station's spatial streaming capability should be initialized before
|
||||
handling VHT OMN, because the handling requires the capability information.
|
||||
|
||||
Fixes: a8bca3e9371d ("wifi: mac80211: track capability/opmode NSS separately")
|
||||
Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -1914,6 +1914,8 @@ static int sta_link_apply_parameters(str
|
||||
params->eht_capa_len,
|
||||
link_sta);
|
||||
|
||||
+ ieee80211_sta_init_nss(link_sta);
|
||||
+
|
||||
if (params->opmode_notif_used) {
|
||||
/* returned value is only needed for rc update, but the
|
||||
* rc isn't initialized here yet, so ignore it
|
||||
@@ -1923,8 +1925,6 @@ static int sta_link_apply_parameters(str
|
||||
sband->band);
|
||||
}
|
||||
|
||||
- ieee80211_sta_init_nss(link_sta);
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
From: "Gustavo A. R. Silva" <gustavoars@kernel.org>
|
||||
Date: Fri, 25 Oct 2024 16:05:50 -0600
|
||||
Subject: [PATCH] wifi: mac80211: ieee80211_i: Fix memory corruption bug in
|
||||
struct ieee80211_chanctx
|
||||
|
||||
Move the `struct ieee80211_chanctx_conf conf` to the end of
|
||||
`struct ieee80211_chanctx` and fix a memory corruption bug
|
||||
triggered e.g. in `hwsim_set_chanctx_magic()`: `radar_detected`
|
||||
is being overwritten when `cp->magic = HWSIM_CHANCTX_MAGIC;`
|
||||
See the function call sequence below:
|
||||
|
||||
drv_add_chanctx(... struct ieee80211_chanctx *ctx) ->
|
||||
local->ops->add_chanctx(&local->hw, &ctx->conf) ->
|
||||
mac80211_hwsim_add_chanctx(... struct ieee80211_chanctx_conf *ctx) ->
|
||||
hwsim_set_chanctx_magic(ctx)
|
||||
|
||||
This also happens in a number of other drivers.
|
||||
|
||||
Also, add a code comment to try to prevent people from introducing
|
||||
new members after `struct ieee80211_chanctx_conf conf`. Notice that
|
||||
`struct ieee80211_chanctx_conf` is a flexible structure --a structure
|
||||
that contains a flexible-array member, so it should always be at
|
||||
the end of any other containing structures.
|
||||
|
||||
This change also fixes 50 of the following warnings:
|
||||
|
||||
net/mac80211/ieee80211_i.h:895:39: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
|
||||
|
||||
-Wflex-array-member-not-at-end was introduced in GCC-14, and we are
|
||||
getting ready to enable it, globally.
|
||||
|
||||
Fixes: bca8bc0399ac ("wifi: mac80211: handle ieee80211_radar_detected() for MLO")
|
||||
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
|
||||
Link: https://patch.msgid.link/ZxwWPrncTeSi1UTq@kspp
|
||||
[also refer to other drivers in commit message]
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -894,9 +894,10 @@ struct ieee80211_chanctx {
|
||||
/* temporary data for search algorithm etc. */
|
||||
struct ieee80211_chan_req req;
|
||||
|
||||
- struct ieee80211_chanctx_conf conf;
|
||||
-
|
||||
bool radar_detected;
|
||||
+
|
||||
+ /* MUST be last - ends in a flexible-array member. */
|
||||
+ struct ieee80211_chanctx_conf conf;
|
||||
};
|
||||
|
||||
struct mac80211_qos_map {
|
||||
@@ -0,0 +1,24 @@
|
||||
From: Ben Greear <greearb@candelatech.com>
|
||||
Date: Thu, 10 Oct 2024 13:39:54 -0700
|
||||
Subject: [PATCH] mac80211: fix user-power when emulating chanctx
|
||||
|
||||
ieee80211_calc_hw_conf_chan was ignoring the configured
|
||||
user_txpower. If it is set, use it to potentially decrease
|
||||
txpower as requested.
|
||||
|
||||
Signed-off-by: Ben Greear <greearb@candelatech.com>
|
||||
Link: https://patch.msgid.link/20241010203954.1219686-1-greearb@candelatech.com
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/main.c
|
||||
+++ b/net/mac80211/main.c
|
||||
@@ -167,6 +167,8 @@ static u32 ieee80211_calc_hw_conf_chan(s
|
||||
}
|
||||
|
||||
power = ieee80211_chandef_max_power(&chandef);
|
||||
+ if (local->user_power_level != IEEE80211_UNSET_POWER_LEVEL)
|
||||
+ power = min(local->user_power_level, power);
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
@@ -0,0 +1,83 @@
|
||||
From: Remi Pommarel <repk@triplefau.lt>
|
||||
Date: Tue, 24 Sep 2024 21:28:04 +0200
|
||||
Subject: [PATCH] wifi: cfg80211: Add wiphy_delayed_work_pending()
|
||||
|
||||
Add wiphy_delayed_work_pending() to check if any delayed work timer is
|
||||
pending, that can be used to be sure that wiphy_delayed_work_queue()
|
||||
won't postpone an already pending delayed work.
|
||||
|
||||
Signed-off-by: Remi Pommarel <repk@triplefau.lt>
|
||||
Link: https://patch.msgid.link/20240924192805.13859-2-repk@triplefau.lt
|
||||
[fix return value kernel-doc]
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -6141,6 +6141,50 @@ void wiphy_delayed_work_flush(struct wip
|
||||
struct wiphy_delayed_work *dwork);
|
||||
|
||||
/**
|
||||
+ * wiphy_delayed_work_pending - Find out whether a wiphy delayable
|
||||
+ * work item is currently pending.
|
||||
+ *
|
||||
+ * @wiphy: the wiphy, for debug purposes
|
||||
+ * @dwork: the delayed work in question
|
||||
+ *
|
||||
+ * Return: true if timer is pending, false otherwise
|
||||
+ *
|
||||
+ * How wiphy_delayed_work_queue() works is by setting a timer which
|
||||
+ * when it expires calls wiphy_work_queue() to queue the wiphy work.
|
||||
+ * Because wiphy_delayed_work_queue() uses mod_timer(), if it is
|
||||
+ * called twice and the second call happens before the first call
|
||||
+ * deadline, the work will rescheduled for the second deadline and
|
||||
+ * won't run before that.
|
||||
+ *
|
||||
+ * wiphy_delayed_work_pending() can be used to detect if calling
|
||||
+ * wiphy_work_delayed_work_queue() would start a new work schedule
|
||||
+ * or delayed a previous one. As seen below it cannot be used to
|
||||
+ * detect precisely if the work has finished to execute nor if it
|
||||
+ * is currently executing.
|
||||
+ *
|
||||
+ * CPU0 CPU1
|
||||
+ * wiphy_delayed_work_queue(wk)
|
||||
+ * mod_timer(wk->timer)
|
||||
+ * wiphy_delayed_work_pending(wk) -> true
|
||||
+ *
|
||||
+ * [...]
|
||||
+ * expire_timers(wk->timer)
|
||||
+ * detach_timer(wk->timer)
|
||||
+ * wiphy_delayed_work_pending(wk) -> false
|
||||
+ * wk->timer->function() |
|
||||
+ * wiphy_work_queue(wk) | delayed work pending
|
||||
+ * list_add_tail() | returns false but
|
||||
+ * queue_work(cfg80211_wiphy_work) | wk->func() has not
|
||||
+ * | been run yet
|
||||
+ * [...] |
|
||||
+ * cfg80211_wiphy_work() |
|
||||
+ * wk->func() V
|
||||
+ *
|
||||
+ */
|
||||
+bool wiphy_delayed_work_pending(struct wiphy *wiphy,
|
||||
+ struct wiphy_delayed_work *dwork);
|
||||
+
|
||||
+/**
|
||||
* enum ieee80211_ap_reg_power - regulatory power for an Access Point
|
||||
*
|
||||
* @IEEE80211_REG_UNSET_AP: Access Point has no regulatory power mode
|
||||
--- a/net/wireless/core.c
|
||||
+++ b/net/wireless/core.c
|
||||
@@ -1735,6 +1735,13 @@ void wiphy_delayed_work_flush(struct wip
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wiphy_delayed_work_flush);
|
||||
|
||||
+bool wiphy_delayed_work_pending(struct wiphy *wiphy,
|
||||
+ struct wiphy_delayed_work *dwork)
|
||||
+{
|
||||
+ return timer_pending(&dwork->timer);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(wiphy_delayed_work_pending);
|
||||
+
|
||||
static int __init cfg80211_init(void)
|
||||
{
|
||||
int err;
|
||||
@@ -0,0 +1,148 @@
|
||||
From: Remi Pommarel <repk@triplefau.lt>
|
||||
Date: Tue, 24 Sep 2024 21:28:05 +0200
|
||||
Subject: [PATCH] wifi: mac80211: Convert color collision detection to wiphy
|
||||
work
|
||||
|
||||
Call to ieee80211_color_collision_detection_work() needs wiphy lock to
|
||||
be held (see lockdep assert in cfg80211_bss_color_notify()). Not locking
|
||||
wiphy causes the following lockdep error:
|
||||
|
||||
WARNING: CPU: 2 PID: 42 at net/wireless/nl80211.c:19505 cfg80211_bss_color_notify+0x1a4/0x25c
|
||||
Modules linked in:
|
||||
CPU: 2 PID: 42 Comm: kworker/u8:3 Tainted: G W 6.4.0-02327-g36c6cb260481 #1048
|
||||
Hardware name:
|
||||
Workqueue: phy1 ieee80211_color_collision_detection_work
|
||||
pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
|
||||
pc : cfg80211_bss_color_notify+0x1a4/0x25c
|
||||
lr : cfg80211_bss_color_notify+0x1a0/0x25c
|
||||
sp : ffff000002947d00
|
||||
x29: ffff000002947d00 x28: ffff800008e1a000 x27: ffff000002bd4705
|
||||
x26: ffff00000d034000 x25: ffff80000903cf40 x24: 0000000000000000
|
||||
x23: ffff00000cb70720 x22: 0000000000800000 x21: ffff800008dfb008
|
||||
x20: 000000000000008d x19: ffff00000d035fa8 x18: 0000000000000010
|
||||
x17: 0000000000000001 x16: 000003564b1ce96a x15: 000d69696d057970
|
||||
x14: 000000000000003b x13: 0000000000000001 x12: 0000000000040000
|
||||
x11: 0000000000000001 x10: ffff80000978f9c0 x9 : ffff0000028d3174
|
||||
x8 : ffff800008e30000 x7 : 0000000000000000 x6 : 0000000000000028
|
||||
x5 : 000000000002f498 x4 : ffff00000d034a80 x3 : 0000000000800000
|
||||
x2 : ffff800016143000 x1 : 0000000000000000 x0 : 0000000000000000
|
||||
Call trace:
|
||||
cfg80211_bss_color_notify+0x1a4/0x25c
|
||||
ieee80211_color_collision_detection_work+0x20/0x118
|
||||
process_one_work+0x294/0x554
|
||||
worker_thread+0x70/0x440
|
||||
kthread+0xf4/0xf8
|
||||
ret_from_fork+0x10/0x20
|
||||
irq event stamp: 77372
|
||||
hardirqs last enabled at (77371): [<ffff800008a346fc>] _raw_spin_unlock_irq+0x2c/0x4c
|
||||
hardirqs last disabled at (77372): [<ffff800008a28754>] el1_dbg+0x20/0x48
|
||||
softirqs last enabled at (77350): [<ffff8000089e120c>] batadv_send_outstanding_bcast_packet+0xb8/0x120
|
||||
softirqs last disabled at (77348): [<ffff8000089e11d4>] batadv_send_outstanding_bcast_packet+0x80/0x120
|
||||
|
||||
The wiphy lock cannot be taken directly from color collision detection
|
||||
delayed work (ieee80211_color_collision_detection_work()) because this
|
||||
work is cancel_delayed_work_sync() under this wiphy lock causing a
|
||||
potential deadlock( see [0] for details).
|
||||
|
||||
To fix that ieee80211_color_collision_detection_work() could be
|
||||
converted to a wiphy work and cancel_delayed_work_sync() can be simply
|
||||
replaced by wiphy_delayed_work_cancel() serving the same purpose under
|
||||
wiphy lock.
|
||||
|
||||
This could potentially fix [1].
|
||||
|
||||
[0]: https://lore.kernel.org/linux-wireless/D4A40Q44OAY2.W3SIF6UEPBUN@freebox.fr/
|
||||
[1]: https://lore.kernel.org/lkml/000000000000612f290618eee3e5@google.com/
|
||||
|
||||
Reported-by: Nicolas Escande <nescande@freebox.fr>
|
||||
Signed-off-by: Remi Pommarel <repk@triplefau.lt>
|
||||
Link: https://patch.msgid.link/20240924192805.13859-3-repk@triplefau.lt
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -4836,12 +4836,12 @@ void ieee80211_color_change_finalize_wor
|
||||
ieee80211_color_change_finalize(link);
|
||||
}
|
||||
|
||||
-void ieee80211_color_collision_detection_work(struct work_struct *work)
|
||||
+void ieee80211_color_collision_detection_work(struct wiphy *wiphy,
|
||||
+ struct wiphy_work *work)
|
||||
{
|
||||
- struct delayed_work *delayed_work = to_delayed_work(work);
|
||||
struct ieee80211_link_data *link =
|
||||
- container_of(delayed_work, struct ieee80211_link_data,
|
||||
- color_collision_detect_work);
|
||||
+ container_of(work, struct ieee80211_link_data,
|
||||
+ color_collision_detect_work.work);
|
||||
struct ieee80211_sub_if_data *sdata = link->sdata;
|
||||
|
||||
cfg80211_obss_color_collision_notify(sdata->dev, link->color_bitmap,
|
||||
@@ -4894,7 +4894,8 @@ ieee80211_obss_color_collision_notify(st
|
||||
return;
|
||||
}
|
||||
|
||||
- if (delayed_work_pending(&link->color_collision_detect_work)) {
|
||||
+ if (wiphy_delayed_work_pending(sdata->local->hw.wiphy,
|
||||
+ &link->color_collision_detect_work)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
@@ -4903,9 +4904,9 @@ ieee80211_obss_color_collision_notify(st
|
||||
/* queue the color collision detection event every 500 ms in order to
|
||||
* avoid sending too much netlink messages to userspace.
|
||||
*/
|
||||
- ieee80211_queue_delayed_work(&sdata->local->hw,
|
||||
- &link->color_collision_detect_work,
|
||||
- msecs_to_jiffies(500));
|
||||
+ wiphy_delayed_work_queue(sdata->local->hw.wiphy,
|
||||
+ &link->color_collision_detect_work,
|
||||
+ msecs_to_jiffies(500));
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1056,7 +1056,7 @@ struct ieee80211_link_data {
|
||||
} csa;
|
||||
|
||||
struct wiphy_work color_change_finalize_work;
|
||||
- struct delayed_work color_collision_detect_work;
|
||||
+ struct wiphy_delayed_work color_collision_detect_work;
|
||||
u64 color_bitmap;
|
||||
|
||||
/* context reservation -- protected with wiphy mutex */
|
||||
@@ -2010,7 +2010,8 @@ int ieee80211_channel_switch(struct wiph
|
||||
/* color change handling */
|
||||
void ieee80211_color_change_finalize_work(struct wiphy *wiphy,
|
||||
struct wiphy_work *work);
|
||||
-void ieee80211_color_collision_detection_work(struct work_struct *work);
|
||||
+void ieee80211_color_collision_detection_work(struct wiphy *wiphy,
|
||||
+ struct wiphy_work *work);
|
||||
|
||||
/* interface handling */
|
||||
#define MAC80211_SUPPORTED_FEATURES_TX (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \
|
||||
--- a/net/mac80211/link.c
|
||||
+++ b/net/mac80211/link.c
|
||||
@@ -41,8 +41,8 @@ void ieee80211_link_init(struct ieee8021
|
||||
ieee80211_csa_finalize_work);
|
||||
wiphy_work_init(&link->color_change_finalize_work,
|
||||
ieee80211_color_change_finalize_work);
|
||||
- INIT_DELAYED_WORK(&link->color_collision_detect_work,
|
||||
- ieee80211_color_collision_detection_work);
|
||||
+ wiphy_delayed_work_init(&link->color_collision_detect_work,
|
||||
+ ieee80211_color_collision_detection_work);
|
||||
INIT_LIST_HEAD(&link->assigned_chanctx_list);
|
||||
INIT_LIST_HEAD(&link->reserved_chanctx_list);
|
||||
wiphy_delayed_work_init(&link->dfs_cac_timer_work,
|
||||
@@ -72,7 +72,8 @@ void ieee80211_link_stop(struct ieee8021
|
||||
if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
ieee80211_mgd_stop_link(link);
|
||||
|
||||
- cancel_delayed_work_sync(&link->color_collision_detect_work);
|
||||
+ wiphy_delayed_work_cancel(link->sdata->local->hw.wiphy,
|
||||
+ &link->color_collision_detect_work);
|
||||
wiphy_work_cancel(link->sdata->local->hw.wiphy,
|
||||
&link->color_change_finalize_work);
|
||||
wiphy_work_cancel(link->sdata->local->hw.wiphy,
|
||||
Reference in New Issue
Block a user