aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ibss.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/ibss.c')
-rw-r--r--net/mac80211/ibss.c90
1 files changed, 33 insertions, 57 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 27a39de89679..2796a198728f 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -293,14 +293,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
293 radar_required = true; 293 radar_required = true;
294 } 294 }
295 295
296 mutex_lock(&local->mtx);
296 ieee80211_vif_release_channel(sdata); 297 ieee80211_vif_release_channel(sdata);
297 if (ieee80211_vif_use_channel(sdata, &chandef, 298 if (ieee80211_vif_use_channel(sdata, &chandef,
298 ifibss->fixed_channel ? 299 ifibss->fixed_channel ?
299 IEEE80211_CHANCTX_SHARED : 300 IEEE80211_CHANCTX_SHARED :
300 IEEE80211_CHANCTX_EXCLUSIVE)) { 301 IEEE80211_CHANCTX_EXCLUSIVE)) {
301 sdata_info(sdata, "Failed to join IBSS, no channel context\n"); 302 sdata_info(sdata, "Failed to join IBSS, no channel context\n");
303 mutex_unlock(&local->mtx);
302 return; 304 return;
303 } 305 }
306 mutex_unlock(&local->mtx);
304 307
305 memcpy(ifibss->bssid, bssid, ETH_ALEN); 308 memcpy(ifibss->bssid, bssid, ETH_ALEN);
306 309
@@ -363,7 +366,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
363 sdata->vif.bss_conf.ssid_len = 0; 366 sdata->vif.bss_conf.ssid_len = 0;
364 RCU_INIT_POINTER(ifibss->presp, NULL); 367 RCU_INIT_POINTER(ifibss->presp, NULL);
365 kfree_rcu(presp, rcu_head); 368 kfree_rcu(presp, rcu_head);
369 mutex_lock(&local->mtx);
366 ieee80211_vif_release_channel(sdata); 370 ieee80211_vif_release_channel(sdata);
371 mutex_unlock(&local->mtx);
367 sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n", 372 sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n",
368 err); 373 err);
369 return; 374 return;
@@ -522,7 +527,7 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
522 if (csa_settings) 527 if (csa_settings)
523 ieee80211_send_action_csa(sdata, csa_settings); 528 ieee80211_send_action_csa(sdata, csa_settings);
524 529
525 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); 530 return BSS_CHANGED_BEACON;
526 out: 531 out:
527 return ret; 532 return ret;
528} 533}
@@ -534,7 +539,8 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
534 int err; 539 int err;
535 u16 capability; 540 u16 capability;
536 541
537 sdata_lock(sdata); 542 sdata_assert_lock(sdata);
543
538 /* update cfg80211 bss information with the new channel */ 544 /* update cfg80211 bss information with the new channel */
539 if (!is_zero_ether_addr(ifibss->bssid)) { 545 if (!is_zero_ether_addr(ifibss->bssid)) {
540 capability = WLAN_CAPABILITY_IBSS; 546 capability = WLAN_CAPABILITY_IBSS;
@@ -550,19 +556,21 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
550 capability); 556 capability);
551 /* XXX: should not really modify cfg80211 data */ 557 /* XXX: should not really modify cfg80211 data */
552 if (cbss) { 558 if (cbss) {
553 cbss->channel = sdata->local->csa_chandef.chan; 559 cbss->channel = sdata->csa_chandef.chan;
554 cfg80211_put_bss(sdata->local->hw.wiphy, cbss); 560 cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
555 } 561 }
556 } 562 }
557 563
558 ifibss->chandef = sdata->local->csa_chandef; 564 ifibss->chandef = sdata->csa_chandef;
559 565
560 /* generate the beacon */ 566 /* generate the beacon */
561 err = ieee80211_ibss_csa_beacon(sdata, NULL); 567 err = ieee80211_ibss_csa_beacon(sdata, NULL);
562 sdata_unlock(sdata);
563 if (err < 0) 568 if (err < 0)
564 return err; 569 return err;
565 570
571 if (err)
572 ieee80211_bss_info_change_notify(sdata, err);
573
566 return 0; 574 return 0;
567} 575}
568 576
@@ -687,12 +695,9 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
687 struct cfg80211_bss *cbss; 695 struct cfg80211_bss *cbss;
688 struct beacon_data *presp; 696 struct beacon_data *presp;
689 struct sta_info *sta; 697 struct sta_info *sta;
690 int active_ibss;
691 u16 capability; 698 u16 capability;
692 699
693 active_ibss = ieee80211_sta_active_ibss(sdata); 700 if (!is_zero_ether_addr(ifibss->bssid)) {
694
695 if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
696 capability = WLAN_CAPABILITY_IBSS; 701 capability = WLAN_CAPABILITY_IBSS;
697 702
698 if (ifibss->privacy) 703 if (ifibss->privacy)
@@ -744,7 +749,9 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
744 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | 749 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
745 BSS_CHANGED_IBSS); 750 BSS_CHANGED_IBSS);
746 drv_leave_ibss(local, sdata); 751 drv_leave_ibss(local, sdata);
752 mutex_lock(&local->mtx);
747 ieee80211_vif_release_channel(sdata); 753 ieee80211_vif_release_channel(sdata);
754 mutex_unlock(&local->mtx);
748} 755}
749 756
750static void ieee80211_csa_connection_drop_work(struct work_struct *work) 757static void ieee80211_csa_connection_drop_work(struct work_struct *work)
@@ -753,12 +760,16 @@ static void ieee80211_csa_connection_drop_work(struct work_struct *work)
753 container_of(work, struct ieee80211_sub_if_data, 760 container_of(work, struct ieee80211_sub_if_data,
754 u.ibss.csa_connection_drop_work); 761 u.ibss.csa_connection_drop_work);
755 762
763 sdata_lock(sdata);
764
756 ieee80211_ibss_disconnect(sdata); 765 ieee80211_ibss_disconnect(sdata);
757 synchronize_rcu(); 766 synchronize_rcu();
758 skb_queue_purge(&sdata->skb_queue); 767 skb_queue_purge(&sdata->skb_queue);
759 768
760 /* trigger a scan to find another IBSS network to join */ 769 /* trigger a scan to find another IBSS network to join */
761 ieee80211_queue_work(&sdata->local->hw, &sdata->work); 770 ieee80211_queue_work(&sdata->local->hw, &sdata->work);
771
772 sdata_unlock(sdata);
762} 773}
763 774
764static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata) 775static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata)
@@ -784,18 +795,10 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
784 struct cfg80211_csa_settings params; 795 struct cfg80211_csa_settings params;
785 struct ieee80211_csa_ie csa_ie; 796 struct ieee80211_csa_ie csa_ie;
786 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; 797 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
787 struct ieee80211_chanctx_conf *chanctx_conf;
788 struct ieee80211_chanctx *chanctx;
789 enum nl80211_channel_type ch_type; 798 enum nl80211_channel_type ch_type;
790 int err, num_chanctx; 799 int err;
791 u32 sta_flags; 800 u32 sta_flags;
792 801
793 if (sdata->vif.csa_active)
794 return true;
795
796 if (!sdata->vif.bss_conf.ibss_joined)
797 return false;
798
799 sta_flags = IEEE80211_STA_DISABLE_VHT; 802 sta_flags = IEEE80211_STA_DISABLE_VHT;
800 switch (ifibss->chandef.width) { 803 switch (ifibss->chandef.width) {
801 case NL80211_CHAN_WIDTH_5: 804 case NL80211_CHAN_WIDTH_5:
@@ -830,9 +833,6 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
830 params.count = csa_ie.count; 833 params.count = csa_ie.count;
831 params.chandef = csa_ie.chandef; 834 params.chandef = csa_ie.chandef;
832 835
833 if (ifibss->chandef.chan->band != params.chandef.chan->band)
834 goto disconnect;
835
836 switch (ifibss->chandef.width) { 836 switch (ifibss->chandef.width) {
837 case NL80211_CHAN_WIDTH_20_NOHT: 837 case NL80211_CHAN_WIDTH_20_NOHT:
838 case NL80211_CHAN_WIDTH_20: 838 case NL80211_CHAN_WIDTH_20:
@@ -888,28 +888,12 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
888 params.radar_required = true; 888 params.radar_required = true;
889 } 889 }
890 890
891 rcu_read_lock(); 891 if (cfg80211_chandef_identical(&params.chandef,
892 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); 892 &sdata->vif.bss_conf.chandef)) {
893 if (!chanctx_conf) { 893 ibss_dbg(sdata,
894 rcu_read_unlock(); 894 "received csa with an identical chandef, ignoring\n");
895 goto disconnect; 895 return true;
896 }
897
898 /* don't handle for multi-VIF cases */
899 chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
900 if (chanctx->refcount > 1) {
901 rcu_read_unlock();
902 goto disconnect;
903 }
904 num_chanctx = 0;
905 list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
906 num_chanctx++;
907
908 if (num_chanctx > 1) {
909 rcu_read_unlock();
910 goto disconnect;
911 } 896 }
912 rcu_read_unlock();
913 897
914 /* all checks done, now perform the channel switch. */ 898 /* all checks done, now perform the channel switch. */
915 ibss_dbg(sdata, 899 ibss_dbg(sdata,
@@ -918,19 +902,9 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
918 902
919 params.block_tx = !!csa_ie.mode; 903 params.block_tx = !!csa_ie.mode;
920 904
921 ieee80211_ibss_csa_beacon(sdata, &params); 905 if (ieee80211_channel_switch(sdata->local->hw.wiphy, sdata->dev,
922 sdata->csa_radar_required = params.radar_required; 906 &params))
923 907 goto disconnect;
924 if (params.block_tx)
925 ieee80211_stop_queues_by_reason(&sdata->local->hw,
926 IEEE80211_MAX_QUEUE_MAP,
927 IEEE80211_QUEUE_STOP_REASON_CSA);
928
929 sdata->local->csa_chandef = params.chandef;
930 sdata->vif.csa_active = true;
931
932 ieee80211_bss_info_change_notify(sdata, err);
933 drv_channel_switch_beacon(sdata, &params.chandef);
934 908
935 ieee80211_ibss_csa_mark_radar(sdata); 909 ieee80211_ibss_csa_mark_radar(sdata);
936 910
@@ -966,7 +940,8 @@ ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata,
966 if (len < required_len) 940 if (len < required_len)
967 return; 941 return;
968 942
969 ieee80211_ibss_process_chanswitch(sdata, elems, false); 943 if (!sdata->vif.csa_active)
944 ieee80211_ibss_process_chanswitch(sdata, elems, false);
970} 945}
971 946
972static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, 947static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata,
@@ -1147,7 +1122,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
1147 goto put_bss; 1122 goto put_bss;
1148 1123
1149 /* process channel switch */ 1124 /* process channel switch */
1150 if (ieee80211_ibss_process_chanswitch(sdata, elems, true)) 1125 if (sdata->vif.csa_active ||
1126 ieee80211_ibss_process_chanswitch(sdata, elems, true))
1151 goto put_bss; 1127 goto put_bss;
1152 1128
1153 /* same BSSID */ 1129 /* same BSSID */