diff mbox

[v5] cfg80211: fix dfs channel state after stopping AP

Message ID 1387209049-25529-1-git-send-email-marek.puzyniak@tieto.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Marek Puzyniak Dec. 16, 2013, 3:50 p.m. UTC
In AP mode DFS channel state is changed to DFS_AVAILABLE
after successful CAC and remains as such until a radar
signal is detected during the In-Service Monitoring.
When AP is stopped it is no longer monitoring current channel
for radar signals. DFS channel state should be changed
to DFS_USABLE when last AP interface is stopped. Starting AP
again on that channel will start CAC instead of starting radiation.

Signed-off-by: Marek Puzyniak <marek.puzyniak@tieto.com>
---

Patch v1:
*Initial version. Partially in mac80211 and cfg80211.

Patch v2:
*Moved all implementation to cfg80211.

Patch v3:
*Rephrase patch description.

Patch v4:
*Fix coding style,
*Do not check if RADAR flag is set, when dfs channel state was AVAILABLE
 change it to USABLE, 
*Handle multiBSSID APs - Change DFS channel state when last AP was stoped. 

Patch v5:
*Fix coding style,
*Remove unnecessary and nested wdev_lock.

 net/wireless/ap.c   | 36 ++++++++++++++++++++++++++++++++++++
 net/wireless/chan.c | 38 ++++++++++++++++++++++++++++++++++++++
 net/wireless/core.h | 11 +++++++++++
 3 files changed, 85 insertions(+)

Comments

Johannes Berg Dec. 16, 2013, 8:31 p.m. UTC | #1
On Mon, 2013-12-16 at 16:50 +0100, Marek Puzyniak wrote:
> In AP mode DFS channel state is changed to DFS_AVAILABLE
> after successful CAC and remains as such until a radar
> signal is detected during the In-Service Monitoring.
> When AP is stopped it is no longer monitoring current channel
> for radar signals. DFS channel state should be changed
> to DFS_USABLE when last AP interface is stopped. Starting AP
> again on that channel will start CAC instead of starting radiation.

Applied. Since it didn't apply/compile on 3.13, I put it into -next
(even though you said before that it should be in 3.13 ... sorry. gotta
make sure your patches actually apply where you want them)

johannes

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Simon Wunderlich Dec. 17, 2013, 2:44 p.m. UTC | #2
> In AP mode DFS channel state is changed to DFS_AVAILABLE
> after successful CAC and remains as such until a radar
> signal is detected during the In-Service Monitoring.
> When AP is stopped it is no longer monitoring current channel
> for radar signals. DFS channel state should be changed
> to DFS_USABLE when last AP interface is stopped. Starting AP
> again on that channel will start CAC instead of starting radiation.
> 

Sorry for answering after so many revisions, but ... why do you think this is 
required? Many APs first do a CAC on all available channels, but then pick one 
channel and use that, while being able to switch to another channel 
immediately.

WIth this patch (if I understand that correctly), this is not possible 
anymore. Why do you think it is required? I can not find this requirement in 
ETSI, at least.

To quote from ETSI 301.893:

Once the RLAN has started operations on an Available Channel, then that 
channel becomes an Operating Channel. During normal operation, the master 
device shall monitor all Operating Channels (In-Service Monitoring) to ensure 
that there is no radar operating within these channel(s). If no radar was 
detected on an Operating Channel but the RLAN stops operating on that channel, 
then the channel becomes an Available Channel.

I think this patch is wrong and should not be applied.

Thanks,
    Simon
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Johannes Berg Dec. 18, 2013, 9:34 a.m. UTC | #3
On Tue, 2013-12-17 at 15:44 +0100, Simon Wunderlich wrote:
> > In AP mode DFS channel state is changed to DFS_AVAILABLE
> > after successful CAC and remains as such until a radar
> > signal is detected during the In-Service Monitoring.
> > When AP is stopped it is no longer monitoring current channel
> > for radar signals. DFS channel state should be changed
> > to DFS_USABLE when last AP interface is stopped. Starting AP
> > again on that channel will start CAC instead of starting radiation.
> > 
> 
> Sorry for answering after so many revisions, but ... why do you think this is 
> required? Many APs first do a CAC on all available channels, but then pick one 
> channel and use that, while being able to switch to another channel 
> immediately.

I'll drop the patch for now - please discuss :P

johannes


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/net/wireless/ap.c b/net/wireless/ap.c
index 324e8d8..28d1a3c 100644
--- a/net/wireless/ap.c
+++ b/net/wireless/ap.c
@@ -6,6 +6,39 @@ 
 #include "rdev-ops.h"
 
 
+static bool cfg80211_is_last_ap_running(struct cfg80211_registered_device *rdev,
+					struct net_device *dev)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct wireless_dev *wdev_iter;
+
+	ASSERT_WDEV_LOCK(wdev);
+
+	if (rdev->num_running_ifaces == 1) {
+		/* Last running AP iface */
+		return true;
+	}
+
+	/* More running interfaces */
+	list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
+		if (wdev_iter == wdev)
+			continue;
+
+		if (!wdev_iter->netdev)
+			continue;
+
+		if (!netif_running(wdev_iter->netdev)) {
+			continue;
+		}
+
+		if (wdev_iter->iftype == NL80211_IFTYPE_AP) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
 static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
 			      struct net_device *dev)
 {
@@ -31,6 +64,9 @@  static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
 		wdev->ssid_len = 0;
 	}
 
+	if (cfg80211_is_last_ap_running(rdev, dev))
+		cfg80211_leave_dfs_chandef(wdev->wiphy, &wdev->preset_chandef);
+
 	return err;
 }
 
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 78559b5..54c217a 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -490,6 +490,44 @@  static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
 	return r;
 }
 
+static void cfg80211_leave_dfs_chans(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);
+
+	for (freq = start_freq; freq <= end_freq; freq += 20) {
+		c = ieee80211_get_channel(wiphy, freq);
+		if (!c)
+			continue;
+		if (c->dfs_state != NL80211_DFS_AVAILABLE)
+			continue;
+
+		c->dfs_state = NL80211_DFS_USABLE;
+		c->dfs_state_entered = jiffies;
+	}
+}
+
+void cfg80211_leave_dfs_chandef(struct wiphy *wiphy,
+				struct cfg80211_chan_def *chandef)
+{
+	int width;
+
+	if (WARN_ON(!cfg80211_chandef_valid(chandef)))
+		return;
+
+	width = cfg80211_chandef_get_width(chandef);
+	cfg80211_leave_dfs_chans(wiphy, chandef->center_freq1, width);
+
+	if (!chandef->center_freq2)
+		return;
+
+	cfg80211_leave_dfs_chans(wiphy, chandef->center_freq2, width);
+}
 
 static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
 					u32 center_freq, u32 bandwidth,
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 37ec16d..4ed2c81 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -398,6 +398,17 @@  void cfg80211_set_dfs_state(struct wiphy *wiphy,
 
 void cfg80211_dfs_channels_update_work(struct work_struct *work);
 
+/**
+ * cfg80211_leave_dfs_chandef - Leaving dfs chandef
+ * @wiphy: the wiphy
+ * @chandef: chandef for the current channel
+ *
+ * This function is called when dfs chandef is being not used for different
+ * reasons. Change channels DFS_AVAILABLE to DFS_USABLE again. Leave channels
+ * DFS_UNAVAILABLE untouched.
+ */
+void cfg80211_leave_dfs_chandef(struct wiphy *wiphy,
+				struct cfg80211_chan_def *chandef);
 
 static inline int
 cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,