aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de>2013-08-28 07:41:31 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-09-26 07:27:14 -0400
commitcd7760e62c2ac8581f050b2d36501d1a60beaf83 (patch)
tree1f4e9fb22e3b952c68c2e055a5381f5f9c5a2f94
parent871a4180b8b62dbed54cd203c33bdab7fce24e6f (diff)
mac80211: add support for CSA in IBSS mode
This function adds the channel switch announcement implementation for the IBSS code. It is triggered by userspace (mac80211/cfg) or by external channel switch announcement, which have to be adopted. Both CSAs in beacons and action frames are supported. As for AP mode, the channel switch is applied after some time. However in IBSS mode, the channel switch IEs are generated in the kernel. Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--net/mac80211/cfg.c87
-rw-r--r--net/mac80211/ibss.c354
-rw-r--r--net/mac80211/ieee80211_i.h5
-rw-r--r--net/mac80211/iface.c4
-rw-r--r--net/mac80211/rx.c36
-rw-r--r--net/mac80211/tx.c37
6 files changed, 480 insertions, 43 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 2e7855a1b10d..b455e7264f4f 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2865,30 +2865,38 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
2865 if (!ieee80211_sdata_running(sdata)) 2865 if (!ieee80211_sdata_running(sdata))
2866 return; 2866 return;
2867 2867
2868 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
2869 return;
2870
2871 sdata->radar_required = sdata->csa_radar_required; 2868 sdata->radar_required = sdata->csa_radar_required;
2872 err = ieee80211_vif_change_channel(sdata, &local->csa_chandef, 2869 err = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
2873 &changed); 2870 &changed);
2874 if (WARN_ON(err < 0)) 2871 if (WARN_ON(err < 0))
2875 return; 2872 return;
2876 2873
2877 err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); 2874 ieee80211_bss_info_change_notify(sdata, changed);
2878 if (err < 0)
2879 return;
2880 2875
2881 changed |= err; 2876 switch (sdata->vif.type) {
2882 kfree(sdata->u.ap.next_beacon); 2877 case NL80211_IFTYPE_AP:
2883 sdata->u.ap.next_beacon = NULL; 2878 err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
2879 if (err < 0)
2880 return;
2881 changed |= err;
2882 kfree(sdata->u.ap.next_beacon);
2883 sdata->u.ap.next_beacon = NULL;
2884
2885 ieee80211_bss_info_change_notify(sdata, err);
2886 break;
2887 case NL80211_IFTYPE_ADHOC:
2888 ieee80211_ibss_finish_csa(sdata);
2889 break;
2890 default:
2891 WARN_ON(1);
2892 return;
2893 }
2884 sdata->vif.csa_active = false; 2894 sdata->vif.csa_active = false;
2885 2895
2886 ieee80211_wake_queues_by_reason(&sdata->local->hw, 2896 ieee80211_wake_queues_by_reason(&sdata->local->hw,
2887 IEEE80211_MAX_QUEUE_MAP, 2897 IEEE80211_MAX_QUEUE_MAP,
2888 IEEE80211_QUEUE_STOP_REASON_CSA); 2898 IEEE80211_QUEUE_STOP_REASON_CSA);
2889 2899
2890 ieee80211_bss_info_change_notify(sdata, changed);
2891
2892 cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef); 2900 cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef);
2893} 2901}
2894 2902
@@ -2936,20 +2944,56 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
2936 if (sdata->vif.csa_active) 2944 if (sdata->vif.csa_active)
2937 return -EBUSY; 2945 return -EBUSY;
2938 2946
2939 /* only handle AP for now. */
2940 switch (sdata->vif.type) { 2947 switch (sdata->vif.type) {
2941 case NL80211_IFTYPE_AP: 2948 case NL80211_IFTYPE_AP:
2949 sdata->csa_counter_offset_beacon =
2950 params->counter_offset_beacon;
2951 sdata->csa_counter_offset_presp = params->counter_offset_presp;
2952 sdata->u.ap.next_beacon =
2953 cfg80211_beacon_dup(&params->beacon_after);
2954 if (!sdata->u.ap.next_beacon)
2955 return -ENOMEM;
2956
2957 err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
2958 if (err < 0) {
2959 kfree(sdata->u.ap.next_beacon);
2960 return err;
2961 }
2962 break;
2963 case NL80211_IFTYPE_ADHOC:
2964 if (!sdata->vif.bss_conf.ibss_joined)
2965 return -EINVAL;
2966
2967 if (params->chandef.width != sdata->u.ibss.chandef.width)
2968 return -EINVAL;
2969
2970 switch (params->chandef.width) {
2971 case NL80211_CHAN_WIDTH_40:
2972 if (cfg80211_get_chandef_type(&params->chandef) !=
2973 cfg80211_get_chandef_type(&sdata->u.ibss.chandef))
2974 return -EINVAL;
2975 case NL80211_CHAN_WIDTH_5:
2976 case NL80211_CHAN_WIDTH_10:
2977 case NL80211_CHAN_WIDTH_20_NOHT:
2978 case NL80211_CHAN_WIDTH_20:
2979 break;
2980 default:
2981 return -EINVAL;
2982 }
2983
2984 /* changes into another band are not supported */
2985 if (sdata->u.ibss.chandef.chan->band !=
2986 params->chandef.chan->band)
2987 return -EINVAL;
2988
2989 err = ieee80211_ibss_csa_beacon(sdata, params);
2990 if (err < 0)
2991 return err;
2942 break; 2992 break;
2943 default: 2993 default:
2944 return -EOPNOTSUPP; 2994 return -EOPNOTSUPP;
2945 } 2995 }
2946 2996
2947 sdata->u.ap.next_beacon = cfg80211_beacon_dup(&params->beacon_after);
2948 if (!sdata->u.ap.next_beacon)
2949 return -ENOMEM;
2950
2951 sdata->csa_counter_offset_beacon = params->counter_offset_beacon;
2952 sdata->csa_counter_offset_presp = params->counter_offset_presp;
2953 sdata->csa_radar_required = params->radar_required; 2997 sdata->csa_radar_required = params->radar_required;
2954 2998
2955 if (params->block_tx) 2999 if (params->block_tx)
@@ -2957,10 +3001,6 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
2957 IEEE80211_MAX_QUEUE_MAP, 3001 IEEE80211_MAX_QUEUE_MAP,
2958 IEEE80211_QUEUE_STOP_REASON_CSA); 3002 IEEE80211_QUEUE_STOP_REASON_CSA);
2959 3003
2960 err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
2961 if (err < 0)
2962 return err;
2963
2964 local->csa_chandef = params->chandef; 3004 local->csa_chandef = params->chandef;
2965 sdata->vif.csa_active = true; 3005 sdata->vif.csa_active = true;
2966 3006
@@ -3014,7 +3054,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
3014 need_offchan = true; 3054 need_offchan = true;
3015 if (!ieee80211_is_action(mgmt->frame_control) || 3055 if (!ieee80211_is_action(mgmt->frame_control) ||
3016 mgmt->u.action.category == WLAN_CATEGORY_PUBLIC || 3056 mgmt->u.action.category == WLAN_CATEGORY_PUBLIC ||
3017 mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED) 3057 mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED ||
3058 mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT)
3018 break; 3059 break;
3019 rcu_read_lock(); 3060 rcu_read_lock();
3020 sta = sta_info_get(sdata, mgmt->da); 3061 sta = sta_info_get(sdata, mgmt->da);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 0c3ec082e4f5..c0042136f1d8 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -39,7 +39,8 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
39 const int beacon_int, const u32 basic_rates, 39 const int beacon_int, const u32 basic_rates,
40 const u16 capability, u64 tsf, 40 const u16 capability, u64 tsf,
41 struct cfg80211_chan_def *chandef, 41 struct cfg80211_chan_def *chandef,
42 bool *have_higher_than_11mbit) 42 bool *have_higher_than_11mbit,
43 struct cfg80211_csa_settings *csa_settings)
43{ 44{
44 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; 45 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
45 struct ieee80211_local *local = sdata->local; 46 struct ieee80211_local *local = sdata->local;
@@ -59,6 +60,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
59 2 + 8 /* max Supported Rates */ + 60 2 + 8 /* max Supported Rates */ +
60 3 /* max DS params */ + 61 3 /* max DS params */ +
61 4 /* IBSS params */ + 62 4 /* IBSS params */ +
63 5 /* Channel Switch Announcement */ +
62 2 + (IEEE80211_MAX_SUPP_RATES - 8) + 64 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
63 2 + sizeof(struct ieee80211_ht_cap) + 65 2 + sizeof(struct ieee80211_ht_cap) +
64 2 + sizeof(struct ieee80211_ht_operation) + 66 2 + sizeof(struct ieee80211_ht_operation) +
@@ -135,6 +137,16 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
135 *pos++ = 0; 137 *pos++ = 0;
136 *pos++ = 0; 138 *pos++ = 0;
137 139
140 if (csa_settings) {
141 *pos++ = WLAN_EID_CHANNEL_SWITCH;
142 *pos++ = 3;
143 *pos++ = csa_settings->block_tx ? 1 : 0;
144 *pos++ = ieee80211_frequency_to_channel(
145 csa_settings->chandef.chan->center_freq);
146 sdata->csa_counter_offset_beacon = (pos - presp->head);
147 *pos++ = csa_settings->count;
148 }
149
138 /* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */ 150 /* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */
139 if (rates_n > 8) { 151 if (rates_n > 8) {
140 *pos++ = WLAN_EID_EXT_SUPP_RATES; 152 *pos++ = WLAN_EID_EXT_SUPP_RATES;
@@ -276,7 +288,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
276 288
277 presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates, 289 presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates,
278 capability, tsf, &chandef, 290 capability, tsf, &chandef,
279 &have_higher_than_11mbit); 291 &have_higher_than_11mbit, NULL);
280 if (!presp) 292 if (!presp)
281 return; 293 return;
282 294
@@ -416,6 +428,109 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
416 tsf, false); 428 tsf, false);
417} 429}
418 430
431int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
432 struct cfg80211_csa_settings *csa_settings)
433{
434 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
435 struct beacon_data *presp, *old_presp;
436 struct cfg80211_bss *cbss;
437 const struct cfg80211_bss_ies *ies;
438 u16 capability;
439 u64 tsf;
440 int ret = 0;
441
442 sdata_assert_lock(sdata);
443
444 capability = WLAN_CAPABILITY_IBSS;
445
446 if (ifibss->privacy)
447 capability |= WLAN_CAPABILITY_PRIVACY;
448
449 cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan,
450 ifibss->bssid, ifibss->ssid,
451 ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
452 WLAN_CAPABILITY_PRIVACY,
453 capability);
454
455 if (WARN_ON(!cbss)) {
456 ret = -EINVAL;
457 goto out;
458 }
459
460 rcu_read_lock();
461 ies = rcu_dereference(cbss->ies);
462 tsf = ies->tsf;
463 rcu_read_unlock();
464 cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
465
466 old_presp = rcu_dereference_protected(ifibss->presp,
467 lockdep_is_held(&sdata->wdev.mtx));
468
469 presp = ieee80211_ibss_build_presp(sdata,
470 sdata->vif.bss_conf.beacon_int,
471 sdata->vif.bss_conf.basic_rates,
472 capability, tsf, &ifibss->chandef,
473 NULL, csa_settings);
474 if (!presp) {
475 ret = -ENOMEM;
476 goto out;
477 }
478
479 rcu_assign_pointer(ifibss->presp, presp);
480 if (old_presp)
481 kfree_rcu(old_presp, rcu_head);
482
483 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
484 out:
485 return ret;
486}
487
488int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
489{
490 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
491 struct cfg80211_bss *cbss;
492 int err;
493 u16 capability;
494
495 sdata_lock(sdata);
496 /* update cfg80211 bss information with the new channel */
497 if (!is_zero_ether_addr(ifibss->bssid)) {
498 capability = WLAN_CAPABILITY_IBSS;
499
500 if (ifibss->privacy)
501 capability |= WLAN_CAPABILITY_PRIVACY;
502
503 cbss = cfg80211_get_bss(sdata->local->hw.wiphy,
504 ifibss->chandef.chan,
505 ifibss->bssid, ifibss->ssid,
506 ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
507 WLAN_CAPABILITY_PRIVACY,
508 capability);
509 /* XXX: should not really modify cfg80211 data */
510 if (cbss) {
511 cbss->channel = sdata->local->csa_chandef.chan;
512 cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
513 }
514 }
515
516 ifibss->chandef = sdata->local->csa_chandef;
517
518 /* generate the beacon */
519 err = ieee80211_ibss_csa_beacon(sdata, NULL);
520 sdata_unlock(sdata);
521 if (err < 0)
522 return err;
523
524 return 0;
525}
526
527void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata)
528{
529 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
530
531 cancel_work_sync(&ifibss->csa_connection_drop_work);
532}
533
419static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta) 534static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta)
420 __acquires(RCU) 535 __acquires(RCU)
421{ 536{
@@ -589,6 +704,204 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
589 ieee80211_vif_release_channel(sdata); 704 ieee80211_vif_release_channel(sdata);
590} 705}
591 706
707static void ieee80211_csa_connection_drop_work(struct work_struct *work)
708{
709 struct ieee80211_sub_if_data *sdata =
710 container_of(work, struct ieee80211_sub_if_data,
711 u.ibss.csa_connection_drop_work);
712
713 ieee80211_ibss_disconnect(sdata);
714 synchronize_rcu();
715 skb_queue_purge(&sdata->skb_queue);
716
717 /* trigger a scan to find another IBSS network to join */
718 ieee80211_queue_work(&sdata->local->hw, &sdata->work);
719}
720
721static bool
722ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
723 struct ieee802_11_elems *elems,
724 bool beacon)
725{
726 struct cfg80211_csa_settings params;
727 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
728 struct ieee80211_chanctx_conf *chanctx_conf;
729 struct ieee80211_chanctx *chanctx;
730 enum nl80211_channel_type ch_type;
731 int err, num_chanctx;
732 u32 sta_flags;
733 u8 mode;
734
735 if (sdata->vif.csa_active)
736 return true;
737
738 if (!sdata->vif.bss_conf.ibss_joined)
739 return false;
740
741 sta_flags = IEEE80211_STA_DISABLE_VHT;
742 switch (ifibss->chandef.width) {
743 case NL80211_CHAN_WIDTH_5:
744 case NL80211_CHAN_WIDTH_10:
745 case NL80211_CHAN_WIDTH_20_NOHT:
746 sta_flags |= IEEE80211_STA_DISABLE_HT;
747 /* fall through */
748 case NL80211_CHAN_WIDTH_20:
749 sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
750 break;
751 default:
752 break;
753 }
754
755 memset(&params, 0, sizeof(params));
756 err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon,
757 ifibss->chandef.chan->band,
758 sta_flags, ifibss->bssid,
759 &params.count, &mode,
760 &params.chandef);
761
762 /* can't switch to destination channel, fail */
763 if (err < 0)
764 goto disconnect;
765
766 /* did not contain a CSA */
767 if (err)
768 return false;
769
770 if (ifibss->chandef.chan->band != params.chandef.chan->band)
771 goto disconnect;
772
773 switch (ifibss->chandef.width) {
774 case NL80211_CHAN_WIDTH_20_NOHT:
775 case NL80211_CHAN_WIDTH_20:
776 case NL80211_CHAN_WIDTH_40:
777 /* keep our current HT mode (HT20/HT40+/HT40-), even if
778 * another mode has been announced. The mode is not adopted
779 * within the beacon while doing CSA and we should therefore
780 * keep the mode which we announce.
781 */
782 ch_type = cfg80211_get_chandef_type(&ifibss->chandef);
783 cfg80211_chandef_create(&params.chandef, params.chandef.chan,
784 ch_type);
785 break;
786 case NL80211_CHAN_WIDTH_5:
787 case NL80211_CHAN_WIDTH_10:
788 if (params.chandef.width != ifibss->chandef.width) {
789 sdata_info(sdata,
790 "IBSS %pM received channel switch from incompatible channel width (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
791 ifibss->bssid,
792 params.chandef.chan->center_freq,
793 params.chandef.width,
794 params.chandef.center_freq1,
795 params.chandef.center_freq2);
796 goto disconnect;
797 }
798 break;
799 default:
800 /* should not happen, sta_flags should prevent VHT modes. */
801 WARN_ON(1);
802 goto disconnect;
803 }
804
805 if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &params.chandef,
806 IEEE80211_CHAN_DISABLED)) {
807 sdata_info(sdata,
808 "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
809 ifibss->bssid,
810 params.chandef.chan->center_freq,
811 params.chandef.width,
812 params.chandef.center_freq1,
813 params.chandef.center_freq2);
814 goto disconnect;
815 }
816
817 err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
818 &params.chandef);
819 if (err < 0)
820 goto disconnect;
821 if (err) {
822 params.radar_required = true;
823
824 /* TODO: IBSS-DFS not (yet) supported, disconnect. */
825 goto disconnect;
826 }
827
828 rcu_read_lock();
829 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
830 if (!chanctx_conf) {
831 rcu_read_unlock();
832 goto disconnect;
833 }
834
835 /* don't handle for multi-VIF cases */
836 chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
837 if (chanctx->refcount > 1) {
838 rcu_read_unlock();
839 goto disconnect;
840 }
841 num_chanctx = 0;
842 list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
843 num_chanctx++;
844
845 if (num_chanctx > 1) {
846 rcu_read_unlock();
847 goto disconnect;
848 }
849 rcu_read_unlock();
850
851 /* all checks done, now perform the channel switch. */
852 ibss_dbg(sdata,
853 "received channel switch announcement to go to channel %d MHz\n",
854 params.chandef.chan->center_freq);
855
856 params.block_tx = !!mode;
857
858 ieee80211_ibss_csa_beacon(sdata, &params);
859 sdata->csa_radar_required = params.radar_required;
860
861 if (params.block_tx)
862 ieee80211_stop_queues_by_reason(&sdata->local->hw,
863 IEEE80211_MAX_QUEUE_MAP,
864 IEEE80211_QUEUE_STOP_REASON_CSA);
865
866 sdata->local->csa_chandef = params.chandef;
867 sdata->vif.csa_active = true;
868
869 ieee80211_bss_info_change_notify(sdata, err);
870 drv_channel_switch_beacon(sdata, &params.chandef);
871
872 return true;
873disconnect:
874 ibss_dbg(sdata, "Can't handle channel switch, disconnect\n");
875 ieee80211_queue_work(&sdata->local->hw,
876 &ifibss->csa_connection_drop_work);
877
878 return true;
879}
880
881static void
882ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata,
883 struct ieee80211_mgmt *mgmt, size_t len,
884 struct ieee80211_rx_status *rx_status,
885 struct ieee802_11_elems *elems)
886{
887 int required_len;
888
889 if (len < IEEE80211_MIN_ACTION_SIZE + 1)
890 return;
891
892 /* CSA is the only action we handle for now */
893 if (mgmt->u.action.u.measurement.action_code !=
894 WLAN_ACTION_SPCT_CHL_SWITCH)
895 return;
896
897 required_len = IEEE80211_MIN_ACTION_SIZE +
898 sizeof(mgmt->u.action.u.chan_switch);
899 if (len < required_len)
900 return;
901
902 ieee80211_ibss_process_chanswitch(sdata, elems, false);
903}
904
592static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, 905static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata,
593 struct ieee80211_mgmt *mgmt, 906 struct ieee80211_mgmt *mgmt,
594 size_t len) 907 size_t len)
@@ -751,10 +1064,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
751 1064
752 /* check if we need to merge IBSS */ 1065 /* check if we need to merge IBSS */
753 1066
754 /* we use a fixed BSSID */
755 if (sdata->u.ibss.fixed_bssid)
756 goto put_bss;
757
758 /* not an IBSS */ 1067 /* not an IBSS */
759 if (!(cbss->capability & WLAN_CAPABILITY_IBSS)) 1068 if (!(cbss->capability & WLAN_CAPABILITY_IBSS))
760 goto put_bss; 1069 goto put_bss;
@@ -770,10 +1079,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
770 sdata->u.ibss.ssid_len)) 1079 sdata->u.ibss.ssid_len))
771 goto put_bss; 1080 goto put_bss;
772 1081
1082 /* process channel switch */
1083 if (ieee80211_ibss_process_chanswitch(sdata, elems, true))
1084 goto put_bss;
1085
773 /* same BSSID */ 1086 /* same BSSID */
774 if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid)) 1087 if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid))
775 goto put_bss; 1088 goto put_bss;
776 1089
1090 /* we use a fixed BSSID */
1091 if (sdata->u.ibss.fixed_bssid)
1092 goto put_bss;
1093
777 if (ieee80211_have_rx_timestamp(rx_status)) { 1094 if (ieee80211_have_rx_timestamp(rx_status)) {
778 /* time when timestamp field was received */ 1095 /* time when timestamp field was received */
779 rx_timestamp = 1096 rx_timestamp =
@@ -1142,6 +1459,8 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
1142 struct ieee80211_rx_status *rx_status; 1459 struct ieee80211_rx_status *rx_status;
1143 struct ieee80211_mgmt *mgmt; 1460 struct ieee80211_mgmt *mgmt;
1144 u16 fc; 1461 u16 fc;
1462 struct ieee802_11_elems elems;
1463 int ies_len;
1145 1464
1146 rx_status = IEEE80211_SKB_RXCB(skb); 1465 rx_status = IEEE80211_SKB_RXCB(skb);
1147 mgmt = (struct ieee80211_mgmt *) skb->data; 1466 mgmt = (struct ieee80211_mgmt *) skb->data;
@@ -1167,6 +1486,27 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
1167 case IEEE80211_STYPE_DEAUTH: 1486 case IEEE80211_STYPE_DEAUTH:
1168 ieee80211_rx_mgmt_deauth_ibss(sdata, mgmt, skb->len); 1487 ieee80211_rx_mgmt_deauth_ibss(sdata, mgmt, skb->len);
1169 break; 1488 break;
1489 case IEEE80211_STYPE_ACTION:
1490 switch (mgmt->u.action.category) {
1491 case WLAN_CATEGORY_SPECTRUM_MGMT:
1492 ies_len = skb->len -
1493 offsetof(struct ieee80211_mgmt,
1494 u.action.u.chan_switch.variable);
1495
1496 if (ies_len < 0)
1497 break;
1498
1499 ieee802_11_parse_elems(
1500 mgmt->u.action.u.chan_switch.variable,
1501 ies_len, true, &elems);
1502
1503 if (elems.parse_error)
1504 break;
1505
1506 ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len,
1507 rx_status, &elems);
1508 break;
1509 }
1170 } 1510 }
1171 1511
1172 mgmt_out: 1512 mgmt_out:
@@ -1233,6 +1573,8 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
1233 (unsigned long) sdata); 1573 (unsigned long) sdata);
1234 INIT_LIST_HEAD(&ifibss->incomplete_stations); 1574 INIT_LIST_HEAD(&ifibss->incomplete_stations);
1235 spin_lock_init(&ifibss->incomplete_lock); 1575 spin_lock_init(&ifibss->incomplete_lock);
1576 INIT_WORK(&ifibss->csa_connection_drop_work,
1577 ieee80211_csa_connection_drop_work);
1236} 1578}
1237 1579
1238/* scan finished notification */ 1580/* scan finished notification */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 7f0e6da8e6f8..3a87c8976a32 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -486,6 +486,7 @@ struct ieee80211_if_managed {
486 486
487struct ieee80211_if_ibss { 487struct ieee80211_if_ibss {
488 struct timer_list timer; 488 struct timer_list timer;
489 struct work_struct csa_connection_drop_work;
489 490
490 unsigned long last_scan_completed; 491 unsigned long last_scan_completed;
491 492
@@ -1329,6 +1330,10 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
1329void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata); 1330void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata);
1330void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, 1331void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
1331 struct sk_buff *skb); 1332 struct sk_buff *skb);
1333int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
1334 struct cfg80211_csa_settings *csa_settings);
1335int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata);
1336void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata);
1332 1337
1333/* mesh code */ 1338/* mesh code */
1334void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); 1339void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index fcecd633514e..e48f103b9ade 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -766,6 +766,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
766 if (sdata->vif.type == NL80211_IFTYPE_STATION) 766 if (sdata->vif.type == NL80211_IFTYPE_STATION)
767 ieee80211_mgd_stop(sdata); 767 ieee80211_mgd_stop(sdata);
768 768
769 if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
770 ieee80211_ibss_stop(sdata);
771
772
769 /* 773 /*
770 * Remove all stations associated with this interface. 774 * Remove all stations associated with this interface.
771 * 775 *
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 54395d7583ba..8e908e17e248 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2402,7 +2402,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
2402 return RX_DROP_UNUSABLE; 2402 return RX_DROP_UNUSABLE;
2403 2403
2404 if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC && 2404 if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC &&
2405 mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED) 2405 mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED &&
2406 mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT)
2406 return RX_DROP_UNUSABLE; 2407 return RX_DROP_UNUSABLE;
2407 2408
2408 if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) 2409 if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
@@ -2566,31 +2567,46 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
2566 2567
2567 goto queue; 2568 goto queue;
2568 case WLAN_CATEGORY_SPECTRUM_MGMT: 2569 case WLAN_CATEGORY_SPECTRUM_MGMT:
2569 if (status->band != IEEE80211_BAND_5GHZ)
2570 break;
2571
2572 if (sdata->vif.type != NL80211_IFTYPE_STATION)
2573 break;
2574
2575 /* verify action_code is present */ 2570 /* verify action_code is present */
2576 if (len < IEEE80211_MIN_ACTION_SIZE + 1) 2571 if (len < IEEE80211_MIN_ACTION_SIZE + 1)
2577 break; 2572 break;
2578 2573
2579 switch (mgmt->u.action.u.measurement.action_code) { 2574 switch (mgmt->u.action.u.measurement.action_code) {
2580 case WLAN_ACTION_SPCT_MSR_REQ: 2575 case WLAN_ACTION_SPCT_MSR_REQ:
2576 if (status->band != IEEE80211_BAND_5GHZ)
2577 break;
2578
2581 if (len < (IEEE80211_MIN_ACTION_SIZE + 2579 if (len < (IEEE80211_MIN_ACTION_SIZE +
2582 sizeof(mgmt->u.action.u.measurement))) 2580 sizeof(mgmt->u.action.u.measurement)))
2583 break; 2581 break;
2582
2583 if (sdata->vif.type != NL80211_IFTYPE_STATION)
2584 break;
2585
2584 ieee80211_process_measurement_req(sdata, mgmt, len); 2586 ieee80211_process_measurement_req(sdata, mgmt, len);
2585 goto handled; 2587 goto handled;
2586 case WLAN_ACTION_SPCT_CHL_SWITCH: 2588 case WLAN_ACTION_SPCT_CHL_SWITCH: {
2587 if (sdata->vif.type != NL80211_IFTYPE_STATION) 2589 u8 *bssid;
2590 if (len < (IEEE80211_MIN_ACTION_SIZE +
2591 sizeof(mgmt->u.action.u.chan_switch)))
2588 break; 2592 break;
2589 2593
2590 if (!ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid)) 2594 if (sdata->vif.type != NL80211_IFTYPE_STATION &&
2595 sdata->vif.type != NL80211_IFTYPE_ADHOC)
2596 break;
2597
2598 if (sdata->vif.type == NL80211_IFTYPE_STATION)
2599 bssid = sdata->u.mgd.bssid;
2600 else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
2601 bssid = sdata->u.ibss.bssid;
2602 else
2603 break;
2604
2605 if (!ether_addr_equal(mgmt->bssid, bssid))
2591 break; 2606 break;
2592 2607
2593 goto queue; 2608 goto queue;
2609 }
2594 } 2610 }
2595 break; 2611 break;
2596 case WLAN_CATEGORY_SA_QUERY: 2612 case WLAN_CATEGORY_SA_QUERY:
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 102ce8adf2d1..4fcbf634b548 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2357,15 +2357,31 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
2357 struct probe_resp *resp; 2357 struct probe_resp *resp;
2358 int counter_offset_beacon = sdata->csa_counter_offset_beacon; 2358 int counter_offset_beacon = sdata->csa_counter_offset_beacon;
2359 int counter_offset_presp = sdata->csa_counter_offset_presp; 2359 int counter_offset_presp = sdata->csa_counter_offset_presp;
2360 u8 *beacon_data;
2361 size_t beacon_data_len;
2362
2363 switch (sdata->vif.type) {
2364 case NL80211_IFTYPE_AP:
2365 beacon_data = beacon->tail;
2366 beacon_data_len = beacon->tail_len;
2367 break;
2368 case NL80211_IFTYPE_ADHOC:
2369 beacon_data = beacon->head;
2370 beacon_data_len = beacon->head_len;
2371 break;
2372 default:
2373 return;
2374 }
2375 if (WARN_ON(counter_offset_beacon >= beacon_data_len))
2376 return;
2360 2377
2361 /* warn if the driver did not check for/react to csa completeness */ 2378 /* warn if the driver did not check for/react to csa completeness */
2362 if (WARN_ON(((u8 *)beacon->tail)[counter_offset_beacon] == 0)) 2379 if (WARN_ON(beacon_data[counter_offset_beacon] == 0))
2363 return; 2380 return;
2364 2381
2365 ((u8 *)beacon->tail)[counter_offset_beacon]--; 2382 beacon_data[counter_offset_beacon]--;
2366 2383
2367 if (sdata->vif.type == NL80211_IFTYPE_AP && 2384 if (sdata->vif.type == NL80211_IFTYPE_AP && counter_offset_presp) {
2368 counter_offset_presp) {
2369 rcu_read_lock(); 2385 rcu_read_lock();
2370 resp = rcu_dereference(sdata->u.ap.probe_resp); 2386 resp = rcu_dereference(sdata->u.ap.probe_resp);
2371 2387
@@ -2400,6 +2416,15 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
2400 goto out; 2416 goto out;
2401 beacon_data = beacon->tail; 2417 beacon_data = beacon->tail;
2402 beacon_data_len = beacon->tail_len; 2418 beacon_data_len = beacon->tail_len;
2419 } else if (vif->type == NL80211_IFTYPE_ADHOC) {
2420 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
2421
2422 beacon = rcu_dereference(ifibss->presp);
2423 if (!beacon)
2424 goto out;
2425
2426 beacon_data = beacon->head;
2427 beacon_data_len = beacon->head_len;
2403 } else { 2428 } else {
2404 WARN_ON(1); 2429 WARN_ON(1);
2405 goto out; 2430 goto out;
@@ -2484,6 +2509,10 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2484 if (!presp) 2509 if (!presp)
2485 goto out; 2510 goto out;
2486 2511
2512 if (sdata->vif.csa_active)
2513 ieee80211_update_csa(sdata, presp);
2514
2515
2487 skb = dev_alloc_skb(local->tx_headroom + presp->head_len); 2516 skb = dev_alloc_skb(local->tx_headroom + presp->head_len);
2488 if (!skb) 2517 if (!skb)
2489 goto out; 2518 goto out;