aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2013-09-01 10:15:51 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-10-02 12:18:23 -0400
commit7578d57520f51093f590d68e16965e2714e69747 (patch)
tree3a984a992a0511d1d73c423e6d1f70366609dcbe /net/mac80211
parentc6ca5e28bc005f109b2772765c62b4d4ec35c954 (diff)
mac80211: implement STA CSA for drivers using channel contexts
Limit the current implementation to a single channel context used by a single vif, thereby avoiding multi-vif/channel complexities. Reuse the main function from AP CSA code, but move a portion out in order to fit the STA scenario. Add a new mac80211 HW flag so we don't break devices that don't support channel switch with channel-contexts. The new behavior will be opt-in. Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/cfg.c5
-rw-r--r--net/mac80211/chan.c5
-rw-r--r--net/mac80211/mlme.c57
3 files changed, 48 insertions, 19 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b455e7264f4f..ac28af74a414 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2871,6 +2871,11 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
2871 if (WARN_ON(err < 0)) 2871 if (WARN_ON(err < 0))
2872 return; 2872 return;
2873 2873
2874 if (!local->use_chanctx) {
2875 local->_oper_chandef = local->csa_chandef;
2876 ieee80211_hw_config(local, 0);
2877 }
2878
2874 ieee80211_bss_info_change_notify(sdata, changed); 2879 ieee80211_bss_info_change_notify(sdata, changed);
2875 2880
2876 switch (sdata->vif.type) { 2881 switch (sdata->vif.type) {
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 3a4764b2869e..03ba6b5c5373 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -453,11 +453,6 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
453 chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; 453 chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL;
454 drv_change_chanctx(local, ctx, chanctx_changed); 454 drv_change_chanctx(local, ctx, chanctx_changed);
455 455
456 if (!local->use_chanctx) {
457 local->_oper_chandef = *chandef;
458 ieee80211_hw_config(local, 0);
459 }
460
461 ieee80211_recalc_chanctx_chantype(local, ctx); 456 ieee80211_recalc_chanctx_chantype(local, ctx);
462 ieee80211_recalc_smps_chanctx(local, ctx); 457 ieee80211_recalc_smps_chanctx(local, ctx);
463 ieee80211_recalc_radar_chanctx(local, ctx); 458 ieee80211_recalc_radar_chanctx(local, ctx);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9fce0f49cd10..91cc8281e266 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -876,6 +876,8 @@ static void ieee80211_chswitch_work(struct work_struct *work)
876 container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); 876 container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
877 struct ieee80211_local *local = sdata->local; 877 struct ieee80211_local *local = sdata->local;
878 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 878 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
879 u32 changed = 0;
880 int ret;
879 881
880 if (!ieee80211_sdata_running(sdata)) 882 if (!ieee80211_sdata_running(sdata))
881 return; 883 return;
@@ -884,24 +886,39 @@ static void ieee80211_chswitch_work(struct work_struct *work)
884 if (!ifmgd->associated) 886 if (!ifmgd->associated)
885 goto out; 887 goto out;
886 888
887 local->_oper_chandef = local->csa_chandef; 889 ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
890 &changed);
891 if (ret) {
892 sdata_info(sdata,
893 "vif channel switch failed, disconnecting\n");
894 ieee80211_queue_work(&sdata->local->hw,
895 &ifmgd->csa_connection_drop_work);
896 goto out;
897 }
888 898
889 if (!local->ops->channel_switch) { 899 if (!local->use_chanctx) {
890 /* call "hw_config" only if doing sw channel switch */ 900 local->_oper_chandef = local->csa_chandef;
891 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); 901 /* Call "hw_config" only if doing sw channel switch.
892 } else { 902 * Otherwise update the channel directly
893 /* update the device channel directly */ 903 */
894 local->hw.conf.chandef = local->_oper_chandef; 904 if (!local->ops->channel_switch)
905 ieee80211_hw_config(local, 0);
906 else
907 local->hw.conf.chandef = local->_oper_chandef;
895 } 908 }
896 909
897 /* XXX: shouldn't really modify cfg80211-owned data! */ 910 /* XXX: shouldn't really modify cfg80211-owned data! */
898 ifmgd->associated->channel = local->_oper_chandef.chan; 911 ifmgd->associated->channel = local->csa_chandef.chan;
899 912
900 /* XXX: wait for a beacon first? */ 913 /* XXX: wait for a beacon first? */
901 ieee80211_wake_queues_by_reason(&local->hw, 914 ieee80211_wake_queues_by_reason(&local->hw,
902 IEEE80211_MAX_QUEUE_MAP, 915 IEEE80211_MAX_QUEUE_MAP,
903 IEEE80211_QUEUE_STOP_REASON_CSA); 916 IEEE80211_QUEUE_STOP_REASON_CSA);
917
918 ieee80211_bss_info_change_notify(sdata, changed);
919
904 out: 920 out:
921 sdata->vif.csa_active = false;
905 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; 922 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
906 sdata_unlock(sdata); 923 sdata_unlock(sdata);
907} 924}
@@ -983,17 +1000,28 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
983 } 1000 }
984 1001
985 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; 1002 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
1003 sdata->vif.csa_active = true;
986 1004
1005 mutex_lock(&local->chanctx_mtx);
987 if (local->use_chanctx) { 1006 if (local->use_chanctx) {
988 sdata_info(sdata, 1007 u32 num_chanctx = 0;
989 "not handling channel switch with channel contexts\n"); 1008 list_for_each_entry(chanctx, &local->chanctx_list, list)
990 ieee80211_queue_work(&local->hw, 1009 num_chanctx++;
991 &ifmgd->csa_connection_drop_work); 1010
992 return; 1011 if (num_chanctx > 1 ||
1012 !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
1013 sdata_info(sdata,
1014 "not handling chan-switch with channel contexts\n");
1015 ieee80211_queue_work(&local->hw,
1016 &ifmgd->csa_connection_drop_work);
1017 mutex_unlock(&local->chanctx_mtx);
1018 return;
1019 }
993 } 1020 }
994 1021
995 mutex_lock(&local->chanctx_mtx);
996 if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { 1022 if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) {
1023 ieee80211_queue_work(&local->hw,
1024 &ifmgd->csa_connection_drop_work);
997 mutex_unlock(&local->chanctx_mtx); 1025 mutex_unlock(&local->chanctx_mtx);
998 return; 1026 return;
999 } 1027 }
@@ -1955,6 +1983,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
1955 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, 1983 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
1956 true, frame_buf); 1984 true, frame_buf);
1957 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; 1985 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
1986 sdata->vif.csa_active = false;
1958 ieee80211_wake_queues_by_reason(&sdata->local->hw, 1987 ieee80211_wake_queues_by_reason(&sdata->local->hw,
1959 IEEE80211_MAX_QUEUE_MAP, 1988 IEEE80211_MAX_QUEUE_MAP,
1960 IEEE80211_QUEUE_STOP_REASON_CSA); 1989 IEEE80211_QUEUE_STOP_REASON_CSA);