summaryrefslogtreecommitdiffstats
path: root/net/wireless/sme.c
diff options
context:
space:
mode:
authorLuis R. Rodriguez <lrodriguez@atheros.com>2010-01-30 01:58:57 +0100
committerJohn W. Linville <linville@tuxdriver.com>2010-02-01 21:40:06 +0100
commit09d989d179d0c679043556dda77c51b41a2dae7e (patch)
tree6dcf9bf260e401aa341cb0f34c1e35690d6bb17b /net/wireless/sme.c
parentcfg80211: avoid flushing the global workqueue for core reg hints (diff)
downloadlinux-09d989d179d0c679043556dda77c51b41a2dae7e.tar.xz
linux-09d989d179d0c679043556dda77c51b41a2dae7e.zip
cfg80211: add regulatory hint disconnect support
This adds a new regulatory hint to be used when we know all devices have been disconnected and idle. This can happen when we suspend, for instance. When we disconnect we can no longer assume the same regulatory rules learned from a country IE or beacon hints are applicable so restore regulatory settings to an initial state. Since driver hints are cached on the wiphy that called the hint, those hints are not reproduced onto cfg80211 as the wiphy will respect its own wiphy->regd regardless. Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/sme.c')
-rw-r--r--net/wireless/sme.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 745c37e7992e..17fde0da1b08 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -34,6 +34,44 @@ struct cfg80211_conn {
bool auto_auth, prev_bssid_valid;
};
+bool cfg80211_is_all_idle(void)
+{
+ struct cfg80211_registered_device *rdev;
+ struct wireless_dev *wdev;
+ bool is_all_idle = true;
+
+ mutex_lock(&cfg80211_mutex);
+
+ /*
+ * All devices must be idle as otherwise if you are actively
+ * scanning some new beacon hints could be learned and would
+ * count as new regulatory hints.
+ */
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+ cfg80211_lock_rdev(rdev);
+ list_for_each_entry(wdev, &rdev->netdev_list, list) {
+ wdev_lock(wdev);
+ if (wdev->sme_state != CFG80211_SME_IDLE)
+ is_all_idle = false;
+ wdev_unlock(wdev);
+ }
+ cfg80211_unlock_rdev(rdev);
+ }
+
+ mutex_unlock(&cfg80211_mutex);
+
+ return is_all_idle;
+}
+
+static void disconnect_work(struct work_struct *work)
+{
+ if (!cfg80211_is_all_idle())
+ return;
+
+ regulatory_hint_disconnect();
+}
+
+static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
static int cfg80211_conn_scan(struct wireless_dev *wdev)
{
@@ -658,6 +696,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
wdev->wext.connect.ssid_len = 0;
#endif
+
+ schedule_work(&cfg80211_disconnect_work);
}
void cfg80211_disconnected(struct net_device *dev, u16 reason,