Search Linux Wireless

[PATCH] wifi: cfg80211: skip regulatory checks when the channel is punctured

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The kernel performs several regulatory checks for AP mode in
nl80211/cfg80211. These checks include radar detection,
verification of whether the sub-channel is disabled, and
an examination to determine if the channel is a DFS channel
(both DFS usable and DFS available). These checks are
performed across a frequency range, examining each sub-channel.

However, these checks are also performed on frequencies that
have been punctured, which should not be examined as they are
not in use.

This leads to the issue where the AP stops because one of
the 20 MHz sub-channels is disabled or radar detected on
the channel, even when the sub-channel is punctured.

To address this issue, add a condition check wherever
regulatory checks exist for AP mode in nl80211/cfg80211.
This check identifies punctured channels and, upon finding
them, skips the regulatory checks for those channels.

Co-developed-by: Manaswini Paluri <quic_mpaluri@xxxxxxxxxxx>
Signed-off-by: Manaswini Paluri <quic_mpaluri@xxxxxxxxxxx>
Signed-off-by: Kavita Kavita <quic_kkavita@xxxxxxxxxxx>
---
 net/wireless/chan.c | 59 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 42 insertions(+), 17 deletions(-)

diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index e579d7e1425f..b363649acd03 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -727,6 +727,7 @@ static bool cfg80211_dfs_permissive_chan(struct wiphy *wiphy,
 static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
 					    u32 center_freq,
 					    u32 bandwidth,
+					    u16 punctured,
 					    enum nl80211_iftype iftype)
 {
 	struct ieee80211_channel *c;
@@ -740,9 +741,11 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
 		if (!c)
 			return -EINVAL;
 
-		if (c->flags & IEEE80211_CHAN_RADAR &&
+		if (!(punctured & 1) && (c->flags & IEEE80211_CHAN_RADAR) &&
 		    !cfg80211_dfs_permissive_chan(wiphy, iftype, c))
 			return 1;
+
+		punctured >>= 1;
 	}
 
 	return 0;
@@ -770,7 +773,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
 
 		ret = cfg80211_get_chans_dfs_required(wiphy,
 					ieee80211_chandef_to_khz(chandef),
-					width, iftype);
+					width, chandef->punctured, iftype);
 		if (ret < 0)
 			return ret;
 		else if (ret > 0)
@@ -781,7 +784,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
 
 		ret = cfg80211_get_chans_dfs_required(wiphy,
 					MHZ_TO_KHZ(chandef->center_freq2),
-					width, iftype);
+					width, chandef->punctured, iftype);
 		if (ret < 0)
 			return ret;
 		else if (ret > 0)
@@ -808,7 +811,7 @@ EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
 
 static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
 					 u32 center_freq,
-					 u32 bandwidth)
+					 u32 bandwidth, u16 punctured)
 {
 	struct ieee80211_channel *c;
 	u32 freq, start_freq, end_freq;
@@ -828,6 +831,12 @@ static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
 		if (!c)
 			return -EINVAL;
 
+		if (punctured & 1) {
+			punctured >>= 1;
+			continue;
+		}
+		punctured >>= 1;
+
 		if (c->flags & IEEE80211_CHAN_DISABLED)
 			return -EINVAL;
 
@@ -858,7 +867,7 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
 
 	r1 = cfg80211_get_chans_dfs_usable(wiphy,
 					   MHZ_TO_KHZ(chandef->center_freq1),
-					   width);
+					   width, chandef->punctured);
 
 	if (r1 < 0)
 		return false;
@@ -868,7 +877,7 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
 		WARN_ON(!chandef->center_freq2);
 		r2 = cfg80211_get_chans_dfs_usable(wiphy,
 					MHZ_TO_KHZ(chandef->center_freq2),
-					width);
+					width, chandef->punctured);
 		if (r2 < 0)
 			return false;
 		break;
@@ -1053,7 +1062,7 @@ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
 
 static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
 					     u32 center_freq,
-					     u32 bandwidth)
+					     u32 bandwidth, u16 punctured)
 {
 	struct ieee80211_channel *c;
 	u32 freq, start_freq, end_freq;
@@ -1075,6 +1084,12 @@ static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
 		if (!c)
 			return false;
 
+		if (punctured & 1) {
+			punctured >>= 1;
+			continue;
+		}
+		punctured >>= 1;
+
 		if (c->flags & IEEE80211_CHAN_DISABLED)
 			return false;
 
@@ -1102,7 +1117,7 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
 
 	r = cfg80211_get_chans_dfs_available(wiphy,
 					     MHZ_TO_KHZ(chandef->center_freq1),
-					     width);
+					     width, chandef->punctured);
 
 	/* If any of channels unavailable for cf1 just return */
 	if (!r)
@@ -1113,7 +1128,7 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
 		WARN_ON(!chandef->center_freq2);
 		r = cfg80211_get_chans_dfs_available(wiphy,
 					MHZ_TO_KHZ(chandef->center_freq2),
-					width);
+					width, chandef->punctured);
 		break;
 	default:
 		WARN_ON(chandef->center_freq2);
@@ -1125,7 +1140,8 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
 
 static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
 						    u32 center_freq,
-						    u32 bandwidth)
+						    u32 bandwidth,
+						    u16 punctured)
 {
 	struct ieee80211_channel *c;
 	u32 start_freq, end_freq, freq;
@@ -1139,6 +1155,12 @@ static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
 		if (!c)
 			return 0;
 
+		if (punctured & 1) {
+			punctured >>= 1;
+			continue;
+		}
+		punctured >>= 1;
+
 		if (c->flags & IEEE80211_CHAN_DISABLED)
 			return 0;
 
@@ -1168,14 +1190,14 @@ cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
 
 	t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
 					     MHZ_TO_KHZ(chandef->center_freq1),
-					     width);
+					     width, chandef->punctured);
 
 	if (!chandef->center_freq2)
 		return t1;
 
 	t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
 					     MHZ_TO_KHZ(chandef->center_freq2),
-					     width);
+					     width, chandef->punctured);
 
 	return max(t1, t2);
 }
@@ -1183,6 +1205,7 @@ EXPORT_SYMBOL(cfg80211_chandef_dfs_cac_time);
 
 static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
 					u32 center_freq, u32 bandwidth,
+					u16 punctured,
 					u32 prohibited_flags,
 					u32 permitting_flags)
 {
@@ -1198,8 +1221,10 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
 			return false;
 		if (c->flags & permitting_flags)
 			continue;
-		if (c->flags & prohibited_flags)
+		if ((c->flags & prohibited_flags) && !(punctured & 1))
 			return false;
+
+		punctured >>= 1;
 	}
 
 	return true;
@@ -1423,16 +1448,16 @@ bool _cfg80211_chandef_usable(struct wiphy *wiphy,
 
 	if (!cfg80211_secondary_chans_ok(wiphy,
 					 ieee80211_chandef_to_khz(chandef),
-					 width, prohibited_flags,
-					 permitting_flags))
+					 width, chandef->punctured,
+					 prohibited_flags, permitting_flags))
 		return false;
 
 	if (!chandef->center_freq2)
 		return true;
 	return cfg80211_secondary_chans_ok(wiphy,
 					   MHZ_TO_KHZ(chandef->center_freq2),
-					   width, prohibited_flags,
-					   permitting_flags);
+					   width, chandef->punctured,
+					   prohibited_flags, permitting_flags);
 }
 
 bool cfg80211_chandef_usable(struct wiphy *wiphy,
-- 
2.17.1





[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux