d264c33f134e9be334ce85977188452cb5b83ed6
[openwrt/openwrt.git] /
1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Thu, 14 Sep 2023 13:17:16 +0200
3 Subject: [PATCH] cfg80211: allow grace period for DFS available after beacon
4 shutdown
5
6 Fixes reconfiguring an AP on a DFS channel in non-ETSI regdomain
7
8 Fixes: b35a51c7dd25 ("cfg80211: Make pre-CAC results valid only for ETSI domain")
9 Signed-off-by: Felix Fietkau <nbd@nbd.name>
10 ---
11
12 --- a/include/net/cfg80211.h
13 +++ b/include/net/cfg80211.h
14 @@ -190,6 +190,8 @@ enum ieee80211_channel_flags {
15 * @dfs_state: current state of this channel. Only relevant if radar is required
16 * on this channel.
17 * @dfs_state_entered: timestamp (jiffies) when the dfs state was entered.
18 + * @dfs_state_last_available: timestamp (jiffies) of the last time when the
19 + * channel was available.
20 * @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels.
21 * @psd: power spectral density (in dBm)
22 */
23 @@ -207,6 +209,7 @@ struct ieee80211_channel {
24 int orig_mag, orig_mpwr;
25 enum nl80211_dfs_state dfs_state;
26 unsigned long dfs_state_entered;
27 + unsigned long dfs_state_last_available;
28 unsigned int dfs_cac_ms;
29 s8 psd;
30 };
31 --- a/net/wireless/ap.c
32 +++ b/net/wireless/ap.c
33 @@ -30,6 +30,9 @@ static int ___cfg80211_stop_ap(struct cf
34 if (!wdev->links[link_id].ap.beacon_interval)
35 return -ENOENT;
36
37 + cfg80211_update_last_available(wdev->wiphy,
38 + &wdev->links[link_id].ap.chandef);
39 +
40 err = rdev_stop_ap(rdev, dev, link_id);
41 if (!err) {
42 wdev->conn_owner_nlportid = 0;
43 @@ -41,9 +44,6 @@ static int ___cfg80211_stop_ap(struct cf
44 if (notify)
45 nl80211_send_ap_stopped(wdev, link_id);
46
47 - /* Should we apply the grace period during beaconing interface
48 - * shutdown also?
49 - */
50 cfg80211_sched_dfs_chan_update(rdev);
51 }
52
53 --- a/net/wireless/chan.c
54 +++ b/net/wireless/chan.c
55 @@ -648,6 +648,8 @@ void cfg80211_set_dfs_state(struct wiphy
56
57 c->dfs_state = dfs_state;
58 c->dfs_state_entered = jiffies;
59 + if (dfs_state == NL80211_DFS_AVAILABLE)
60 + c->dfs_state_last_available = jiffies;
61 }
62 }
63
64 @@ -995,6 +997,53 @@ bool cfg80211_any_wiphy_oper_chan(struct
65 return false;
66 }
67
68 +static void
69 +__cfg80211_update_last_available(struct wiphy *wiphy,
70 + u32 center_freq,
71 + u32 bandwidth)
72 +{
73 + struct ieee80211_channel *c;
74 + u32 freq, start_freq, end_freq;
75 +
76 + if (bandwidth <= MHZ_TO_KHZ(20))
77 + start_freq = end_freq = center_freq;
78 + else {
79 + start_freq = center_freq - bandwidth / 2 + MHZ_TO_KHZ(10);
80 + end_freq = center_freq + bandwidth / 2 - MHZ_TO_KHZ(10);
81 + }
82 +
83 + /*
84 + * Check entire range of channels for the bandwidth.
85 + * If any channel in between is disabled or has not
86 + * had gone through CAC return false
87 + */
88 + for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
89 + c = ieee80211_get_channel_khz(wiphy, freq);
90 + if (!c)
91 + return;
92 +
93 + c->dfs_state_last_available = jiffies;
94 + }
95 +}
96 +
97 +void cfg80211_update_last_available(struct wiphy *wiphy,
98 + const struct cfg80211_chan_def *chandef)
99 +{
100 + int width;
101 +
102 + width = cfg80211_chandef_get_width(chandef);
103 + if (width < 0)
104 + return;
105 +
106 + __cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq1),
107 + width);
108 + if (chandef->width != NL80211_CHAN_WIDTH_80P80)
109 + return;
110 +
111 + __cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq2),
112 + width);
113 +}
114 +
115 static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
116 const struct cfg80211_chan_def *chandef)
117 {
118 --- a/net/wireless/core.h
119 +++ b/net/wireless/core.h
120 @@ -475,6 +475,8 @@ void cfg80211_set_dfs_state(struct wiphy
121 enum nl80211_dfs_state dfs_state);
122
123 void cfg80211_dfs_channels_update_work(struct work_struct *work);
124 +void cfg80211_update_last_available(struct wiphy *wiphy,
125 + const struct cfg80211_chan_def *chandef);
126
127 void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev);
128
129 --- a/net/wireless/mlme.c
130 +++ b/net/wireless/mlme.c
131 @@ -1038,6 +1038,8 @@ void cfg80211_dfs_channels_update_work(s
132 if (c->dfs_state == NL80211_DFS_UNAVAILABLE) {
133 time_dfs_update = IEEE80211_DFS_MIN_NOP_TIME_MS;
134 radar_event = NL80211_RADAR_NOP_FINISHED;
135 + timeout = c->dfs_state_entered +
136 + msecs_to_jiffies(time_dfs_update);
137 } else {
138 if (regulatory_pre_cac_allowed(wiphy) ||
139 cfg80211_any_wiphy_oper_chan(wiphy, c))
140 @@ -1045,11 +1047,10 @@ void cfg80211_dfs_channels_update_work(s
141
142 time_dfs_update = REG_PRE_CAC_EXPIRY_GRACE_MS;
143 radar_event = NL80211_RADAR_PRE_CAC_EXPIRED;
144 + timeout = c->dfs_state_last_available +
145 + msecs_to_jiffies(time_dfs_update);
146 }
147
148 - timeout = c->dfs_state_entered +
149 - msecs_to_jiffies(time_dfs_update);
150 -
151 if (time_after_eq(jiffies, timeout)) {
152 c->dfs_state = NL80211_DFS_USABLE;
153 c->dfs_state_entered = jiffies;