aboutsummaryrefslogtreecommitdiffstats
path: root/net
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
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')
-rw-r--r--net/mac80211/cfg.c82
-rw-r--r--net/mac80211/chan.c35
2 files changed, 88 insertions, 29 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,
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 0e4302bb5b34..ea4db2f0db87 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -1056,6 +1056,30 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
1056 return 0; 1056 return 0;
1057} 1057}
1058 1058
1059static void
1060ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
1061{
1062 switch (sdata->vif.type) {
1063 case NL80211_IFTYPE_ADHOC:
1064 case NL80211_IFTYPE_AP:
1065 case NL80211_IFTYPE_MESH_POINT:
1066 ieee80211_queue_work(&sdata->local->hw,
1067 &sdata->csa_finalize_work);
1068 break;
1069 case NL80211_IFTYPE_UNSPECIFIED:
1070 case NL80211_IFTYPE_STATION:
1071 case NL80211_IFTYPE_AP_VLAN:
1072 case NL80211_IFTYPE_WDS:
1073 case NL80211_IFTYPE_MONITOR:
1074 case NL80211_IFTYPE_P2P_CLIENT:
1075 case NL80211_IFTYPE_P2P_GO:
1076 case NL80211_IFTYPE_P2P_DEVICE:
1077 case NUM_NL80211_IFTYPES:
1078 WARN_ON(1);
1079 break;
1080 }
1081}
1082
1059static int 1083static int
1060ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) 1084ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
1061{ 1085{
@@ -1103,7 +1127,7 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
1103 if (ieee80211_chanctx_refcount(local, new_ctx) == 0) 1127 if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
1104 ieee80211_free_chanctx(local, new_ctx); 1128 ieee80211_free_chanctx(local, new_ctx);
1105 1129
1106 return err; 1130 goto out;
1107 } 1131 }
1108 1132
1109 list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs); 1133 list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs);
@@ -1123,6 +1147,8 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
1123 if (changed) 1147 if (changed)
1124 ieee80211_bss_info_change_notify(sdata, changed); 1148 ieee80211_bss_info_change_notify(sdata, changed);
1125 1149
1150out:
1151 ieee80211_vif_chanctx_reservation_complete(sdata);
1126 return err; 1152 return err;
1127} 1153}
1128 1154
@@ -1167,6 +1193,7 @@ ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata)
1167 } 1193 }
1168 1194
1169out: 1195out:
1196 ieee80211_vif_chanctx_reservation_complete(sdata);
1170 return err; 1197 return err;
1171} 1198}
1172 1199
@@ -1480,6 +1507,8 @@ ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
1480 list_move(&sdata->assigned_chanctx_list, 1507 list_move(&sdata->assigned_chanctx_list,
1481 &new_ctx->assigned_vifs); 1508 &new_ctx->assigned_vifs);
1482 sdata->reserved_chanctx = NULL; 1509 sdata->reserved_chanctx = NULL;
1510
1511 ieee80211_vif_chanctx_reservation_complete(sdata);
1483 } 1512 }
1484 1513
1485 /* 1514 /*
@@ -1543,8 +1572,10 @@ err:
1543 continue; 1572 continue;
1544 1573
1545 list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, 1574 list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
1546 reserved_chanctx_list) 1575 reserved_chanctx_list) {
1547 ieee80211_vif_unreserve_chanctx(sdata); 1576 ieee80211_vif_unreserve_chanctx(sdata);
1577 ieee80211_vif_chanctx_reservation_complete(sdata);
1578 }
1548 } 1579 }
1549 1580
1550 return err; 1581 return err;