aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/net/mac80211.h6
-rw-r--r--net/mac80211/cfg.c5
-rw-r--r--net/mac80211/chan.c5
-rw-r--r--net/mac80211/mlme.c57
4 files changed, 54 insertions, 19 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index da8011920b65..f386c480e134 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1502,6 +1502,11 @@ struct ieee80211_tx_control {
1502 * 1502 *
1503 * @IEEE80211_HW_TIMING_BEACON_ONLY: Use sync timing from beacon frames 1503 * @IEEE80211_HW_TIMING_BEACON_ONLY: Use sync timing from beacon frames
1504 * only, to allow getting TBTT of a DTIM beacon. 1504 * only, to allow getting TBTT of a DTIM beacon.
1505 *
1506 * @IEEE80211_HW_CHANCTX_STA_CSA: Support 802.11h based channel-switch (CSA)
1507 * for a single active channel while using channel contexts. When support
1508 * is not enabled the default action is to disconnect when getting the
1509 * CSA frame.
1505 */ 1510 */
1506enum ieee80211_hw_flags { 1511enum ieee80211_hw_flags {
1507 IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, 1512 IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
@@ -1532,6 +1537,7 @@ enum ieee80211_hw_flags {
1532 IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF = 1<<25, 1537 IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF = 1<<25,
1533 IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26, 1538 IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26,
1534 IEEE80211_HW_SUPPORTS_HT_CCK_RATES = 1<<27, 1539 IEEE80211_HW_SUPPORTS_HT_CCK_RATES = 1<<27,
1540 IEEE80211_HW_CHANCTX_STA_CSA = 1<<28,
1535}; 1541};
1536 1542
1537/** 1543/**
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);