aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/cfg.c
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2014-06-25 06:35:08 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-06-25 12:06:20 -0400
commit03078de4f928ffcbe629a914dea8bdf66a9d6a48 (patch)
treea52ef5c76e459885efe13b13492434777959f670 /net/mac80211/cfg.c
parent71e6195ed2541d764fb0d7ef39cdb2236817116b (diff)
mac80211: use chanctx reservation for AP CSA
Channel switch finalization is now 2-step. First step is when driver calls csa_finish(), the other is when reservation is actually finalized (which can be deferred for in-place reservation). It is now safe to call ieee80211_csa_finish() more than once. Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r--net/mac80211/cfg.c82
1 files changed, 55 insertions, 27 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 73c9e1003e25..927b4ea0128b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2792,17 +2792,35 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
2792 2792
2793 sdata_assert_lock(sdata); 2793 sdata_assert_lock(sdata);
2794 lockdep_assert_held(&local->mtx); 2794 lockdep_assert_held(&local->mtx);
2795 lockdep_assert_held(&local->chanctx_mtx);
2795 2796
2796 sdata->radar_required = sdata->csa_radar_required; 2797 /*
2797 err = ieee80211_vif_change_channel(sdata, &changed); 2798 * using reservation isn't immediate as it may be deferred until later
2798 if (err < 0) 2799 * with multi-vif. once reservation is complete it will re-schedule the
2799 return err; 2800 * work with no reserved_chanctx so verify chandef to check if it
2801 * completed successfully
2802 */
2800 2803
2801 if (!local->use_chanctx) { 2804 if (sdata->reserved_chanctx) {
2802 local->_oper_chandef = sdata->csa_chandef; 2805 /*
2803 ieee80211_hw_config(local, 0); 2806 * with multi-vif csa driver may call ieee80211_csa_finish()
2807 * many times while waiting for other interfaces to use their
2808 * reservations
2809 */
2810 if (sdata->reserved_ready)
2811 return 0;
2812
2813 err = ieee80211_vif_use_reserved_context(sdata);
2814 if (err)
2815 return err;
2816
2817 return 0;
2804 } 2818 }
2805 2819
2820 if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
2821 &sdata->csa_chandef))
2822 return -EINVAL;
2823
2806 sdata->vif.csa_active = false; 2824 sdata->vif.csa_active = false;
2807 2825
2808 err = ieee80211_set_after_csa_beacon(sdata, &changed); 2826 err = ieee80211_set_after_csa_beacon(sdata, &changed);
@@ -2839,6 +2857,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
2839 2857
2840 sdata_lock(sdata); 2858 sdata_lock(sdata);
2841 mutex_lock(&local->mtx); 2859 mutex_lock(&local->mtx);
2860 mutex_lock(&local->chanctx_mtx);
2842 2861
2843 /* AP might have been stopped while waiting for the lock. */ 2862 /* AP might have been stopped while waiting for the lock. */
2844 if (!sdata->vif.csa_active) 2863 if (!sdata->vif.csa_active)
@@ -2850,6 +2869,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
2850 ieee80211_csa_finalize(sdata); 2869 ieee80211_csa_finalize(sdata);
2851 2870
2852unlock: 2871unlock:
2872 mutex_unlock(&local->chanctx_mtx);
2853 mutex_unlock(&local->mtx); 2873 mutex_unlock(&local->mtx);
2854 sdata_unlock(sdata); 2874 sdata_unlock(sdata);
2855} 2875}
@@ -2995,7 +3015,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
2995 struct ieee80211_local *local = sdata->local; 3015 struct ieee80211_local *local = sdata->local;
2996 struct ieee80211_chanctx_conf *conf; 3016 struct ieee80211_chanctx_conf *conf;
2997 struct ieee80211_chanctx *chanctx; 3017 struct ieee80211_chanctx *chanctx;
2998 int err, num_chanctx, changed = 0; 3018 int err, changed = 0;
2999 3019
3000 sdata_assert_lock(sdata); 3020 sdata_assert_lock(sdata);
3001 lockdep_assert_held(&local->mtx); 3021 lockdep_assert_held(&local->mtx);
@@ -3010,37 +3030,43 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
3010 &sdata->vif.bss_conf.chandef)) 3030 &sdata->vif.bss_conf.chandef))
3011 return -EINVAL; 3031 return -EINVAL;
3012 3032
3033 /* don't allow another channel switch if one is already active. */
3034 if (sdata->vif.csa_active)
3035 return -EBUSY;
3036
3013 mutex_lock(&local->chanctx_mtx); 3037 mutex_lock(&local->chanctx_mtx);
3014 conf = rcu_dereference_protected(sdata->vif.chanctx_conf, 3038 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
3015 lockdep_is_held(&local->chanctx_mtx)); 3039 lockdep_is_held(&local->chanctx_mtx));
3016 if (!conf) { 3040 if (!conf) {
3017 mutex_unlock(&local->chanctx_mtx); 3041 err = -EBUSY;
3018 return -EBUSY; 3042 goto out;
3019 } 3043 }
3020 3044
3021 /* don't handle for multi-VIF cases */
3022 chanctx = container_of(conf, struct ieee80211_chanctx, conf); 3045 chanctx = container_of(conf, struct ieee80211_chanctx, conf);
3023 if (ieee80211_chanctx_refcount(local, chanctx) > 1) { 3046 if (!chanctx) {
3024 mutex_unlock(&local->chanctx_mtx); 3047 err = -EBUSY;
3025 return -EBUSY; 3048 goto out;
3026 } 3049 }
3027 num_chanctx = 0;
3028 list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
3029 num_chanctx++;
3030 mutex_unlock(&local->chanctx_mtx);
3031 3050
3032 if (num_chanctx > 1) 3051 err = ieee80211_vif_reserve_chanctx(sdata, &params->chandef,
3033 return -EBUSY; 3052 chanctx->mode,
3053 params->radar_required);
3054 if (err)
3055 goto out;
3034 3056
3035 /* don't allow another channel switch if one is already active. */ 3057 /* if reservation is invalid then this will fail */
3036 if (sdata->vif.csa_active) 3058 err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0);
3037 return -EBUSY; 3059 if (err) {
3060 ieee80211_vif_unreserve_chanctx(sdata);
3061 goto out;
3062 }
3038 3063
3039 err = ieee80211_set_csa_beacon(sdata, params, &changed); 3064 err = ieee80211_set_csa_beacon(sdata, params, &changed);
3040 if (err) 3065 if (err) {
3041 return err; 3066 ieee80211_vif_unreserve_chanctx(sdata);
3067 goto out;
3068 }
3042 3069
3043 sdata->csa_radar_required = params->radar_required;
3044 sdata->csa_chandef = params->chandef; 3070 sdata->csa_chandef = params->chandef;
3045 sdata->csa_block_tx = params->block_tx; 3071 sdata->csa_block_tx = params->block_tx;
3046 sdata->vif.csa_active = true; 3072 sdata->vif.csa_active = true;
@@ -3057,7 +3083,9 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
3057 ieee80211_csa_finalize(sdata); 3083 ieee80211_csa_finalize(sdata);
3058 } 3084 }
3059 3085
3060 return 0; 3086out:
3087 mutex_unlock(&local->chanctx_mtx);
3088 return err;
3061} 3089}
3062 3090
3063int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, 3091int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,