diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2012-06-26 08:37:22 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-10-16 14:22:44 -0400 |
commit | e89a96f5cc4c39c268c771f52d675e15e3ba8123 (patch) | |
tree | 170ea6f86a7f04ad8035a90c53c967f4b02cf633 /net/mac80211/chan.c | |
parent | 35f2fce9a4376f89f2ebac705a2742ffc058f988 (diff) |
mac80211: reuse channels for channel contexts
Reuse channels with compatible channel types. Some
channel types are compatible and can be used
concurrently.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/chan.c')
-rw-r--r-- | net/mac80211/chan.c | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index ff3b29ec396a..1a8dee42e546 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -167,7 +167,17 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local, | |||
167 | sdata->vif.bss_conf.channel_type = chantype; | 167 | sdata->vif.bss_conf.channel_type = chantype; |
168 | 168 | ||
169 | return true; | 169 | return true; |
170 | } | ||
171 | |||
172 | static void ieee80211_change_chantype(struct ieee80211_local *local, | ||
173 | struct ieee80211_chanctx *ctx, | ||
174 | enum nl80211_channel_type chantype) | ||
175 | { | ||
176 | if (chantype == ctx->conf.channel_type) | ||
177 | return; | ||
170 | 178 | ||
179 | ctx->conf.channel_type = chantype; | ||
180 | drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE); | ||
171 | } | 181 | } |
172 | 182 | ||
173 | static struct ieee80211_chanctx * | 183 | static struct ieee80211_chanctx * |
@@ -177,6 +187,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local, | |||
177 | enum ieee80211_chanctx_mode mode) | 187 | enum ieee80211_chanctx_mode mode) |
178 | { | 188 | { |
179 | struct ieee80211_chanctx *ctx; | 189 | struct ieee80211_chanctx *ctx; |
190 | enum nl80211_channel_type compat_type; | ||
180 | 191 | ||
181 | lockdep_assert_held(&local->chanctx_mtx); | 192 | lockdep_assert_held(&local->chanctx_mtx); |
182 | 193 | ||
@@ -186,13 +197,19 @@ ieee80211_find_chanctx(struct ieee80211_local *local, | |||
186 | return NULL; | 197 | return NULL; |
187 | 198 | ||
188 | list_for_each_entry(ctx, &local->chanctx_list, list) { | 199 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
200 | compat_type = ctx->conf.channel_type; | ||
201 | |||
189 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) | 202 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) |
190 | continue; | 203 | continue; |
191 | if (ctx->conf.channel != channel) | 204 | if (ctx->conf.channel != channel) |
192 | continue; | 205 | continue; |
193 | if (ctx->conf.channel_type != channel_type) | 206 | if (!ieee80211_channel_types_are_compatible(ctx->conf.channel_type, |
207 | channel_type, | ||
208 | &compat_type)) | ||
194 | continue; | 209 | continue; |
195 | 210 | ||
211 | ieee80211_change_chantype(local, ctx, compat_type); | ||
212 | |||
196 | return ctx; | 213 | return ctx; |
197 | } | 214 | } |
198 | 215 | ||
@@ -260,6 +277,43 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | |||
260 | return 0; | 277 | return 0; |
261 | } | 278 | } |
262 | 279 | ||
280 | static enum nl80211_channel_type | ||
281 | ieee80211_calc_chantype(struct ieee80211_local *local, | ||
282 | struct ieee80211_chanctx *ctx) | ||
283 | { | ||
284 | struct ieee80211_chanctx_conf *conf = &ctx->conf; | ||
285 | struct ieee80211_sub_if_data *sdata; | ||
286 | enum nl80211_channel_type result = NL80211_CHAN_NO_HT; | ||
287 | |||
288 | lockdep_assert_held(&local->chanctx_mtx); | ||
289 | |||
290 | rcu_read_lock(); | ||
291 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
292 | if (!ieee80211_sdata_running(sdata)) | ||
293 | continue; | ||
294 | if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) | ||
295 | continue; | ||
296 | |||
297 | WARN_ON_ONCE(!ieee80211_channel_types_are_compatible( | ||
298 | sdata->vif.bss_conf.channel_type, | ||
299 | result, &result)); | ||
300 | } | ||
301 | rcu_read_unlock(); | ||
302 | |||
303 | return result; | ||
304 | } | ||
305 | |||
306 | static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, | ||
307 | struct ieee80211_chanctx *ctx) | ||
308 | { | ||
309 | enum nl80211_channel_type chantype; | ||
310 | |||
311 | lockdep_assert_held(&local->chanctx_mtx); | ||
312 | |||
313 | chantype = ieee80211_calc_chantype(local, ctx); | ||
314 | ieee80211_change_chantype(local, ctx, chantype); | ||
315 | } | ||
316 | |||
263 | static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | 317 | static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, |
264 | struct ieee80211_chanctx *ctx) | 318 | struct ieee80211_chanctx *ctx) |
265 | { | 319 | { |
@@ -271,6 +325,9 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | |||
271 | rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); | 325 | rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); |
272 | 326 | ||
273 | drv_unassign_vif_chanctx(local, sdata, ctx); | 327 | drv_unassign_vif_chanctx(local, sdata, ctx); |
328 | |||
329 | if (ctx->refcount > 0) | ||
330 | ieee80211_recalc_chanctx_chantype(sdata->local, ctx); | ||
274 | } | 331 | } |
275 | 332 | ||
276 | static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | 333 | static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) |