Просмотр исходного кода

mac80211: improve patch to allow grace period for DFS

Fix corner cases in updates.
Improve channel puncturing handling.
Fix dealing with CSA.

Signed-off-by: Felix Fietkau <[email protected]>
Felix Fietkau 2 недель назад
Родитель
Сommit
8e3de10b44

+ 2 - 2
package/kernel/mac80211/patches/ath/404-regd_no_assoc_hints.patch

@@ -1,6 +1,6 @@
 --- a/net/wireless/reg.c
 +++ b/net/wireless/reg.c
-@@ -3335,6 +3335,8 @@ void regulatory_hint_country_ie(struct w
+@@ -3336,6 +3336,8 @@ void regulatory_hint_country_ie(struct w
  	enum environment_cap env = ENVIRON_ANY;
  	struct regulatory_request *request = NULL, *lr;
  
@@ -9,7 +9,7 @@
  	/* IE len must be evenly divisible by 2 */
  	if (country_ie_len & 0x01)
  		return;
-@@ -3584,6 +3586,7 @@ static bool is_wiphy_all_set_reg_flag(en
+@@ -3585,6 +3587,7 @@ static bool is_wiphy_all_set_reg_flag(en
  
  void regulatory_hint_disconnect(void)
  {

+ 54 - 37
package/kernel/mac80211/patches/subsys/310-cfg80211-allow-grace-period-for-DFS-available-after-.patch

@@ -3,7 +3,27 @@ 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
+In non-ETSI regulatory domains, DFS channel availability from completed CAC
+expires after REG_PRE_CAC_EXPIRY_GRACE_MS (2 seconds) when no longer in use.
+This creates a problem when reconfiguring an AP on a DFS channel: stopping
+the AP to apply new settings causes the channel to immediately expire to
+USABLE state, requiring a full CAC again.
+
+The root cause is that the grace period timeout was calculated from
+dfs_state_entered, which records when CAC completed. For an AP that has
+been running for hours, this timestamp is far in the past, causing
+immediate expiration.
+
+Fix this by introducing a new field dfs_state_last_available that tracks
+when a DFS channel was last actively used. This timestamp is updated:
+- When DFS state transitions to AVAILABLE (CAC completion)
+- When an AP stops beaconing on the channel
+- When a channel switch moves away from the channel
+- When DFS state is copied between wiphys
+
+The grace period for AVAILABLE->USABLE transitions now uses this new
+timestamp, giving a 2-second window to reconfigure the AP without losing
+DFS availability.
 
 Fixes: b35a51c7dd25 ("cfg80211: Make pre-CAC results valid only for ETSI domain")
 Signed-off-by: Felix Fietkau <[email protected]>
@@ -61,55 +81,30 @@ Signed-off-by: Felix Fietkau <[email protected]>
  	}
  }
  
-@@ -990,6 +992,53 @@ bool cfg80211_any_wiphy_oper_chan(struct
+@@ -990,6 +992,28 @@ bool cfg80211_any_wiphy_oper_chan(struct
  	return false;
  }
  
-+static void
-+__cfg80211_update_last_available(struct wiphy *wiphy,
-+					 u32 center_freq,
-+					 u32 bandwidth)
-+{
-+	struct ieee80211_channel *c;
-+	u32 freq, start_freq, end_freq;
-+
-+	if (bandwidth <= MHZ_TO_KHZ(20))
-+		start_freq = end_freq = center_freq;
-+	else {
-+		start_freq = center_freq - bandwidth / 2 + MHZ_TO_KHZ(10);
-+		end_freq = center_freq + bandwidth / 2 - MHZ_TO_KHZ(10);
-+	}
-+
-+	/*
-+	 * 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)
 +{
++	struct ieee80211_channel *c;
 +	int width;
 +
++	if (WARN_ON(!cfg80211_chandef_valid(chandef)))
++		return;
++
 +	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;
++	for_each_subchan(chandef, freq, cf) {
++		c = ieee80211_get_channel_khz(wiphy, freq);
++		if (!c)
++			return;
 +
-+	__cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq2),
-+						 width);
++		c->dfs_state_last_available = jiffies;
++	}
 +}
 +
  static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
@@ -151,3 +146,25 @@ Signed-off-by: Felix Fietkau <[email protected]>
  			if (time_after_eq(jiffies, timeout)) {
  				c->dfs_state = NL80211_DFS_USABLE;
  				c->dfs_state_entered = jiffies;
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -20967,6 +20967,9 @@ void cfg80211_ch_switch_notify(struct ne
+ 		break;
+ 	case NL80211_IFTYPE_AP:
+ 	case NL80211_IFTYPE_P2P_GO:
++		if (wdev->links[link_id].ap.chandef.chan)
++			cfg80211_update_last_available(wdev->wiphy,
++						       &wdev->links[link_id].ap.chandef);
+ 		wdev->links[link_id].ap.chandef = *chandef;
+ 		break;
+ 	case NL80211_IFTYPE_ADHOC:
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -2954,6 +2954,7 @@ static void reg_copy_dfs_chan_state(stru
+ 	    dst_chan->dfs_state == NL80211_DFS_USABLE) {
+ 		dst_chan->dfs_state = src_chan->dfs_state;
+ 		dst_chan->dfs_state_entered = src_chan->dfs_state_entered;
++		dst_chan->dfs_state_last_available = src_chan->dfs_state_last_available;
+ 	}
+ }
+