Skip to content

Commit 6fbf6d0

Browse files
committed
mac80211: extend connection monitoring for MLO
Required for latest mt76 Signed-off-by: Felix Fietkau <nbd@nbd.name>
1 parent 2760a08 commit 6fbf6d0

6 files changed

Lines changed: 295 additions & 5 deletions
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
From: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
2+
Date: Fri, 18 Jul 2025 11:38:35 +0530
3+
Subject: [PATCH] wifi: mac80211: Add link iteration macro for link data
4+
with rcu_dereference
5+
6+
Currently, the existing macro for_each_link_data() uses sdata_dereference()
7+
which requires the wiphy lock. This lock cannot be used in atomic or RCU
8+
read-side contexts, such as in the RX path.
9+
10+
Introduce a new macro, for_each_link_data_rcu(), that iterates over link of
11+
sdata using rcu_dereference(), making it safe to use in RCU contexts. This
12+
allows callers to access link data without requiring the wiphy lock.
13+
14+
The macro takes into account the vif.valid_links bitmap and ensures only
15+
valid links are accessed safely. Callers are responsible for ensuring that
16+
rcu_read_lock() is held when using this macro.
17+
18+
Signed-off-by: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
19+
Link: https://patch.msgid.link/20250718060837.59371-3-maharaja.kennadyrajan@oss.qualcomm.com
20+
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
21+
---
22+
23+
--- a/net/mac80211/ieee80211_i.h
24+
+++ b/net/mac80211/ieee80211_i.h
25+
@@ -1237,6 +1237,19 @@ struct ieee80211_sub_if_data *vif_to_sda
26+
((__link) = sdata_dereference((__sdata)->link[__link_id], \
27+
(__sdata))))
28+
29+
+/*
30+
+ * for_each_link_data_rcu should be used under RCU read lock.
31+
+ */
32+
+#define for_each_link_data_rcu(sdata, __link) \
33+
+ /* outer loop just to define the variable ... */ \
34+
+ for (struct ieee80211_sub_if_data *__sdata = (sdata); __sdata; \
35+
+ __sdata = NULL /* always stop */) \
36+
+ for (int __link_id = 0; \
37+
+ __link_id < ARRAY_SIZE((__sdata)->link); __link_id++) \
38+
+ if ((!(__sdata)->vif.valid_links || \
39+
+ (__sdata)->vif.valid_links & BIT(__link_id)) && \
40+
+ ((__link) = rcu_dereference((__sdata)->link[__link_id]))) \
41+
+
42+
static inline int
43+
ieee80211_get_mbssid_beacon_len(struct cfg80211_mbssid_elems *elems,
44+
struct cfg80211_rnr_elems *rnr_elems,
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
From: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
2+
Date: Fri, 18 Jul 2025 11:38:36 +0530
3+
Subject: [PATCH] wifi: mac80211: extend beacon monitoring for MLO
4+
5+
Currently, reset beacon monitor (ieee80211_sta_reset_beacon_monitor())
6+
timer is handled only for non-AP non-MLD STA and do not support non-AP MLD
7+
STA. When the beacon loss occurs in non-AP MLD STA with the current
8+
implementation, it is treated as a single link and the timer will reset
9+
based on the timeout of the deflink, without checking all the links.
10+
11+
Check the CSA flags for all the links in the MLO and decide whether to
12+
schedule the work queue for beacon loss. If any of the links has CSA
13+
active, then beacon loss work is not scheduled.
14+
15+
Also, call the functions ieee80211_sta_reset_beacon_monitor() and
16+
ieee80211_sta_reset_conn_monitor() from ieee80211_csa_switch_work() only
17+
when all the links are CSA active.
18+
19+
Signed-off-by: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
20+
Link: https://patch.msgid.link/20250718060837.59371-4-maharaja.kennadyrajan@oss.qualcomm.com
21+
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
22+
---
23+
24+
--- a/net/mac80211/mlme.c
25+
+++ b/net/mac80211/mlme.c
26+
@@ -2439,6 +2439,21 @@ static void ieee80211_csa_switch_work(st
27+
}
28+
}
29+
30+
+ /*
31+
+ * It is not necessary to reset these timers if any link does not
32+
+ * have an active CSA and that link still receives the beacons
33+
+ * when other links have active CSA.
34+
+ */
35+
+ for_each_link_data(sdata, link) {
36+
+ if (!link->conf->csa_active)
37+
+ return;
38+
+ }
39+
+
40+
+ /*
41+
+ * Reset the beacon monitor and connection monitor timers when CSA
42+
+ * is active for all links in MLO when channel switch occurs in all
43+
+ * the links.
44+
+ */
45+
ieee80211_sta_reset_beacon_monitor(sdata);
46+
ieee80211_sta_reset_conn_monitor(sdata);
47+
}
48+
@@ -8389,16 +8404,32 @@ void ieee80211_sta_work(struct ieee80211
49+
}
50+
}
51+
52+
+static bool
53+
+ieee80211_is_csa_in_progress(struct ieee80211_sub_if_data *sdata)
54+
+{
55+
+ /*
56+
+ * In MLO, check the CSA flags 'active' and 'waiting_bcn' for all
57+
+ * the links.
58+
+ */
59+
+ struct ieee80211_link_data *link;
60+
+
61+
+ guard(rcu)();
62+
+
63+
+ for_each_link_data_rcu(sdata, link) {
64+
+ if (!(link->conf->csa_active &&
65+
+ !link->u.mgd.csa.waiting_bcn))
66+
+ return false;
67+
+ }
68+
+
69+
+ return true;
70+
+}
71+
+
72+
static void ieee80211_sta_bcn_mon_timer(struct timer_list *t)
73+
{
74+
struct ieee80211_sub_if_data *sdata =
75+
timer_container_of(sdata, t, u.mgd.bcn_mon_timer);
76+
77+
- if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif)))
78+
- return;
79+
-
80+
- if (sdata->vif.bss_conf.csa_active &&
81+
- !sdata->deflink.u.mgd.csa.waiting_bcn)
82+
+ if (ieee80211_is_csa_in_progress(sdata))
83+
return;
84+
85+
if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
From: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
2+
Date: Fri, 18 Jul 2025 11:38:37 +0530
3+
Subject: [PATCH] wifi: mac80211: extend connection monitoring for MLO
4+
5+
Currently, reset connection monitor (ieee80211_sta_reset_conn_monitor())
6+
timer is handled only for non-AP non-MLD STA and do not support non-AP MLD
7+
STA. The current implementation checks for the CSA active and update the
8+
monitor timer with the timeout value of deflink and reset the timer based
9+
on the deflink's timeout value else schedule the connection loss work when
10+
the deflink is timed out and it won't work for the non-AP MLD STA.
11+
12+
Handle the reset connection monitor timer for non-AP MLD STA by updating
13+
the monitor timer with the timeout value which is determined based on the
14+
link that will expire last among all the links in MLO. If at least one link
15+
has not timed out, the timer is updated accordingly with the latest timeout
16+
value else schedule the connection loss work when all links have timed out.
17+
18+
Remove the MLO-related WARN_ON() checks in the beacon and connection
19+
monitoring logic code paths as they support MLO now.
20+
21+
Signed-off-by: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
22+
Link: https://patch.msgid.link/20250718060837.59371-5-maharaja.kennadyrajan@oss.qualcomm.com
23+
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
24+
---
25+
26+
--- a/net/mac80211/mlme.c
27+
+++ b/net/mac80211/mlme.c
28+
@@ -4300,9 +4300,6 @@ static void ieee80211_mgd_probe_ap_send(
29+
30+
lockdep_assert_wiphy(sdata->local->hw.wiphy);
31+
32+
- if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif)))
33+
- return;
34+
-
35+
/*
36+
* Try sending broadcast probe requests for the last three
37+
* probe requests after the first ones failed since some
38+
@@ -4348,9 +4345,6 @@ static void ieee80211_mgd_probe_ap(struc
39+
40+
lockdep_assert_wiphy(sdata->local->hw.wiphy);
41+
42+
- if (WARN_ON_ONCE(ieee80211_vif_is_mld(&sdata->vif)))
43+
- return;
44+
-
45+
if (!ieee80211_sdata_running(sdata))
46+
return;
47+
48+
@@ -8440,36 +8434,70 @@ static void ieee80211_sta_bcn_mon_timer(
49+
&sdata->u.mgd.beacon_connection_loss_work);
50+
}
51+
52+
+static unsigned long
53+
+ieee80211_latest_active_link_conn_timeout(struct ieee80211_sub_if_data *sdata)
54+
+{
55+
+ unsigned long latest_timeout;
56+
+ unsigned int link_id;
57+
+ struct sta_info *sta;
58+
+
59+
+ guard(rcu)();
60+
+
61+
+ sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);
62+
+ if (!sta)
63+
+ return 0;
64+
+
65+
+ for (link_id = 0; link_id < ARRAY_SIZE(sta->link);
66+
+ link_id++) {
67+
+ struct link_sta_info *link_sta;
68+
+ unsigned long timeout;
69+
+
70+
+ link_sta = rcu_dereference(sta->link[link_id]);
71+
+ if (!link_sta)
72+
+ continue;
73+
+
74+
+ timeout = link_sta->status_stats.last_ack;
75+
+ if (time_before(timeout, link_sta->rx_stats.last_rx))
76+
+ timeout = link_sta->rx_stats.last_rx;
77+
+
78+
+ timeout += IEEE80211_CONNECTION_IDLE_TIME;
79+
+
80+
+ /*
81+
+ * latest_timeout holds the timeout of the link
82+
+ * that will expire last among all links in an
83+
+ * non-AP MLD STA. This ensures that the connection
84+
+ * monitor timer is only reset if at least one link
85+
+ * is still active, and it is scheduled to fire at
86+
+ * the latest possible timeout.
87+
+ */
88+
+ if (time_is_after_jiffies(timeout) &&
89+
+ time_after(timeout, latest_timeout))
90+
+ latest_timeout = timeout;
91+
+ }
92+
+
93+
+ return latest_timeout;
94+
+}
95+
+
96+
static void ieee80211_sta_conn_mon_timer(struct timer_list *t)
97+
{
98+
struct ieee80211_sub_if_data *sdata =
99+
timer_container_of(sdata, t, u.mgd.conn_mon_timer);
100+
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
101+
struct ieee80211_local *local = sdata->local;
102+
- struct sta_info *sta;
103+
- unsigned long timeout;
104+
+ unsigned long latest_timeout;
105+
106+
- if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif)))
107+
- return;
108+
-
109+
- if (sdata->vif.bss_conf.csa_active &&
110+
- !sdata->deflink.u.mgd.csa.waiting_bcn)
111+
- return;
112+
-
113+
- sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);
114+
- if (!sta)
115+
+ if (ieee80211_is_csa_in_progress(sdata))
116+
return;
117+
118+
- timeout = sta->deflink.status_stats.last_ack;
119+
- if (time_before(sta->deflink.status_stats.last_ack, sta->deflink.rx_stats.last_rx))
120+
- timeout = sta->deflink.rx_stats.last_rx;
121+
- timeout += IEEE80211_CONNECTION_IDLE_TIME;
122+
+ latest_timeout = ieee80211_latest_active_link_conn_timeout(sdata);
123+
124+
- /* If timeout is after now, then update timer to fire at
125+
+ /*
126+
+ * If latest timeout is after now, then update timer to fire at
127+
* the later date, but do not actually probe at this time.
128+
*/
129+
- if (time_is_after_jiffies(timeout)) {
130+
- mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(timeout));
131+
+ if (latest_timeout) {
132+
+ mod_timer(&ifmgd->conn_mon_timer,
133+
+ round_jiffies_up(latest_timeout));
134+
return;
135+
}
136+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
From: Lorenzo Bianconi <lorenzo@kernel.org>
2+
Date: Tue, 26 Aug 2025 13:54:31 +0200
3+
Subject: [PATCH] wifi: mac80211: Make CONNECTION_MONITOR optional for MLO sta
4+
5+
Since commit '1bc892d76a6f ("wifi: mac80211: extend connection
6+
monitoring for MLO")' mac80211 supports connection monitor for MLO
7+
client interfaces. Remove the CONNECTION_MONITOR requirement in
8+
ieee80211_register_hw routine.
9+
10+
Fixes: 1bc892d76a6f ("wifi: mac80211: extend connection monitoring for MLO")
11+
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
12+
---
13+
14+
--- a/net/mac80211/main.c
15+
+++ b/net/mac80211/main.c
16+
@@ -1179,9 +1179,6 @@ int ieee80211_register_hw(struct ieee802
17+
if (WARN_ON(!ieee80211_hw_check(hw, MFP_CAPABLE)))
18+
return -EINVAL;
19+
20+
- if (WARN_ON(!ieee80211_hw_check(hw, CONNECTION_MONITOR)))
21+
- return -EINVAL;
22+
-
23+
if (WARN_ON(ieee80211_hw_check(hw, NEED_DTIM_BEFORE_ASSOC)))
24+
return -EINVAL;
25+

package/kernel/mac80211/patches/subsys/350-mac80211-allow-scanning-while-on-radar-channel.patch

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777

7878
--- a/net/mac80211/ieee80211_i.h
7979
+++ b/net/mac80211/ieee80211_i.h
80-
@@ -1975,6 +1975,12 @@ int ieee80211_mesh_finish_csa(struct iee
80+
@@ -1988,6 +1988,12 @@ int ieee80211_mesh_finish_csa(struct iee
8181
u64 *changed);
8282

8383
/* scan/BSS handling */
@@ -90,15 +90,15 @@
9090
void ieee80211_scan_work(struct wiphy *wiphy, struct wiphy_work *work);
9191
int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
9292
const u8 *ssid, u8 ssid_len,
93-
@@ -2013,6 +2019,7 @@ void ieee80211_sched_scan_stopped_work(s
93+
@@ -2026,6 +2032,7 @@ void ieee80211_sched_scan_stopped_work(s
9494
/* off-channel/mgmt-tx */
9595
void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local);
9696
void ieee80211_offchannel_return(struct ieee80211_local *local);
9797
+u32 ieee80211_offchannel_radio_mask(struct ieee80211_local *local);
9898
void ieee80211_roc_setup(struct ieee80211_local *local);
9999
void ieee80211_start_next_roc(struct ieee80211_local *local);
100100
void ieee80211_reconfig_roc(struct ieee80211_local *local);
101-
@@ -2660,6 +2667,8 @@ bool ieee80211_chandef_s1g_oper(const st
101+
@@ -2673,6 +2680,8 @@ bool ieee80211_chandef_s1g_oper(const st
102102
struct cfg80211_chan_def *chandef);
103103
void ieee80211_chandef_downgrade(struct cfg80211_chan_def *chandef,
104104
struct ieee80211_conn_settings *conn);
@@ -107,7 +107,7 @@
107107
static inline void
108108
ieee80211_chanreq_downgrade(struct ieee80211_chan_req *chanreq,
109109
struct ieee80211_conn_settings *conn)
110-
@@ -2716,7 +2725,7 @@ void ieee80211_recalc_chanctx_min_def(st
110+
@@ -2729,7 +2738,7 @@ void ieee80211_recalc_chanctx_min_def(st
111111
struct ieee80211_chanctx *ctx,
112112
struct ieee80211_link_data *rsvd_for,
113113
bool check_reserved);

package/kernel/mac80211/patches/subsys/360-mac80211-factor-out-part-of-ieee80211_calc_expected_.patch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
126126
}
127127
--- a/net/mac80211/ieee80211_i.h
128128
+++ b/net/mac80211/ieee80211_i.h
129-
@@ -2776,6 +2776,11 @@ u8 *ieee80211_get_bssid(struct ieee80211
129+
@@ -2789,6 +2789,11 @@ u8 *ieee80211_get_bssid(struct ieee80211
130130

131131
extern const struct ethtool_ops ieee80211_ethtool_ops;
132132

0 commit comments

Comments
 (0)