aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h14
-rw-r--r--net/mac80211/driver-ops.h108
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/scan.c15
-rw-r--r--net/mac80211/util.c46
-rw-r--r--net/wireless/core.c20
6 files changed, 153 insertions, 51 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 28f6f1a5b445..5c7169b0ac57 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4771,6 +4771,20 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
4771void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev, 4771void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev,
4772 gfp_t gfp); 4772 gfp_t gfp);
4773 4773
4774/**
4775 * cfg80211_shutdown_all_interfaces - shut down all interfaces for a wiphy
4776 * @wiphy: the wiphy to shut down
4777 *
4778 * This function shuts down all interfaces belonging to this wiphy by
4779 * calling dev_close() (and treating non-netdev interfaces as needed).
4780 * It shouldn't really be used unless there are some fatal device errors
4781 * that really can't be recovered in any other way.
4782 *
4783 * Callers must hold the RTNL and be able to deal with callbacks into
4784 * the driver while the function is running.
4785 */
4786void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy);
4787
4774/* Logging, debugging and troubleshooting/diagnostic helpers. */ 4788/* Logging, debugging and troubleshooting/diagnostic helpers. */
4775 4789
4776/* wiphy_printk helpers, similar to dev_printk */ 4790/* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 5331582a2c81..df1d50291344 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -5,11 +5,11 @@
5#include "ieee80211_i.h" 5#include "ieee80211_i.h"
6#include "trace.h" 6#include "trace.h"
7 7
8static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata) 8static inline bool check_sdata_in_driver(struct ieee80211_sub_if_data *sdata)
9{ 9{
10 WARN(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER), 10 return !WARN(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER),
11 "%s: Failed check-sdata-in-driver check, flags: 0x%x\n", 11 "%s: Failed check-sdata-in-driver check, flags: 0x%x\n",
12 sdata->dev ? sdata->dev->name : sdata->name, sdata->flags); 12 sdata->dev ? sdata->dev->name : sdata->name, sdata->flags);
13} 13}
14 14
15static inline struct ieee80211_sub_if_data * 15static inline struct ieee80211_sub_if_data *
@@ -168,7 +168,8 @@ static inline int drv_change_interface(struct ieee80211_local *local,
168 168
169 might_sleep(); 169 might_sleep();
170 170
171 check_sdata_in_driver(sdata); 171 if (!check_sdata_in_driver(sdata))
172 return -EIO;
172 173
173 trace_drv_change_interface(local, sdata, type, p2p); 174 trace_drv_change_interface(local, sdata, type, p2p);
174 ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p); 175 ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
@@ -181,7 +182,8 @@ static inline void drv_remove_interface(struct ieee80211_local *local,
181{ 182{
182 might_sleep(); 183 might_sleep();
183 184
184 check_sdata_in_driver(sdata); 185 if (!check_sdata_in_driver(sdata))
186 return;
185 187
186 trace_drv_remove_interface(local, sdata); 188 trace_drv_remove_interface(local, sdata);
187 local->ops->remove_interface(&local->hw, &sdata->vif); 189 local->ops->remove_interface(&local->hw, &sdata->vif);
@@ -219,7 +221,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
219 sdata->vif.type == NL80211_IFTYPE_MONITOR)) 221 sdata->vif.type == NL80211_IFTYPE_MONITOR))
220 return; 222 return;
221 223
222 check_sdata_in_driver(sdata); 224 if (!check_sdata_in_driver(sdata))
225 return;
223 226
224 trace_drv_bss_info_changed(local, sdata, info, changed); 227 trace_drv_bss_info_changed(local, sdata, info, changed);
225 if (local->ops->bss_info_changed) 228 if (local->ops->bss_info_changed)
@@ -278,7 +281,8 @@ static inline int drv_set_key(struct ieee80211_local *local,
278 might_sleep(); 281 might_sleep();
279 282
280 sdata = get_bss_sdata(sdata); 283 sdata = get_bss_sdata(sdata);
281 check_sdata_in_driver(sdata); 284 if (!check_sdata_in_driver(sdata))
285 return -EIO;
282 286
283 trace_drv_set_key(local, cmd, sdata, sta, key); 287 trace_drv_set_key(local, cmd, sdata, sta, key);
284 ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key); 288 ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
@@ -298,7 +302,8 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
298 ista = &sta->sta; 302 ista = &sta->sta;
299 303
300 sdata = get_bss_sdata(sdata); 304 sdata = get_bss_sdata(sdata);
301 check_sdata_in_driver(sdata); 305 if (!check_sdata_in_driver(sdata))
306 return;
302 307
303 trace_drv_update_tkip_key(local, sdata, conf, ista, iv32); 308 trace_drv_update_tkip_key(local, sdata, conf, ista, iv32);
304 if (local->ops->update_tkip_key) 309 if (local->ops->update_tkip_key)
@@ -315,7 +320,8 @@ static inline int drv_hw_scan(struct ieee80211_local *local,
315 320
316 might_sleep(); 321 might_sleep();
317 322
318 check_sdata_in_driver(sdata); 323 if (!check_sdata_in_driver(sdata))
324 return -EIO;
319 325
320 trace_drv_hw_scan(local, sdata); 326 trace_drv_hw_scan(local, sdata);
321 ret = local->ops->hw_scan(&local->hw, &sdata->vif, req); 327 ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
@@ -328,7 +334,8 @@ static inline void drv_cancel_hw_scan(struct ieee80211_local *local,
328{ 334{
329 might_sleep(); 335 might_sleep();
330 336
331 check_sdata_in_driver(sdata); 337 if (!check_sdata_in_driver(sdata))
338 return;
332 339
333 trace_drv_cancel_hw_scan(local, sdata); 340 trace_drv_cancel_hw_scan(local, sdata);
334 local->ops->cancel_hw_scan(&local->hw, &sdata->vif); 341 local->ops->cancel_hw_scan(&local->hw, &sdata->vif);
@@ -345,7 +352,8 @@ drv_sched_scan_start(struct ieee80211_local *local,
345 352
346 might_sleep(); 353 might_sleep();
347 354
348 check_sdata_in_driver(sdata); 355 if (!check_sdata_in_driver(sdata))
356 return -EIO;
349 357
350 trace_drv_sched_scan_start(local, sdata); 358 trace_drv_sched_scan_start(local, sdata);
351 ret = local->ops->sched_scan_start(&local->hw, &sdata->vif, 359 ret = local->ops->sched_scan_start(&local->hw, &sdata->vif,
@@ -361,7 +369,8 @@ static inline int drv_sched_scan_stop(struct ieee80211_local *local,
361 369
362 might_sleep(); 370 might_sleep();
363 371
364 check_sdata_in_driver(sdata); 372 if (!check_sdata_in_driver(sdata))
373 return -EIO;
365 374
366 trace_drv_sched_scan_stop(local, sdata); 375 trace_drv_sched_scan_stop(local, sdata);
367 ret = local->ops->sched_scan_stop(&local->hw, &sdata->vif); 376 ret = local->ops->sched_scan_stop(&local->hw, &sdata->vif);
@@ -462,7 +471,8 @@ static inline void drv_sta_notify(struct ieee80211_local *local,
462 struct ieee80211_sta *sta) 471 struct ieee80211_sta *sta)
463{ 472{
464 sdata = get_bss_sdata(sdata); 473 sdata = get_bss_sdata(sdata);
465 check_sdata_in_driver(sdata); 474 if (!check_sdata_in_driver(sdata))
475 return;
466 476
467 trace_drv_sta_notify(local, sdata, cmd, sta); 477 trace_drv_sta_notify(local, sdata, cmd, sta);
468 if (local->ops->sta_notify) 478 if (local->ops->sta_notify)
@@ -479,7 +489,8 @@ static inline int drv_sta_add(struct ieee80211_local *local,
479 might_sleep(); 489 might_sleep();
480 490
481 sdata = get_bss_sdata(sdata); 491 sdata = get_bss_sdata(sdata);
482 check_sdata_in_driver(sdata); 492 if (!check_sdata_in_driver(sdata))
493 return -EIO;
483 494
484 trace_drv_sta_add(local, sdata, sta); 495 trace_drv_sta_add(local, sdata, sta);
485 if (local->ops->sta_add) 496 if (local->ops->sta_add)
@@ -497,7 +508,8 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
497 might_sleep(); 508 might_sleep();
498 509
499 sdata = get_bss_sdata(sdata); 510 sdata = get_bss_sdata(sdata);
500 check_sdata_in_driver(sdata); 511 if (!check_sdata_in_driver(sdata))
512 return;
501 513
502 trace_drv_sta_remove(local, sdata, sta); 514 trace_drv_sta_remove(local, sdata, sta);
503 if (local->ops->sta_remove) 515 if (local->ops->sta_remove)
@@ -515,7 +527,8 @@ static inline void drv_sta_add_debugfs(struct ieee80211_local *local,
515 might_sleep(); 527 might_sleep();
516 528
517 sdata = get_bss_sdata(sdata); 529 sdata = get_bss_sdata(sdata);
518 check_sdata_in_driver(sdata); 530 if (!check_sdata_in_driver(sdata))
531 return;
519 532
520 if (local->ops->sta_add_debugfs) 533 if (local->ops->sta_add_debugfs)
521 local->ops->sta_add_debugfs(&local->hw, &sdata->vif, 534 local->ops->sta_add_debugfs(&local->hw, &sdata->vif,
@@ -545,7 +558,8 @@ static inline void drv_sta_pre_rcu_remove(struct ieee80211_local *local,
545 might_sleep(); 558 might_sleep();
546 559
547 sdata = get_bss_sdata(sdata); 560 sdata = get_bss_sdata(sdata);
548 check_sdata_in_driver(sdata); 561 if (!check_sdata_in_driver(sdata))
562 return;
549 563
550 trace_drv_sta_pre_rcu_remove(local, sdata, &sta->sta); 564 trace_drv_sta_pre_rcu_remove(local, sdata, &sta->sta);
551 if (local->ops->sta_pre_rcu_remove) 565 if (local->ops->sta_pre_rcu_remove)
@@ -566,7 +580,8 @@ int drv_sta_state(struct ieee80211_local *local,
566 might_sleep(); 580 might_sleep();
567 581
568 sdata = get_bss_sdata(sdata); 582 sdata = get_bss_sdata(sdata);
569 check_sdata_in_driver(sdata); 583 if (!check_sdata_in_driver(sdata))
584 return -EIO;
570 585
571 trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state); 586 trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
572 if (local->ops->sta_state) { 587 if (local->ops->sta_state) {
@@ -590,7 +605,8 @@ static inline void drv_sta_rc_update(struct ieee80211_local *local,
590 struct ieee80211_sta *sta, u32 changed) 605 struct ieee80211_sta *sta, u32 changed)
591{ 606{
592 sdata = get_bss_sdata(sdata); 607 sdata = get_bss_sdata(sdata);
593 check_sdata_in_driver(sdata); 608 if (!check_sdata_in_driver(sdata))
609 return;
594 610
595 WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED && 611 WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED &&
596 (sdata->vif.type != NL80211_IFTYPE_ADHOC && 612 (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
@@ -612,7 +628,8 @@ static inline int drv_conf_tx(struct ieee80211_local *local,
612 628
613 might_sleep(); 629 might_sleep();
614 630
615 check_sdata_in_driver(sdata); 631 if (!check_sdata_in_driver(sdata))
632 return -EIO;
616 633
617 trace_drv_conf_tx(local, sdata, ac, params); 634 trace_drv_conf_tx(local, sdata, ac, params);
618 if (local->ops->conf_tx) 635 if (local->ops->conf_tx)
@@ -629,7 +646,8 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local,
629 646
630 might_sleep(); 647 might_sleep();
631 648
632 check_sdata_in_driver(sdata); 649 if (!check_sdata_in_driver(sdata))
650 return ret;
633 651
634 trace_drv_get_tsf(local, sdata); 652 trace_drv_get_tsf(local, sdata);
635 if (local->ops->get_tsf) 653 if (local->ops->get_tsf)
@@ -644,7 +662,8 @@ static inline void drv_set_tsf(struct ieee80211_local *local,
644{ 662{
645 might_sleep(); 663 might_sleep();
646 664
647 check_sdata_in_driver(sdata); 665 if (!check_sdata_in_driver(sdata))
666 return;
648 667
649 trace_drv_set_tsf(local, sdata, tsf); 668 trace_drv_set_tsf(local, sdata, tsf);
650 if (local->ops->set_tsf) 669 if (local->ops->set_tsf)
@@ -657,7 +676,8 @@ static inline void drv_reset_tsf(struct ieee80211_local *local,
657{ 676{
658 might_sleep(); 677 might_sleep();
659 678
660 check_sdata_in_driver(sdata); 679 if (!check_sdata_in_driver(sdata))
680 return;
661 681
662 trace_drv_reset_tsf(local, sdata); 682 trace_drv_reset_tsf(local, sdata);
663 if (local->ops->reset_tsf) 683 if (local->ops->reset_tsf)
@@ -689,7 +709,8 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
689 might_sleep(); 709 might_sleep();
690 710
691 sdata = get_bss_sdata(sdata); 711 sdata = get_bss_sdata(sdata);
692 check_sdata_in_driver(sdata); 712 if (!check_sdata_in_driver(sdata))
713 return -EIO;
693 714
694 trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size); 715 trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size);
695 716
@@ -733,8 +754,8 @@ static inline void drv_flush(struct ieee80211_local *local,
733 754
734 might_sleep(); 755 might_sleep();
735 756
736 if (sdata) 757 if (sdata && !check_sdata_in_driver(sdata))
737 check_sdata_in_driver(sdata); 758 return;
738 759
739 trace_drv_flush(local, queues, drop); 760 trace_drv_flush(local, queues, drop);
740 if (local->ops->flush) 761 if (local->ops->flush)
@@ -854,7 +875,8 @@ static inline int drv_set_bitrate_mask(struct ieee80211_local *local,
854 875
855 might_sleep(); 876 might_sleep();
856 877
857 check_sdata_in_driver(sdata); 878 if (!check_sdata_in_driver(sdata))
879 return -EIO;
858 880
859 trace_drv_set_bitrate_mask(local, sdata, mask); 881 trace_drv_set_bitrate_mask(local, sdata, mask);
860 if (local->ops->set_bitrate_mask) 882 if (local->ops->set_bitrate_mask)
@@ -869,7 +891,8 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local,
869 struct ieee80211_sub_if_data *sdata, 891 struct ieee80211_sub_if_data *sdata,
870 struct cfg80211_gtk_rekey_data *data) 892 struct cfg80211_gtk_rekey_data *data)
871{ 893{
872 check_sdata_in_driver(sdata); 894 if (!check_sdata_in_driver(sdata))
895 return;
873 896
874 trace_drv_set_rekey_data(local, sdata, data); 897 trace_drv_set_rekey_data(local, sdata, data);
875 if (local->ops->set_rekey_data) 898 if (local->ops->set_rekey_data)
@@ -937,7 +960,8 @@ static inline void drv_mgd_prepare_tx(struct ieee80211_local *local,
937{ 960{
938 might_sleep(); 961 might_sleep();
939 962
940 check_sdata_in_driver(sdata); 963 if (!check_sdata_in_driver(sdata))
964 return;
941 WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION); 965 WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION);
942 966
943 trace_drv_mgd_prepare_tx(local, sdata); 967 trace_drv_mgd_prepare_tx(local, sdata);
@@ -964,6 +988,9 @@ static inline int drv_add_chanctx(struct ieee80211_local *local,
964static inline void drv_remove_chanctx(struct ieee80211_local *local, 988static inline void drv_remove_chanctx(struct ieee80211_local *local,
965 struct ieee80211_chanctx *ctx) 989 struct ieee80211_chanctx *ctx)
966{ 990{
991 if (WARN_ON(!ctx->driver_present))
992 return;
993
967 trace_drv_remove_chanctx(local, ctx); 994 trace_drv_remove_chanctx(local, ctx);
968 if (local->ops->remove_chanctx) 995 if (local->ops->remove_chanctx)
969 local->ops->remove_chanctx(&local->hw, &ctx->conf); 996 local->ops->remove_chanctx(&local->hw, &ctx->conf);
@@ -989,7 +1016,8 @@ static inline int drv_assign_vif_chanctx(struct ieee80211_local *local,
989{ 1016{
990 int ret = 0; 1017 int ret = 0;
991 1018
992 check_sdata_in_driver(sdata); 1019 if (!check_sdata_in_driver(sdata))
1020 return -EIO;
993 1021
994 trace_drv_assign_vif_chanctx(local, sdata, ctx); 1022 trace_drv_assign_vif_chanctx(local, sdata, ctx);
995 if (local->ops->assign_vif_chanctx) { 1023 if (local->ops->assign_vif_chanctx) {
@@ -1007,7 +1035,8 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
1007 struct ieee80211_sub_if_data *sdata, 1035 struct ieee80211_sub_if_data *sdata,
1008 struct ieee80211_chanctx *ctx) 1036 struct ieee80211_chanctx *ctx)
1009{ 1037{
1010 check_sdata_in_driver(sdata); 1038 if (!check_sdata_in_driver(sdata))
1039 return;
1011 1040
1012 trace_drv_unassign_vif_chanctx(local, sdata, ctx); 1041 trace_drv_unassign_vif_chanctx(local, sdata, ctx);
1013 if (local->ops->unassign_vif_chanctx) { 1042 if (local->ops->unassign_vif_chanctx) {
@@ -1024,7 +1053,8 @@ static inline int drv_start_ap(struct ieee80211_local *local,
1024{ 1053{
1025 int ret = 0; 1054 int ret = 0;
1026 1055
1027 check_sdata_in_driver(sdata); 1056 if (!check_sdata_in_driver(sdata))
1057 return -EIO;
1028 1058
1029 trace_drv_start_ap(local, sdata, &sdata->vif.bss_conf); 1059 trace_drv_start_ap(local, sdata, &sdata->vif.bss_conf);
1030 if (local->ops->start_ap) 1060 if (local->ops->start_ap)
@@ -1036,7 +1066,8 @@ static inline int drv_start_ap(struct ieee80211_local *local,
1036static inline void drv_stop_ap(struct ieee80211_local *local, 1066static inline void drv_stop_ap(struct ieee80211_local *local,
1037 struct ieee80211_sub_if_data *sdata) 1067 struct ieee80211_sub_if_data *sdata)
1038{ 1068{
1039 check_sdata_in_driver(sdata); 1069 if (!check_sdata_in_driver(sdata))
1070 return;
1040 1071
1041 trace_drv_stop_ap(local, sdata); 1072 trace_drv_stop_ap(local, sdata);
1042 if (local->ops->stop_ap) 1073 if (local->ops->stop_ap)
@@ -1059,7 +1090,8 @@ drv_set_default_unicast_key(struct ieee80211_local *local,
1059 struct ieee80211_sub_if_data *sdata, 1090 struct ieee80211_sub_if_data *sdata,
1060 int key_idx) 1091 int key_idx)
1061{ 1092{
1062 check_sdata_in_driver(sdata); 1093 if (!check_sdata_in_driver(sdata))
1094 return;
1063 1095
1064 WARN_ON_ONCE(key_idx < -1 || key_idx > 3); 1096 WARN_ON_ONCE(key_idx < -1 || key_idx > 3);
1065 1097
@@ -1101,7 +1133,8 @@ static inline int drv_join_ibss(struct ieee80211_local *local,
1101 int ret = 0; 1133 int ret = 0;
1102 1134
1103 might_sleep(); 1135 might_sleep();
1104 check_sdata_in_driver(sdata); 1136 if (!check_sdata_in_driver(sdata))
1137 return -EIO;
1105 1138
1106 trace_drv_join_ibss(local, sdata, &sdata->vif.bss_conf); 1139 trace_drv_join_ibss(local, sdata, &sdata->vif.bss_conf);
1107 if (local->ops->join_ibss) 1140 if (local->ops->join_ibss)
@@ -1114,7 +1147,8 @@ static inline void drv_leave_ibss(struct ieee80211_local *local,
1114 struct ieee80211_sub_if_data *sdata) 1147 struct ieee80211_sub_if_data *sdata)
1115{ 1148{
1116 might_sleep(); 1149 might_sleep();
1117 check_sdata_in_driver(sdata); 1150 if (!check_sdata_in_driver(sdata))
1151 return;
1118 1152
1119 trace_drv_leave_ibss(local, sdata); 1153 trace_drv_leave_ibss(local, sdata);
1120 if (local->ops->leave_ibss) 1154 if (local->ops->leave_ibss)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f4ba0c4a4314..4668ce9a1d3f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1459,6 +1459,7 @@ __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
1459int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, 1459int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
1460 struct cfg80211_sched_scan_request *req); 1460 struct cfg80211_sched_scan_request *req);
1461int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata); 1461int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata);
1462void ieee80211_sched_scan_end(struct ieee80211_local *local);
1462void ieee80211_sched_scan_stopped_work(struct work_struct *work); 1463void ieee80211_sched_scan_stopped_work(struct work_struct *work);
1463 1464
1464/* off-channel helpers */ 1465/* off-channel helpers */
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 28185c8dc19a..f40661eb75b5 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -1076,12 +1076,8 @@ void ieee80211_sched_scan_results(struct ieee80211_hw *hw)
1076} 1076}
1077EXPORT_SYMBOL(ieee80211_sched_scan_results); 1077EXPORT_SYMBOL(ieee80211_sched_scan_results);
1078 1078
1079void ieee80211_sched_scan_stopped_work(struct work_struct *work) 1079void ieee80211_sched_scan_end(struct ieee80211_local *local)
1080{ 1080{
1081 struct ieee80211_local *local =
1082 container_of(work, struct ieee80211_local,
1083 sched_scan_stopped_work);
1084
1085 mutex_lock(&local->mtx); 1081 mutex_lock(&local->mtx);
1086 1082
1087 if (!rcu_access_pointer(local->sched_scan_sdata)) { 1083 if (!rcu_access_pointer(local->sched_scan_sdata)) {
@@ -1099,6 +1095,15 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)
1099 cfg80211_sched_scan_stopped(local->hw.wiphy); 1095 cfg80211_sched_scan_stopped(local->hw.wiphy);
1100} 1096}
1101 1097
1098void ieee80211_sched_scan_stopped_work(struct work_struct *work)
1099{
1100 struct ieee80211_local *local =
1101 container_of(work, struct ieee80211_local,
1102 sched_scan_stopped_work);
1103
1104 ieee80211_sched_scan_end(local);
1105}
1106
1102void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw) 1107void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw)
1103{ 1108{
1104 struct ieee80211_local *local = hw_to_local(hw); 1109 struct ieee80211_local *local = hw_to_local(hw);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index ad058759e85e..7e0dd4be8097 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1457,6 +1457,44 @@ void ieee80211_stop_device(struct ieee80211_local *local)
1457 drv_stop(local); 1457 drv_stop(local);
1458} 1458}
1459 1459
1460static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
1461{
1462 struct ieee80211_sub_if_data *sdata;
1463 struct ieee80211_chanctx *ctx;
1464
1465 /*
1466 * We get here if during resume the device can't be restarted properly.
1467 * We might also get here if this happens during HW reset, which is a
1468 * slightly different situation and we need to drop all connections in
1469 * the latter case.
1470 *
1471 * Ask cfg80211 to turn off all interfaces, this will result in more
1472 * warnings but at least we'll then get into a clean stopped state.
1473 */
1474
1475 local->resuming = false;
1476 local->suspended = false;
1477 local->started = false;
1478
1479 /* scheduled scan clearly can't be running any more, but tell
1480 * cfg80211 and clear local state
1481 */
1482 ieee80211_sched_scan_end(local);
1483
1484 list_for_each_entry(sdata, &local->interfaces, list)
1485 sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
1486
1487 /* Mark channel contexts as not being in the driver any more to avoid
1488 * removing them from the driver during the shutdown process...
1489 */
1490 mutex_lock(&local->chanctx_mtx);
1491 list_for_each_entry(ctx, &local->chanctx_list, list)
1492 ctx->driver_present = false;
1493 mutex_unlock(&local->chanctx_mtx);
1494
1495 cfg80211_shutdown_all_interfaces(local->hw.wiphy);
1496}
1497
1460static void ieee80211_assign_chanctx(struct ieee80211_local *local, 1498static void ieee80211_assign_chanctx(struct ieee80211_local *local,
1461 struct ieee80211_sub_if_data *sdata) 1499 struct ieee80211_sub_if_data *sdata)
1462{ 1500{
@@ -1520,9 +1558,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1520 */ 1558 */
1521 res = drv_start(local); 1559 res = drv_start(local);
1522 if (res) { 1560 if (res) {
1523 WARN(local->suspended, "Hardware became unavailable " 1561 if (local->suspended)
1524 "upon resume. This could be a software issue " 1562 WARN(1, "Hardware became unavailable upon resume. This could be a software issue prior to suspend or a hardware issue.\n");
1525 "prior to suspend or a hardware issue.\n"); 1563 else
1564 WARN(1, "Hardware became unavailable during restart.\n");
1565 ieee80211_handle_reconfig_failure(local);
1526 return res; 1566 return res;
1527 } 1567 }
1528 1568
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 7e023b74f009..39788711ce6e 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -210,15 +210,12 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
210 } 210 }
211} 211}
212 212
213static int cfg80211_rfkill_set_block(void *data, bool blocked) 213void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
214{ 214{
215 struct cfg80211_registered_device *rdev = data; 215 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
216 struct wireless_dev *wdev; 216 struct wireless_dev *wdev;
217 217
218 if (!blocked) 218 ASSERT_RTNL();
219 return 0;
220
221 rtnl_lock();
222 219
223 list_for_each_entry(wdev, &rdev->wdev_list, list) { 220 list_for_each_entry(wdev, &rdev->wdev_list, list) {
224 if (wdev->netdev) { 221 if (wdev->netdev) {
@@ -234,7 +231,18 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
234 break; 231 break;
235 } 232 }
236 } 233 }
234}
235EXPORT_SYMBOL_GPL(cfg80211_shutdown_all_interfaces);
237 236
237static int cfg80211_rfkill_set_block(void *data, bool blocked)
238{
239 struct cfg80211_registered_device *rdev = data;
240
241 if (!blocked)
242 return 0;
243
244 rtnl_lock();
245 cfg80211_shutdown_all_interfaces(&rdev->wiphy);
238 rtnl_unlock(); 246 rtnl_unlock();
239 247
240 return 0; 248 return 0;