aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/chan.c
diff options
context:
space:
mode:
authorSimon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de>2013-04-08 16:43:16 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-04-10 14:24:16 -0400
commite47468518b9dc42db459e7240909946316d9c6c9 (patch)
tree46e35f5017ed635c2d9b930145ae542776a3fc32 /net/mac80211/chan.c
parent3088f7d2db42925808c4b43a6258647ee4d1dd5f (diff)
mac80211: fix recalc_radar hwconf sync problem
local->hw.conf maybe not be synced when recalcing whether radar is enabled, sometimes leaving radar enabled even if it's not neccesary anymore. Fix this by: * setting radar_enabled when creating the chanctx * turning radar_enabled off before destroying the last channel context Reported-by: Zefir Kurtisi <zefir.kurtisi@neratec.com> Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/chan.c')
-rw-r--r--net/mac80211/chan.c43
1 files changed, 33 insertions, 10 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 8024874ba95d..166165efd8e2 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -57,6 +57,22 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
57 return NULL; 57 return NULL;
58} 58}
59 59
60static bool ieee80211_is_radar_required(struct ieee80211_local *local)
61{
62 struct ieee80211_sub_if_data *sdata;
63
64 rcu_read_lock();
65 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
66 if (sdata->radar_required) {
67 rcu_read_unlock();
68 return true;
69 }
70 }
71 rcu_read_unlock();
72
73 return false;
74}
75
60static struct ieee80211_chanctx * 76static struct ieee80211_chanctx *
61ieee80211_new_chanctx(struct ieee80211_local *local, 77ieee80211_new_chanctx(struct ieee80211_local *local,
62 const struct cfg80211_chan_def *chandef, 78 const struct cfg80211_chan_def *chandef,
@@ -75,6 +91,9 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
75 ctx->conf.rx_chains_static = 1; 91 ctx->conf.rx_chains_static = 1;
76 ctx->conf.rx_chains_dynamic = 1; 92 ctx->conf.rx_chains_dynamic = 1;
77 ctx->mode = mode; 93 ctx->mode = mode;
94 ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
95 if (!local->use_chanctx)
96 local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
78 97
79 if (!local->use_chanctx) { 98 if (!local->use_chanctx) {
80 local->_oper_chandef = *chandef; 99 local->_oper_chandef = *chandef;
@@ -99,6 +118,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
99static void ieee80211_free_chanctx(struct ieee80211_local *local, 118static void ieee80211_free_chanctx(struct ieee80211_local *local,
100 struct ieee80211_chanctx *ctx) 119 struct ieee80211_chanctx *ctx)
101{ 120{
121 bool check_single_channel = false;
102 lockdep_assert_held(&local->chanctx_mtx); 122 lockdep_assert_held(&local->chanctx_mtx);
103 123
104 WARN_ON_ONCE(ctx->refcount != 0); 124 WARN_ON_ONCE(ctx->refcount != 0);
@@ -108,6 +128,14 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
108 chandef->width = NL80211_CHAN_WIDTH_20_NOHT; 128 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
109 chandef->center_freq1 = chandef->chan->center_freq; 129 chandef->center_freq1 = chandef->chan->center_freq;
110 chandef->center_freq2 = 0; 130 chandef->center_freq2 = 0;
131
132 /* NOTE: Disabling radar is only valid here for
133 * single channel context. To be sure, check it ...
134 */
135 if (local->hw.conf.radar_enabled)
136 check_single_channel = true;
137 local->hw.conf.radar_enabled = false;
138
111 ieee80211_hw_config(local, 0); 139 ieee80211_hw_config(local, 0);
112 } else { 140 } else {
113 drv_remove_chanctx(local, ctx); 141 drv_remove_chanctx(local, ctx);
@@ -116,6 +144,9 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
116 list_del_rcu(&ctx->list); 144 list_del_rcu(&ctx->list);
117 kfree_rcu(ctx, rcu_head); 145 kfree_rcu(ctx, rcu_head);
118 146
147 /* throw a warning if this wasn't the only channel context. */
148 WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
149
119 mutex_lock(&local->mtx); 150 mutex_lock(&local->mtx);
120 ieee80211_recalc_idle(local); 151 ieee80211_recalc_idle(local);
121 mutex_unlock(&local->mtx); 152 mutex_unlock(&local->mtx);
@@ -227,19 +258,11 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
227void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, 258void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
228 struct ieee80211_chanctx *chanctx) 259 struct ieee80211_chanctx *chanctx)
229{ 260{
230 struct ieee80211_sub_if_data *sdata; 261 bool radar_enabled;
231 bool radar_enabled = false;
232 262
233 lockdep_assert_held(&local->chanctx_mtx); 263 lockdep_assert_held(&local->chanctx_mtx);
234 264
235 rcu_read_lock(); 265 radar_enabled = ieee80211_is_radar_required(local);
236 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
237 if (sdata->radar_required) {
238 radar_enabled = true;
239 break;
240 }
241 }
242 rcu_read_unlock();
243 266
244 if (radar_enabled == chanctx->conf.radar_enabled) 267 if (radar_enabled == chanctx->conf.radar_enabled)
245 return; 268 return;