diff options
author | Arik Nemtsov <arik@wizery.com> | 2013-09-01 10:15:51 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-10-02 12:18:23 -0400 |
commit | 7578d57520f51093f590d68e16965e2714e69747 (patch) | |
tree | 3a984a992a0511d1d73c423e6d1f70366609dcbe /net/mac80211/mlme.c | |
parent | c6ca5e28bc005f109b2772765c62b4d4ec35c954 (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/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 57 |
1 files changed, 43 insertions, 14 deletions
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); |