diff options
-rw-r--r-- | net/mac80211/ieee80211_i.h | 4 | ||||
-rw-r--r-- | net/mac80211/main.c | 8 | ||||
-rw-r--r-- | net/mac80211/scan.c | 53 | ||||
-rw-r--r-- | net/mac80211/util.c | 23 |
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 */ |
1425 | int | ||
1426 | __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | ||
1427 | struct cfg80211_sched_scan_request *req); | ||
1424 | int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | 1428 | int 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); |
1426 | int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata); | 1430 | int 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 | ||
974 | int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | 974 | int __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 | ||
1019 | out_free: | 1014 | out_free: |
1020 | while (i > 0) | 1015 | while (i > 0) |
1021 | kfree(sched_scan_ies.ie[--i]); | 1016 | kfree(sched_scan_ies.ie[--i]); |
1022 | out: | 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 | |||
1027 | int 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 | ||