blob: 0dfb04a07f3069113acd5ad5920b3b8bb455b546 [file] [log] [blame]
Johannes Bergf444de02010-05-05 15:25:02 +02001/*
2 * mac80211 - channel management
3 */
4
Johannes Berg0aaffa92010-05-05 15:28:27 +02005#include <linux/nl80211.h>
Johannes Berg3448c002012-09-11 17:57:42 +02006#include <linux/export.h>
Johannes Berg4d76d212012-12-11 20:38:41 +01007#include <linux/rtnetlink.h>
Paul Stewart3117bbdb2012-03-13 07:46:18 -07008#include <net/cfg80211.h>
Johannes Bergf444de02010-05-05 15:25:02 +02009#include "ieee80211_i.h"
Michal Kazior35f2fce2012-06-26 14:37:20 +020010#include "driver-ops.h"
Johannes Bergf444de02010-05-05 15:25:02 +020011
Michal Kaziorc2b90ad2014-04-09 15:29:24 +020012static int ieee80211_num_chanctx(struct ieee80211_local *local)
13{
14 struct ieee80211_chanctx *ctx;
15 int num = 0;
16
17 lockdep_assert_held(&local->chanctx_mtx);
18
19 list_for_each_entry(ctx, &local->chanctx_list, list)
20 num++;
21
22 return num;
23}
24
25static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
26{
27 lockdep_assert_held(&local->chanctx_mtx);
28 return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
29}
30
Michal Kazior02881572014-04-09 15:29:28 +020031static const struct cfg80211_chan_def *
32ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
33 struct ieee80211_chanctx *ctx,
34 const struct cfg80211_chan_def *compat)
35{
36 struct ieee80211_sub_if_data *sdata;
37
38 lockdep_assert_held(&local->chanctx_mtx);
39
40 list_for_each_entry(sdata, &ctx->reserved_vifs,
41 reserved_chanctx_list) {
42 if (!compat)
43 compat = &sdata->reserved_chandef;
44
45 compat = cfg80211_chandef_compatible(&sdata->reserved_chandef,
46 compat);
47 if (!compat)
48 break;
49 }
50
51 return compat;
52}
53
Eliad Peller21f659b2013-11-11 20:14:01 +020054static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
55{
56 switch (sta->bandwidth) {
57 case IEEE80211_STA_RX_BW_20:
58 if (sta->ht_cap.ht_supported)
59 return NL80211_CHAN_WIDTH_20;
60 else
61 return NL80211_CHAN_WIDTH_20_NOHT;
62 case IEEE80211_STA_RX_BW_40:
63 return NL80211_CHAN_WIDTH_40;
64 case IEEE80211_STA_RX_BW_80:
65 return NL80211_CHAN_WIDTH_80;
66 case IEEE80211_STA_RX_BW_160:
67 /*
68 * This applied for both 160 and 80+80. since we use
69 * the returned value to consider degradation of
70 * ctx->conf.min_def, we have to make sure to take
71 * the bigger one (NL80211_CHAN_WIDTH_160).
72 * Otherwise we might try degrading even when not
73 * needed, as the max required sta_bw returned (80+80)
74 * might be smaller than the configured bw (160).
75 */
76 return NL80211_CHAN_WIDTH_160;
77 default:
78 WARN_ON(1);
79 return NL80211_CHAN_WIDTH_20;
80 }
81}
82
83static enum nl80211_chan_width
84ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata)
85{
86 enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
87 struct sta_info *sta;
88
89 rcu_read_lock();
90 list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
91 if (sdata != sta->sdata &&
92 !(sta->sdata->bss && sta->sdata->bss == sdata->bss))
93 continue;
94
95 if (!sta->uploaded)
96 continue;
97
98 max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta));
99 }
100 rcu_read_unlock();
101
102 return max_bw;
103}
104
105static enum nl80211_chan_width
106ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
107 struct ieee80211_chanctx_conf *conf)
108{
109 struct ieee80211_sub_if_data *sdata;
110 enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
111
112 rcu_read_lock();
113 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
114 struct ieee80211_vif *vif = &sdata->vif;
115 enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;
116
117 if (!ieee80211_sdata_running(sdata))
118 continue;
119
120 if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
121 continue;
122
123 switch (vif->type) {
124 case NL80211_IFTYPE_AP:
125 case NL80211_IFTYPE_AP_VLAN:
126 width = ieee80211_get_max_required_bw(sdata);
127 break;
128 case NL80211_IFTYPE_P2P_DEVICE:
129 continue;
130 case NL80211_IFTYPE_STATION:
131 case NL80211_IFTYPE_ADHOC:
132 case NL80211_IFTYPE_WDS:
133 case NL80211_IFTYPE_MESH_POINT:
134 width = vif->bss_conf.chandef.width;
135 break;
136 case NL80211_IFTYPE_UNSPECIFIED:
137 case NUM_NL80211_IFTYPES:
138 case NL80211_IFTYPE_MONITOR:
139 case NL80211_IFTYPE_P2P_CLIENT:
140 case NL80211_IFTYPE_P2P_GO:
141 WARN_ON_ONCE(1);
142 }
143 max_bw = max(max_bw, width);
144 }
Eliad Peller1c37a722014-03-03 13:37:14 +0200145
146 /* use the configured bandwidth in case of monitor interface */
147 sdata = rcu_dereference(local->monitor_sdata);
148 if (sdata && rcu_access_pointer(sdata->vif.chanctx_conf) == conf)
149 max_bw = max(max_bw, conf->def.width);
150
Eliad Peller21f659b2013-11-11 20:14:01 +0200151 rcu_read_unlock();
152
153 return max_bw;
154}
155
156/*
157 * recalc the min required chan width of the channel context, which is
158 * the max of min required widths of all the interfaces bound to this
159 * channel context.
160 */
161void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
162 struct ieee80211_chanctx *ctx)
163{
164 enum nl80211_chan_width max_bw;
165 struct cfg80211_chan_def min_def;
166
167 lockdep_assert_held(&local->chanctx_mtx);
168
169 /* don't optimize 5MHz, 10MHz, and radar_enabled confs */
170 if (ctx->conf.def.width == NL80211_CHAN_WIDTH_5 ||
171 ctx->conf.def.width == NL80211_CHAN_WIDTH_10 ||
172 ctx->conf.radar_enabled) {
173 ctx->conf.min_def = ctx->conf.def;
174 return;
175 }
176
177 max_bw = ieee80211_get_chanctx_max_required_bw(local, &ctx->conf);
178
179 /* downgrade chandef up to max_bw */
180 min_def = ctx->conf.def;
181 while (min_def.width > max_bw)
182 ieee80211_chandef_downgrade(&min_def);
183
184 if (cfg80211_chandef_identical(&ctx->conf.min_def, &min_def))
185 return;
186
187 ctx->conf.min_def = min_def;
188 if (!ctx->driver_present)
189 return;
190
191 drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_MIN_WIDTH);
192}
193
Johannes Berg18942d32013-02-07 21:30:37 +0100194static void ieee80211_change_chanctx(struct ieee80211_local *local,
Johannes Berg4bf88532012-11-09 11:39:59 +0100195 struct ieee80211_chanctx *ctx,
196 const struct cfg80211_chan_def *chandef)
Michal Kazior23a85b452012-06-26 14:37:21 +0200197{
Johannes Berg4bf88532012-11-09 11:39:59 +0100198 if (cfg80211_chandef_identical(&ctx->conf.def, chandef))
Michal Kaziore89a96f2012-06-26 14:37:22 +0200199 return;
200
Johannes Berg4bf88532012-11-09 11:39:59 +0100201 WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef));
202
203 ctx->conf.def = *chandef;
204 drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);
Eliad Peller21f659b2013-11-11 20:14:01 +0200205 ieee80211_recalc_chanctx_min_def(local, ctx);
Johannes Berg55de9082012-07-26 17:24:39 +0200206
207 if (!local->use_chanctx) {
Karl Beldan675a0b02013-03-25 16:26:57 +0100208 local->_oper_chandef = *chandef;
Johannes Berg55de9082012-07-26 17:24:39 +0200209 ieee80211_hw_config(local, 0);
210 }
Johannes Berg0aaffa92010-05-05 15:28:27 +0200211}
Michal Kaziord01a1e62012-06-26 14:37:16 +0200212
213static struct ieee80211_chanctx *
214ieee80211_find_chanctx(struct ieee80211_local *local,
Johannes Berg4bf88532012-11-09 11:39:59 +0100215 const struct cfg80211_chan_def *chandef,
Michal Kaziord01a1e62012-06-26 14:37:16 +0200216 enum ieee80211_chanctx_mode mode)
217{
218 struct ieee80211_chanctx *ctx;
219
220 lockdep_assert_held(&local->chanctx_mtx);
221
222 if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
223 return NULL;
Michal Kaziord01a1e62012-06-26 14:37:16 +0200224
225 list_for_each_entry(ctx, &local->chanctx_list, list) {
Johannes Berg4bf88532012-11-09 11:39:59 +0100226 const struct cfg80211_chan_def *compat;
Michal Kaziore89a96f2012-06-26 14:37:22 +0200227
Michal Kazior02881572014-04-09 15:29:28 +0200228 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
Michal Kaziord01a1e62012-06-26 14:37:16 +0200229 continue;
Johannes Berg4bf88532012-11-09 11:39:59 +0100230
231 compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef);
232 if (!compat)
Michal Kaziord01a1e62012-06-26 14:37:16 +0200233 continue;
234
Michal Kazior02881572014-04-09 15:29:28 +0200235 compat = ieee80211_chanctx_reserved_chandef(local, ctx,
236 compat);
237 if (!compat)
238 continue;
239
Johannes Berg18942d32013-02-07 21:30:37 +0100240 ieee80211_change_chanctx(local, ctx, compat);
Michal Kaziore89a96f2012-06-26 14:37:22 +0200241
Michal Kaziord01a1e62012-06-26 14:37:16 +0200242 return ctx;
243 }
244
245 return NULL;
246}
247
Simon Wunderliche4746852013-04-08 22:43:16 +0200248static bool ieee80211_is_radar_required(struct ieee80211_local *local)
249{
250 struct ieee80211_sub_if_data *sdata;
251
Michal Kaziorcc901de2014-01-29 07:56:20 +0100252 lockdep_assert_held(&local->mtx);
253
Simon Wunderliche4746852013-04-08 22:43:16 +0200254 rcu_read_lock();
255 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
256 if (sdata->radar_required) {
257 rcu_read_unlock();
258 return true;
259 }
260 }
261 rcu_read_unlock();
262
263 return false;
264}
265
Michal Kaziord01a1e62012-06-26 14:37:16 +0200266static struct ieee80211_chanctx *
267ieee80211_new_chanctx(struct ieee80211_local *local,
Johannes Berg4bf88532012-11-09 11:39:59 +0100268 const struct cfg80211_chan_def *chandef,
Michal Kaziord01a1e62012-06-26 14:37:16 +0200269 enum ieee80211_chanctx_mode mode)
270{
271 struct ieee80211_chanctx *ctx;
Johannes Berg382a1032013-03-22 22:30:09 +0100272 u32 changed;
Michal Kazior35f2fce2012-06-26 14:37:20 +0200273 int err;
Michal Kaziord01a1e62012-06-26 14:37:16 +0200274
275 lockdep_assert_held(&local->chanctx_mtx);
276
277 ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
278 if (!ctx)
279 return ERR_PTR(-ENOMEM);
280
Michal Kazior484298a2014-04-09 15:29:26 +0200281 INIT_LIST_HEAD(&ctx->assigned_vifs);
Michal Kaziore3afb922014-04-09 15:29:27 +0200282 INIT_LIST_HEAD(&ctx->reserved_vifs);
Johannes Berg4bf88532012-11-09 11:39:59 +0100283 ctx->conf.def = *chandef;
Johannes Berg04ecd252012-09-11 14:34:12 +0200284 ctx->conf.rx_chains_static = 1;
285 ctx->conf.rx_chains_dynamic = 1;
Michal Kaziord01a1e62012-06-26 14:37:16 +0200286 ctx->mode = mode;
Simon Wunderliche4746852013-04-08 22:43:16 +0200287 ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
Eliad Peller21f659b2013-11-11 20:14:01 +0200288 ieee80211_recalc_chanctx_min_def(local, ctx);
Simon Wunderliche4746852013-04-08 22:43:16 +0200289 if (!local->use_chanctx)
290 local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
Michal Kaziord01a1e62012-06-26 14:37:16 +0200291
Johannes Berg34a37402013-12-18 09:43:33 +0100292 /* we hold the mutex to prevent idle from changing */
293 lockdep_assert_held(&local->mtx);
Johannes Berg382a1032013-03-22 22:30:09 +0100294 /* turn idle off *before* setting channel -- some drivers need that */
295 changed = ieee80211_idle_off(local);
296 if (changed)
297 ieee80211_hw_config(local, changed);
298
Johannes Berg55de9082012-07-26 17:24:39 +0200299 if (!local->use_chanctx) {
Karl Beldan675a0b02013-03-25 16:26:57 +0100300 local->_oper_chandef = *chandef;
Johannes Berg55de9082012-07-26 17:24:39 +0200301 ieee80211_hw_config(local, 0);
302 } else {
303 err = drv_add_chanctx(local, ctx);
304 if (err) {
305 kfree(ctx);
Johannes Berg382a1032013-03-22 22:30:09 +0100306 ieee80211_recalc_idle(local);
Johannes Berg34a37402013-12-18 09:43:33 +0100307 return ERR_PTR(err);
Johannes Berg55de9082012-07-26 17:24:39 +0200308 }
Michal Kazior35f2fce2012-06-26 14:37:20 +0200309 }
310
Johannes Berg382a1032013-03-22 22:30:09 +0100311 /* and keep the mutex held until the new chanctx is on the list */
Johannes Berg3448c002012-09-11 17:57:42 +0200312 list_add_rcu(&ctx->list, &local->chanctx_list);
Michal Kaziord01a1e62012-06-26 14:37:16 +0200313
314 return ctx;
315}
316
317static void ieee80211_free_chanctx(struct ieee80211_local *local,
318 struct ieee80211_chanctx *ctx)
319{
Simon Wunderliche4746852013-04-08 22:43:16 +0200320 bool check_single_channel = false;
Michal Kaziord01a1e62012-06-26 14:37:16 +0200321 lockdep_assert_held(&local->chanctx_mtx);
322
323 WARN_ON_ONCE(ctx->refcount != 0);
324
Johannes Berg55de9082012-07-26 17:24:39 +0200325 if (!local->use_chanctx) {
Karl Beldan675a0b02013-03-25 16:26:57 +0100326 struct cfg80211_chan_def *chandef = &local->_oper_chandef;
327 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
328 chandef->center_freq1 = chandef->chan->center_freq;
329 chandef->center_freq2 = 0;
Simon Wunderliche4746852013-04-08 22:43:16 +0200330
331 /* NOTE: Disabling radar is only valid here for
332 * single channel context. To be sure, check it ...
333 */
334 if (local->hw.conf.radar_enabled)
335 check_single_channel = true;
336 local->hw.conf.radar_enabled = false;
337
Johannes Berg55de9082012-07-26 17:24:39 +0200338 ieee80211_hw_config(local, 0);
339 } else {
340 drv_remove_chanctx(local, ctx);
341 }
Michal Kazior35f2fce2012-06-26 14:37:20 +0200342
Johannes Berg3448c002012-09-11 17:57:42 +0200343 list_del_rcu(&ctx->list);
Michal Kaziord01a1e62012-06-26 14:37:16 +0200344 kfree_rcu(ctx, rcu_head);
Johannes Bergfd0f9792013-02-07 00:14:51 +0100345
Simon Wunderliche4746852013-04-08 22:43:16 +0200346 /* throw a warning if this wasn't the only channel context. */
347 WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
348
Johannes Bergfd0f9792013-02-07 00:14:51 +0100349 ieee80211_recalc_idle(local);
Michal Kaziord01a1e62012-06-26 14:37:16 +0200350}
351
Johannes Berg4bf88532012-11-09 11:39:59 +0100352static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
353 struct ieee80211_chanctx *ctx)
Michal Kaziore89a96f2012-06-26 14:37:22 +0200354{
355 struct ieee80211_chanctx_conf *conf = &ctx->conf;
356 struct ieee80211_sub_if_data *sdata;
Johannes Berg4bf88532012-11-09 11:39:59 +0100357 const struct cfg80211_chan_def *compat = NULL;
Michal Kaziore89a96f2012-06-26 14:37:22 +0200358
359 lockdep_assert_held(&local->chanctx_mtx);
360
361 rcu_read_lock();
362 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
Johannes Berg4bf88532012-11-09 11:39:59 +0100363
Michal Kaziore89a96f2012-06-26 14:37:22 +0200364 if (!ieee80211_sdata_running(sdata))
365 continue;
366 if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
367 continue;
368
Johannes Berg4bf88532012-11-09 11:39:59 +0100369 if (!compat)
370 compat = &sdata->vif.bss_conf.chandef;
371
372 compat = cfg80211_chandef_compatible(
373 &sdata->vif.bss_conf.chandef, compat);
374 if (!compat)
375 break;
Michal Kaziore89a96f2012-06-26 14:37:22 +0200376 }
377 rcu_read_unlock();
378
Johannes Berg4bf88532012-11-09 11:39:59 +0100379 if (WARN_ON_ONCE(!compat))
380 return;
Michal Kaziore89a96f2012-06-26 14:37:22 +0200381
Johannes Berg18942d32013-02-07 21:30:37 +0100382 ieee80211_change_chanctx(local, ctx, compat);
Michal Kaziore89a96f2012-06-26 14:37:22 +0200383}
384
Johannes Berg367bbd12013-12-18 09:36:09 +0100385static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
386 struct ieee80211_chanctx *chanctx)
387{
388 bool radar_enabled;
389
390 lockdep_assert_held(&local->chanctx_mtx);
Johannes Berg34a37402013-12-18 09:43:33 +0100391 /* for setting local->radar_detect_enabled */
392 lockdep_assert_held(&local->mtx);
Johannes Berg367bbd12013-12-18 09:36:09 +0100393
394 radar_enabled = ieee80211_is_radar_required(local);
395
396 if (radar_enabled == chanctx->conf.radar_enabled)
397 return;
398
399 chanctx->conf.radar_enabled = radar_enabled;
400 local->radar_detect_enabled = chanctx->conf.radar_enabled;
401
402 if (!local->use_chanctx) {
403 local->hw.conf.radar_enabled = chanctx->conf.radar_enabled;
404 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
405 }
406
407 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
408}
409
Luciano Coelho77eeba92014-03-11 18:24:12 +0200410static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
411 struct ieee80211_chanctx *new_ctx)
Michal Kaziord01a1e62012-06-26 14:37:16 +0200412{
Michal Kazior35f2fce2012-06-26 14:37:20 +0200413 struct ieee80211_local *local = sdata->local;
Luciano Coelho77eeba92014-03-11 18:24:12 +0200414 struct ieee80211_chanctx_conf *conf;
415 struct ieee80211_chanctx *curr_ctx = NULL;
416 int ret = 0;
Michal Kaziord01a1e62012-06-26 14:37:16 +0200417
Luciano Coelho77eeba92014-03-11 18:24:12 +0200418 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
419 lockdep_is_held(&local->chanctx_mtx));
Michal Kaziord01a1e62012-06-26 14:37:16 +0200420
Luciano Coelho77eeba92014-03-11 18:24:12 +0200421 if (conf) {
422 curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
Michal Kazior35f2fce2012-06-26 14:37:20 +0200423
Luciano Coelho77eeba92014-03-11 18:24:12 +0200424 curr_ctx->refcount--;
425 drv_unassign_vif_chanctx(local, sdata, curr_ctx);
426 conf = NULL;
Michal Kazior484298a2014-04-09 15:29:26 +0200427 list_del(&sdata->assigned_chanctx_list);
Luciano Coelho77eeba92014-03-11 18:24:12 +0200428 }
429
430 if (new_ctx) {
431 ret = drv_assign_vif_chanctx(local, sdata, new_ctx);
432 if (ret)
433 goto out;
434
435 new_ctx->refcount++;
436 conf = &new_ctx->conf;
Michal Kazior484298a2014-04-09 15:29:26 +0200437 list_add(&sdata->assigned_chanctx_list,
438 &new_ctx->assigned_vifs);
Luciano Coelho77eeba92014-03-11 18:24:12 +0200439 }
440
441out:
442 rcu_assign_pointer(sdata->vif.chanctx_conf, conf);
443
444 sdata->vif.bss_conf.idle = !conf;
445
446 if (curr_ctx && curr_ctx->refcount > 0) {
447 ieee80211_recalc_chanctx_chantype(local, curr_ctx);
448 ieee80211_recalc_smps_chanctx(local, curr_ctx);
449 ieee80211_recalc_radar_chanctx(local, curr_ctx);
450 ieee80211_recalc_chanctx_min_def(local, curr_ctx);
451 }
452
453 if (new_ctx && new_ctx->refcount > 0) {
454 ieee80211_recalc_txpower(sdata);
455 ieee80211_recalc_chanctx_min_def(local, new_ctx);
456 }
Johannes Berg5bbe754d2013-02-13 13:50:51 +0100457
458 if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
459 sdata->vif.type != NL80211_IFTYPE_MONITOR)
Luciano Coelho77eeba92014-03-11 18:24:12 +0200460 ieee80211_bss_info_change_notify(sdata,
461 BSS_CHANGED_IDLE);
Johannes Bergfd0f9792013-02-07 00:14:51 +0100462
Luciano Coelho77eeba92014-03-11 18:24:12 +0200463 return ret;
Michal Kaziord01a1e62012-06-26 14:37:16 +0200464}
465
466static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
467{
468 struct ieee80211_local *local = sdata->local;
469 struct ieee80211_chanctx_conf *conf;
470 struct ieee80211_chanctx *ctx;
471
472 lockdep_assert_held(&local->chanctx_mtx);
473
474 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
475 lockdep_is_held(&local->chanctx_mtx));
476 if (!conf)
477 return;
478
479 ctx = container_of(conf, struct ieee80211_chanctx, conf);
480
Luciano Coelho11335a52013-10-30 13:09:39 +0200481 if (sdata->reserved_chanctx)
482 ieee80211_vif_unreserve_chanctx(sdata);
483
Luciano Coelho77eeba92014-03-11 18:24:12 +0200484 ieee80211_assign_vif_chanctx(sdata, NULL);
Michal Kaziord01a1e62012-06-26 14:37:16 +0200485 if (ctx->refcount == 0)
486 ieee80211_free_chanctx(local, ctx);
487}
488
Johannes Berg04ecd252012-09-11 14:34:12 +0200489void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
490 struct ieee80211_chanctx *chanctx)
491{
492 struct ieee80211_sub_if_data *sdata;
493 u8 rx_chains_static, rx_chains_dynamic;
494
495 lockdep_assert_held(&local->chanctx_mtx);
496
497 rx_chains_static = 1;
498 rx_chains_dynamic = 1;
499
500 rcu_read_lock();
501 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
502 u8 needed_static, needed_dynamic;
503
504 if (!ieee80211_sdata_running(sdata))
505 continue;
506
507 if (rcu_access_pointer(sdata->vif.chanctx_conf) !=
508 &chanctx->conf)
509 continue;
510
511 switch (sdata->vif.type) {
512 case NL80211_IFTYPE_P2P_DEVICE:
513 continue;
514 case NL80211_IFTYPE_STATION:
515 if (!sdata->u.mgd.associated)
516 continue;
517 break;
518 case NL80211_IFTYPE_AP_VLAN:
519 continue;
520 case NL80211_IFTYPE_AP:
521 case NL80211_IFTYPE_ADHOC:
522 case NL80211_IFTYPE_WDS:
523 case NL80211_IFTYPE_MESH_POINT:
524 break;
525 default:
526 WARN_ON_ONCE(1);
527 }
528
529 switch (sdata->smps_mode) {
530 default:
531 WARN_ONCE(1, "Invalid SMPS mode %d\n",
532 sdata->smps_mode);
533 /* fall through */
534 case IEEE80211_SMPS_OFF:
535 needed_static = sdata->needed_rx_chains;
536 needed_dynamic = sdata->needed_rx_chains;
537 break;
538 case IEEE80211_SMPS_DYNAMIC:
539 needed_static = 1;
540 needed_dynamic = sdata->needed_rx_chains;
541 break;
542 case IEEE80211_SMPS_STATIC:
543 needed_static = 1;
544 needed_dynamic = 1;
545 break;
546 }
547
548 rx_chains_static = max(rx_chains_static, needed_static);
549 rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
550 }
551 rcu_read_unlock();
552
553 if (!local->use_chanctx) {
554 if (rx_chains_static > 1)
555 local->smps_mode = IEEE80211_SMPS_OFF;
556 else if (rx_chains_dynamic > 1)
557 local->smps_mode = IEEE80211_SMPS_DYNAMIC;
558 else
559 local->smps_mode = IEEE80211_SMPS_STATIC;
560 ieee80211_hw_config(local, 0);
561 }
562
563 if (rx_chains_static == chanctx->conf.rx_chains_static &&
564 rx_chains_dynamic == chanctx->conf.rx_chains_dynamic)
565 return;
566
567 chanctx->conf.rx_chains_static = rx_chains_static;
568 chanctx->conf.rx_chains_dynamic = rx_chains_dynamic;
569 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
570}
571
Michal Kaziord01a1e62012-06-26 14:37:16 +0200572int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
Johannes Berg4bf88532012-11-09 11:39:59 +0100573 const struct cfg80211_chan_def *chandef,
Michal Kaziord01a1e62012-06-26 14:37:16 +0200574 enum ieee80211_chanctx_mode mode)
575{
576 struct ieee80211_local *local = sdata->local;
577 struct ieee80211_chanctx *ctx;
Luciano Coelho73de86a2014-02-13 11:31:59 +0200578 u8 radar_detect_width = 0;
Michal Kaziord01a1e62012-06-26 14:37:16 +0200579 int ret;
580
Johannes Berg34a37402013-12-18 09:43:33 +0100581 lockdep_assert_held(&local->mtx);
582
Johannes Berg55de9082012-07-26 17:24:39 +0200583 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
584
Michal Kaziord01a1e62012-06-26 14:37:16 +0200585 mutex_lock(&local->chanctx_mtx);
Luciano Coelho73de86a2014-02-13 11:31:59 +0200586
587 ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
588 chandef,
589 sdata->wdev.iftype);
590 if (ret < 0)
591 goto out;
592 if (ret > 0)
593 radar_detect_width = BIT(chandef->width);
594
595 sdata->radar_required = ret;
596
597 ret = ieee80211_check_combinations(sdata, chandef, mode,
598 radar_detect_width);
599 if (ret < 0)
600 goto out;
601
Michal Kaziord01a1e62012-06-26 14:37:16 +0200602 __ieee80211_vif_release_channel(sdata);
603
Johannes Berg4bf88532012-11-09 11:39:59 +0100604 ctx = ieee80211_find_chanctx(local, chandef, mode);
Michal Kaziord01a1e62012-06-26 14:37:16 +0200605 if (!ctx)
Johannes Berg4bf88532012-11-09 11:39:59 +0100606 ctx = ieee80211_new_chanctx(local, chandef, mode);
Michal Kaziord01a1e62012-06-26 14:37:16 +0200607 if (IS_ERR(ctx)) {
608 ret = PTR_ERR(ctx);
609 goto out;
610 }
611
Johannes Berg4bf88532012-11-09 11:39:59 +0100612 sdata->vif.bss_conf.chandef = *chandef;
Johannes Berg55de9082012-07-26 17:24:39 +0200613
Michal Kaziord01a1e62012-06-26 14:37:16 +0200614 ret = ieee80211_assign_vif_chanctx(sdata, ctx);
615 if (ret) {
616 /* if assign fails refcount stays the same */
617 if (ctx->refcount == 0)
618 ieee80211_free_chanctx(local, ctx);
619 goto out;
620 }
621
Johannes Berg04ecd252012-09-11 14:34:12 +0200622 ieee80211_recalc_smps_chanctx(local, ctx);
Simon Wunderlich164eb022013-02-08 18:16:20 +0100623 ieee80211_recalc_radar_chanctx(local, ctx);
Michal Kaziord01a1e62012-06-26 14:37:16 +0200624 out:
625 mutex_unlock(&local->chanctx_mtx);
626 return ret;
627}
628
Luciano Coelho33ffd952014-01-30 22:08:16 +0200629static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
630 struct ieee80211_chanctx *ctx,
631 u32 *changed)
Simon Wunderlich73da7d52013-07-11 16:09:06 +0200632{
633 struct ieee80211_local *local = sdata->local;
Luciano Coelho33787fc2013-11-11 20:34:54 +0200634 const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;
Simon Wunderlich73da7d52013-07-11 16:09:06 +0200635 u32 chanctx_changed = 0;
636
Simon Wunderlich73da7d52013-07-11 16:09:06 +0200637 if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
638 IEEE80211_CHAN_DISABLED))
639 return -EINVAL;
640
Luciano Coelho33ffd952014-01-30 22:08:16 +0200641 if (ctx->refcount != 1)
642 return -EINVAL;
Simon Wunderlich73da7d52013-07-11 16:09:06 +0200643
644 if (sdata->vif.bss_conf.chandef.width != chandef->width) {
645 chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH;
646 *changed |= BSS_CHANGED_BANDWIDTH;
647 }
648
649 sdata->vif.bss_conf.chandef = *chandef;
650 ctx->conf.def = *chandef;
651
652 chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL;
653 drv_change_chanctx(local, ctx, chanctx_changed);
654
Simon Wunderlich73da7d52013-07-11 16:09:06 +0200655 ieee80211_recalc_chanctx_chantype(local, ctx);
656 ieee80211_recalc_smps_chanctx(local, ctx);
657 ieee80211_recalc_radar_chanctx(local, ctx);
Eliad Peller21f659b2013-11-11 20:14:01 +0200658 ieee80211_recalc_chanctx_min_def(local, ctx);
Simon Wunderlich73da7d52013-07-11 16:09:06 +0200659
Luciano Coelho33ffd952014-01-30 22:08:16 +0200660 return 0;
661}
662
663int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
664 u32 *changed)
665{
666 struct ieee80211_local *local = sdata->local;
667 struct ieee80211_chanctx_conf *conf;
668 struct ieee80211_chanctx *ctx;
669 int ret;
670
671 lockdep_assert_held(&local->mtx);
672
673 /* should never be called if not performing a channel switch. */
674 if (WARN_ON(!sdata->vif.csa_active))
675 return -EINVAL;
676
677 mutex_lock(&local->chanctx_mtx);
678 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
679 lockdep_is_held(&local->chanctx_mtx));
680 if (!conf) {
681 ret = -EINVAL;
682 goto out;
683 }
684
685 ctx = container_of(conf, struct ieee80211_chanctx, conf);
686
687 ret = __ieee80211_vif_change_channel(sdata, ctx, changed);
Simon Wunderlich73da7d52013-07-11 16:09:06 +0200688 out:
689 mutex_unlock(&local->chanctx_mtx);
690 return ret;
691}
692
Luciano Coelho11335a52013-10-30 13:09:39 +0200693static void
694__ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
695 bool clear)
696{
697 struct ieee80211_local *local = sdata->local;
698 struct ieee80211_sub_if_data *vlan;
699 struct ieee80211_chanctx_conf *conf;
700
701 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
702 return;
703
704 lockdep_assert_held(&local->mtx);
705
706 /* Check that conf exists, even when clearing this function
707 * must be called with the AP's channel context still there
708 * as it would otherwise cause VLANs to have an invalid
709 * channel context pointer for a while, possibly pointing
710 * to a channel context that has already been freed.
711 */
712 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
713 lockdep_is_held(&local->chanctx_mtx));
714 WARN_ON(!conf);
715
716 if (clear)
717 conf = NULL;
718
719 list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
720 rcu_assign_pointer(vlan->vif.chanctx_conf, conf);
721}
722
723void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
724 bool clear)
725{
726 struct ieee80211_local *local = sdata->local;
727
728 mutex_lock(&local->chanctx_mtx);
729
730 __ieee80211_vif_copy_chanctx_to_vlans(sdata, clear);
731
732 mutex_unlock(&local->chanctx_mtx);
733}
734
735int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
736{
Michal Kaziore3afb922014-04-09 15:29:27 +0200737 struct ieee80211_chanctx *ctx = sdata->reserved_chanctx;
738
Luciano Coelho11335a52013-10-30 13:09:39 +0200739 lockdep_assert_held(&sdata->local->chanctx_mtx);
740
Michal Kaziore3afb922014-04-09 15:29:27 +0200741 if (WARN_ON(!ctx))
Luciano Coelho11335a52013-10-30 13:09:39 +0200742 return -EINVAL;
743
Michal Kaziore3afb922014-04-09 15:29:27 +0200744 list_del(&sdata->reserved_chanctx_list);
Luciano Coelho11335a52013-10-30 13:09:39 +0200745 sdata->reserved_chanctx = NULL;
746
Michal Kaziore3afb922014-04-09 15:29:27 +0200747 if (--ctx->refcount == 0)
748 ieee80211_free_chanctx(sdata->local, ctx);
749
Luciano Coelho11335a52013-10-30 13:09:39 +0200750 return 0;
751}
752
753int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
754 const struct cfg80211_chan_def *chandef,
Michal Kazior09332482014-04-09 15:29:25 +0200755 enum ieee80211_chanctx_mode mode,
756 bool radar_required)
Luciano Coelho11335a52013-10-30 13:09:39 +0200757{
758 struct ieee80211_local *local = sdata->local;
759 struct ieee80211_chanctx_conf *conf;
760 struct ieee80211_chanctx *new_ctx, *curr_ctx;
761 int ret = 0;
762
763 mutex_lock(&local->chanctx_mtx);
764
765 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
766 lockdep_is_held(&local->chanctx_mtx));
767 if (!conf) {
768 ret = -EINVAL;
769 goto out;
770 }
771
772 curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
773
774 /* try to find another context with the chandef we want */
775 new_ctx = ieee80211_find_chanctx(local, chandef, mode);
776 if (!new_ctx) {
Luciano Coelho5d52ee82014-02-27 14:33:47 +0200777 if (curr_ctx->refcount == 1 &&
778 (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
779 /* if we're the only users of the chanctx and
780 * the driver supports changing a running
781 * context, reserve our current context
782 */
783 new_ctx = curr_ctx;
Michal Kaziorc2b90ad2014-04-09 15:29:24 +0200784 } else if (ieee80211_can_create_new_chanctx(local)) {
Luciano Coelho5d52ee82014-02-27 14:33:47 +0200785 /* create a new context and reserve it */
786 new_ctx = ieee80211_new_chanctx(local, chandef, mode);
787 if (IS_ERR(new_ctx)) {
788 ret = PTR_ERR(new_ctx);
789 goto out;
790 }
Michal Kaziorc2b90ad2014-04-09 15:29:24 +0200791 } else {
792 ret = -EBUSY;
793 goto out;
Luciano Coelho11335a52013-10-30 13:09:39 +0200794 }
795 }
796
Michal Kaziore3afb922014-04-09 15:29:27 +0200797 list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
Luciano Coelho11335a52013-10-30 13:09:39 +0200798 new_ctx->refcount++;
799 sdata->reserved_chanctx = new_ctx;
800 sdata->reserved_chandef = *chandef;
Michal Kazior09332482014-04-09 15:29:25 +0200801 sdata->reserved_radar_required = radar_required;
Luciano Coelho11335a52013-10-30 13:09:39 +0200802out:
803 mutex_unlock(&local->chanctx_mtx);
804 return ret;
805}
806
807int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
808 u32 *changed)
809{
810 struct ieee80211_local *local = sdata->local;
811 struct ieee80211_chanctx *ctx;
812 struct ieee80211_chanctx *old_ctx;
813 struct ieee80211_chanctx_conf *conf;
814 int ret;
815 u32 tmp_changed = *changed;
816
817 /* TODO: need to recheck if the chandef is usable etc.? */
818
819 lockdep_assert_held(&local->mtx);
820
821 mutex_lock(&local->chanctx_mtx);
822
823 ctx = sdata->reserved_chanctx;
824 if (WARN_ON(!ctx)) {
825 ret = -EINVAL;
826 goto out;
827 }
828
829 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
830 lockdep_is_held(&local->chanctx_mtx));
831 if (!conf) {
832 ret = -EINVAL;
833 goto out;
834 }
835
836 old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
837
838 if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
839 tmp_changed |= BSS_CHANGED_BANDWIDTH;
840
841 sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
842
Luciano Coelho5d52ee82014-02-27 14:33:47 +0200843 /* unref our reservation */
Luciano Coelho11335a52013-10-30 13:09:39 +0200844 ctx->refcount--;
845 sdata->reserved_chanctx = NULL;
Michal Kazior09332482014-04-09 15:29:25 +0200846 sdata->radar_required = sdata->reserved_radar_required;
Michal Kaziore3afb922014-04-09 15:29:27 +0200847 list_del(&sdata->reserved_chanctx_list);
Luciano Coelho11335a52013-10-30 13:09:39 +0200848
Luciano Coelho5d52ee82014-02-27 14:33:47 +0200849 if (old_ctx == ctx) {
850 /* This is our own context, just change it */
851 ret = __ieee80211_vif_change_channel(sdata, old_ctx,
852 &tmp_changed);
853 if (ret)
854 goto out;
855 } else {
856 ret = ieee80211_assign_vif_chanctx(sdata, ctx);
857 if (old_ctx->refcount == 0)
858 ieee80211_free_chanctx(local, old_ctx);
859 if (ret) {
860 /* if assign fails refcount stays the same */
861 if (ctx->refcount == 0)
862 ieee80211_free_chanctx(local, ctx);
863 goto out;
864 }
Luciano Coelho11335a52013-10-30 13:09:39 +0200865
Luciano Coelho5d52ee82014-02-27 14:33:47 +0200866 if (sdata->vif.type == NL80211_IFTYPE_AP)
867 __ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
868 }
Luciano Coelho11335a52013-10-30 13:09:39 +0200869
870 *changed = tmp_changed;
871
872 ieee80211_recalc_chanctx_chantype(local, ctx);
873 ieee80211_recalc_smps_chanctx(local, ctx);
874 ieee80211_recalc_radar_chanctx(local, ctx);
875 ieee80211_recalc_chanctx_min_def(local, ctx);
876out:
877 mutex_unlock(&local->chanctx_mtx);
878 return ret;
879}
880
Johannes Berg2c9b7352013-02-07 21:37:29 +0100881int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
882 const struct cfg80211_chan_def *chandef,
883 u32 *changed)
884{
885 struct ieee80211_local *local = sdata->local;
886 struct ieee80211_chanctx_conf *conf;
887 struct ieee80211_chanctx *ctx;
888 int ret;
889
890 if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
891 IEEE80211_CHAN_DISABLED))
892 return -EINVAL;
893
894 mutex_lock(&local->chanctx_mtx);
895 if (cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef)) {
896 ret = 0;
897 goto out;
898 }
899
900 if (chandef->width == NL80211_CHAN_WIDTH_20_NOHT ||
901 sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) {
902 ret = -EINVAL;
903 goto out;
904 }
905
906 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
907 lockdep_is_held(&local->chanctx_mtx));
908 if (!conf) {
909 ret = -EINVAL;
910 goto out;
911 }
912
913 ctx = container_of(conf, struct ieee80211_chanctx, conf);
914 if (!cfg80211_chandef_compatible(&conf->def, chandef)) {
915 ret = -EINVAL;
916 goto out;
917 }
918
919 sdata->vif.bss_conf.chandef = *chandef;
920
921 ieee80211_recalc_chanctx_chantype(local, ctx);
922
923 *changed |= BSS_CHANGED_BANDWIDTH;
924 ret = 0;
925 out:
926 mutex_unlock(&local->chanctx_mtx);
927 return ret;
928}
929
Michal Kaziord01a1e62012-06-26 14:37:16 +0200930void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
931{
Johannes Berg55de9082012-07-26 17:24:39 +0200932 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
933
Johannes Berg34a37402013-12-18 09:43:33 +0100934 lockdep_assert_held(&sdata->local->mtx);
935
Michal Kaziord01a1e62012-06-26 14:37:16 +0200936 mutex_lock(&sdata->local->chanctx_mtx);
937 __ieee80211_vif_release_channel(sdata);
938 mutex_unlock(&sdata->local->chanctx_mtx);
939}
Johannes Berg3448c002012-09-11 17:57:42 +0200940
Johannes Berg4d76d212012-12-11 20:38:41 +0100941void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
942{
943 struct ieee80211_local *local = sdata->local;
944 struct ieee80211_sub_if_data *ap;
945 struct ieee80211_chanctx_conf *conf;
946
947 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->bss))
948 return;
949
950 ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
951
952 mutex_lock(&local->chanctx_mtx);
953
954 conf = rcu_dereference_protected(ap->vif.chanctx_conf,
955 lockdep_is_held(&local->chanctx_mtx));
956 rcu_assign_pointer(sdata->vif.chanctx_conf, conf);
957 mutex_unlock(&local->chanctx_mtx);
958}
959
Johannes Berg3448c002012-09-11 17:57:42 +0200960void ieee80211_iter_chan_contexts_atomic(
961 struct ieee80211_hw *hw,
962 void (*iter)(struct ieee80211_hw *hw,
963 struct ieee80211_chanctx_conf *chanctx_conf,
964 void *data),
965 void *iter_data)
966{
967 struct ieee80211_local *local = hw_to_local(hw);
968 struct ieee80211_chanctx *ctx;
969
970 rcu_read_lock();
971 list_for_each_entry_rcu(ctx, &local->chanctx_list, list)
Johannes Berg8a61af62012-12-13 17:42:30 +0100972 if (ctx->driver_present)
973 iter(hw, &ctx->conf, iter_data);
Johannes Berg3448c002012-09-11 17:57:42 +0200974 rcu_read_unlock();
975}
976EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic);