mac80211: don't reconfigure sched scan in case of wowlan
authorEliad Peller <eliad@wizery.com>
Sun, 25 Oct 2015 08:59:33 +0000 (10:59 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 3 Nov 2015 09:42:05 +0000 (10:42 +0100)
Scheduled scan has to be reconfigured only if wowlan wasn't
configured, since otherwise it should continue to run (with
the 'any' trigger) or be aborted.

The current code will end up asking the driver to start a new
scheduled scan without stopping the previous one, and leaking
some memory (from the previous request.)

Fix this by doing the abort/restart under the proper conditions.

Signed-off-by: Eliad Peller <eliadx.peller@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/cfg.c
net/mac80211/ieee80211_i.h
net/mac80211/pm.c
net/mac80211/scan.c
net/mac80211/util.c

index 713cdbf6fb3c111d0d5ce736368116538e960df2..c2bd1b6a69224e4e07b6247c71077e2a79939dac 100644 (file)
@@ -2010,12 +2010,12 @@ ieee80211_sched_scan_start(struct wiphy *wiphy,
 static int
 ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wiphy_priv(wiphy);
 
-       if (!sdata->local->ops->sched_scan_stop)
+       if (!local->ops->sched_scan_stop)
                return -EOPNOTSUPP;
 
-       return ieee80211_request_sched_scan_stop(sdata);
+       return ieee80211_request_sched_scan_stop(local);
 }
 
 static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
index 62f2a97cd2a69632abd74cd936ee2e2e702c41dc..68680ad04cefe6e8a7bd8db53ce4dd1bfcca458a 100644 (file)
@@ -1573,7 +1573,7 @@ __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
                                     struct cfg80211_sched_scan_request *req);
 int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
                                       struct cfg80211_sched_scan_request *req);
-int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata);
+int ieee80211_request_sched_scan_stop(struct ieee80211_local *local);
 void ieee80211_sched_scan_end(struct ieee80211_local *local);
 void ieee80211_sched_scan_stopped_work(struct work_struct *work);
 
index ad88ad4e8eb1370d321931536f166d298e645dd8..00a43a70e1fc30eedb09ab9dcdde8af2a9c89673 100644 (file)
@@ -6,6 +6,13 @@
 #include "driver-ops.h"
 #include "led.h"
 
+static void ieee80211_sched_scan_cancel(struct ieee80211_local *local)
+{
+       if (ieee80211_request_sched_scan_stop(local))
+               return;
+       cfg80211_sched_scan_stopped_rtnl(local->hw.wiphy);
+}
+
 int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 {
        struct ieee80211_local *local = hw_to_local(hw);
@@ -34,6 +41,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                mutex_unlock(&local->sta_mtx);
        }
 
+       /* keep sched_scan only in case of 'any' trigger */
+       if (!(wowlan && wowlan->any))
+               ieee80211_sched_scan_cancel(local);
+
        ieee80211_stop_queues_by_reason(hw,
                                        IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_SUSPEND,
index b64fd2b2d95accd23cf1207b828c8f822e35f929..4aeca4b0c3cb426ba65b23d4a8ebc756e7a826a4 100644 (file)
@@ -1140,10 +1140,10 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
        return ret;
 }
 
-int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
+int ieee80211_request_sched_scan_stop(struct ieee80211_local *local)
 {
-       struct ieee80211_local *local = sdata->local;
-       int ret = 0;
+       struct ieee80211_sub_if_data *sched_scan_sdata;
+       int ret = -ENOENT;
 
        mutex_lock(&local->mtx);
 
@@ -1155,8 +1155,10 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
        /* We don't want to restart sched scan anymore. */
        RCU_INIT_POINTER(local->sched_scan_req, NULL);
 
-       if (rcu_access_pointer(local->sched_scan_sdata)) {
-               ret = drv_sched_scan_stop(local, sdata);
+       sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
+                                               lockdep_is_held(&local->mtx));
+       if (sched_scan_sdata) {
+               ret = drv_sched_scan_stop(local, sched_scan_sdata);
                if (!ret)
                        RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
        }
index 551164dabbafc865f3af66b8b659ecd564f3c50d..d38daf0181e8355f0c3db7716bb85f2ec981054c 100644 (file)
@@ -2008,6 +2008,29 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                if (ieee80211_sdata_running(sdata))
                        ieee80211_enable_keys(sdata);
 
+       /* Reconfigure sched scan if it was interrupted by FW restart */
+       mutex_lock(&local->mtx);
+       sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
+                                               lockdep_is_held(&local->mtx));
+       sched_scan_req = rcu_dereference_protected(local->sched_scan_req,
+                                               lockdep_is_held(&local->mtx));
+       if (sched_scan_sdata && sched_scan_req)
+               /*
+                * Sched scan stopped, but we don't want to report it. Instead,
+                * we're trying to reschedule. However, if more than one scan
+                * plan was set, we cannot reschedule since we don't know which
+                * scan plan was currently running (and some scan plans may have
+                * already finished).
+                */
+               if (sched_scan_req->n_scan_plans > 1 ||
+                   __ieee80211_request_sched_scan_start(sched_scan_sdata,
+                                                        sched_scan_req))
+                       sched_scan_stopped = true;
+       mutex_unlock(&local->mtx);
+
+       if (sched_scan_stopped)
+               cfg80211_sched_scan_stopped_rtnl(local->hw.wiphy);
+
  wake_up:
        local->in_reconfig = false;
        barrier();
@@ -2042,32 +2065,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                                        IEEE80211_QUEUE_STOP_REASON_SUSPEND,
                                        false);
 
-       /*
-        * Reconfigure sched scan if it was interrupted by FW restart or
-        * suspend.
-        */
-       mutex_lock(&local->mtx);
-       sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
-                                               lockdep_is_held(&local->mtx));
-       sched_scan_req = rcu_dereference_protected(local->sched_scan_req,
-                                               lockdep_is_held(&local->mtx));
-       if (sched_scan_sdata && sched_scan_req)
-               /*
-                * Sched scan stopped, but we don't want to report it. Instead,
-                * we're trying to reschedule. However, if more than one scan
-                * plan was set, we cannot reschedule since we don't know which
-                * scan plan was currently running (and some scan plans may have
-                * already finished).
-                */
-               if (sched_scan_req->n_scan_plans > 1 ||
-                   __ieee80211_request_sched_scan_start(sched_scan_sdata,
-                                                        sched_scan_req))
-                       sched_scan_stopped = true;
-       mutex_unlock(&local->mtx);
-
-       if (sched_scan_stopped)
-               cfg80211_sched_scan_stopped_rtnl(local->hw.wiphy);
-
        /*
         * If this is for hw restart things are still running.
         * We may want to change that later, however.