diff options
author | Simon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de> | 2013-04-08 16:43:16 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-04-10 14:24:16 -0400 |
commit | e47468518b9dc42db459e7240909946316d9c6c9 (patch) | |
tree | 46e35f5017ed635c2d9b930145ae542776a3fc32 /net/mac80211/chan.c | |
parent | 3088f7d2db42925808c4b43a6258647ee4d1dd5f (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.c | 43 |
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 | ||
60 | static 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 | |||
60 | static struct ieee80211_chanctx * | 76 | static struct ieee80211_chanctx * |
61 | ieee80211_new_chanctx(struct ieee80211_local *local, | 77 | ieee80211_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, | |||
99 | static void ieee80211_free_chanctx(struct ieee80211_local *local, | 118 | static 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) | |||
227 | void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, | 258 | void 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; |