aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/chan.c
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2012-06-26 08:37:22 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-10-16 14:22:44 -0400
commite89a96f5cc4c39c268c771f52d675e15e3ba8123 (patch)
tree170ea6f86a7f04ad8035a90c53c967f4b02cf633 /net/mac80211/chan.c
parent35f2fce9a4376f89f2ebac705a2742ffc058f988 (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.c59
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
172static 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
173static struct ieee80211_chanctx * 183static 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
280static enum nl80211_channel_type
281ieee80211_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
306static 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
263static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, 317static 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
276static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) 333static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)