diff options
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/iface.c | 9 | ||||
-rw-r--r-- | net/mac80211/scan.c | 33 |
3 files changed, 30 insertions, 14 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c3241c3ec6d1..9f2534a41243 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -972,7 +972,7 @@ struct ieee80211_local { | |||
972 | unsigned long leave_oper_channel_time; | 972 | unsigned long leave_oper_channel_time; |
973 | enum mac80211_scan_state next_scan_state; | 973 | enum mac80211_scan_state next_scan_state; |
974 | struct delayed_work scan_work; | 974 | struct delayed_work scan_work; |
975 | struct ieee80211_sub_if_data *scan_sdata; | 975 | struct ieee80211_sub_if_data __rcu *scan_sdata; |
976 | enum nl80211_channel_type _oper_channel_type; | 976 | enum nl80211_channel_type _oper_channel_type; |
977 | struct ieee80211_channel *oper_channel, *csa_channel; | 977 | struct ieee80211_channel *oper_channel, *csa_channel; |
978 | 978 | ||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b1edf60fbba7..e3c49748ce8f 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -112,10 +112,11 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
112 | } | 112 | } |
113 | } | 113 | } |
114 | 114 | ||
115 | if (local->scan_sdata && | 115 | sdata = rcu_dereference_protected(local->scan_sdata, |
116 | !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { | 116 | lockdep_is_held(&local->mtx)); |
117 | if (sdata && !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { | ||
117 | scanning = true; | 118 | scanning = true; |
118 | local->scan_sdata->vif.bss_conf.idle = false; | 119 | sdata->vif.bss_conf.idle = false; |
119 | } | 120 | } |
120 | 121 | ||
121 | list_for_each_entry(sdata, &local->interfaces, list) { | 122 | list_for_each_entry(sdata, &local->interfaces, list) { |
@@ -628,7 +629,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
628 | 629 | ||
629 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | 630 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); |
630 | 631 | ||
631 | if (local->scan_sdata == sdata) | 632 | if (rcu_access_pointer(local->scan_sdata) == sdata) |
632 | ieee80211_scan_cancel(local); | 633 | ieee80211_scan_cancel(local); |
633 | 634 | ||
634 | /* | 635 | /* |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 1ff04f689d1f..704dcf847761 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -293,7 +293,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, | |||
293 | return; | 293 | return; |
294 | 294 | ||
295 | if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { | 295 | if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { |
296 | int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req); | 296 | int rc; |
297 | |||
298 | rc = drv_hw_scan(local, | ||
299 | rcu_dereference_protected(local->scan_sdata, | ||
300 | lockdep_is_held(&local->mtx)), | ||
301 | local->hw_scan_req); | ||
302 | |||
297 | if (rc == 0) | 303 | if (rc == 0) |
298 | return; | 304 | return; |
299 | } | 305 | } |
@@ -394,7 +400,10 @@ void ieee80211_run_deferred_scan(struct ieee80211_local *local) | |||
394 | if (!local->scan_req || local->scanning) | 400 | if (!local->scan_req || local->scanning) |
395 | return; | 401 | return; |
396 | 402 | ||
397 | if (!ieee80211_can_scan(local, local->scan_sdata)) | 403 | if (!ieee80211_can_scan(local, |
404 | rcu_dereference_protected( | ||
405 | local->scan_sdata, | ||
406 | lockdep_is_held(&local->mtx)))) | ||
398 | return; | 407 | return; |
399 | 408 | ||
400 | ieee80211_queue_delayed_work(&local->hw, &local->scan_work, | 409 | ieee80211_queue_delayed_work(&local->hw, &local->scan_work, |
@@ -405,9 +414,12 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | |||
405 | unsigned long *next_delay) | 414 | unsigned long *next_delay) |
406 | { | 415 | { |
407 | int i; | 416 | int i; |
408 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | 417 | struct ieee80211_sub_if_data *sdata; |
409 | enum ieee80211_band band = local->hw.conf.channel->band; | 418 | enum ieee80211_band band = local->hw.conf.channel->band; |
410 | 419 | ||
420 | sdata = rcu_dereference_protected(local->scan_sdata, | ||
421 | lockdep_is_held(&local->mtx));; | ||
422 | |||
411 | for (i = 0; i < local->scan_req->n_ssids; i++) | 423 | for (i = 0; i < local->scan_req->n_ssids; i++) |
412 | ieee80211_send_probe_req( | 424 | ieee80211_send_probe_req( |
413 | sdata, NULL, | 425 | sdata, NULL, |
@@ -439,7 +451,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
439 | if (!ieee80211_can_scan(local, sdata)) { | 451 | if (!ieee80211_can_scan(local, sdata)) { |
440 | /* wait for the work to finish/time out */ | 452 | /* wait for the work to finish/time out */ |
441 | local->scan_req = req; | 453 | local->scan_req = req; |
442 | local->scan_sdata = sdata; | 454 | rcu_assign_pointer(local->scan_sdata, sdata); |
443 | return 0; | 455 | return 0; |
444 | } | 456 | } |
445 | 457 | ||
@@ -473,7 +485,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
473 | } | 485 | } |
474 | 486 | ||
475 | local->scan_req = req; | 487 | local->scan_req = req; |
476 | local->scan_sdata = sdata; | 488 | rcu_assign_pointer(local->scan_sdata, sdata); |
477 | 489 | ||
478 | if (local->ops->hw_scan) { | 490 | if (local->ops->hw_scan) { |
479 | __set_bit(SCAN_HW_SCANNING, &local->scanning); | 491 | __set_bit(SCAN_HW_SCANNING, &local->scanning); |
@@ -533,7 +545,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
533 | ieee80211_recalc_idle(local); | 545 | ieee80211_recalc_idle(local); |
534 | 546 | ||
535 | local->scan_req = NULL; | 547 | local->scan_req = NULL; |
536 | local->scan_sdata = NULL; | 548 | rcu_assign_pointer(local->scan_sdata, NULL); |
537 | } | 549 | } |
538 | 550 | ||
539 | return rc; | 551 | return rc; |
@@ -720,7 +732,8 @@ void ieee80211_scan_work(struct work_struct *work) | |||
720 | 732 | ||
721 | mutex_lock(&local->mtx); | 733 | mutex_lock(&local->mtx); |
722 | 734 | ||
723 | sdata = local->scan_sdata; | 735 | sdata = rcu_dereference_protected(local->scan_sdata, |
736 | lockdep_is_held(&local->mtx)); | ||
724 | 737 | ||
725 | /* When scanning on-channel, the first-callback means completed. */ | 738 | /* When scanning on-channel, the first-callback means completed. */ |
726 | if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { | 739 | if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { |
@@ -741,7 +754,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
741 | int rc; | 754 | int rc; |
742 | 755 | ||
743 | local->scan_req = NULL; | 756 | local->scan_req = NULL; |
744 | local->scan_sdata = NULL; | 757 | rcu_assign_pointer(local->scan_sdata, NULL); |
745 | 758 | ||
746 | rc = __ieee80211_start_scan(sdata, req); | 759 | rc = __ieee80211_start_scan(sdata, req); |
747 | if (rc) { | 760 | if (rc) { |
@@ -893,7 +906,9 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) | |||
893 | 906 | ||
894 | if (test_bit(SCAN_HW_SCANNING, &local->scanning)) { | 907 | if (test_bit(SCAN_HW_SCANNING, &local->scanning)) { |
895 | if (local->ops->cancel_hw_scan) | 908 | if (local->ops->cancel_hw_scan) |
896 | drv_cancel_hw_scan(local, local->scan_sdata); | 909 | drv_cancel_hw_scan(local, |
910 | rcu_dereference_protected(local->scan_sdata, | ||
911 | lockdep_is_held(&local->mtx))); | ||
897 | goto out; | 912 | goto out; |
898 | } | 913 | } |
899 | 914 | ||