Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: don't reconfigure sched scan in case of wowlan

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>

authored by

Eliad Peller and committed by
Johannes Berg
0d440ea2 968a76ce

+45 -35
+3 -3
net/mac80211/cfg.c
··· 2010 2010 static int 2011 2011 ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) 2012 2012 { 2013 - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 2013 + struct ieee80211_local *local = wiphy_priv(wiphy); 2014 2014 2015 - if (!sdata->local->ops->sched_scan_stop) 2015 + if (!local->ops->sched_scan_stop) 2016 2016 return -EOPNOTSUPP; 2017 2017 2018 - return ieee80211_request_sched_scan_stop(sdata); 2018 + return ieee80211_request_sched_scan_stop(local); 2019 2019 } 2020 2020 2021 2021 static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
+1 -1
net/mac80211/ieee80211_i.h
··· 1573 1573 struct cfg80211_sched_scan_request *req); 1574 1574 int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, 1575 1575 struct cfg80211_sched_scan_request *req); 1576 - int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata); 1576 + int ieee80211_request_sched_scan_stop(struct ieee80211_local *local); 1577 1577 void ieee80211_sched_scan_end(struct ieee80211_local *local); 1578 1578 void ieee80211_sched_scan_stopped_work(struct work_struct *work); 1579 1579
+11
net/mac80211/pm.c
··· 6 6 #include "driver-ops.h" 7 7 #include "led.h" 8 8 9 + static void ieee80211_sched_scan_cancel(struct ieee80211_local *local) 10 + { 11 + if (ieee80211_request_sched_scan_stop(local)) 12 + return; 13 + cfg80211_sched_scan_stopped_rtnl(local->hw.wiphy); 14 + } 15 + 9 16 int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) 10 17 { 11 18 struct ieee80211_local *local = hw_to_local(hw); ··· 40 33 } 41 34 mutex_unlock(&local->sta_mtx); 42 35 } 36 + 37 + /* keep sched_scan only in case of 'any' trigger */ 38 + if (!(wowlan && wowlan->any)) 39 + ieee80211_sched_scan_cancel(local); 43 40 44 41 ieee80211_stop_queues_by_reason(hw, 45 42 IEEE80211_MAX_QUEUE_MAP,
+7 -5
net/mac80211/scan.c
··· 1140 1140 return ret; 1141 1141 } 1142 1142 1143 - int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) 1143 + int ieee80211_request_sched_scan_stop(struct ieee80211_local *local) 1144 1144 { 1145 - struct ieee80211_local *local = sdata->local; 1146 - int ret = 0; 1145 + struct ieee80211_sub_if_data *sched_scan_sdata; 1146 + int ret = -ENOENT; 1147 1147 1148 1148 mutex_lock(&local->mtx); 1149 1149 ··· 1155 1155 /* We don't want to restart sched scan anymore. */ 1156 1156 RCU_INIT_POINTER(local->sched_scan_req, NULL); 1157 1157 1158 - if (rcu_access_pointer(local->sched_scan_sdata)) { 1159 - ret = drv_sched_scan_stop(local, sdata); 1158 + sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, 1159 + lockdep_is_held(&local->mtx)); 1160 + if (sched_scan_sdata) { 1161 + ret = drv_sched_scan_stop(local, sched_scan_sdata); 1160 1162 if (!ret) 1161 1163 RCU_INIT_POINTER(local->sched_scan_sdata, NULL); 1162 1164 }
+23 -26
net/mac80211/util.c
··· 2008 2008 if (ieee80211_sdata_running(sdata)) 2009 2009 ieee80211_enable_keys(sdata); 2010 2010 2011 + /* Reconfigure sched scan if it was interrupted by FW restart */ 2012 + mutex_lock(&local->mtx); 2013 + sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, 2014 + lockdep_is_held(&local->mtx)); 2015 + sched_scan_req = rcu_dereference_protected(local->sched_scan_req, 2016 + lockdep_is_held(&local->mtx)); 2017 + if (sched_scan_sdata && sched_scan_req) 2018 + /* 2019 + * Sched scan stopped, but we don't want to report it. Instead, 2020 + * we're trying to reschedule. However, if more than one scan 2021 + * plan was set, we cannot reschedule since we don't know which 2022 + * scan plan was currently running (and some scan plans may have 2023 + * already finished). 2024 + */ 2025 + if (sched_scan_req->n_scan_plans > 1 || 2026 + __ieee80211_request_sched_scan_start(sched_scan_sdata, 2027 + sched_scan_req)) 2028 + sched_scan_stopped = true; 2029 + mutex_unlock(&local->mtx); 2030 + 2031 + if (sched_scan_stopped) 2032 + cfg80211_sched_scan_stopped_rtnl(local->hw.wiphy); 2033 + 2011 2034 wake_up: 2012 2035 local->in_reconfig = false; 2013 2036 barrier(); ··· 2064 2041 ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, 2065 2042 IEEE80211_QUEUE_STOP_REASON_SUSPEND, 2066 2043 false); 2067 - 2068 - /* 2069 - * Reconfigure sched scan if it was interrupted by FW restart or 2070 - * suspend. 2071 - */ 2072 - mutex_lock(&local->mtx); 2073 - sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, 2074 - lockdep_is_held(&local->mtx)); 2075 - sched_scan_req = rcu_dereference_protected(local->sched_scan_req, 2076 - lockdep_is_held(&local->mtx)); 2077 - if (sched_scan_sdata && sched_scan_req) 2078 - /* 2079 - * Sched scan stopped, but we don't want to report it. Instead, 2080 - * we're trying to reschedule. However, if more than one scan 2081 - * plan was set, we cannot reschedule since we don't know which 2082 - * scan plan was currently running (and some scan plans may have 2083 - * already finished). 2084 - */ 2085 - if (sched_scan_req->n_scan_plans > 1 || 2086 - __ieee80211_request_sched_scan_start(sched_scan_sdata, 2087 - sched_scan_req)) 2088 - sched_scan_stopped = true; 2089 - mutex_unlock(&local->mtx); 2090 - 2091 - if (sched_scan_stopped) 2092 - cfg80211_sched_scan_stopped_rtnl(local->hw.wiphy); 2093 2044 2094 2045 /* 2095 2046 * If this is for hw restart things are still running.