aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/chan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/chan.c')
-rw-r--r--net/mac80211/chan.c1238
1 files changed, 1103 insertions, 135 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 0c1ecfdf9a12..399ad82c997f 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -9,6 +9,187 @@
9#include "ieee80211_i.h" 9#include "ieee80211_i.h"
10#include "driver-ops.h" 10#include "driver-ops.h"
11 11
12static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
13 struct ieee80211_chanctx *ctx)
14{
15 struct ieee80211_sub_if_data *sdata;
16 int num = 0;
17
18 lockdep_assert_held(&local->chanctx_mtx);
19
20 list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
21 num++;
22
23 return num;
24}
25
26static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
27 struct ieee80211_chanctx *ctx)
28{
29 struct ieee80211_sub_if_data *sdata;
30 int num = 0;
31
32 lockdep_assert_held(&local->chanctx_mtx);
33
34 list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list)
35 num++;
36
37 return num;
38}
39
40int ieee80211_chanctx_refcount(struct ieee80211_local *local,
41 struct ieee80211_chanctx *ctx)
42{
43 return ieee80211_chanctx_num_assigned(local, ctx) +
44 ieee80211_chanctx_num_reserved(local, ctx);
45}
46
47static int ieee80211_num_chanctx(struct ieee80211_local *local)
48{
49 struct ieee80211_chanctx *ctx;
50 int num = 0;
51
52 lockdep_assert_held(&local->chanctx_mtx);
53
54 list_for_each_entry(ctx, &local->chanctx_list, list)
55 num++;
56
57 return num;
58}
59
60static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
61{
62 lockdep_assert_held(&local->chanctx_mtx);
63 return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
64}
65
66static struct ieee80211_chanctx *
67ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata)
68{
69 struct ieee80211_local *local __maybe_unused = sdata->local;
70 struct ieee80211_chanctx_conf *conf;
71
72 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
73 lockdep_is_held(&local->chanctx_mtx));
74 if (!conf)
75 return NULL;
76
77 return container_of(conf, struct ieee80211_chanctx, conf);
78}
79
80static const struct cfg80211_chan_def *
81ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
82 struct ieee80211_chanctx *ctx,
83 const struct cfg80211_chan_def *compat)
84{
85 struct ieee80211_sub_if_data *sdata;
86
87 lockdep_assert_held(&local->chanctx_mtx);
88
89 list_for_each_entry(sdata, &ctx->reserved_vifs,
90 reserved_chanctx_list) {
91 if (!compat)
92 compat = &sdata->reserved_chandef;
93
94 compat = cfg80211_chandef_compatible(&sdata->reserved_chandef,
95 compat);
96 if (!compat)
97 break;
98 }
99
100 return compat;
101}
102
103static const struct cfg80211_chan_def *
104ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
105 struct ieee80211_chanctx *ctx,
106 const struct cfg80211_chan_def *compat)
107{
108 struct ieee80211_sub_if_data *sdata;
109
110 lockdep_assert_held(&local->chanctx_mtx);
111
112 list_for_each_entry(sdata, &ctx->assigned_vifs,
113 assigned_chanctx_list) {
114 if (sdata->reserved_chanctx != NULL)
115 continue;
116
117 if (!compat)
118 compat = &sdata->vif.bss_conf.chandef;
119
120 compat = cfg80211_chandef_compatible(
121 &sdata->vif.bss_conf.chandef, compat);
122 if (!compat)
123 break;
124 }
125
126 return compat;
127}
128
129static const struct cfg80211_chan_def *
130ieee80211_chanctx_combined_chandef(struct ieee80211_local *local,
131 struct ieee80211_chanctx *ctx,
132 const struct cfg80211_chan_def *compat)
133{
134 lockdep_assert_held(&local->chanctx_mtx);
135
136 compat = ieee80211_chanctx_reserved_chandef(local, ctx, compat);
137 if (!compat)
138 return NULL;
139
140 compat = ieee80211_chanctx_non_reserved_chandef(local, ctx, compat);
141 if (!compat)
142 return NULL;
143
144 return compat;
145}
146
147static bool
148ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local,
149 struct ieee80211_chanctx *ctx,
150 const struct cfg80211_chan_def *def)
151{
152 lockdep_assert_held(&local->chanctx_mtx);
153
154 if (ieee80211_chanctx_combined_chandef(local, ctx, def))
155 return true;
156
157 if (!list_empty(&ctx->reserved_vifs) &&
158 ieee80211_chanctx_reserved_chandef(local, ctx, def))
159 return true;
160
161 return false;
162}
163
164static struct ieee80211_chanctx *
165ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
166 const struct cfg80211_chan_def *chandef,
167 enum ieee80211_chanctx_mode mode)
168{
169 struct ieee80211_chanctx *ctx;
170
171 lockdep_assert_held(&local->chanctx_mtx);
172
173 if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
174 return NULL;
175
176 list_for_each_entry(ctx, &local->chanctx_list, list) {
177 if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
178 continue;
179
180 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
181 continue;
182
183 if (!ieee80211_chanctx_can_reserve_chandef(local, ctx,
184 chandef))
185 continue;
186
187 return ctx;
188 }
189
190 return NULL;
191}
192
12static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta) 193static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
13{ 194{
14 switch (sta->bandwidth) { 195 switch (sta->bandwidth) {
@@ -183,6 +364,9 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
183 list_for_each_entry(ctx, &local->chanctx_list, list) { 364 list_for_each_entry(ctx, &local->chanctx_list, list) {
184 const struct cfg80211_chan_def *compat; 365 const struct cfg80211_chan_def *compat;
185 366
367 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACE_NONE)
368 continue;
369
186 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) 370 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
187 continue; 371 continue;
188 372
@@ -190,6 +374,11 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
190 if (!compat) 374 if (!compat)
191 continue; 375 continue;
192 376
377 compat = ieee80211_chanctx_reserved_chandef(local, ctx,
378 compat);
379 if (!compat)
380 continue;
381
193 ieee80211_change_chanctx(local, ctx, compat); 382 ieee80211_change_chanctx(local, ctx, compat);
194 383
195 return ctx; 384 return ctx;
@@ -202,6 +391,8 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local)
202{ 391{
203 struct ieee80211_sub_if_data *sdata; 392 struct ieee80211_sub_if_data *sdata;
204 393
394 lockdep_assert_held(&local->mtx);
395
205 rcu_read_lock(); 396 rcu_read_lock();
206 list_for_each_entry_rcu(sdata, &local->interfaces, list) { 397 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
207 if (sdata->radar_required) { 398 if (sdata->radar_required) {
@@ -215,62 +406,91 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local)
215} 406}
216 407
217static struct ieee80211_chanctx * 408static struct ieee80211_chanctx *
218ieee80211_new_chanctx(struct ieee80211_local *local, 409ieee80211_alloc_chanctx(struct ieee80211_local *local,
219 const struct cfg80211_chan_def *chandef, 410 const struct cfg80211_chan_def *chandef,
220 enum ieee80211_chanctx_mode mode) 411 enum ieee80211_chanctx_mode mode)
221{ 412{
222 struct ieee80211_chanctx *ctx; 413 struct ieee80211_chanctx *ctx;
223 u32 changed;
224 int err;
225 414
226 lockdep_assert_held(&local->chanctx_mtx); 415 lockdep_assert_held(&local->chanctx_mtx);
227 416
228 ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL); 417 ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
229 if (!ctx) 418 if (!ctx)
230 return ERR_PTR(-ENOMEM); 419 return NULL;
231 420
421 INIT_LIST_HEAD(&ctx->assigned_vifs);
422 INIT_LIST_HEAD(&ctx->reserved_vifs);
232 ctx->conf.def = *chandef; 423 ctx->conf.def = *chandef;
233 ctx->conf.rx_chains_static = 1; 424 ctx->conf.rx_chains_static = 1;
234 ctx->conf.rx_chains_dynamic = 1; 425 ctx->conf.rx_chains_dynamic = 1;
235 ctx->mode = mode; 426 ctx->mode = mode;
236 ctx->conf.radar_enabled = ieee80211_is_radar_required(local); 427 ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
237 ieee80211_recalc_chanctx_min_def(local, ctx); 428 ieee80211_recalc_chanctx_min_def(local, ctx);
429
430 return ctx;
431}
432
433static int ieee80211_add_chanctx(struct ieee80211_local *local,
434 struct ieee80211_chanctx *ctx)
435{
436 u32 changed;
437 int err;
438
439 lockdep_assert_held(&local->mtx);
440 lockdep_assert_held(&local->chanctx_mtx);
441
238 if (!local->use_chanctx) 442 if (!local->use_chanctx)
239 local->hw.conf.radar_enabled = ctx->conf.radar_enabled; 443 local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
240 444
241 /* we hold the mutex to prevent idle from changing */
242 lockdep_assert_held(&local->mtx);
243 /* turn idle off *before* setting channel -- some drivers need that */ 445 /* turn idle off *before* setting channel -- some drivers need that */
244 changed = ieee80211_idle_off(local); 446 changed = ieee80211_idle_off(local);
245 if (changed) 447 if (changed)
246 ieee80211_hw_config(local, changed); 448 ieee80211_hw_config(local, changed);
247 449
248 if (!local->use_chanctx) { 450 if (!local->use_chanctx) {
249 local->_oper_chandef = *chandef; 451 local->_oper_chandef = ctx->conf.def;
250 ieee80211_hw_config(local, 0); 452 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
251 } else { 453 } else {
252 err = drv_add_chanctx(local, ctx); 454 err = drv_add_chanctx(local, ctx);
253 if (err) { 455 if (err) {
254 kfree(ctx);
255 ieee80211_recalc_idle(local); 456 ieee80211_recalc_idle(local);
256 return ERR_PTR(err); 457 return err;
257 } 458 }
258 } 459 }
259 460
260 /* and keep the mutex held until the new chanctx is on the list */ 461 return 0;
261 list_add_rcu(&ctx->list, &local->chanctx_list); 462}
463
464static struct ieee80211_chanctx *
465ieee80211_new_chanctx(struct ieee80211_local *local,
466 const struct cfg80211_chan_def *chandef,
467 enum ieee80211_chanctx_mode mode)
468{
469 struct ieee80211_chanctx *ctx;
470 int err;
471
472 lockdep_assert_held(&local->mtx);
473 lockdep_assert_held(&local->chanctx_mtx);
474
475 ctx = ieee80211_alloc_chanctx(local, chandef, mode);
476 if (!ctx)
477 return ERR_PTR(-ENOMEM);
478
479 err = ieee80211_add_chanctx(local, ctx);
480 if (err) {
481 kfree(ctx);
482 return ERR_PTR(err);
483 }
262 484
485 list_add_rcu(&ctx->list, &local->chanctx_list);
263 return ctx; 486 return ctx;
264} 487}
265 488
266static void ieee80211_free_chanctx(struct ieee80211_local *local, 489static void ieee80211_del_chanctx(struct ieee80211_local *local,
267 struct ieee80211_chanctx *ctx) 490 struct ieee80211_chanctx *ctx)
268{ 491{
269 bool check_single_channel = false;
270 lockdep_assert_held(&local->chanctx_mtx); 492 lockdep_assert_held(&local->chanctx_mtx);
271 493
272 WARN_ON_ONCE(ctx->refcount != 0);
273
274 if (!local->use_chanctx) { 494 if (!local->use_chanctx) {
275 struct cfg80211_chan_def *chandef = &local->_oper_chandef; 495 struct cfg80211_chan_def *chandef = &local->_oper_chandef;
276 chandef->width = NL80211_CHAN_WIDTH_20_NOHT; 496 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
@@ -280,48 +500,29 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
280 /* NOTE: Disabling radar is only valid here for 500 /* NOTE: Disabling radar is only valid here for
281 * single channel context. To be sure, check it ... 501 * single channel context. To be sure, check it ...
282 */ 502 */
283 if (local->hw.conf.radar_enabled) 503 WARN_ON(local->hw.conf.radar_enabled &&
284 check_single_channel = true; 504 !list_empty(&local->chanctx_list));
505
285 local->hw.conf.radar_enabled = false; 506 local->hw.conf.radar_enabled = false;
286 507
287 ieee80211_hw_config(local, 0); 508 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
288 } else { 509 } else {
289 drv_remove_chanctx(local, ctx); 510 drv_remove_chanctx(local, ctx);
290 } 511 }
291 512
292 list_del_rcu(&ctx->list);
293 kfree_rcu(ctx, rcu_head);
294
295 /* throw a warning if this wasn't the only channel context. */
296 WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
297
298 ieee80211_recalc_idle(local); 513 ieee80211_recalc_idle(local);
299} 514}
300 515
301static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, 516static void ieee80211_free_chanctx(struct ieee80211_local *local,
302 struct ieee80211_chanctx *ctx) 517 struct ieee80211_chanctx *ctx)
303{ 518{
304 struct ieee80211_local *local = sdata->local;
305 int ret;
306
307 lockdep_assert_held(&local->chanctx_mtx); 519 lockdep_assert_held(&local->chanctx_mtx);
308 520
309 ret = drv_assign_vif_chanctx(local, sdata, ctx); 521 WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
310 if (ret)
311 return ret;
312 522
313 rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); 523 list_del_rcu(&ctx->list);
314 ctx->refcount++; 524 ieee80211_del_chanctx(local, ctx);
315 525 kfree_rcu(ctx, rcu_head);
316 ieee80211_recalc_txpower(sdata);
317 ieee80211_recalc_chanctx_min_def(local, ctx);
318 sdata->vif.bss_conf.idle = false;
319
320 if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
321 sdata->vif.type != NL80211_IFTYPE_MONITOR)
322 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
323
324 return 0;
325} 526}
326 527
327static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, 528static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
@@ -340,6 +541,8 @@ static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
340 continue; 541 continue;
341 if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) 542 if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
342 continue; 543 continue;
544 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
545 continue;
343 546
344 if (!compat) 547 if (!compat)
345 compat = &sdata->vif.bss_conf.chandef; 548 compat = &sdata->vif.bss_conf.chandef;
@@ -382,30 +585,58 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
382 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR); 585 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
383} 586}
384 587
385static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, 588static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
386 struct ieee80211_chanctx *ctx) 589 struct ieee80211_chanctx *new_ctx)
387{ 590{
388 struct ieee80211_local *local = sdata->local; 591 struct ieee80211_local *local = sdata->local;
592 struct ieee80211_chanctx_conf *conf;
593 struct ieee80211_chanctx *curr_ctx = NULL;
594 int ret = 0;
389 595
390 lockdep_assert_held(&local->chanctx_mtx); 596 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
597 lockdep_is_held(&local->chanctx_mtx));
391 598
392 ctx->refcount--; 599 if (conf) {
393 rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); 600 curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
394 601
395 sdata->vif.bss_conf.idle = true; 602 drv_unassign_vif_chanctx(local, sdata, curr_ctx);
603 conf = NULL;
604 list_del(&sdata->assigned_chanctx_list);
605 }
396 606
397 if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && 607 if (new_ctx) {
398 sdata->vif.type != NL80211_IFTYPE_MONITOR) 608 ret = drv_assign_vif_chanctx(local, sdata, new_ctx);
399 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); 609 if (ret)
610 goto out;
400 611
401 drv_unassign_vif_chanctx(local, sdata, ctx); 612 conf = &new_ctx->conf;
613 list_add(&sdata->assigned_chanctx_list,
614 &new_ctx->assigned_vifs);
615 }
402 616
403 if (ctx->refcount > 0) { 617out:
404 ieee80211_recalc_chanctx_chantype(sdata->local, ctx); 618 rcu_assign_pointer(sdata->vif.chanctx_conf, conf);
405 ieee80211_recalc_smps_chanctx(local, ctx); 619
406 ieee80211_recalc_radar_chanctx(local, ctx); 620 sdata->vif.bss_conf.idle = !conf;
407 ieee80211_recalc_chanctx_min_def(local, ctx); 621
622 if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
623 ieee80211_recalc_chanctx_chantype(local, curr_ctx);
624 ieee80211_recalc_smps_chanctx(local, curr_ctx);
625 ieee80211_recalc_radar_chanctx(local, curr_ctx);
626 ieee80211_recalc_chanctx_min_def(local, curr_ctx);
627 }
628
629 if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
630 ieee80211_recalc_txpower(sdata);
631 ieee80211_recalc_chanctx_min_def(local, new_ctx);
408 } 632 }
633
634 if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
635 sdata->vif.type != NL80211_IFTYPE_MONITOR)
636 ieee80211_bss_info_change_notify(sdata,
637 BSS_CHANGED_IDLE);
638
639 return ret;
409} 640}
410 641
411static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) 642static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
@@ -413,6 +644,7 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
413 struct ieee80211_local *local = sdata->local; 644 struct ieee80211_local *local = sdata->local;
414 struct ieee80211_chanctx_conf *conf; 645 struct ieee80211_chanctx_conf *conf;
415 struct ieee80211_chanctx *ctx; 646 struct ieee80211_chanctx *ctx;
647 bool use_reserved_switch = false;
416 648
417 lockdep_assert_held(&local->chanctx_mtx); 649 lockdep_assert_held(&local->chanctx_mtx);
418 650
@@ -423,9 +655,23 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
423 655
424 ctx = container_of(conf, struct ieee80211_chanctx, conf); 656 ctx = container_of(conf, struct ieee80211_chanctx, conf);
425 657
426 ieee80211_unassign_vif_chanctx(sdata, ctx); 658 if (sdata->reserved_chanctx) {
427 if (ctx->refcount == 0) 659 if (sdata->reserved_chanctx->replace_state ==
660 IEEE80211_CHANCTX_REPLACES_OTHER &&
661 ieee80211_chanctx_num_reserved(local,
662 sdata->reserved_chanctx) > 1)
663 use_reserved_switch = true;
664
665 ieee80211_vif_unreserve_chanctx(sdata);
666 }
667
668 ieee80211_assign_vif_chanctx(sdata, NULL);
669 if (ieee80211_chanctx_refcount(local, ctx) == 0)
428 ieee80211_free_chanctx(local, ctx); 670 ieee80211_free_chanctx(local, ctx);
671
672 /* Unreserving may ready an in-place reservation. */
673 if (use_reserved_switch)
674 ieee80211_vif_use_reserved_switch(local);
429} 675}
430 676
431void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, 677void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
@@ -490,6 +736,13 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
490 rx_chains_static = max(rx_chains_static, needed_static); 736 rx_chains_static = max(rx_chains_static, needed_static);
491 rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic); 737 rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
492 } 738 }
739
740 /* Disable SMPS for the monitor interface */
741 sdata = rcu_dereference(local->monitor_sdata);
742 if (sdata &&
743 rcu_access_pointer(sdata->vif.chanctx_conf) == &chanctx->conf)
744 rx_chains_dynamic = rx_chains_static = local->rx_chains;
745
493 rcu_read_unlock(); 746 rcu_read_unlock();
494 747
495 if (!local->use_chanctx) { 748 if (!local->use_chanctx) {
@@ -517,6 +770,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
517{ 770{
518 struct ieee80211_local *local = sdata->local; 771 struct ieee80211_local *local = sdata->local;
519 struct ieee80211_chanctx *ctx; 772 struct ieee80211_chanctx *ctx;
773 u8 radar_detect_width = 0;
520 int ret; 774 int ret;
521 775
522 lockdep_assert_held(&local->mtx); 776 lockdep_assert_held(&local->mtx);
@@ -524,6 +778,22 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
524 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); 778 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
525 779
526 mutex_lock(&local->chanctx_mtx); 780 mutex_lock(&local->chanctx_mtx);
781
782 ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
783 chandef,
784 sdata->wdev.iftype);
785 if (ret < 0)
786 goto out;
787 if (ret > 0)
788 radar_detect_width = BIT(chandef->width);
789
790 sdata->radar_required = ret;
791
792 ret = ieee80211_check_combinations(sdata, chandef, mode,
793 radar_detect_width);
794 if (ret < 0)
795 goto out;
796
527 __ieee80211_vif_release_channel(sdata); 797 __ieee80211_vif_release_channel(sdata);
528 798
529 ctx = ieee80211_find_chanctx(local, chandef, mode); 799 ctx = ieee80211_find_chanctx(local, chandef, mode);
@@ -539,7 +809,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
539 ret = ieee80211_assign_vif_chanctx(sdata, ctx); 809 ret = ieee80211_assign_vif_chanctx(sdata, ctx);
540 if (ret) { 810 if (ret) {
541 /* if assign fails refcount stays the same */ 811 /* if assign fails refcount stays the same */
542 if (ctx->refcount == 0) 812 if (ieee80211_chanctx_refcount(local, ctx) == 0)
543 ieee80211_free_chanctx(local, ctx); 813 ieee80211_free_chanctx(local, ctx);
544 goto out; 814 goto out;
545 } 815 }
@@ -551,60 +821,769 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
551 return ret; 821 return ret;
552} 822}
553 823
554int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, 824static void
555 u32 *changed) 825__ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
826 bool clear)
556{ 827{
557 struct ieee80211_local *local = sdata->local; 828 struct ieee80211_local *local __maybe_unused = sdata->local;
829 struct ieee80211_sub_if_data *vlan;
558 struct ieee80211_chanctx_conf *conf; 830 struct ieee80211_chanctx_conf *conf;
559 struct ieee80211_chanctx *ctx; 831
560 const struct cfg80211_chan_def *chandef = &sdata->csa_chandef; 832 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
561 int ret; 833 return;
562 u32 chanctx_changed = 0;
563 834
564 lockdep_assert_held(&local->mtx); 835 lockdep_assert_held(&local->mtx);
565 836
566 /* should never be called if not performing a channel switch. */ 837 /* Check that conf exists, even when clearing this function
567 if (WARN_ON(!sdata->vif.csa_active)) 838 * must be called with the AP's channel context still there
839 * as it would otherwise cause VLANs to have an invalid
840 * channel context pointer for a while, possibly pointing
841 * to a channel context that has already been freed.
842 */
843 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
844 lockdep_is_held(&local->chanctx_mtx));
845 WARN_ON(!conf);
846
847 if (clear)
848 conf = NULL;
849
850 list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
851 rcu_assign_pointer(vlan->vif.chanctx_conf, conf);
852}
853
854void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
855 bool clear)
856{
857 struct ieee80211_local *local = sdata->local;
858
859 mutex_lock(&local->chanctx_mtx);
860
861 __ieee80211_vif_copy_chanctx_to_vlans(sdata, clear);
862
863 mutex_unlock(&local->chanctx_mtx);
864}
865
866int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
867{
868 struct ieee80211_chanctx *ctx = sdata->reserved_chanctx;
869
870 lockdep_assert_held(&sdata->local->chanctx_mtx);
871
872 if (WARN_ON(!ctx))
568 return -EINVAL; 873 return -EINVAL;
569 874
570 if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, 875 list_del(&sdata->reserved_chanctx_list);
571 IEEE80211_CHAN_DISABLED)) 876 sdata->reserved_chanctx = NULL;
877
878 if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) {
879 if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) {
880 if (WARN_ON(!ctx->replace_ctx))
881 return -EINVAL;
882
883 WARN_ON(ctx->replace_ctx->replace_state !=
884 IEEE80211_CHANCTX_WILL_BE_REPLACED);
885 WARN_ON(ctx->replace_ctx->replace_ctx != ctx);
886
887 ctx->replace_ctx->replace_ctx = NULL;
888 ctx->replace_ctx->replace_state =
889 IEEE80211_CHANCTX_REPLACE_NONE;
890
891 list_del_rcu(&ctx->list);
892 kfree_rcu(ctx, rcu_head);
893 } else {
894 ieee80211_free_chanctx(sdata->local, ctx);
895 }
896 }
897
898 return 0;
899}
900
901int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
902 const struct cfg80211_chan_def *chandef,
903 enum ieee80211_chanctx_mode mode,
904 bool radar_required)
905{
906 struct ieee80211_local *local = sdata->local;
907 struct ieee80211_chanctx *new_ctx, *curr_ctx, *ctx;
908
909 lockdep_assert_held(&local->chanctx_mtx);
910
911 curr_ctx = ieee80211_vif_get_chanctx(sdata);
912 if (curr_ctx && local->use_chanctx && !local->ops->switch_vif_chanctx)
913 return -ENOTSUPP;
914
915 new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
916 if (!new_ctx) {
917 if (ieee80211_can_create_new_chanctx(local)) {
918 new_ctx = ieee80211_new_chanctx(local, chandef, mode);
919 if (IS_ERR(new_ctx))
920 return PTR_ERR(new_ctx);
921 } else {
922 if (!curr_ctx ||
923 (curr_ctx->replace_state ==
924 IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
925 !list_empty(&curr_ctx->reserved_vifs)) {
926 /*
927 * Another vif already requested this context
928 * for a reservation. Find another one hoping
929 * all vifs assigned to it will also switch
930 * soon enough.
931 *
932 * TODO: This needs a little more work as some
933 * cases (more than 2 chanctx capable devices)
934 * may fail which could otherwise succeed
935 * provided some channel context juggling was
936 * performed.
937 *
938 * Consider ctx1..3, vif1..6, each ctx has 2
939 * vifs. vif1 and vif2 from ctx1 request new
940 * different chandefs starting 2 in-place
941 * reserations with ctx4 and ctx5 replacing
942 * ctx1 and ctx2 respectively. Next vif5 and
943 * vif6 from ctx3 reserve ctx4. If vif3 and
944 * vif4 remain on ctx2 as they are then this
945 * fails unless `replace_ctx` from ctx5 is
946 * replaced with ctx3.
947 */
948 list_for_each_entry(ctx, &local->chanctx_list,
949 list) {
950 if (ctx->replace_state !=
951 IEEE80211_CHANCTX_REPLACE_NONE)
952 continue;
953
954 if (!list_empty(&ctx->reserved_vifs))
955 continue;
956
957 curr_ctx = ctx;
958 break;
959 }
960 }
961
962 /*
963 * If that's true then all available contexts already
964 * have reservations and cannot be used.
965 */
966 if (!curr_ctx ||
967 (curr_ctx->replace_state ==
968 IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
969 !list_empty(&curr_ctx->reserved_vifs))
970 return -EBUSY;
971
972 new_ctx = ieee80211_alloc_chanctx(local, chandef, mode);
973 if (!new_ctx)
974 return -ENOMEM;
975
976 new_ctx->replace_ctx = curr_ctx;
977 new_ctx->replace_state =
978 IEEE80211_CHANCTX_REPLACES_OTHER;
979
980 curr_ctx->replace_ctx = new_ctx;
981 curr_ctx->replace_state =
982 IEEE80211_CHANCTX_WILL_BE_REPLACED;
983
984 list_add_rcu(&new_ctx->list, &local->chanctx_list);
985 }
986 }
987
988 list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
989 sdata->reserved_chanctx = new_ctx;
990 sdata->reserved_chandef = *chandef;
991 sdata->reserved_radar_required = radar_required;
992 sdata->reserved_ready = false;
993
994 return 0;
995}
996
997static void
998ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
999{
1000 switch (sdata->vif.type) {
1001 case NL80211_IFTYPE_ADHOC:
1002 case NL80211_IFTYPE_AP:
1003 case NL80211_IFTYPE_MESH_POINT:
1004 ieee80211_queue_work(&sdata->local->hw,
1005 &sdata->csa_finalize_work);
1006 break;
1007 case NL80211_IFTYPE_STATION:
1008 ieee80211_queue_work(&sdata->local->hw,
1009 &sdata->u.mgd.chswitch_work);
1010 break;
1011 case NL80211_IFTYPE_UNSPECIFIED:
1012 case NL80211_IFTYPE_AP_VLAN:
1013 case NL80211_IFTYPE_WDS:
1014 case NL80211_IFTYPE_MONITOR:
1015 case NL80211_IFTYPE_P2P_CLIENT:
1016 case NL80211_IFTYPE_P2P_GO:
1017 case NL80211_IFTYPE_P2P_DEVICE:
1018 case NUM_NL80211_IFTYPES:
1019 WARN_ON(1);
1020 break;
1021 }
1022}
1023
1024static int
1025ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
1026{
1027 struct ieee80211_local *local = sdata->local;
1028 struct ieee80211_vif_chanctx_switch vif_chsw[1] = {};
1029 struct ieee80211_chanctx *old_ctx, *new_ctx;
1030 const struct cfg80211_chan_def *chandef;
1031 u32 changed = 0;
1032 int err;
1033
1034 lockdep_assert_held(&local->mtx);
1035 lockdep_assert_held(&local->chanctx_mtx);
1036
1037 new_ctx = sdata->reserved_chanctx;
1038 old_ctx = ieee80211_vif_get_chanctx(sdata);
1039
1040 if (WARN_ON(!sdata->reserved_ready))
1041 return -EBUSY;
1042
1043 if (WARN_ON(!new_ctx))
572 return -EINVAL; 1044 return -EINVAL;
573 1045
574 mutex_lock(&local->chanctx_mtx); 1046 if (WARN_ON(!old_ctx))
575 conf = rcu_dereference_protected(sdata->vif.chanctx_conf, 1047 return -EINVAL;
576 lockdep_is_held(&local->chanctx_mtx)); 1048
577 if (!conf) { 1049 if (WARN_ON(new_ctx->replace_state ==
578 ret = -EINVAL; 1050 IEEE80211_CHANCTX_REPLACES_OTHER))
1051 return -EINVAL;
1052
1053 chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx,
1054 &sdata->reserved_chandef);
1055 if (WARN_ON(!chandef))
1056 return -EINVAL;
1057
1058 vif_chsw[0].vif = &sdata->vif;
1059 vif_chsw[0].old_ctx = &old_ctx->conf;
1060 vif_chsw[0].new_ctx = &new_ctx->conf;
1061
1062 list_del(&sdata->reserved_chanctx_list);
1063 sdata->reserved_chanctx = NULL;
1064
1065 err = drv_switch_vif_chanctx(local, vif_chsw, 1,
1066 CHANCTX_SWMODE_REASSIGN_VIF);
1067 if (err) {
1068 if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
1069 ieee80211_free_chanctx(local, new_ctx);
1070
579 goto out; 1071 goto out;
580 } 1072 }
581 1073
582 ctx = container_of(conf, struct ieee80211_chanctx, conf); 1074 list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs);
583 if (ctx->refcount != 1) { 1075 rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
584 ret = -EINVAL; 1076
1077 if (sdata->vif.type == NL80211_IFTYPE_AP)
1078 __ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
1079
1080 if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
1081 ieee80211_free_chanctx(local, old_ctx);
1082
1083 if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
1084 changed = BSS_CHANGED_BANDWIDTH;
1085
1086 sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
1087
1088 if (changed)
1089 ieee80211_bss_info_change_notify(sdata, changed);
1090
1091out:
1092 ieee80211_vif_chanctx_reservation_complete(sdata);
1093 return err;
1094}
1095
1096static int
1097ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata)
1098{
1099 struct ieee80211_local *local = sdata->local;
1100 struct ieee80211_chanctx *old_ctx, *new_ctx;
1101 const struct cfg80211_chan_def *chandef;
1102 int err;
1103
1104 old_ctx = ieee80211_vif_get_chanctx(sdata);
1105 new_ctx = sdata->reserved_chanctx;
1106
1107 if (WARN_ON(!sdata->reserved_ready))
1108 return -EINVAL;
1109
1110 if (WARN_ON(old_ctx))
1111 return -EINVAL;
1112
1113 if (WARN_ON(!new_ctx))
1114 return -EINVAL;
1115
1116 if (WARN_ON(new_ctx->replace_state ==
1117 IEEE80211_CHANCTX_REPLACES_OTHER))
1118 return -EINVAL;
1119
1120 chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx,
1121 &sdata->reserved_chandef);
1122 if (WARN_ON(!chandef))
1123 return -EINVAL;
1124
1125 list_del(&sdata->reserved_chanctx_list);
1126 sdata->reserved_chanctx = NULL;
1127
1128 err = ieee80211_assign_vif_chanctx(sdata, new_ctx);
1129 if (err) {
1130 if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
1131 ieee80211_free_chanctx(local, new_ctx);
1132
585 goto out; 1133 goto out;
586 } 1134 }
587 1135
588 if (sdata->vif.bss_conf.chandef.width != chandef->width) { 1136out:
589 chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH; 1137 ieee80211_vif_chanctx_reservation_complete(sdata);
590 *changed |= BSS_CHANGED_BANDWIDTH; 1138 return err;
1139}
1140
1141static bool
1142ieee80211_vif_has_in_place_reservation(struct ieee80211_sub_if_data *sdata)
1143{
1144 struct ieee80211_chanctx *old_ctx, *new_ctx;
1145
1146 lockdep_assert_held(&sdata->local->chanctx_mtx);
1147
1148 new_ctx = sdata->reserved_chanctx;
1149 old_ctx = ieee80211_vif_get_chanctx(sdata);
1150
1151 if (!old_ctx)
1152 return false;
1153
1154 if (WARN_ON(!new_ctx))
1155 return false;
1156
1157 if (old_ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED)
1158 return false;
1159
1160 if (new_ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1161 return false;
1162
1163 return true;
1164}
1165
1166static int ieee80211_chsw_switch_hwconf(struct ieee80211_local *local,
1167 struct ieee80211_chanctx *new_ctx)
1168{
1169 const struct cfg80211_chan_def *chandef;
1170
1171 lockdep_assert_held(&local->mtx);
1172 lockdep_assert_held(&local->chanctx_mtx);
1173
1174 chandef = ieee80211_chanctx_reserved_chandef(local, new_ctx, NULL);
1175 if (WARN_ON(!chandef))
1176 return -EINVAL;
1177
1178 local->hw.conf.radar_enabled = new_ctx->conf.radar_enabled;
1179 local->_oper_chandef = *chandef;
1180 ieee80211_hw_config(local, 0);
1181
1182 return 0;
1183}
1184
1185static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local,
1186 int n_vifs)
1187{
1188 struct ieee80211_vif_chanctx_switch *vif_chsw;
1189 struct ieee80211_sub_if_data *sdata;
1190 struct ieee80211_chanctx *ctx, *old_ctx;
1191 int i, err;
1192
1193 lockdep_assert_held(&local->mtx);
1194 lockdep_assert_held(&local->chanctx_mtx);
1195
1196 vif_chsw = kzalloc(sizeof(vif_chsw[0]) * n_vifs, GFP_KERNEL);
1197 if (!vif_chsw)
1198 return -ENOMEM;
1199
1200 i = 0;
1201 list_for_each_entry(ctx, &local->chanctx_list, list) {
1202 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1203 continue;
1204
1205 if (WARN_ON(!ctx->replace_ctx)) {
1206 err = -EINVAL;
1207 goto out;
1208 }
1209
1210 list_for_each_entry(sdata, &ctx->reserved_vifs,
1211 reserved_chanctx_list) {
1212 if (!ieee80211_vif_has_in_place_reservation(
1213 sdata))
1214 continue;
1215
1216 old_ctx = ieee80211_vif_get_chanctx(sdata);
1217 vif_chsw[i].vif = &sdata->vif;
1218 vif_chsw[i].old_ctx = &old_ctx->conf;
1219 vif_chsw[i].new_ctx = &ctx->conf;
1220
1221 i++;
1222 }
591 } 1223 }
592 1224
593 sdata->vif.bss_conf.chandef = *chandef; 1225 err = drv_switch_vif_chanctx(local, vif_chsw, n_vifs,
594 ctx->conf.def = *chandef; 1226 CHANCTX_SWMODE_SWAP_CONTEXTS);
595 1227
596 chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; 1228out:
597 drv_change_chanctx(local, ctx, chanctx_changed); 1229 kfree(vif_chsw);
1230 return err;
1231}
598 1232
599 ieee80211_recalc_chanctx_chantype(local, ctx); 1233static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local)
600 ieee80211_recalc_smps_chanctx(local, ctx); 1234{
601 ieee80211_recalc_radar_chanctx(local, ctx); 1235 struct ieee80211_chanctx *ctx;
602 ieee80211_recalc_chanctx_min_def(local, ctx); 1236 int err;
603 1237
604 ret = 0; 1238 lockdep_assert_held(&local->mtx);
605 out: 1239 lockdep_assert_held(&local->chanctx_mtx);
606 mutex_unlock(&local->chanctx_mtx); 1240
607 return ret; 1241 list_for_each_entry(ctx, &local->chanctx_list, list) {
1242 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1243 continue;
1244
1245 if (!list_empty(&ctx->replace_ctx->assigned_vifs))
1246 continue;
1247
1248 ieee80211_del_chanctx(local, ctx->replace_ctx);
1249 err = ieee80211_add_chanctx(local, ctx);
1250 if (err)
1251 goto err;
1252 }
1253
1254 return 0;
1255
1256err:
1257 WARN_ON(ieee80211_add_chanctx(local, ctx));
1258 list_for_each_entry_continue_reverse(ctx, &local->chanctx_list, list) {
1259 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1260 continue;
1261
1262 if (!list_empty(&ctx->replace_ctx->assigned_vifs))
1263 continue;
1264
1265 ieee80211_del_chanctx(local, ctx);
1266 WARN_ON(ieee80211_add_chanctx(local, ctx->replace_ctx));
1267 }
1268
1269 return err;
1270}
1271
1272int
1273ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
1274{
1275 struct ieee80211_sub_if_data *sdata, *sdata_tmp;
1276 struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx;
1277 struct ieee80211_chanctx *new_ctx = NULL;
1278 int i, err, n_assigned, n_reserved, n_ready;
1279 int n_ctx = 0, n_vifs_switch = 0, n_vifs_assign = 0, n_vifs_ctxless = 0;
1280
1281 lockdep_assert_held(&local->mtx);
1282 lockdep_assert_held(&local->chanctx_mtx);
1283
1284 /*
1285 * If there are 2 independent pairs of channel contexts performing
1286 * cross-switch of their vifs this code will still wait until both are
1287 * ready even though it could be possible to switch one before the
1288 * other is ready.
1289 *
1290 * For practical reasons and code simplicity just do a single huge
1291 * switch.
1292 */
1293
1294 /*
1295 * Verify if the reservation is still feasible.
1296 * - if it's not then disconnect
1297 * - if it is but not all vifs necessary are ready then defer
1298 */
1299
1300 list_for_each_entry(ctx, &local->chanctx_list, list) {
1301 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1302 continue;
1303
1304 if (WARN_ON(!ctx->replace_ctx)) {
1305 err = -EINVAL;
1306 goto err;
1307 }
1308
1309 if (!local->use_chanctx)
1310 new_ctx = ctx;
1311
1312 n_ctx++;
1313
1314 n_assigned = 0;
1315 n_reserved = 0;
1316 n_ready = 0;
1317
1318 list_for_each_entry(sdata, &ctx->replace_ctx->assigned_vifs,
1319 assigned_chanctx_list) {
1320 n_assigned++;
1321 if (sdata->reserved_chanctx) {
1322 n_reserved++;
1323 if (sdata->reserved_ready)
1324 n_ready++;
1325 }
1326 }
1327
1328 if (n_assigned != n_reserved) {
1329 if (n_ready == n_reserved) {
1330 wiphy_info(local->hw.wiphy,
1331 "channel context reservation cannot be finalized because some interfaces aren't switching\n");
1332 err = -EBUSY;
1333 goto err;
1334 }
1335
1336 return -EAGAIN;
1337 }
1338
1339 ctx->conf.radar_enabled = false;
1340 list_for_each_entry(sdata, &ctx->reserved_vifs,
1341 reserved_chanctx_list) {
1342 if (ieee80211_vif_has_in_place_reservation(sdata) &&
1343 !sdata->reserved_ready)
1344 return -EAGAIN;
1345
1346 old_ctx = ieee80211_vif_get_chanctx(sdata);
1347 if (old_ctx) {
1348 if (old_ctx->replace_state ==
1349 IEEE80211_CHANCTX_WILL_BE_REPLACED)
1350 n_vifs_switch++;
1351 else
1352 n_vifs_assign++;
1353 } else {
1354 n_vifs_ctxless++;
1355 }
1356
1357 if (sdata->reserved_radar_required)
1358 ctx->conf.radar_enabled = true;
1359 }
1360 }
1361
1362 if (WARN_ON(n_ctx == 0) ||
1363 WARN_ON(n_vifs_switch == 0 &&
1364 n_vifs_assign == 0 &&
1365 n_vifs_ctxless == 0) ||
1366 WARN_ON(n_ctx > 1 && !local->use_chanctx) ||
1367 WARN_ON(!new_ctx && !local->use_chanctx)) {
1368 err = -EINVAL;
1369 goto err;
1370 }
1371
1372 /*
1373 * All necessary vifs are ready. Perform the switch now depending on
1374 * reservations and driver capabilities.
1375 */
1376
1377 if (local->use_chanctx) {
1378 if (n_vifs_switch > 0) {
1379 err = ieee80211_chsw_switch_vifs(local, n_vifs_switch);
1380 if (err)
1381 goto err;
1382 }
1383
1384 if (n_vifs_assign > 0 || n_vifs_ctxless > 0) {
1385 err = ieee80211_chsw_switch_ctxs(local);
1386 if (err)
1387 goto err;
1388 }
1389 } else {
1390 err = ieee80211_chsw_switch_hwconf(local, new_ctx);
1391 if (err)
1392 goto err;
1393 }
1394
1395 /*
1396 * Update all structures, values and pointers to point to new channel
1397 * context(s).
1398 */
1399
1400 i = 0;
1401 list_for_each_entry(ctx, &local->chanctx_list, list) {
1402 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1403 continue;
1404
1405 if (WARN_ON(!ctx->replace_ctx)) {
1406 err = -EINVAL;
1407 goto err;
1408 }
1409
1410 list_for_each_entry(sdata, &ctx->reserved_vifs,
1411 reserved_chanctx_list) {
1412 u32 changed = 0;
1413
1414 if (!ieee80211_vif_has_in_place_reservation(sdata))
1415 continue;
1416
1417 rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
1418
1419 if (sdata->vif.type == NL80211_IFTYPE_AP)
1420 __ieee80211_vif_copy_chanctx_to_vlans(sdata,
1421 false);
1422
1423 sdata->radar_required = sdata->reserved_radar_required;
1424
1425 if (sdata->vif.bss_conf.chandef.width !=
1426 sdata->reserved_chandef.width)
1427 changed = BSS_CHANGED_BANDWIDTH;
1428
1429 sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
1430 if (changed)
1431 ieee80211_bss_info_change_notify(sdata,
1432 changed);
1433
1434 ieee80211_recalc_txpower(sdata);
1435 }
1436
1437 ieee80211_recalc_chanctx_chantype(local, ctx);
1438 ieee80211_recalc_smps_chanctx(local, ctx);
1439 ieee80211_recalc_radar_chanctx(local, ctx);
1440 ieee80211_recalc_chanctx_min_def(local, ctx);
1441
1442 list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
1443 reserved_chanctx_list) {
1444 if (ieee80211_vif_get_chanctx(sdata) != ctx)
1445 continue;
1446
1447 list_del(&sdata->reserved_chanctx_list);
1448 list_move(&sdata->assigned_chanctx_list,
1449 &ctx->assigned_vifs);
1450 sdata->reserved_chanctx = NULL;
1451
1452 ieee80211_vif_chanctx_reservation_complete(sdata);
1453 }
1454
1455 /*
1456 * This context might have been a dependency for an already
1457 * ready re-assign reservation interface that was deferred. Do
1458 * not propagate error to the caller though. The in-place
1459 * reservation for originally requested interface has already
1460 * succeeded at this point.
1461 */
1462 list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
1463 reserved_chanctx_list) {
1464 if (WARN_ON(ieee80211_vif_has_in_place_reservation(
1465 sdata)))
1466 continue;
1467
1468 if (WARN_ON(sdata->reserved_chanctx != ctx))
1469 continue;
1470
1471 if (!sdata->reserved_ready)
1472 continue;
1473
1474 if (ieee80211_vif_get_chanctx(sdata))
1475 err = ieee80211_vif_use_reserved_reassign(
1476 sdata);
1477 else
1478 err = ieee80211_vif_use_reserved_assign(sdata);
1479
1480 if (err) {
1481 sdata_info(sdata,
1482 "failed to finalize (re-)assign reservation (err=%d)\n",
1483 err);
1484 ieee80211_vif_unreserve_chanctx(sdata);
1485 cfg80211_stop_iface(local->hw.wiphy,
1486 &sdata->wdev,
1487 GFP_KERNEL);
1488 }
1489 }
1490 }
1491
1492 /*
1493 * Finally free old contexts
1494 */
1495
1496 list_for_each_entry_safe(ctx, ctx_tmp, &local->chanctx_list, list) {
1497 if (ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED)
1498 continue;
1499
1500 ctx->replace_ctx->replace_ctx = NULL;
1501 ctx->replace_ctx->replace_state =
1502 IEEE80211_CHANCTX_REPLACE_NONE;
1503
1504 list_del_rcu(&ctx->list);
1505 kfree_rcu(ctx, rcu_head);
1506 }
1507
1508 return 0;
1509
1510err:
1511 list_for_each_entry(ctx, &local->chanctx_list, list) {
1512 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1513 continue;
1514
1515 list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
1516 reserved_chanctx_list) {
1517 ieee80211_vif_unreserve_chanctx(sdata);
1518 ieee80211_vif_chanctx_reservation_complete(sdata);
1519 }
1520 }
1521
1522 return err;
1523}
1524
1525int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
1526{
1527 struct ieee80211_local *local = sdata->local;
1528 struct ieee80211_chanctx *new_ctx;
1529 struct ieee80211_chanctx *old_ctx;
1530 int err;
1531
1532 lockdep_assert_held(&local->mtx);
1533 lockdep_assert_held(&local->chanctx_mtx);
1534
1535 new_ctx = sdata->reserved_chanctx;
1536 old_ctx = ieee80211_vif_get_chanctx(sdata);
1537
1538 if (WARN_ON(!new_ctx))
1539 return -EINVAL;
1540
1541 if (WARN_ON(new_ctx->replace_state ==
1542 IEEE80211_CHANCTX_WILL_BE_REPLACED))
1543 return -EINVAL;
1544
1545 if (WARN_ON(sdata->reserved_ready))
1546 return -EINVAL;
1547
1548 sdata->reserved_ready = true;
1549
1550 if (new_ctx->replace_state == IEEE80211_CHANCTX_REPLACE_NONE) {
1551 if (old_ctx)
1552 err = ieee80211_vif_use_reserved_reassign(sdata);
1553 else
1554 err = ieee80211_vif_use_reserved_assign(sdata);
1555
1556 if (err)
1557 return err;
1558 }
1559
1560 /*
1561 * In-place reservation may need to be finalized now either if:
1562 * a) sdata is taking part in the swapping itself and is the last one
1563 * b) sdata has switched with a re-assign reservation to an existing
1564 * context readying in-place switching of old_ctx
1565 *
1566 * In case of (b) do not propagate the error up because the requested
1567 * sdata already switched successfully. Just spill an extra warning.
1568 * The ieee80211_vif_use_reserved_switch() already stops all necessary
1569 * interfaces upon failure.
1570 */
1571 if ((old_ctx &&
1572 old_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
1573 new_ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) {
1574 err = ieee80211_vif_use_reserved_switch(local);
1575 if (err && err != -EAGAIN) {
1576 if (new_ctx->replace_state ==
1577 IEEE80211_CHANCTX_REPLACES_OTHER)
1578 return err;
1579
1580 wiphy_info(local->hw.wiphy,
1581 "depending in-place reservation failed (err=%d)\n",
1582 err);
1583 }
1584 }
1585
1586 return 0;
608} 1587}
609 1588
610int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, 1589int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
@@ -614,6 +1593,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
614 struct ieee80211_local *local = sdata->local; 1593 struct ieee80211_local *local = sdata->local;
615 struct ieee80211_chanctx_conf *conf; 1594 struct ieee80211_chanctx_conf *conf;
616 struct ieee80211_chanctx *ctx; 1595 struct ieee80211_chanctx *ctx;
1596 const struct cfg80211_chan_def *compat;
617 int ret; 1597 int ret;
618 1598
619 if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, 1599 if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
@@ -640,11 +1620,33 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
640 } 1620 }
641 1621
642 ctx = container_of(conf, struct ieee80211_chanctx, conf); 1622 ctx = container_of(conf, struct ieee80211_chanctx, conf);
643 if (!cfg80211_chandef_compatible(&conf->def, chandef)) { 1623
1624 compat = cfg80211_chandef_compatible(&conf->def, chandef);
1625 if (!compat) {
644 ret = -EINVAL; 1626 ret = -EINVAL;
645 goto out; 1627 goto out;
646 } 1628 }
647 1629
1630 switch (ctx->replace_state) {
1631 case IEEE80211_CHANCTX_REPLACE_NONE:
1632 if (!ieee80211_chanctx_reserved_chandef(local, ctx, compat)) {
1633 ret = -EBUSY;
1634 goto out;
1635 }
1636 break;
1637 case IEEE80211_CHANCTX_WILL_BE_REPLACED:
1638 /* TODO: Perhaps the bandwith change could be treated as a
1639 * reservation itself? */
1640 ret = -EBUSY;
1641 goto out;
1642 case IEEE80211_CHANCTX_REPLACES_OTHER:
1643 /* channel context that is going to replace another channel
1644 * context doesn't really exist and shouldn't be assigned
1645 * anywhere yet */
1646 WARN_ON(1);
1647 break;
1648 }
1649
648 sdata->vif.bss_conf.chandef = *chandef; 1650 sdata->vif.bss_conf.chandef = *chandef;
649 1651
650 ieee80211_recalc_chanctx_chantype(local, ctx); 1652 ieee80211_recalc_chanctx_chantype(local, ctx);
@@ -686,40 +1688,6 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
686 mutex_unlock(&local->chanctx_mtx); 1688 mutex_unlock(&local->chanctx_mtx);
687} 1689}
688 1690
689void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
690 bool clear)
691{
692 struct ieee80211_local *local = sdata->local;
693 struct ieee80211_sub_if_data *vlan;
694 struct ieee80211_chanctx_conf *conf;
695
696 ASSERT_RTNL();
697
698 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
699 return;
700
701 mutex_lock(&local->chanctx_mtx);
702
703 /*
704 * Check that conf exists, even when clearing this function
705 * must be called with the AP's channel context still there
706 * as it would otherwise cause VLANs to have an invalid
707 * channel context pointer for a while, possibly pointing
708 * to a channel context that has already been freed.
709 */
710 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
711 lockdep_is_held(&local->chanctx_mtx));
712 WARN_ON(!conf);
713
714 if (clear)
715 conf = NULL;
716
717 list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
718 rcu_assign_pointer(vlan->vif.chanctx_conf, conf);
719
720 mutex_unlock(&local->chanctx_mtx);
721}
722
723void ieee80211_iter_chan_contexts_atomic( 1691void ieee80211_iter_chan_contexts_atomic(
724 struct ieee80211_hw *hw, 1692 struct ieee80211_hw *hw,
725 void (*iter)(struct ieee80211_hw *hw, 1693 void (*iter)(struct ieee80211_hw *hw,