diff options
-rw-r--r-- | net/mac80211/ibss.c | 97 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 7 |
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 | ||
761 | void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata) | 781 | void 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 | ||
781 | static 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 | ||
790 | static void ieee80211_ibss_timer(unsigned long data) | 811 | static 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 | ||
380 | enum ieee80211_ibss_request { | ||
381 | IEEE80211_IBSS_REQ_RUN = 0, | ||
382 | }; | ||
383 | |||
384 | struct ieee80211_if_ibss { | 380 | struct 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; |