aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-07-21 05:30:27 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-07-21 15:13:42 -0400
commit7a17a33c0da37f8d24222c967550d19dabf13617 (patch)
tree14e736fd4add85528d24c62b0b9268dde0d87eab /net
parentbc05d19f4b884b1dbbce48912710ae3f972c89d2 (diff)
mac80211: proper IBSS locking
IBSS has never had locking, instead relying on some memory barriers etc. That's hard to get right, and I think we had it wrong too until the previous patch. Since this is not performance sensitive, it doesn't make sense to have the maintenance overhead of that, so add proper locking. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/ibss.c97
-rw-r--r--net/mac80211/ieee80211_i.h7
2 files changed, 54 insertions, 50 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 090e344d5f90..c691780725a7 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -43,6 +43,8 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
43{ 43{
44 u16 auth_alg, auth_transaction, status_code; 44 u16 auth_alg, auth_transaction, status_code;
45 45
46 lockdep_assert_held(&sdata->u.ibss.mtx);
47
46 if (len < 24 + 6) 48 if (len < 24 + 6)
47 return; 49 return;
48 50
@@ -78,6 +80,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
78 u32 bss_change; 80 u32 bss_change;
79 u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; 81 u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
80 82
83 lockdep_assert_held(&ifibss->mtx);
84
81 /* Reset own TSF to allow time synchronization work. */ 85 /* Reset own TSF to allow time synchronization work. */
82 drv_reset_tsf(local); 86 drv_reset_tsf(local);
83 87
@@ -205,6 +209,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
205 int i, j; 209 int i, j;
206 u16 beacon_int = cbss->beacon_interval; 210 u16 beacon_int = cbss->beacon_interval;
207 211
212 lockdep_assert_held(&sdata->u.ibss.mtx);
213
208 if (beacon_int < 10) 214 if (beacon_int < 10)
209 beacon_int = 10; 215 beacon_int = 10;
210 216
@@ -449,6 +455,8 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
449 int active = 0; 455 int active = 0;
450 struct sta_info *sta; 456 struct sta_info *sta;
451 457
458 lockdep_assert_held(&sdata->u.ibss.mtx);
459
452 rcu_read_lock(); 460 rcu_read_lock();
453 461
454 list_for_each_entry_rcu(sta, &local->sta_list, list) { 462 list_for_each_entry_rcu(sta, &local->sta_list, list) {
@@ -473,6 +481,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
473{ 481{
474 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; 482 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
475 483
484 lockdep_assert_held(&ifibss->mtx);
485
476 mod_timer(&ifibss->timer, 486 mod_timer(&ifibss->timer,
477 round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); 487 round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
478 488
@@ -505,6 +515,8 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
505 u16 capability; 515 u16 capability;
506 int i; 516 int i;
507 517
518 lockdep_assert_held(&ifibss->mtx);
519
508 if (ifibss->fixed_bssid) { 520 if (ifibss->fixed_bssid) {
509 memcpy(bssid, ifibss->bssid, ETH_ALEN); 521 memcpy(bssid, ifibss->bssid, ETH_ALEN);
510 } else { 522 } else {
@@ -549,6 +561,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
549 int active_ibss; 561 int active_ibss;
550 u16 capability; 562 u16 capability;
551 563
564 lockdep_assert_held(&ifibss->mtx);
565
552 active_ibss = ieee80211_sta_active_ibss(sdata); 566 active_ibss = ieee80211_sta_active_ibss(sdata);
553#ifdef CONFIG_MAC80211_IBSS_DEBUG 567#ifdef CONFIG_MAC80211_IBSS_DEBUG
554 printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", 568 printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
@@ -637,6 +651,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
637 struct ieee80211_mgmt *resp; 651 struct ieee80211_mgmt *resp;
638 u8 *pos, *end; 652 u8 *pos, *end;
639 653
654 lockdep_assert_held(&ifibss->mtx);
655
640 if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || 656 if (ifibss->state != IEEE80211_IBSS_MLME_JOINED ||
641 len < 24 + 2 || !ifibss->presp) 657 len < 24 + 2 || !ifibss->presp)
642 return; 658 return;
@@ -740,6 +756,8 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
740 mgmt = (struct ieee80211_mgmt *) skb->data; 756 mgmt = (struct ieee80211_mgmt *) skb->data;
741 fc = le16_to_cpu(mgmt->frame_control); 757 fc = le16_to_cpu(mgmt->frame_control);
742 758
759 mutex_lock(&sdata->u.ibss.mtx);
760
743 switch (fc & IEEE80211_FCTL_STYPE) { 761 switch (fc & IEEE80211_FCTL_STYPE) {
744 case IEEE80211_STYPE_PROBE_REQ: 762 case IEEE80211_STYPE_PROBE_REQ:
745 ieee80211_rx_mgmt_probe_req(sdata, mgmt, skb->len); 763 ieee80211_rx_mgmt_probe_req(sdata, mgmt, skb->len);
@@ -756,14 +774,23 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
756 ieee80211_rx_mgmt_auth_ibss(sdata, mgmt, skb->len); 774 ieee80211_rx_mgmt_auth_ibss(sdata, mgmt, skb->len);
757 break; 775 break;
758 } 776 }
777
778 mutex_unlock(&sdata->u.ibss.mtx);
759} 779}
760 780
761void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata) 781void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata)
762{ 782{
763 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; 783 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
764 784
765 if (!test_and_clear_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request)) 785 mutex_lock(&ifibss->mtx);
766 return; 786
787 /*
788 * Work could be scheduled after scan or similar
789 * when we aren't even joined (or trying) with a
790 * network.
791 */
792 if (!ifibss->ssid_len)
793 goto out;
767 794
768 switch (ifibss->state) { 795 switch (ifibss->state) {
769 case IEEE80211_IBSS_MLME_SEARCH: 796 case IEEE80211_IBSS_MLME_SEARCH:
@@ -776,15 +803,9 @@ void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata)
776 WARN_ON(1); 803 WARN_ON(1);
777 break; 804 break;
778 } 805 }
779}
780 806
781static void ieee80211_queue_ibss_work(struct ieee80211_sub_if_data *sdata) 807 out:
782{ 808 mutex_unlock(&ifibss->mtx);
783 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
784 struct ieee80211_local *local = sdata->local;
785
786 set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request);
787 ieee80211_queue_work(&local->hw, &sdata->work);
788} 809}
789 810
790static void ieee80211_ibss_timer(unsigned long data) 811static void ieee80211_ibss_timer(unsigned long data)
@@ -799,7 +820,7 @@ static void ieee80211_ibss_timer(unsigned long data)
799 return; 820 return;
800 } 821 }
801 822
802 ieee80211_queue_ibss_work(sdata); 823 ieee80211_queue_work(&local->hw, &sdata->work);
803} 824}
804 825
805#ifdef CONFIG_PM 826#ifdef CONFIG_PM
@@ -828,6 +849,7 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
828 849
829 setup_timer(&ifibss->timer, ieee80211_ibss_timer, 850 setup_timer(&ifibss->timer, ieee80211_ibss_timer,
830 (unsigned long) sdata); 851 (unsigned long) sdata);
852 mutex_init(&ifibss->mtx);
831} 853}
832 854
833/* scan finished notification */ 855/* scan finished notification */
@@ -841,10 +863,8 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local)
841 continue; 863 continue;
842 if (sdata->vif.type != NL80211_IFTYPE_ADHOC) 864 if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
843 continue; 865 continue;
844 if (!sdata->u.ibss.ssid_len)
845 continue;
846 sdata->u.ibss.last_scan_completed = jiffies; 866 sdata->u.ibss.last_scan_completed = jiffies;
847 ieee80211_queue_ibss_work(sdata); 867 ieee80211_queue_work(&local->hw, &sdata->work);
848 } 868 }
849 mutex_unlock(&local->iflist_mtx); 869 mutex_unlock(&local->iflist_mtx);
850} 870}
@@ -854,6 +874,17 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
854{ 874{
855 struct sk_buff *skb; 875 struct sk_buff *skb;
856 876
877 skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
878 36 /* bitrates */ +
879 34 /* SSID */ +
880 3 /* DS params */ +
881 4 /* IBSS params */ +
882 params->ie_len);
883 if (!skb)
884 return -ENOMEM;
885
886 mutex_lock(&sdata->u.ibss.mtx);
887
857 if (params->bssid) { 888 if (params->bssid) {
858 memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); 889 memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN);
859 sdata->u.ibss.fixed_bssid = true; 890 sdata->u.ibss.fixed_bssid = true;
@@ -882,35 +913,19 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
882 sdata->u.ibss.ie_len = params->ie_len; 913 sdata->u.ibss.ie_len = params->ie_len;
883 } 914 }
884 915
885 skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
886 36 /* bitrates */ +
887 34 /* SSID */ +
888 3 /* DS params */ +
889 4 /* IBSS params */ +
890 params->ie_len);
891 if (!skb)
892 return -ENOMEM;
893
894 sdata->u.ibss.skb = skb; 916 sdata->u.ibss.skb = skb;
895 sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH; 917 sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH;
896 sdata->u.ibss.ibss_join_req = jiffies; 918 sdata->u.ibss.ibss_join_req = jiffies;
897 919
898 memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN); 920 memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN);
899
900 /*
901 * The ssid_len setting below is used to see whether
902 * we are active, and we need all other settings
903 * before that may get visible.
904 */
905 mb();
906
907 sdata->u.ibss.ssid_len = params->ssid_len; 921 sdata->u.ibss.ssid_len = params->ssid_len;
908 922
909 ieee80211_recalc_idle(sdata->local); 923 ieee80211_recalc_idle(sdata->local);
910 924
911 set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
912 ieee80211_queue_work(&sdata->local->hw, &sdata->work); 925 ieee80211_queue_work(&sdata->local->hw, &sdata->work);
913 926
927 mutex_unlock(&sdata->u.ibss.mtx);
928
914 return 0; 929 return 0;
915} 930}
916 931
@@ -921,7 +936,9 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
921 struct ieee80211_local *local = sdata->local; 936 struct ieee80211_local *local = sdata->local;
922 struct cfg80211_bss *cbss; 937 struct cfg80211_bss *cbss;
923 u16 capability; 938 u16 capability;
924 int active_ibss = 0; 939 int active_ibss;
940
941 mutex_lock(&sdata->u.ibss.mtx);
925 942
926 active_ibss = ieee80211_sta_active_ibss(sdata); 943 active_ibss = ieee80211_sta_active_ibss(sdata);
927 944
@@ -959,19 +976,9 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
959 memset(sdata->u.ibss.bssid, 0, ETH_ALEN); 976 memset(sdata->u.ibss.bssid, 0, ETH_ALEN);
960 sdata->u.ibss.ssid_len = 0; 977 sdata->u.ibss.ssid_len = 0;
961 978
962 /*
963 * ssid_len indicates active or not, so needs to be visible to
964 * everybody, especially ieee80211_ibss_notify_scan_completed,
965 * so it won't restart the timer after we remove it here.
966 */
967 mb();
968
969 del_timer_sync(&sdata->u.ibss.timer); 979 del_timer_sync(&sdata->u.ibss.timer);
970 clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); 980
971 /* 981 mutex_unlock(&sdata->u.ibss.mtx);
972 * Since the REQ_RUN bit is clear, the work won't do
973 * anything if it runs after this.
974 */
975 982
976 ieee80211_recalc_idle(sdata->local); 983 ieee80211_recalc_idle(sdata->local);
977 984
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f9251d50192c..c6b5c2d3ffde 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -377,14 +377,11 @@ struct ieee80211_if_managed {
377 int last_cqm_event_signal; 377 int last_cqm_event_signal;
378}; 378};
379 379
380enum ieee80211_ibss_request {
381 IEEE80211_IBSS_REQ_RUN = 0,
382};
383
384struct ieee80211_if_ibss { 380struct ieee80211_if_ibss {
385 struct timer_list timer; 381 struct timer_list timer;
386 382
387 unsigned long request; 383 struct mutex mtx;
384
388 unsigned long last_scan_completed; 385 unsigned long last_scan_completed;
389 386
390 u32 basic_rates; 387 u32 basic_rates;