2 * mac80211 - channel management
5 #include <linux/nl80211.h>
6 #include <linux/export.h>
7 #include <net/cfg80211.h>
8 #include "ieee80211_i.h"
9 #include "driver-ops.h"
12 ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1,
13 enum nl80211_channel_type chantype2,
14 enum nl80211_channel_type *compat)
17 * start out with chantype1 being the result,
18 * overwriting later if needed
24 case NL80211_CHAN_NO_HT:
28 case NL80211_CHAN_HT20:
30 * allow any change that doesn't go to no-HT
31 * (if it already is no-HT no change is needed)
33 if (chantype2 == NL80211_CHAN_NO_HT)
38 case NL80211_CHAN_HT40PLUS:
39 case NL80211_CHAN_HT40MINUS:
40 /* allow smaller bandwidth and same */
41 if (chantype2 == NL80211_CHAN_NO_HT)
43 if (chantype2 == NL80211_CHAN_HT20)
45 if (chantype2 == chantype1)
53 static void ieee80211_change_chantype(struct ieee80211_local *local,
54 struct ieee80211_chanctx *ctx,
55 enum nl80211_channel_type chantype)
57 if (chantype == ctx->conf.channel_type)
60 ctx->conf.channel_type = chantype;
61 drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE);
63 if (!local->use_chanctx) {
64 local->_oper_channel_type = chantype;
65 ieee80211_hw_config(local, 0);
69 static struct ieee80211_chanctx *
70 ieee80211_find_chanctx(struct ieee80211_local *local,
71 struct ieee80211_channel *channel,
72 enum nl80211_channel_type channel_type,
73 enum ieee80211_chanctx_mode mode)
75 struct ieee80211_chanctx *ctx;
76 enum nl80211_channel_type compat_type;
78 lockdep_assert_held(&local->chanctx_mtx);
80 if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
82 if (WARN_ON(!channel))
85 list_for_each_entry(ctx, &local->chanctx_list, list) {
86 compat_type = ctx->conf.channel_type;
88 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
90 if (ctx->conf.channel != channel)
92 if (!ieee80211_channel_types_are_compatible(ctx->conf.channel_type,
97 ieee80211_change_chantype(local, ctx, compat_type);
105 static struct ieee80211_chanctx *
106 ieee80211_new_chanctx(struct ieee80211_local *local,
107 struct ieee80211_channel *channel,
108 enum nl80211_channel_type channel_type,
109 enum ieee80211_chanctx_mode mode)
111 struct ieee80211_chanctx *ctx;
114 lockdep_assert_held(&local->chanctx_mtx);
116 ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
118 return ERR_PTR(-ENOMEM);
120 ctx->conf.channel = channel;
121 ctx->conf.channel_type = channel_type;
122 ctx->conf.rx_chains_static = 1;
123 ctx->conf.rx_chains_dynamic = 1;
126 if (!local->use_chanctx) {
127 local->_oper_channel_type = channel_type;
128 local->_oper_channel = channel;
129 ieee80211_hw_config(local, 0);
131 err = drv_add_chanctx(local, ctx);
138 list_add_rcu(&ctx->list, &local->chanctx_list);
143 static void ieee80211_free_chanctx(struct ieee80211_local *local,
144 struct ieee80211_chanctx *ctx)
146 lockdep_assert_held(&local->chanctx_mtx);
148 WARN_ON_ONCE(ctx->refcount != 0);
150 if (!local->use_chanctx) {
151 local->_oper_channel_type = NL80211_CHAN_NO_HT;
152 ieee80211_hw_config(local, 0);
154 drv_remove_chanctx(local, ctx);
157 list_del_rcu(&ctx->list);
158 kfree_rcu(ctx, rcu_head);
161 static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
162 struct ieee80211_chanctx *ctx)
164 struct ieee80211_local *local = sdata->local;
167 lockdep_assert_held(&local->chanctx_mtx);
169 ret = drv_assign_vif_chanctx(local, sdata, ctx);
173 rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
179 static enum nl80211_channel_type
180 ieee80211_calc_chantype(struct ieee80211_local *local,
181 struct ieee80211_chanctx *ctx)
183 struct ieee80211_chanctx_conf *conf = &ctx->conf;
184 struct ieee80211_sub_if_data *sdata;
185 enum nl80211_channel_type result = NL80211_CHAN_NO_HT;
187 lockdep_assert_held(&local->chanctx_mtx);
190 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
191 if (!ieee80211_sdata_running(sdata))
193 if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
196 WARN_ON_ONCE(!ieee80211_channel_types_are_compatible(
197 sdata->vif.bss_conf.channel_type,
205 static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
206 struct ieee80211_chanctx *ctx)
208 enum nl80211_channel_type chantype;
210 lockdep_assert_held(&local->chanctx_mtx);
212 chantype = ieee80211_calc_chantype(local, ctx);
213 ieee80211_change_chantype(local, ctx, chantype);
216 static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
217 struct ieee80211_chanctx *ctx)
219 struct ieee80211_local *local = sdata->local;
221 lockdep_assert_held(&local->chanctx_mtx);
224 rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
226 drv_unassign_vif_chanctx(local, sdata, ctx);
228 if (ctx->refcount > 0) {
229 ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
230 ieee80211_recalc_smps_chanctx(local, ctx);
234 static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
236 struct ieee80211_local *local = sdata->local;
237 struct ieee80211_chanctx_conf *conf;
238 struct ieee80211_chanctx *ctx;
240 lockdep_assert_held(&local->chanctx_mtx);
242 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
243 lockdep_is_held(&local->chanctx_mtx));
247 ctx = container_of(conf, struct ieee80211_chanctx, conf);
249 ieee80211_unassign_vif_chanctx(sdata, ctx);
250 if (ctx->refcount == 0)
251 ieee80211_free_chanctx(local, ctx);
254 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
255 struct ieee80211_chanctx *chanctx)
257 struct ieee80211_sub_if_data *sdata;
258 u8 rx_chains_static, rx_chains_dynamic;
260 lockdep_assert_held(&local->chanctx_mtx);
262 rx_chains_static = 1;
263 rx_chains_dynamic = 1;
266 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
267 u8 needed_static, needed_dynamic;
269 if (!ieee80211_sdata_running(sdata))
272 if (rcu_access_pointer(sdata->vif.chanctx_conf) !=
276 switch (sdata->vif.type) {
277 case NL80211_IFTYPE_P2P_DEVICE:
279 case NL80211_IFTYPE_STATION:
280 if (!sdata->u.mgd.associated)
283 case NL80211_IFTYPE_AP_VLAN:
285 case NL80211_IFTYPE_AP:
286 case NL80211_IFTYPE_ADHOC:
287 case NL80211_IFTYPE_WDS:
288 case NL80211_IFTYPE_MESH_POINT:
294 switch (sdata->smps_mode) {
296 WARN_ONCE(1, "Invalid SMPS mode %d\n",
299 case IEEE80211_SMPS_OFF:
300 needed_static = sdata->needed_rx_chains;
301 needed_dynamic = sdata->needed_rx_chains;
303 case IEEE80211_SMPS_DYNAMIC:
305 needed_dynamic = sdata->needed_rx_chains;
307 case IEEE80211_SMPS_STATIC:
313 rx_chains_static = max(rx_chains_static, needed_static);
314 rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
318 if (!local->use_chanctx) {
319 if (rx_chains_static > 1)
320 local->smps_mode = IEEE80211_SMPS_OFF;
321 else if (rx_chains_dynamic > 1)
322 local->smps_mode = IEEE80211_SMPS_DYNAMIC;
324 local->smps_mode = IEEE80211_SMPS_STATIC;
325 ieee80211_hw_config(local, 0);
328 if (rx_chains_static == chanctx->conf.rx_chains_static &&
329 rx_chains_dynamic == chanctx->conf.rx_chains_dynamic)
332 chanctx->conf.rx_chains_static = rx_chains_static;
333 chanctx->conf.rx_chains_dynamic = rx_chains_dynamic;
334 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
337 int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
338 struct ieee80211_channel *channel,
339 enum nl80211_channel_type channel_type,
340 enum ieee80211_chanctx_mode mode)
342 struct ieee80211_local *local = sdata->local;
343 struct ieee80211_chanctx *ctx;
346 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
348 mutex_lock(&local->chanctx_mtx);
349 __ieee80211_vif_release_channel(sdata);
351 ctx = ieee80211_find_chanctx(local, channel, channel_type, mode);
353 ctx = ieee80211_new_chanctx(local, channel, channel_type, mode);
359 sdata->vif.bss_conf.channel_type = channel_type;
361 ret = ieee80211_assign_vif_chanctx(sdata, ctx);
363 /* if assign fails refcount stays the same */
364 if (ctx->refcount == 0)
365 ieee80211_free_chanctx(local, ctx);
369 ieee80211_recalc_smps_chanctx(local, ctx);
371 mutex_unlock(&local->chanctx_mtx);
375 void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
377 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
379 mutex_lock(&sdata->local->chanctx_mtx);
380 __ieee80211_vif_release_channel(sdata);
381 mutex_unlock(&sdata->local->chanctx_mtx);
384 void ieee80211_iter_chan_contexts_atomic(
385 struct ieee80211_hw *hw,
386 void (*iter)(struct ieee80211_hw *hw,
387 struct ieee80211_chanctx_conf *chanctx_conf,
391 struct ieee80211_local *local = hw_to_local(hw);
392 struct ieee80211_chanctx *ctx;
395 list_for_each_entry_rcu(ctx, &local->chanctx_list, list)
396 iter(hw, &ctx->conf, iter_data);
399 EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic);