aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2014-11-19 05:55:49 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-11-19 12:45:58 -0500
commit6ea0a69ca21bbddab5b3979c2190013b0263e749 (patch)
tree27fe05578c960fa946d68ce8db3dfead88b47b49 /net/mac80211
parentad2b26abc157460ca6fac1a53a2bfeade283adfa (diff)
mac80211: rcu-ify scan and scheduled scan request pointers
In order to use the scan and scheduled scan request pointers during RX to check for randomisation, make them accessible using RCU. Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/scan.c79
-rw-r--r--net/mac80211/util.c7
3 files changed, 56 insertions, 34 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 34168c21bf06..dd27180060b9 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1238,7 +1238,7 @@ struct ieee80211_local {
1238 unsigned long scanning; 1238 unsigned long scanning;
1239 struct cfg80211_ssid scan_ssid; 1239 struct cfg80211_ssid scan_ssid;
1240 struct cfg80211_scan_request *int_scan_req; 1240 struct cfg80211_scan_request *int_scan_req;
1241 struct cfg80211_scan_request *scan_req; 1241 struct cfg80211_scan_request __rcu *scan_req;
1242 struct ieee80211_scan_request *hw_scan_req; 1242 struct ieee80211_scan_request *hw_scan_req;
1243 struct cfg80211_chan_def scan_chandef; 1243 struct cfg80211_chan_def scan_chandef;
1244 enum ieee80211_band hw_scan_band; 1244 enum ieee80211_band hw_scan_band;
@@ -1248,7 +1248,7 @@ struct ieee80211_local {
1248 1248
1249 struct work_struct sched_scan_stopped_work; 1249 struct work_struct sched_scan_stopped_work;
1250 struct ieee80211_sub_if_data __rcu *sched_scan_sdata; 1250 struct ieee80211_sub_if_data __rcu *sched_scan_sdata;
1251 struct cfg80211_sched_scan_request *sched_scan_req; 1251 struct cfg80211_sched_scan_request __rcu *sched_scan_req;
1252 1252
1253 unsigned long leave_oper_channel_time; 1253 unsigned long leave_oper_channel_time;
1254 enum mac80211_scan_state next_scan_state; 1254 enum mac80211_scan_state next_scan_state;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index d23c8d90c3b4..e75e64b8042c 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -234,11 +234,14 @@ ieee80211_prepare_scan_chandef(struct cfg80211_chan_def *chandef,
234/* return false if no more work */ 234/* return false if no more work */
235static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) 235static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
236{ 236{
237 struct cfg80211_scan_request *req = local->scan_req; 237 struct cfg80211_scan_request *req;
238 struct cfg80211_chan_def chandef; 238 struct cfg80211_chan_def chandef;
239 u8 bands_used = 0; 239 u8 bands_used = 0;
240 int i, ielen, n_chans; 240 int i, ielen, n_chans;
241 241
242 req = rcu_dereference_protected(local->scan_req,
243 lockdep_is_held(&local->mtx));
244
242 if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) 245 if (test_bit(SCAN_HW_CANCELLED, &local->scanning))
243 return false; 246 return false;
244 247
@@ -290,6 +293,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
290 struct ieee80211_local *local = hw_to_local(hw); 293 struct ieee80211_local *local = hw_to_local(hw);
291 bool hw_scan = local->ops->hw_scan; 294 bool hw_scan = local->ops->hw_scan;
292 bool was_scanning = local->scanning; 295 bool was_scanning = local->scanning;
296 struct cfg80211_scan_request *scan_req;
293 297
294 lockdep_assert_held(&local->mtx); 298 lockdep_assert_held(&local->mtx);
295 299
@@ -322,9 +326,12 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
322 kfree(local->hw_scan_req); 326 kfree(local->hw_scan_req);
323 local->hw_scan_req = NULL; 327 local->hw_scan_req = NULL;
324 328
325 if (local->scan_req != local->int_scan_req) 329 scan_req = rcu_dereference_protected(local->scan_req,
326 cfg80211_scan_done(local->scan_req, aborted); 330 lockdep_is_held(&local->mtx));
327 local->scan_req = NULL; 331
332 if (scan_req != local->int_scan_req)
333 cfg80211_scan_done(scan_req, aborted);
334 RCU_INIT_POINTER(local->scan_req, NULL);
328 RCU_INIT_POINTER(local->scan_sdata, NULL); 335 RCU_INIT_POINTER(local->scan_sdata, NULL);
329 336
330 local->scanning = 0; 337 local->scanning = 0;
@@ -440,23 +447,26 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
440{ 447{
441 int i; 448 int i;
442 struct ieee80211_sub_if_data *sdata; 449 struct ieee80211_sub_if_data *sdata;
450 struct cfg80211_scan_request *scan_req;
443 enum ieee80211_band band = local->hw.conf.chandef.chan->band; 451 enum ieee80211_band band = local->hw.conf.chandef.chan->band;
444 u32 tx_flags; 452 u32 tx_flags;
445 453
454 scan_req = rcu_dereference_protected(local->scan_req,
455 lockdep_is_held(&local->mtx));
456
446 tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK; 457 tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
447 if (local->scan_req->no_cck) 458 if (scan_req->no_cck)
448 tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE; 459 tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
449 460
450 sdata = rcu_dereference_protected(local->scan_sdata, 461 sdata = rcu_dereference_protected(local->scan_sdata,
451 lockdep_is_held(&local->mtx)); 462 lockdep_is_held(&local->mtx));
452 463
453 for (i = 0; i < local->scan_req->n_ssids; i++) 464 for (i = 0; i < scan_req->n_ssids; i++)
454 ieee80211_send_probe_req( 465 ieee80211_send_probe_req(
455 sdata, NULL, 466 sdata, NULL,
456 local->scan_req->ssids[i].ssid, 467 scan_req->ssids[i].ssid, scan_req->ssids[i].ssid_len,
457 local->scan_req->ssids[i].ssid_len, 468 scan_req->ie, scan_req->ie_len,
458 local->scan_req->ie, local->scan_req->ie_len, 469 scan_req->rates[band], false,
459 local->scan_req->rates[band], false,
460 tx_flags, local->hw.conf.chandef.chan, true); 470 tx_flags, local->hw.conf.chandef.chan, true);
461 471
462 /* 472 /*
@@ -480,7 +490,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
480 490
481 if (!ieee80211_can_scan(local, sdata)) { 491 if (!ieee80211_can_scan(local, sdata)) {
482 /* wait for the work to finish/time out */ 492 /* wait for the work to finish/time out */
483 local->scan_req = req; 493 rcu_assign_pointer(local->scan_req, req);
484 rcu_assign_pointer(local->scan_sdata, sdata); 494 rcu_assign_pointer(local->scan_sdata, sdata);
485 return 0; 495 return 0;
486 } 496 }
@@ -530,7 +540,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
530 */ 540 */
531 } 541 }
532 542
533 local->scan_req = req; 543 rcu_assign_pointer(local->scan_req, req);
534 rcu_assign_pointer(local->scan_sdata, sdata); 544 rcu_assign_pointer(local->scan_sdata, sdata);
535 545
536 if (local->ops->hw_scan) { 546 if (local->ops->hw_scan) {
@@ -558,7 +568,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
558 568
559 if ((req->channels[0]->flags & 569 if ((req->channels[0]->flags &
560 IEEE80211_CHAN_NO_IR) || 570 IEEE80211_CHAN_NO_IR) ||
561 !local->scan_req->n_ssids) { 571 !req->n_ssids) {
562 next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; 572 next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
563 } else { 573 } else {
564 ieee80211_scan_state_send_probe(local, &next_delay); 574 ieee80211_scan_state_send_probe(local, &next_delay);
@@ -617,6 +627,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
617 struct ieee80211_sub_if_data *sdata; 627 struct ieee80211_sub_if_data *sdata;
618 struct ieee80211_channel *next_chan; 628 struct ieee80211_channel *next_chan;
619 enum mac80211_scan_state next_scan_state; 629 enum mac80211_scan_state next_scan_state;
630 struct cfg80211_scan_request *scan_req;
620 631
621 /* 632 /*
622 * check if at least one STA interface is associated, 633 * check if at least one STA interface is associated,
@@ -641,7 +652,10 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
641 } 652 }
642 mutex_unlock(&local->iflist_mtx); 653 mutex_unlock(&local->iflist_mtx);
643 654
644 next_chan = local->scan_req->channels[local->scan_channel_idx]; 655 scan_req = rcu_dereference_protected(local->scan_req,
656 lockdep_is_held(&local->mtx));
657
658 next_chan = scan_req->channels[local->scan_channel_idx];
645 659
646 /* 660 /*
647 * we're currently scanning a different channel, let's 661 * we're currently scanning a different channel, let's
@@ -656,7 +670,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
656 local->leave_oper_channel_time + HZ / 8); 670 local->leave_oper_channel_time + HZ / 8);
657 671
658 if (associated && !tx_empty) { 672 if (associated && !tx_empty) {
659 if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) 673 if (scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
660 next_scan_state = SCAN_ABORT; 674 next_scan_state = SCAN_ABORT;
661 else 675 else
662 next_scan_state = SCAN_SUSPEND; 676 next_scan_state = SCAN_SUSPEND;
@@ -677,14 +691,18 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
677 int skip; 691 int skip;
678 struct ieee80211_channel *chan; 692 struct ieee80211_channel *chan;
679 enum nl80211_bss_scan_width oper_scan_width; 693 enum nl80211_bss_scan_width oper_scan_width;
694 struct cfg80211_scan_request *scan_req;
695
696 scan_req = rcu_dereference_protected(local->scan_req,
697 lockdep_is_held(&local->mtx));
680 698
681 skip = 0; 699 skip = 0;
682 chan = local->scan_req->channels[local->scan_channel_idx]; 700 chan = scan_req->channels[local->scan_channel_idx];
683 701
684 local->scan_chandef.chan = chan; 702 local->scan_chandef.chan = chan;
685 local->scan_chandef.center_freq1 = chan->center_freq; 703 local->scan_chandef.center_freq1 = chan->center_freq;
686 local->scan_chandef.center_freq2 = 0; 704 local->scan_chandef.center_freq2 = 0;
687 switch (local->scan_req->scan_width) { 705 switch (scan_req->scan_width) {
688 case NL80211_BSS_CHAN_WIDTH_5: 706 case NL80211_BSS_CHAN_WIDTH_5:
689 local->scan_chandef.width = NL80211_CHAN_WIDTH_5; 707 local->scan_chandef.width = NL80211_CHAN_WIDTH_5;
690 break; 708 break;
@@ -698,7 +716,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
698 oper_scan_width = cfg80211_chandef_to_scan_width( 716 oper_scan_width = cfg80211_chandef_to_scan_width(
699 &local->_oper_chandef); 717 &local->_oper_chandef);
700 if (chan == local->_oper_chandef.chan && 718 if (chan == local->_oper_chandef.chan &&
701 oper_scan_width == local->scan_req->scan_width) 719 oper_scan_width == scan_req->scan_width)
702 local->scan_chandef = local->_oper_chandef; 720 local->scan_chandef = local->_oper_chandef;
703 else 721 else
704 local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT; 722 local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
@@ -727,8 +745,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
727 * 745 *
728 * In any case, it is not necessary for a passive scan. 746 * In any case, it is not necessary for a passive scan.
729 */ 747 */
730 if (chan->flags & IEEE80211_CHAN_NO_IR || 748 if (chan->flags & IEEE80211_CHAN_NO_IR || !scan_req->n_ssids) {
731 !local->scan_req->n_ssids) {
732 *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; 749 *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
733 local->next_scan_state = SCAN_DECISION; 750 local->next_scan_state = SCAN_DECISION;
734 return; 751 return;
@@ -777,6 +794,7 @@ void ieee80211_scan_work(struct work_struct *work)
777 struct ieee80211_local *local = 794 struct ieee80211_local *local =
778 container_of(work, struct ieee80211_local, scan_work.work); 795 container_of(work, struct ieee80211_local, scan_work.work);
779 struct ieee80211_sub_if_data *sdata; 796 struct ieee80211_sub_if_data *sdata;
797 struct cfg80211_scan_request *scan_req;
780 unsigned long next_delay = 0; 798 unsigned long next_delay = 0;
781 bool aborted; 799 bool aborted;
782 800
@@ -784,6 +802,8 @@ void ieee80211_scan_work(struct work_struct *work)
784 802
785 sdata = rcu_dereference_protected(local->scan_sdata, 803 sdata = rcu_dereference_protected(local->scan_sdata,
786 lockdep_is_held(&local->mtx)); 804 lockdep_is_held(&local->mtx));
805 scan_req = rcu_dereference_protected(local->scan_req,
806 lockdep_is_held(&local->mtx));
787 807
788 /* When scanning on-channel, the first-callback means completed. */ 808 /* When scanning on-channel, the first-callback means completed. */
789 if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { 809 if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) {
@@ -796,20 +816,19 @@ void ieee80211_scan_work(struct work_struct *work)
796 goto out_complete; 816 goto out_complete;
797 } 817 }
798 818
799 if (!sdata || !local->scan_req) 819 if (!sdata || !scan_req)
800 goto out; 820 goto out;
801 821
802 if (!local->scanning) { 822 if (!local->scanning) {
803 struct cfg80211_scan_request *req = local->scan_req;
804 int rc; 823 int rc;
805 824
806 local->scan_req = NULL; 825 RCU_INIT_POINTER(local->scan_req, NULL);
807 RCU_INIT_POINTER(local->scan_sdata, NULL); 826 RCU_INIT_POINTER(local->scan_sdata, NULL);
808 827
809 rc = __ieee80211_start_scan(sdata, req); 828 rc = __ieee80211_start_scan(sdata, scan_req);
810 if (rc) { 829 if (rc) {
811 /* need to complete scan in cfg80211 */ 830 /* need to complete scan in cfg80211 */
812 local->scan_req = req; 831 rcu_assign_pointer(local->scan_req, scan_req);
813 aborted = true; 832 aborted = true;
814 goto out_complete; 833 goto out_complete;
815 } else 834 } else
@@ -829,7 +848,7 @@ void ieee80211_scan_work(struct work_struct *work)
829 switch (local->next_scan_state) { 848 switch (local->next_scan_state) {
830 case SCAN_DECISION: 849 case SCAN_DECISION:
831 /* if no more bands/channels left, complete scan */ 850 /* if no more bands/channels left, complete scan */
832 if (local->scan_channel_idx >= local->scan_req->n_channels) { 851 if (local->scan_channel_idx >= scan_req->n_channels) {
833 aborted = false; 852 aborted = false;
834 goto out_complete; 853 goto out_complete;
835 } 854 }
@@ -1043,7 +1062,7 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
1043 ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); 1062 ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
1044 if (ret == 0) { 1063 if (ret == 0) {
1045 rcu_assign_pointer(local->sched_scan_sdata, sdata); 1064 rcu_assign_pointer(local->sched_scan_sdata, sdata);
1046 local->sched_scan_req = req; 1065 rcu_assign_pointer(local->sched_scan_req, req);
1047 } 1066 }
1048 1067
1049 kfree(ie); 1068 kfree(ie);
@@ -1052,7 +1071,7 @@ out:
1052 if (ret) { 1071 if (ret) {
1053 /* Clean in case of failure after HW restart or upon resume. */ 1072 /* Clean in case of failure after HW restart or upon resume. */
1054 RCU_INIT_POINTER(local->sched_scan_sdata, NULL); 1073 RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
1055 local->sched_scan_req = NULL; 1074 RCU_INIT_POINTER(local->sched_scan_req, NULL);
1056 } 1075 }
1057 1076
1058 return ret; 1077 return ret;
@@ -1090,7 +1109,7 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
1090 } 1109 }
1091 1110
1092 /* We don't want to restart sched scan anymore. */ 1111 /* We don't want to restart sched scan anymore. */
1093 local->sched_scan_req = NULL; 1112 RCU_INIT_POINTER(local->sched_scan_req, NULL);
1094 1113
1095 if (rcu_access_pointer(local->sched_scan_sdata)) { 1114 if (rcu_access_pointer(local->sched_scan_sdata)) {
1096 ret = drv_sched_scan_stop(local, sdata); 1115 ret = drv_sched_scan_stop(local, sdata);
@@ -1125,7 +1144,7 @@ void ieee80211_sched_scan_end(struct ieee80211_local *local)
1125 RCU_INIT_POINTER(local->sched_scan_sdata, NULL); 1144 RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
1126 1145
1127 /* If sched scan was aborted by the driver. */ 1146 /* If sched scan was aborted by the driver. */
1128 local->sched_scan_req = NULL; 1147 RCU_INIT_POINTER(local->sched_scan_req, NULL);
1129 1148
1130 mutex_unlock(&local->mtx); 1149 mutex_unlock(&local->mtx);
1131 1150
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 745a8a9cbbb5..0ad534abc008 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1721,6 +1721,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1721 int res, i; 1721 int res, i;
1722 bool reconfig_due_to_wowlan = false; 1722 bool reconfig_due_to_wowlan = false;
1723 struct ieee80211_sub_if_data *sched_scan_sdata; 1723 struct ieee80211_sub_if_data *sched_scan_sdata;
1724 struct cfg80211_sched_scan_request *sched_scan_req;
1724 bool sched_scan_stopped = false; 1725 bool sched_scan_stopped = false;
1725 1726
1726#ifdef CONFIG_PM 1727#ifdef CONFIG_PM
@@ -2011,13 +2012,15 @@ int ieee80211_reconfig(struct ieee80211_local *local)
2011 mutex_lock(&local->mtx); 2012 mutex_lock(&local->mtx);
2012 sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, 2013 sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
2013 lockdep_is_held(&local->mtx)); 2014 lockdep_is_held(&local->mtx));
2014 if (sched_scan_sdata && local->sched_scan_req) 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)
2015 /* 2018 /*
2016 * Sched scan stopped, but we don't want to report it. Instead, 2019 * Sched scan stopped, but we don't want to report it. Instead,
2017 * we're trying to reschedule. 2020 * we're trying to reschedule.
2018 */ 2021 */
2019 if (__ieee80211_request_sched_scan_start(sched_scan_sdata, 2022 if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
2020 local->sched_scan_req)) 2023 sched_scan_req))
2021 sched_scan_stopped = true; 2024 sched_scan_stopped = true;
2022 mutex_unlock(&local->mtx); 2025 mutex_unlock(&local->mtx);
2023 2026