aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/main.c8
-rw-r--r--net/mac80211/scan.c53
-rw-r--r--net/mac80211/util.c23
4 files changed, 68 insertions, 20 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 287462875857..ee13c6593b9a 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1113,6 +1113,7 @@ struct ieee80211_local {
1113 1113
1114 struct work_struct sched_scan_stopped_work; 1114 struct work_struct sched_scan_stopped_work;
1115 struct ieee80211_sub_if_data __rcu *sched_scan_sdata; 1115 struct ieee80211_sub_if_data __rcu *sched_scan_sdata;
1116 struct cfg80211_sched_scan_request *sched_scan_req;
1116 1117
1117 unsigned long leave_oper_channel_time; 1118 unsigned long leave_oper_channel_time;
1118 enum mac80211_scan_state next_scan_state; 1119 enum mac80211_scan_state next_scan_state;
@@ -1421,6 +1422,9 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local,
1421 struct ieee80211_bss *bss); 1422 struct ieee80211_bss *bss);
1422 1423
1423/* scheduled scan handling */ 1424/* scheduled scan handling */
1425int
1426__ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
1427 struct cfg80211_sched_scan_request *req);
1424int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, 1428int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
1425 struct cfg80211_sched_scan_request *req); 1429 struct cfg80211_sched_scan_request *req);
1426int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata); 1430int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index fa34cd2344b9..2bd5b552b2f6 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -250,12 +250,8 @@ static void ieee80211_restart_work(struct work_struct *work)
250 /* wait for scan work complete */ 250 /* wait for scan work complete */
251 flush_workqueue(local->workqueue); 251 flush_workqueue(local->workqueue);
252 252
253 mutex_lock(&local->mtx); 253 WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
254 WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) || 254 "%s called with hardware scan in progress\n", __func__);
255 rcu_dereference_protected(local->sched_scan_sdata,
256 lockdep_is_held(&local->mtx)),
257 "%s called with hardware scan in progress\n", __func__);
258 mutex_unlock(&local->mtx);
259 255
260 rtnl_lock(); 256 rtnl_lock();
261 ieee80211_scan_cancel(local); 257 ieee80211_scan_cancel(local);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index ee6c8515f97b..88c81616f8f7 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -971,8 +971,8 @@ out:
971 mutex_unlock(&local->mtx); 971 mutex_unlock(&local->mtx);
972} 972}
973 973
974int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, 974int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
975 struct cfg80211_sched_scan_request *req) 975 struct cfg80211_sched_scan_request *req)
976{ 976{
977 struct ieee80211_local *local = sdata->local; 977 struct ieee80211_local *local = sdata->local;
978 struct ieee80211_sched_scan_ies sched_scan_ies = {}; 978 struct ieee80211_sched_scan_ies sched_scan_ies = {};
@@ -982,17 +982,10 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
982 iebufsz = 2 + IEEE80211_MAX_SSID_LEN + 982 iebufsz = 2 + IEEE80211_MAX_SSID_LEN +
983 local->scan_ies_len + req->ie_len; 983 local->scan_ies_len + req->ie_len;
984 984
985 mutex_lock(&local->mtx); 985 lockdep_assert_held(&local->mtx);
986 986
987 if (rcu_access_pointer(local->sched_scan_sdata)) { 987 if (!local->ops->sched_scan_start)
988 ret = -EBUSY; 988 return -ENOTSUPP;
989 goto out;
990 }
991
992 if (!local->ops->sched_scan_start) {
993 ret = -ENOTSUPP;
994 goto out;
995 }
996 989
997 for (i = 0; i < IEEE80211_NUM_BANDS; i++) { 990 for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
998 if (!local->hw.wiphy->bands[i]) 991 if (!local->hw.wiphy->bands[i])
@@ -1013,13 +1006,39 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
1013 } 1006 }
1014 1007
1015 ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); 1008 ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
1016 if (ret == 0) 1009 if (ret == 0) {
1017 rcu_assign_pointer(local->sched_scan_sdata, sdata); 1010 rcu_assign_pointer(local->sched_scan_sdata, sdata);
1011 local->sched_scan_req = req;
1012 }
1018 1013
1019out_free: 1014out_free:
1020 while (i > 0) 1015 while (i > 0)
1021 kfree(sched_scan_ies.ie[--i]); 1016 kfree(sched_scan_ies.ie[--i]);
1022out: 1017
1018 if (ret) {
1019 /* Clean in case of failure after HW restart or upon resume. */
1020 rcu_assign_pointer(local->sched_scan_sdata, NULL);
1021 local->sched_scan_req = NULL;
1022 }
1023
1024 return ret;
1025}
1026
1027int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
1028 struct cfg80211_sched_scan_request *req)
1029{
1030 struct ieee80211_local *local = sdata->local;
1031 int ret;
1032
1033 mutex_lock(&local->mtx);
1034
1035 if (rcu_access_pointer(local->sched_scan_sdata)) {
1036 mutex_unlock(&local->mtx);
1037 return -EBUSY;
1038 }
1039
1040 ret = __ieee80211_request_sched_scan_start(sdata, req);
1041
1023 mutex_unlock(&local->mtx); 1042 mutex_unlock(&local->mtx);
1024 return ret; 1043 return ret;
1025} 1044}
@@ -1036,6 +1055,9 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
1036 goto out; 1055 goto out;
1037 } 1056 }
1038 1057
1058 /* We don't want to restart sched scan anymore. */
1059 local->sched_scan_req = NULL;
1060
1039 if (rcu_access_pointer(local->sched_scan_sdata)) 1061 if (rcu_access_pointer(local->sched_scan_sdata))
1040 drv_sched_scan_stop(local, sdata); 1062 drv_sched_scan_stop(local, sdata);
1041 1063
@@ -1070,6 +1092,9 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)
1070 1092
1071 rcu_assign_pointer(local->sched_scan_sdata, NULL); 1093 rcu_assign_pointer(local->sched_scan_sdata, NULL);
1072 1094
1095 /* If sched scan was aborted by the driver. */
1096 local->sched_scan_req = NULL;
1097
1073 mutex_unlock(&local->mtx); 1098 mutex_unlock(&local->mtx);
1074 1099
1075 cfg80211_sched_scan_stopped(local->hw.wiphy); 1100 cfg80211_sched_scan_stopped(local->hw.wiphy);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index adf81f023681..591b46b72462 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1462,6 +1462,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1462 struct sta_info *sta; 1462 struct sta_info *sta;
1463 int res, i; 1463 int res, i;
1464 bool reconfig_due_to_wowlan = false; 1464 bool reconfig_due_to_wowlan = false;
1465 struct ieee80211_sub_if_data *sched_scan_sdata;
1466 bool sched_scan_stopped = false;
1465 1467
1466#ifdef CONFIG_PM 1468#ifdef CONFIG_PM
1467 if (local->suspended) 1469 if (local->suspended)
@@ -1765,6 +1767,27 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1765#else 1767#else
1766 WARN_ON(1); 1768 WARN_ON(1);
1767#endif 1769#endif
1770
1771 /*
1772 * Reconfigure sched scan if it was interrupted by FW restart or
1773 * suspend.
1774 */
1775 mutex_lock(&local->mtx);
1776 sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
1777 lockdep_is_held(&local->mtx));
1778 if (sched_scan_sdata && local->sched_scan_req)
1779 /*
1780 * Sched scan stopped, but we don't want to report it. Instead,
1781 * we're trying to reschedule.
1782 */
1783 if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
1784 local->sched_scan_req))
1785 sched_scan_stopped = true;
1786 mutex_unlock(&local->mtx);
1787
1788 if (sched_scan_stopped)
1789 cfg80211_sched_scan_stopped(local->hw.wiphy);
1790
1768 return 0; 1791 return 0;
1769} 1792}
1770 1793