mac80211: fix recalc_radar hwconf sync problem
[linux-block.git] / net / mac80211 / chan.c
CommitLineData
f444de05
JB
1/*
2 * mac80211 - channel management
3 */
4
0aaffa9b 5#include <linux/nl80211.h>
3448c005 6#include <linux/export.h>
4d76d21b 7#include <linux/rtnetlink.h>
3117bbdb 8#include <net/cfg80211.h>
f444de05 9#include "ieee80211_i.h"
35f2fce9 10#include "driver-ops.h"
f444de05 11
18942d3b 12static void ieee80211_change_chanctx(struct ieee80211_local *local,
4bf88530
JB
13 struct ieee80211_chanctx *ctx,
14 const struct cfg80211_chan_def *chandef)
23a85b45 15{
4bf88530 16 if (cfg80211_chandef_identical(&ctx->conf.def, chandef))
e89a96f5 17 return;
0aaffa9b 18
4bf88530
JB
19 WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef));
20
21 ctx->conf.def = *chandef;
22 drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);
55de908a
JB
23
24 if (!local->use_chanctx) {
675a0b04 25 local->_oper_chandef = *chandef;
55de908a
JB
26 ieee80211_hw_config(local, 0);
27 }
0aaffa9b 28}
d01a1e65
MK
29
30static struct ieee80211_chanctx *
31ieee80211_find_chanctx(struct ieee80211_local *local,
4bf88530 32 const struct cfg80211_chan_def *chandef,
d01a1e65
MK
33 enum ieee80211_chanctx_mode mode)
34{
35 struct ieee80211_chanctx *ctx;
36
37 lockdep_assert_held(&local->chanctx_mtx);
38
39 if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
40 return NULL;
d01a1e65
MK
41
42 list_for_each_entry(ctx, &local->chanctx_list, list) {
4bf88530 43 const struct cfg80211_chan_def *compat;
e89a96f5 44
d01a1e65
MK
45 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
46 continue;
4bf88530
JB
47
48 compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef);
49 if (!compat)
d01a1e65
MK
50 continue;
51
18942d3b 52 ieee80211_change_chanctx(local, ctx, compat);
e89a96f5 53
d01a1e65
MK
54 return ctx;
55 }
56
57 return NULL;
58}
59
e4746851
SW
60static 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
d01a1e65
MK
76static struct ieee80211_chanctx *
77ieee80211_new_chanctx(struct ieee80211_local *local,
4bf88530 78 const struct cfg80211_chan_def *chandef,
d01a1e65
MK
79 enum ieee80211_chanctx_mode mode)
80{
81 struct ieee80211_chanctx *ctx;
35f2fce9 82 int err;
d01a1e65
MK
83
84 lockdep_assert_held(&local->chanctx_mtx);
85
86 ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
87 if (!ctx)
88 return ERR_PTR(-ENOMEM);
89
4bf88530 90 ctx->conf.def = *chandef;
04ecd257
JB
91 ctx->conf.rx_chains_static = 1;
92 ctx->conf.rx_chains_dynamic = 1;
d01a1e65 93 ctx->mode = mode;
e4746851
SW
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;
d01a1e65 97
55de908a 98 if (!local->use_chanctx) {
675a0b04 99 local->_oper_chandef = *chandef;
55de908a
JB
100 ieee80211_hw_config(local, 0);
101 } else {
102 err = drv_add_chanctx(local, ctx);
103 if (err) {
104 kfree(ctx);
105 return ERR_PTR(err);
106 }
35f2fce9
MK
107 }
108
3448c005 109 list_add_rcu(&ctx->list, &local->chanctx_list);
d01a1e65 110
fd0f979a
JB
111 mutex_lock(&local->mtx);
112 ieee80211_recalc_idle(local);
113 mutex_unlock(&local->mtx);
114
d01a1e65
MK
115 return ctx;
116}
117
118static void ieee80211_free_chanctx(struct ieee80211_local *local,
119 struct ieee80211_chanctx *ctx)
120{
e4746851 121 bool check_single_channel = false;
d01a1e65
MK
122 lockdep_assert_held(&local->chanctx_mtx);
123
124 WARN_ON_ONCE(ctx->refcount != 0);
125
55de908a 126 if (!local->use_chanctx) {
675a0b04
KB
127 struct cfg80211_chan_def *chandef = &local->_oper_chandef;
128 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
129 chandef->center_freq1 = chandef->chan->center_freq;
130 chandef->center_freq2 = 0;
e4746851
SW
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
55de908a
JB
139 ieee80211_hw_config(local, 0);
140 } else {
141 drv_remove_chanctx(local, ctx);
142 }
35f2fce9 143
3448c005 144 list_del_rcu(&ctx->list);
d01a1e65 145 kfree_rcu(ctx, rcu_head);
fd0f979a 146
e4746851
SW
147 /* throw a warning if this wasn't the only channel context. */
148 WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
149
fd0f979a
JB
150 mutex_lock(&local->mtx);
151 ieee80211_recalc_idle(local);
152 mutex_unlock(&local->mtx);
d01a1e65
MK
153}
154
155static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
156 struct ieee80211_chanctx *ctx)
157{
35f2fce9
MK
158 struct ieee80211_local *local = sdata->local;
159 int ret;
d01a1e65
MK
160
161 lockdep_assert_held(&local->chanctx_mtx);
162
35f2fce9
MK
163 ret = drv_assign_vif_chanctx(local, sdata, ctx);
164 if (ret)
165 return ret;
166
d01a1e65
MK
167 rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
168 ctx->refcount++;
169
1ea6f9c0 170 ieee80211_recalc_txpower(sdata);
fd0f979a 171 sdata->vif.bss_conf.idle = false;
5bbe754d
JB
172
173 if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
174 sdata->vif.type != NL80211_IFTYPE_MONITOR)
175 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
1ea6f9c0 176
d01a1e65
MK
177 return 0;
178}
179
4bf88530
JB
180static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
181 struct ieee80211_chanctx *ctx)
e89a96f5
MK
182{
183 struct ieee80211_chanctx_conf *conf = &ctx->conf;
184 struct ieee80211_sub_if_data *sdata;
4bf88530 185 const struct cfg80211_chan_def *compat = NULL;
e89a96f5
MK
186
187 lockdep_assert_held(&local->chanctx_mtx);
188
189 rcu_read_lock();
190 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
4bf88530 191
e89a96f5
MK
192 if (!ieee80211_sdata_running(sdata))
193 continue;
194 if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
195 continue;
196
4bf88530
JB
197 if (!compat)
198 compat = &sdata->vif.bss_conf.chandef;
199
200 compat = cfg80211_chandef_compatible(
201 &sdata->vif.bss_conf.chandef, compat);
202 if (!compat)
203 break;
e89a96f5
MK
204 }
205 rcu_read_unlock();
206
4bf88530
JB
207 if (WARN_ON_ONCE(!compat))
208 return;
e89a96f5 209
18942d3b 210 ieee80211_change_chanctx(local, ctx, compat);
e89a96f5
MK
211}
212
d01a1e65
MK
213static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
214 struct ieee80211_chanctx *ctx)
215{
35f2fce9 216 struct ieee80211_local *local = sdata->local;
d01a1e65
MK
217
218 lockdep_assert_held(&local->chanctx_mtx);
219
220 ctx->refcount--;
221 rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
35f2fce9 222
fd0f979a 223 sdata->vif.bss_conf.idle = true;
5bbe754d
JB
224
225 if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
226 sdata->vif.type != NL80211_IFTYPE_MONITOR)
227 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
fd0f979a 228
35f2fce9 229 drv_unassign_vif_chanctx(local, sdata, ctx);
e89a96f5 230
04ecd257 231 if (ctx->refcount > 0) {
e89a96f5 232 ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
04ecd257 233 ieee80211_recalc_smps_chanctx(local, ctx);
164eb02d 234 ieee80211_recalc_radar_chanctx(local, ctx);
04ecd257 235 }
d01a1e65
MK
236}
237
238static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
239{
240 struct ieee80211_local *local = sdata->local;
241 struct ieee80211_chanctx_conf *conf;
242 struct ieee80211_chanctx *ctx;
243
244 lockdep_assert_held(&local->chanctx_mtx);
245
246 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
247 lockdep_is_held(&local->chanctx_mtx));
248 if (!conf)
249 return;
250
251 ctx = container_of(conf, struct ieee80211_chanctx, conf);
252
253 ieee80211_unassign_vif_chanctx(sdata, ctx);
254 if (ctx->refcount == 0)
255 ieee80211_free_chanctx(local, ctx);
256}
257
164eb02d
SW
258void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
259 struct ieee80211_chanctx *chanctx)
260{
e4746851 261 bool radar_enabled;
164eb02d
SW
262
263 lockdep_assert_held(&local->chanctx_mtx);
264
e4746851 265 radar_enabled = ieee80211_is_radar_required(local);
164eb02d
SW
266
267 if (radar_enabled == chanctx->conf.radar_enabled)
268 return;
269
270 chanctx->conf.radar_enabled = radar_enabled;
271 local->radar_detect_enabled = chanctx->conf.radar_enabled;
272
273 if (!local->use_chanctx) {
274 local->hw.conf.radar_enabled = chanctx->conf.radar_enabled;
275 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
276 }
277
278 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
279}
280
04ecd257
JB
281void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
282 struct ieee80211_chanctx *chanctx)
283{
284 struct ieee80211_sub_if_data *sdata;
285 u8 rx_chains_static, rx_chains_dynamic;
286
287 lockdep_assert_held(&local->chanctx_mtx);
288
289 rx_chains_static = 1;
290 rx_chains_dynamic = 1;
291
292 rcu_read_lock();
293 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
294 u8 needed_static, needed_dynamic;
295
296 if (!ieee80211_sdata_running(sdata))
297 continue;
298
299 if (rcu_access_pointer(sdata->vif.chanctx_conf) !=
300 &chanctx->conf)
301 continue;
302
303 switch (sdata->vif.type) {
304 case NL80211_IFTYPE_P2P_DEVICE:
305 continue;
306 case NL80211_IFTYPE_STATION:
307 if (!sdata->u.mgd.associated)
308 continue;
309 break;
310 case NL80211_IFTYPE_AP_VLAN:
311 continue;
312 case NL80211_IFTYPE_AP:
313 case NL80211_IFTYPE_ADHOC:
314 case NL80211_IFTYPE_WDS:
315 case NL80211_IFTYPE_MESH_POINT:
316 break;
317 default:
318 WARN_ON_ONCE(1);
319 }
320
321 switch (sdata->smps_mode) {
322 default:
323 WARN_ONCE(1, "Invalid SMPS mode %d\n",
324 sdata->smps_mode);
325 /* fall through */
326 case IEEE80211_SMPS_OFF:
327 needed_static = sdata->needed_rx_chains;
328 needed_dynamic = sdata->needed_rx_chains;
329 break;
330 case IEEE80211_SMPS_DYNAMIC:
331 needed_static = 1;
332 needed_dynamic = sdata->needed_rx_chains;
333 break;
334 case IEEE80211_SMPS_STATIC:
335 needed_static = 1;
336 needed_dynamic = 1;
337 break;
338 }
339
340 rx_chains_static = max(rx_chains_static, needed_static);
341 rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
342 }
343 rcu_read_unlock();
344
345 if (!local->use_chanctx) {
346 if (rx_chains_static > 1)
347 local->smps_mode = IEEE80211_SMPS_OFF;
348 else if (rx_chains_dynamic > 1)
349 local->smps_mode = IEEE80211_SMPS_DYNAMIC;
350 else
351 local->smps_mode = IEEE80211_SMPS_STATIC;
352 ieee80211_hw_config(local, 0);
353 }
354
355 if (rx_chains_static == chanctx->conf.rx_chains_static &&
356 rx_chains_dynamic == chanctx->conf.rx_chains_dynamic)
357 return;
358
359 chanctx->conf.rx_chains_static = rx_chains_static;
360 chanctx->conf.rx_chains_dynamic = rx_chains_dynamic;
361 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
362}
363
d01a1e65 364int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
4bf88530 365 const struct cfg80211_chan_def *chandef,
d01a1e65
MK
366 enum ieee80211_chanctx_mode mode)
367{
368 struct ieee80211_local *local = sdata->local;
369 struct ieee80211_chanctx *ctx;
370 int ret;
371
55de908a
JB
372 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
373
d01a1e65
MK
374 mutex_lock(&local->chanctx_mtx);
375 __ieee80211_vif_release_channel(sdata);
376
4bf88530 377 ctx = ieee80211_find_chanctx(local, chandef, mode);
d01a1e65 378 if (!ctx)
4bf88530 379 ctx = ieee80211_new_chanctx(local, chandef, mode);
d01a1e65
MK
380 if (IS_ERR(ctx)) {
381 ret = PTR_ERR(ctx);
382 goto out;
383 }
384
4bf88530 385 sdata->vif.bss_conf.chandef = *chandef;
55de908a 386
d01a1e65
MK
387 ret = ieee80211_assign_vif_chanctx(sdata, ctx);
388 if (ret) {
389 /* if assign fails refcount stays the same */
390 if (ctx->refcount == 0)
391 ieee80211_free_chanctx(local, ctx);
392 goto out;
393 }
394
04ecd257 395 ieee80211_recalc_smps_chanctx(local, ctx);
164eb02d 396 ieee80211_recalc_radar_chanctx(local, ctx);
d01a1e65
MK
397 out:
398 mutex_unlock(&local->chanctx_mtx);
399 return ret;
400}
401
2c9b7359
JB
402int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
403 const struct cfg80211_chan_def *chandef,
404 u32 *changed)
405{
406 struct ieee80211_local *local = sdata->local;
407 struct ieee80211_chanctx_conf *conf;
408 struct ieee80211_chanctx *ctx;
409 int ret;
410
411 if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
412 IEEE80211_CHAN_DISABLED))
413 return -EINVAL;
414
415 mutex_lock(&local->chanctx_mtx);
416 if (cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef)) {
417 ret = 0;
418 goto out;
419 }
420
421 if (chandef->width == NL80211_CHAN_WIDTH_20_NOHT ||
422 sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) {
423 ret = -EINVAL;
424 goto out;
425 }
426
427 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
428 lockdep_is_held(&local->chanctx_mtx));
429 if (!conf) {
430 ret = -EINVAL;
431 goto out;
432 }
433
434 ctx = container_of(conf, struct ieee80211_chanctx, conf);
435 if (!cfg80211_chandef_compatible(&conf->def, chandef)) {
436 ret = -EINVAL;
437 goto out;
438 }
439
440 sdata->vif.bss_conf.chandef = *chandef;
441
442 ieee80211_recalc_chanctx_chantype(local, ctx);
443
444 *changed |= BSS_CHANGED_BANDWIDTH;
445 ret = 0;
446 out:
447 mutex_unlock(&local->chanctx_mtx);
448 return ret;
449}
450
d01a1e65
MK
451void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
452{
55de908a
JB
453 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
454
d01a1e65
MK
455 mutex_lock(&sdata->local->chanctx_mtx);
456 __ieee80211_vif_release_channel(sdata);
457 mutex_unlock(&sdata->local->chanctx_mtx);
458}
3448c005 459
4d76d21b
JB
460void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
461{
462 struct ieee80211_local *local = sdata->local;
463 struct ieee80211_sub_if_data *ap;
464 struct ieee80211_chanctx_conf *conf;
465
466 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->bss))
467 return;
468
469 ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
470
471 mutex_lock(&local->chanctx_mtx);
472
473 conf = rcu_dereference_protected(ap->vif.chanctx_conf,
474 lockdep_is_held(&local->chanctx_mtx));
475 rcu_assign_pointer(sdata->vif.chanctx_conf, conf);
476 mutex_unlock(&local->chanctx_mtx);
477}
478
1f4ac5a6
JB
479void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
480 bool clear)
481{
482 struct ieee80211_local *local = sdata->local;
483 struct ieee80211_sub_if_data *vlan;
484 struct ieee80211_chanctx_conf *conf;
485
486 ASSERT_RTNL();
487
488 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
489 return;
490
491 mutex_lock(&local->chanctx_mtx);
492
493 /*
494 * Check that conf exists, even when clearing this function
495 * must be called with the AP's channel context still there
496 * as it would otherwise cause VLANs to have an invalid
497 * channel context pointer for a while, possibly pointing
498 * to a channel context that has already been freed.
499 */
500 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
501 lockdep_is_held(&local->chanctx_mtx));
502 WARN_ON(!conf);
503
504 if (clear)
505 conf = NULL;
506
507 list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
508 rcu_assign_pointer(vlan->vif.chanctx_conf, conf);
509
510 mutex_unlock(&local->chanctx_mtx);
511}
512
3448c005
JB
513void ieee80211_iter_chan_contexts_atomic(
514 struct ieee80211_hw *hw,
515 void (*iter)(struct ieee80211_hw *hw,
516 struct ieee80211_chanctx_conf *chanctx_conf,
517 void *data),
518 void *iter_data)
519{
520 struct ieee80211_local *local = hw_to_local(hw);
521 struct ieee80211_chanctx *ctx;
522
523 rcu_read_lock();
524 list_for_each_entry_rcu(ctx, &local->chanctx_list, list)
8a61af65
JB
525 if (ctx->driver_present)
526 iter(hw, &ctx->conf, iter_data);
3448c005
JB
527 rcu_read_unlock();
528}
529EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic);