Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/mac80211/chan.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* mac80211 - channel management
4
* Copyright 2020 - 2025 Intel Corporation
5
*/
6
7
#include <linux/nl80211.h>
8
#include <linux/export.h>
9
#include <linux/rtnetlink.h>
10
#include <net/cfg80211.h>
11
#include "ieee80211_i.h"
12
#include "driver-ops.h"
13
#include "rate.h"
14
15
static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
16
struct ieee80211_chanctx *ctx)
17
{
18
struct ieee80211_link_data *link;
19
int num = 0;
20
21
lockdep_assert_wiphy(local->hw.wiphy);
22
23
list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list)
24
num++;
25
26
return num;
27
}
28
29
static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
30
struct ieee80211_chanctx *ctx)
31
{
32
struct ieee80211_link_data *link;
33
int num = 0;
34
35
lockdep_assert_wiphy(local->hw.wiphy);
36
37
list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list)
38
num++;
39
40
return num;
41
}
42
43
int ieee80211_chanctx_refcount(struct ieee80211_local *local,
44
struct ieee80211_chanctx *ctx)
45
{
46
return ieee80211_chanctx_num_assigned(local, ctx) +
47
ieee80211_chanctx_num_reserved(local, ctx);
48
}
49
50
static int ieee80211_num_chanctx(struct ieee80211_local *local, int radio_idx)
51
{
52
struct ieee80211_chanctx *ctx;
53
int num = 0;
54
55
lockdep_assert_wiphy(local->hw.wiphy);
56
57
list_for_each_entry(ctx, &local->chanctx_list, list) {
58
if (radio_idx >= 0 && ctx->conf.radio_idx != radio_idx)
59
continue;
60
num++;
61
}
62
63
return num;
64
}
65
66
static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local,
67
int radio_idx)
68
{
69
lockdep_assert_wiphy(local->hw.wiphy);
70
71
return ieee80211_num_chanctx(local, radio_idx) <
72
ieee80211_max_num_channels(local, radio_idx);
73
}
74
75
static struct ieee80211_chanctx *
76
ieee80211_link_get_chanctx(struct ieee80211_link_data *link)
77
{
78
struct ieee80211_local *local __maybe_unused = link->sdata->local;
79
struct ieee80211_chanctx_conf *conf;
80
81
conf = rcu_dereference_protected(link->conf->chanctx_conf,
82
lockdep_is_held(&local->hw.wiphy->mtx));
83
if (!conf)
84
return NULL;
85
86
return container_of(conf, struct ieee80211_chanctx, conf);
87
}
88
89
bool ieee80211_chanreq_identical(const struct ieee80211_chan_req *a,
90
const struct ieee80211_chan_req *b)
91
{
92
if (!cfg80211_chandef_identical(&a->oper, &b->oper))
93
return false;
94
if (!a->ap.chan && !b->ap.chan)
95
return true;
96
return cfg80211_chandef_identical(&a->ap, &b->ap);
97
}
98
99
static const struct ieee80211_chan_req *
100
ieee80211_chanreq_compatible(const struct ieee80211_chan_req *a,
101
const struct ieee80211_chan_req *b,
102
struct ieee80211_chan_req *tmp)
103
{
104
const struct cfg80211_chan_def *compat;
105
106
if (a->ap.chan && b->ap.chan &&
107
!cfg80211_chandef_identical(&a->ap, &b->ap))
108
return NULL;
109
110
compat = cfg80211_chandef_compatible(&a->oper, &b->oper);
111
if (!compat)
112
return NULL;
113
114
/* Note: later code assumes this always fills & returns tmp if compat */
115
tmp->oper = *compat;
116
tmp->ap = a->ap.chan ? a->ap : b->ap;
117
return tmp;
118
}
119
120
static const struct ieee80211_chan_req *
121
ieee80211_chanctx_compatible(struct ieee80211_chanctx *ctx,
122
const struct ieee80211_chan_req *req,
123
struct ieee80211_chan_req *tmp)
124
{
125
const struct ieee80211_chan_req *ret;
126
struct ieee80211_chan_req tmp2;
127
128
*tmp = (struct ieee80211_chan_req){
129
.oper = ctx->conf.def,
130
.ap = ctx->conf.ap,
131
};
132
133
ret = ieee80211_chanreq_compatible(tmp, req, &tmp2);
134
if (!ret)
135
return NULL;
136
*tmp = *ret;
137
return tmp;
138
}
139
140
static const struct ieee80211_chan_req *
141
ieee80211_chanctx_reserved_chanreq(struct ieee80211_local *local,
142
struct ieee80211_chanctx *ctx,
143
const struct ieee80211_chan_req *req,
144
struct ieee80211_chan_req *tmp)
145
{
146
struct ieee80211_link_data *link;
147
148
lockdep_assert_wiphy(local->hw.wiphy);
149
150
if (WARN_ON(!req))
151
return NULL;
152
153
list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) {
154
req = ieee80211_chanreq_compatible(&link->reserved, req, tmp);
155
if (!req)
156
break;
157
}
158
159
return req;
160
}
161
162
static const struct ieee80211_chan_req *
163
ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
164
struct ieee80211_chanctx *ctx,
165
const struct ieee80211_chan_req *compat,
166
struct ieee80211_chan_req *tmp)
167
{
168
struct ieee80211_link_data *link;
169
const struct ieee80211_chan_req *comp_def = compat;
170
171
lockdep_assert_wiphy(local->hw.wiphy);
172
173
list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) {
174
struct ieee80211_bss_conf *link_conf = link->conf;
175
176
if (link->reserved_chanctx)
177
continue;
178
179
comp_def = ieee80211_chanreq_compatible(&link_conf->chanreq,
180
comp_def, tmp);
181
if (!comp_def)
182
break;
183
}
184
185
return comp_def;
186
}
187
188
static bool
189
ieee80211_chanctx_can_reserve(struct ieee80211_local *local,
190
struct ieee80211_chanctx *ctx,
191
const struct ieee80211_chan_req *req)
192
{
193
struct ieee80211_chan_req tmp;
194
195
lockdep_assert_wiphy(local->hw.wiphy);
196
197
if (!ieee80211_chanctx_reserved_chanreq(local, ctx, req, &tmp))
198
return false;
199
200
if (!ieee80211_chanctx_non_reserved_chandef(local, ctx, req, &tmp))
201
return false;
202
203
if (!list_empty(&ctx->reserved_links) &&
204
ieee80211_chanctx_reserved_chanreq(local, ctx, req, &tmp))
205
return true;
206
207
return false;
208
}
209
210
static struct ieee80211_chanctx *
211
ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
212
const struct ieee80211_chan_req *chanreq,
213
enum ieee80211_chanctx_mode mode)
214
{
215
struct ieee80211_chanctx *ctx;
216
217
lockdep_assert_wiphy(local->hw.wiphy);
218
219
if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
220
return NULL;
221
222
list_for_each_entry(ctx, &local->chanctx_list, list) {
223
if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
224
continue;
225
226
if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
227
continue;
228
229
if (!ieee80211_chanctx_can_reserve(local, ctx, chanreq))
230
continue;
231
232
return ctx;
233
}
234
235
return NULL;
236
}
237
238
static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta,
239
unsigned int link_id)
240
{
241
enum ieee80211_sta_rx_bandwidth width;
242
struct link_sta_info *link_sta;
243
244
link_sta = wiphy_dereference(sta->local->hw.wiphy, sta->link[link_id]);
245
246
/* no effect if this STA has no presence on this link */
247
if (!link_sta)
248
return NL80211_CHAN_WIDTH_20_NOHT;
249
250
/*
251
* We assume that TX/RX might be asymmetric (so e.g. VHT operating
252
* mode notification changes what a STA wants to receive, but not
253
* necessarily what it will transmit to us), and therefore use the
254
* capabilities here. Calling it RX bandwidth capability is a bit
255
* wrong though, since capabilities are in fact symmetric.
256
*/
257
width = ieee80211_sta_cap_rx_bw(link_sta);
258
259
switch (width) {
260
case IEEE80211_STA_RX_BW_20:
261
if (link_sta->pub->ht_cap.ht_supported)
262
return NL80211_CHAN_WIDTH_20;
263
else
264
return NL80211_CHAN_WIDTH_20_NOHT;
265
case IEEE80211_STA_RX_BW_40:
266
return NL80211_CHAN_WIDTH_40;
267
case IEEE80211_STA_RX_BW_80:
268
return NL80211_CHAN_WIDTH_80;
269
case IEEE80211_STA_RX_BW_160:
270
/*
271
* This applied for both 160 and 80+80. since we use
272
* the returned value to consider degradation of
273
* ctx->conf.min_def, we have to make sure to take
274
* the bigger one (NL80211_CHAN_WIDTH_160).
275
* Otherwise we might try degrading even when not
276
* needed, as the max required sta_bw returned (80+80)
277
* might be smaller than the configured bw (160).
278
*/
279
return NL80211_CHAN_WIDTH_160;
280
case IEEE80211_STA_RX_BW_320:
281
return NL80211_CHAN_WIDTH_320;
282
default:
283
WARN_ON(1);
284
return NL80211_CHAN_WIDTH_20;
285
}
286
}
287
288
static enum nl80211_chan_width
289
ieee80211_get_max_required_bw(struct ieee80211_link_data *link)
290
{
291
struct ieee80211_sub_if_data *sdata = link->sdata;
292
unsigned int link_id = link->link_id;
293
enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
294
struct sta_info *sta;
295
296
lockdep_assert_wiphy(sdata->local->hw.wiphy);
297
298
list_for_each_entry(sta, &sdata->local->sta_list, list) {
299
if (sdata != sta->sdata &&
300
!(sta->sdata->bss && sta->sdata->bss == sdata->bss))
301
continue;
302
303
max_bw = max(max_bw, ieee80211_get_sta_bw(sta, link_id));
304
}
305
306
return max_bw;
307
}
308
309
static enum nl80211_chan_width
310
ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
311
struct ieee80211_chanctx *ctx,
312
struct ieee80211_link_data *rsvd_for,
313
bool check_reserved)
314
{
315
struct ieee80211_sub_if_data *sdata;
316
struct ieee80211_link_data *link;
317
enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
318
319
if (WARN_ON(check_reserved && rsvd_for))
320
return ctx->conf.def.width;
321
322
for_each_sdata_link(local, link) {
323
enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;
324
325
if (check_reserved) {
326
if (link->reserved_chanctx != ctx)
327
continue;
328
} else if (link != rsvd_for &&
329
rcu_access_pointer(link->conf->chanctx_conf) != &ctx->conf)
330
continue;
331
332
switch (link->sdata->vif.type) {
333
case NL80211_IFTYPE_STATION:
334
if (!link->sdata->vif.cfg.assoc) {
335
/*
336
* The AP's sta->bandwidth may not yet be set
337
* at this point (pre-association), so simply
338
* take the width from the chandef. We cannot
339
* have TDLS peers yet (only after association).
340
*/
341
width = link->conf->chanreq.oper.width;
342
break;
343
}
344
/*
345
* otherwise just use min_def like in AP, depending on what
346
* we currently think the AP STA (and possibly TDLS peers)
347
* require(s)
348
*/
349
fallthrough;
350
case NL80211_IFTYPE_AP:
351
case NL80211_IFTYPE_AP_VLAN:
352
width = ieee80211_get_max_required_bw(link);
353
break;
354
case NL80211_IFTYPE_P2P_DEVICE:
355
case NL80211_IFTYPE_NAN:
356
continue;
357
case NL80211_IFTYPE_MONITOR:
358
WARN_ON_ONCE(!ieee80211_hw_check(&local->hw,
359
NO_VIRTUAL_MONITOR));
360
fallthrough;
361
case NL80211_IFTYPE_ADHOC:
362
case NL80211_IFTYPE_MESH_POINT:
363
case NL80211_IFTYPE_OCB:
364
width = link->conf->chanreq.oper.width;
365
break;
366
case NL80211_IFTYPE_WDS:
367
case NL80211_IFTYPE_UNSPECIFIED:
368
case NUM_NL80211_IFTYPES:
369
case NL80211_IFTYPE_P2P_CLIENT:
370
case NL80211_IFTYPE_P2P_GO:
371
WARN_ON_ONCE(1);
372
}
373
374
max_bw = max(max_bw, width);
375
}
376
377
/* use the configured bandwidth in case of monitor interface */
378
sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata);
379
if (sdata &&
380
rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &ctx->conf)
381
max_bw = max(max_bw, ctx->conf.def.width);
382
383
return max_bw;
384
}
385
386
/*
387
* recalc the min required chan width of the channel context, which is
388
* the max of min required widths of all the interfaces bound to this
389
* channel context.
390
*/
391
static u32
392
_ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
393
struct ieee80211_chanctx *ctx,
394
struct ieee80211_link_data *rsvd_for,
395
bool check_reserved)
396
{
397
enum nl80211_chan_width max_bw;
398
struct cfg80211_chan_def min_def;
399
400
lockdep_assert_wiphy(local->hw.wiphy);
401
402
/* don't optimize non-20MHz based and radar_enabled confs */
403
if (ctx->conf.def.width == NL80211_CHAN_WIDTH_5 ||
404
ctx->conf.def.width == NL80211_CHAN_WIDTH_10 ||
405
ctx->conf.def.width == NL80211_CHAN_WIDTH_1 ||
406
ctx->conf.def.width == NL80211_CHAN_WIDTH_2 ||
407
ctx->conf.def.width == NL80211_CHAN_WIDTH_4 ||
408
ctx->conf.def.width == NL80211_CHAN_WIDTH_8 ||
409
ctx->conf.def.width == NL80211_CHAN_WIDTH_16 ||
410
ctx->conf.radar_enabled) {
411
ctx->conf.min_def = ctx->conf.def;
412
return 0;
413
}
414
415
max_bw = ieee80211_get_chanctx_max_required_bw(local, ctx, rsvd_for,
416
check_reserved);
417
418
/* downgrade chandef up to max_bw */
419
min_def = ctx->conf.def;
420
while (min_def.width > max_bw)
421
ieee80211_chandef_downgrade(&min_def, NULL);
422
423
if (cfg80211_chandef_identical(&ctx->conf.min_def, &min_def))
424
return 0;
425
426
ctx->conf.min_def = min_def;
427
if (!ctx->driver_present)
428
return 0;
429
430
return IEEE80211_CHANCTX_CHANGE_MIN_DEF;
431
}
432
433
static void ieee80211_chan_bw_change(struct ieee80211_local *local,
434
struct ieee80211_chanctx *ctx,
435
bool reserved, bool narrowed)
436
{
437
struct sta_info *sta;
438
struct ieee80211_supported_band *sband =
439
local->hw.wiphy->bands[ctx->conf.def.chan->band];
440
441
rcu_read_lock();
442
list_for_each_entry_rcu(sta, &local->sta_list,
443
list) {
444
struct ieee80211_sub_if_data *sdata = sta->sdata;
445
enum ieee80211_sta_rx_bandwidth new_sta_bw;
446
unsigned int link_id;
447
448
if (!ieee80211_sdata_running(sta->sdata))
449
continue;
450
451
for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) {
452
struct ieee80211_link_data *link =
453
rcu_dereference(sdata->link[link_id]);
454
struct ieee80211_bss_conf *link_conf;
455
struct cfg80211_chan_def *new_chandef;
456
struct link_sta_info *link_sta;
457
458
if (!link)
459
continue;
460
461
link_conf = link->conf;
462
463
if (rcu_access_pointer(link_conf->chanctx_conf) != &ctx->conf)
464
continue;
465
466
link_sta = rcu_dereference(sta->link[link_id]);
467
if (!link_sta)
468
continue;
469
470
if (reserved)
471
new_chandef = &link->reserved.oper;
472
else
473
new_chandef = &link_conf->chanreq.oper;
474
475
new_sta_bw = _ieee80211_sta_cur_vht_bw(link_sta,
476
new_chandef);
477
478
/* nothing change */
479
if (new_sta_bw == link_sta->pub->bandwidth)
480
continue;
481
482
/* vif changed to narrow BW and narrow BW for station wasn't
483
* requested or vice versa */
484
if ((new_sta_bw < link_sta->pub->bandwidth) == !narrowed)
485
continue;
486
487
link_sta->pub->bandwidth = new_sta_bw;
488
rate_control_rate_update(local, sband, link_sta,
489
IEEE80211_RC_BW_CHANGED);
490
}
491
}
492
rcu_read_unlock();
493
}
494
495
/*
496
* recalc the min required chan width of the channel context, which is
497
* the max of min required widths of all the interfaces bound to this
498
* channel context.
499
*/
500
void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
501
struct ieee80211_chanctx *ctx,
502
struct ieee80211_link_data *rsvd_for,
503
bool check_reserved)
504
{
505
u32 changed = _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for,
506
check_reserved);
507
508
if (!changed)
509
return;
510
511
/* check is BW narrowed */
512
ieee80211_chan_bw_change(local, ctx, false, true);
513
514
drv_change_chanctx(local, ctx, changed);
515
516
/* check is BW wider */
517
ieee80211_chan_bw_change(local, ctx, false, false);
518
}
519
520
static void _ieee80211_change_chanctx(struct ieee80211_local *local,
521
struct ieee80211_chanctx *ctx,
522
struct ieee80211_chanctx *old_ctx,
523
const struct ieee80211_chan_req *chanreq,
524
struct ieee80211_link_data *rsvd_for)
525
{
526
const struct cfg80211_chan_def *chandef = &chanreq->oper;
527
struct ieee80211_chan_req ctx_req = {
528
.oper = ctx->conf.def,
529
.ap = ctx->conf.ap,
530
};
531
u32 changed = 0;
532
533
/* expected to handle only 20/40/80/160/320 channel widths */
534
switch (chandef->width) {
535
case NL80211_CHAN_WIDTH_20_NOHT:
536
case NL80211_CHAN_WIDTH_20:
537
case NL80211_CHAN_WIDTH_40:
538
case NL80211_CHAN_WIDTH_80:
539
case NL80211_CHAN_WIDTH_80P80:
540
case NL80211_CHAN_WIDTH_160:
541
case NL80211_CHAN_WIDTH_320:
542
break;
543
default:
544
WARN_ON(1);
545
}
546
547
/* Check maybe BW narrowed - we do this _before_ calling recalc_chanctx_min_def
548
* due to maybe not returning from it, e.g in case new context was added
549
* first time with all parameters up to date.
550
*/
551
ieee80211_chan_bw_change(local, old_ctx, false, true);
552
553
if (ieee80211_chanreq_identical(&ctx_req, chanreq)) {
554
ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for, false);
555
return;
556
}
557
558
WARN_ON(ieee80211_chanctx_refcount(local, ctx) > 1 &&
559
!cfg80211_chandef_compatible(&ctx->conf.def, &chanreq->oper));
560
561
ieee80211_remove_wbrf(local, &ctx->conf.def);
562
563
if (!cfg80211_chandef_identical(&ctx->conf.def, &chanreq->oper)) {
564
if (ctx->conf.def.width != chanreq->oper.width)
565
changed |= IEEE80211_CHANCTX_CHANGE_WIDTH;
566
if (ctx->conf.def.punctured != chanreq->oper.punctured)
567
changed |= IEEE80211_CHANCTX_CHANGE_PUNCTURING;
568
}
569
if (!cfg80211_chandef_identical(&ctx->conf.ap, &chanreq->ap))
570
changed |= IEEE80211_CHANCTX_CHANGE_AP;
571
ctx->conf.def = *chandef;
572
ctx->conf.ap = chanreq->ap;
573
574
/* check if min chanctx also changed */
575
changed |= _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for, false);
576
577
ieee80211_add_wbrf(local, &ctx->conf.def);
578
579
drv_change_chanctx(local, ctx, changed);
580
581
/* check if BW is wider */
582
ieee80211_chan_bw_change(local, old_ctx, false, false);
583
}
584
585
static void ieee80211_change_chanctx(struct ieee80211_local *local,
586
struct ieee80211_chanctx *ctx,
587
struct ieee80211_chanctx *old_ctx,
588
const struct ieee80211_chan_req *chanreq)
589
{
590
_ieee80211_change_chanctx(local, ctx, old_ctx, chanreq, NULL);
591
}
592
593
/* Note: if successful, the returned chanctx is reserved for the link */
594
static struct ieee80211_chanctx *
595
ieee80211_find_chanctx(struct ieee80211_local *local,
596
struct ieee80211_link_data *link,
597
const struct ieee80211_chan_req *chanreq,
598
enum ieee80211_chanctx_mode mode)
599
{
600
struct ieee80211_chan_req tmp;
601
struct ieee80211_chanctx *ctx;
602
603
lockdep_assert_wiphy(local->hw.wiphy);
604
605
if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
606
return NULL;
607
608
if (WARN_ON(link->reserved_chanctx))
609
return NULL;
610
611
list_for_each_entry(ctx, &local->chanctx_list, list) {
612
const struct ieee80211_chan_req *compat;
613
614
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACE_NONE)
615
continue;
616
617
if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
618
continue;
619
620
compat = ieee80211_chanctx_compatible(ctx, chanreq, &tmp);
621
if (!compat)
622
continue;
623
624
compat = ieee80211_chanctx_reserved_chanreq(local, ctx,
625
compat, &tmp);
626
if (!compat)
627
continue;
628
629
/*
630
* Reserve the chanctx temporarily, as the driver might change
631
* active links during callbacks we make into it below and/or
632
* later during assignment, which could (otherwise) cause the
633
* context to actually be removed.
634
*/
635
link->reserved_chanctx = ctx;
636
list_add(&link->reserved_chanctx_list,
637
&ctx->reserved_links);
638
639
ieee80211_change_chanctx(local, ctx, ctx, compat);
640
641
return ctx;
642
}
643
644
return NULL;
645
}
646
647
bool ieee80211_is_radar_required(struct ieee80211_local *local,
648
struct cfg80211_scan_request *req)
649
{
650
struct wiphy *wiphy = local->hw.wiphy;
651
struct ieee80211_link_data *link;
652
struct ieee80211_channel *chan;
653
int radio_idx;
654
655
lockdep_assert_wiphy(local->hw.wiphy);
656
657
if (!req)
658
return false;
659
660
for_each_sdata_link(local, link) {
661
if (link->radar_required) {
662
if (wiphy->n_radio < 2)
663
return true;
664
665
chan = link->conf->chanreq.oper.chan;
666
radio_idx = cfg80211_get_radio_idx_by_chan(wiphy, chan);
667
/*
668
* The radio index (radio_idx) is expected to be valid,
669
* as it's derived from a channel tied to a link. If
670
* it's invalid (i.e., negative), return true to avoid
671
* potential issues with radar-sensitive operations.
672
*/
673
if (radio_idx < 0)
674
return true;
675
676
if (ieee80211_is_radio_idx_in_scan_req(wiphy, req,
677
radio_idx))
678
return true;
679
}
680
}
681
682
return false;
683
}
684
685
static bool
686
ieee80211_chanctx_radar_required(struct ieee80211_local *local,
687
struct ieee80211_chanctx *ctx)
688
{
689
struct ieee80211_chanctx_conf *conf = &ctx->conf;
690
struct ieee80211_link_data *link;
691
692
lockdep_assert_wiphy(local->hw.wiphy);
693
694
for_each_sdata_link(local, link) {
695
if (rcu_access_pointer(link->conf->chanctx_conf) != conf)
696
continue;
697
if (!link->radar_required)
698
continue;
699
return true;
700
}
701
702
return false;
703
}
704
705
static struct ieee80211_chanctx *
706
ieee80211_alloc_chanctx(struct ieee80211_local *local,
707
const struct ieee80211_chan_req *chanreq,
708
enum ieee80211_chanctx_mode mode,
709
int radio_idx)
710
{
711
struct ieee80211_chanctx *ctx;
712
713
lockdep_assert_wiphy(local->hw.wiphy);
714
715
ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
716
if (!ctx)
717
return NULL;
718
719
INIT_LIST_HEAD(&ctx->assigned_links);
720
INIT_LIST_HEAD(&ctx->reserved_links);
721
ctx->conf.def = chanreq->oper;
722
ctx->conf.ap = chanreq->ap;
723
ctx->conf.rx_chains_static = 1;
724
ctx->conf.rx_chains_dynamic = 1;
725
ctx->mode = mode;
726
ctx->conf.radar_enabled = false;
727
ctx->conf.radio_idx = radio_idx;
728
ctx->radar_detected = false;
729
_ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
730
731
return ctx;
732
}
733
734
static int ieee80211_add_chanctx(struct ieee80211_local *local,
735
struct ieee80211_chanctx *ctx)
736
{
737
u32 changed;
738
int err;
739
740
lockdep_assert_wiphy(local->hw.wiphy);
741
742
ieee80211_add_wbrf(local, &ctx->conf.def);
743
744
/* turn idle off *before* setting channel -- some drivers need that */
745
changed = ieee80211_idle_off(local);
746
if (changed)
747
ieee80211_hw_config(local, -1, changed);
748
749
err = drv_add_chanctx(local, ctx);
750
if (err) {
751
ieee80211_recalc_idle(local);
752
return err;
753
}
754
755
return 0;
756
}
757
758
static struct ieee80211_chanctx *
759
ieee80211_new_chanctx(struct ieee80211_local *local,
760
const struct ieee80211_chan_req *chanreq,
761
enum ieee80211_chanctx_mode mode,
762
bool assign_on_failure,
763
int radio_idx)
764
{
765
struct ieee80211_chanctx *ctx;
766
int err;
767
768
lockdep_assert_wiphy(local->hw.wiphy);
769
770
ctx = ieee80211_alloc_chanctx(local, chanreq, mode, radio_idx);
771
if (!ctx)
772
return ERR_PTR(-ENOMEM);
773
774
err = ieee80211_add_chanctx(local, ctx);
775
if (!assign_on_failure && err) {
776
kfree(ctx);
777
return ERR_PTR(err);
778
}
779
/* We ignored a driver error, see _ieee80211_set_active_links */
780
WARN_ON_ONCE(err && !local->in_reconfig);
781
782
list_add_rcu(&ctx->list, &local->chanctx_list);
783
return ctx;
784
}
785
786
static void ieee80211_del_chanctx(struct ieee80211_local *local,
787
struct ieee80211_chanctx *ctx,
788
bool skip_idle_recalc)
789
{
790
lockdep_assert_wiphy(local->hw.wiphy);
791
792
drv_remove_chanctx(local, ctx);
793
794
if (!skip_idle_recalc)
795
ieee80211_recalc_idle(local);
796
797
ieee80211_remove_wbrf(local, &ctx->conf.def);
798
}
799
800
static void ieee80211_free_chanctx(struct ieee80211_local *local,
801
struct ieee80211_chanctx *ctx,
802
bool skip_idle_recalc)
803
{
804
lockdep_assert_wiphy(local->hw.wiphy);
805
806
WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
807
808
list_del_rcu(&ctx->list);
809
ieee80211_del_chanctx(local, ctx, skip_idle_recalc);
810
kfree_rcu(ctx, rcu_head);
811
}
812
813
void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
814
struct ieee80211_chanctx *ctx)
815
{
816
struct ieee80211_chanctx_conf *conf = &ctx->conf;
817
const struct ieee80211_chan_req *compat = NULL;
818
struct ieee80211_link_data *link;
819
struct ieee80211_chan_req tmp;
820
struct sta_info *sta;
821
822
lockdep_assert_wiphy(local->hw.wiphy);
823
824
for_each_sdata_link(local, link) {
825
struct ieee80211_bss_conf *link_conf;
826
827
if (link->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
828
continue;
829
830
link_conf = link->conf;
831
832
if (rcu_access_pointer(link_conf->chanctx_conf) != conf)
833
continue;
834
835
if (!compat)
836
compat = &link_conf->chanreq;
837
838
compat = ieee80211_chanreq_compatible(&link_conf->chanreq,
839
compat, &tmp);
840
if (WARN_ON_ONCE(!compat))
841
return;
842
}
843
844
if (WARN_ON_ONCE(!compat))
845
return;
846
847
/* TDLS peers can sometimes affect the chandef width */
848
list_for_each_entry(sta, &local->sta_list, list) {
849
struct ieee80211_sub_if_data *sdata = sta->sdata;
850
struct ieee80211_chan_req tdls_chanreq = {};
851
int tdls_link_id;
852
853
if (!sta->uploaded ||
854
!test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW) ||
855
!test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
856
!sta->tdls_chandef.chan)
857
continue;
858
859
tdls_link_id = ieee80211_tdls_sta_link_id(sta);
860
link = sdata_dereference(sdata->link[tdls_link_id], sdata);
861
if (!link)
862
continue;
863
864
if (rcu_access_pointer(link->conf->chanctx_conf) != conf)
865
continue;
866
867
tdls_chanreq.oper = sta->tdls_chandef;
868
869
/* note this always fills and returns &tmp if compat */
870
compat = ieee80211_chanreq_compatible(&tdls_chanreq,
871
compat, &tmp);
872
if (WARN_ON_ONCE(!compat))
873
return;
874
}
875
876
ieee80211_change_chanctx(local, ctx, ctx, compat);
877
}
878
879
static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
880
struct ieee80211_chanctx *chanctx)
881
{
882
bool radar_enabled;
883
884
lockdep_assert_wiphy(local->hw.wiphy);
885
886
radar_enabled = ieee80211_chanctx_radar_required(local, chanctx);
887
888
if (radar_enabled == chanctx->conf.radar_enabled)
889
return;
890
891
chanctx->conf.radar_enabled = radar_enabled;
892
893
drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
894
}
895
896
static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
897
struct ieee80211_chanctx *new_ctx,
898
bool assign_on_failure)
899
{
900
struct ieee80211_sub_if_data *sdata = link->sdata;
901
struct ieee80211_local *local = sdata->local;
902
struct ieee80211_chanctx_conf *conf;
903
struct ieee80211_chanctx *curr_ctx = NULL;
904
bool new_idle;
905
int ret;
906
907
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN))
908
return -EOPNOTSUPP;
909
910
conf = rcu_dereference_protected(link->conf->chanctx_conf,
911
lockdep_is_held(&local->hw.wiphy->mtx));
912
913
if (conf && !local->in_reconfig) {
914
curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
915
916
drv_unassign_vif_chanctx(local, sdata, link->conf, curr_ctx);
917
conf = NULL;
918
list_del(&link->assigned_chanctx_list);
919
}
920
921
if (new_ctx) {
922
/* recalc considering the link we'll use it for now */
923
ieee80211_recalc_chanctx_min_def(local, new_ctx, link, false);
924
925
ret = drv_assign_vif_chanctx(local, sdata, link->conf, new_ctx);
926
if (assign_on_failure || !ret) {
927
/* Need to continue, see _ieee80211_set_active_links */
928
WARN_ON_ONCE(ret && !local->in_reconfig);
929
ret = 0;
930
931
/* succeeded, so commit it to the data structures */
932
conf = &new_ctx->conf;
933
if (!local->in_reconfig)
934
list_add(&link->assigned_chanctx_list,
935
&new_ctx->assigned_links);
936
}
937
} else {
938
ret = 0;
939
}
940
941
rcu_assign_pointer(link->conf->chanctx_conf, conf);
942
943
if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
944
ieee80211_recalc_chanctx_chantype(local, curr_ctx);
945
ieee80211_recalc_smps_chanctx(local, curr_ctx);
946
ieee80211_recalc_radar_chanctx(local, curr_ctx);
947
ieee80211_recalc_chanctx_min_def(local, curr_ctx, NULL, false);
948
}
949
950
if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
951
ieee80211_recalc_txpower(link, false);
952
ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL, false);
953
}
954
955
if (conf) {
956
new_idle = false;
957
} else {
958
struct ieee80211_link_data *tmp;
959
960
new_idle = true;
961
for_each_sdata_link(local, tmp) {
962
if (rcu_access_pointer(tmp->conf->chanctx_conf)) {
963
new_idle = false;
964
break;
965
}
966
}
967
}
968
969
if (new_idle != sdata->vif.cfg.idle) {
970
sdata->vif.cfg.idle = new_idle;
971
972
if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
973
sdata->vif.type != NL80211_IFTYPE_MONITOR)
974
ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_IDLE);
975
}
976
977
ieee80211_check_fast_xmit_iface(sdata);
978
979
return ret;
980
}
981
982
void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
983
struct ieee80211_chanctx *chanctx)
984
{
985
struct ieee80211_sub_if_data *sdata;
986
u8 rx_chains_static, rx_chains_dynamic;
987
struct ieee80211_link_data *link;
988
989
lockdep_assert_wiphy(local->hw.wiphy);
990
991
rx_chains_static = 1;
992
rx_chains_dynamic = 1;
993
994
for_each_sdata_link(local, link) {
995
u8 needed_static, needed_dynamic;
996
997
switch (link->sdata->vif.type) {
998
case NL80211_IFTYPE_STATION:
999
if (!link->sdata->u.mgd.associated)
1000
continue;
1001
break;
1002
case NL80211_IFTYPE_MONITOR:
1003
if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
1004
continue;
1005
break;
1006
case NL80211_IFTYPE_AP:
1007
case NL80211_IFTYPE_ADHOC:
1008
case NL80211_IFTYPE_MESH_POINT:
1009
case NL80211_IFTYPE_OCB:
1010
break;
1011
default:
1012
continue;
1013
}
1014
1015
if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf)
1016
continue;
1017
1018
if (link->sdata->vif.type == NL80211_IFTYPE_MONITOR) {
1019
rx_chains_dynamic = rx_chains_static = local->rx_chains;
1020
break;
1021
}
1022
1023
switch (link->smps_mode) {
1024
default:
1025
WARN_ONCE(1, "Invalid SMPS mode %d\n",
1026
link->smps_mode);
1027
fallthrough;
1028
case IEEE80211_SMPS_OFF:
1029
needed_static = link->needed_rx_chains;
1030
needed_dynamic = link->needed_rx_chains;
1031
break;
1032
case IEEE80211_SMPS_DYNAMIC:
1033
needed_static = 1;
1034
needed_dynamic = link->needed_rx_chains;
1035
break;
1036
case IEEE80211_SMPS_STATIC:
1037
needed_static = 1;
1038
needed_dynamic = 1;
1039
break;
1040
}
1041
1042
rx_chains_static = max(rx_chains_static, needed_static);
1043
rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
1044
}
1045
1046
/* Disable SMPS for the monitor interface */
1047
sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata);
1048
if (sdata &&
1049
rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &chanctx->conf)
1050
rx_chains_dynamic = rx_chains_static = local->rx_chains;
1051
1052
if (rx_chains_static == chanctx->conf.rx_chains_static &&
1053
rx_chains_dynamic == chanctx->conf.rx_chains_dynamic)
1054
return;
1055
1056
chanctx->conf.rx_chains_static = rx_chains_static;
1057
chanctx->conf.rx_chains_dynamic = rx_chains_dynamic;
1058
drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
1059
}
1060
1061
static void
1062
__ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
1063
bool clear)
1064
{
1065
struct ieee80211_sub_if_data *sdata = link->sdata;
1066
unsigned int link_id = link->link_id;
1067
struct ieee80211_bss_conf *link_conf = link->conf;
1068
struct ieee80211_local *local __maybe_unused = sdata->local;
1069
struct ieee80211_sub_if_data *vlan;
1070
struct ieee80211_chanctx_conf *conf;
1071
1072
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
1073
return;
1074
1075
lockdep_assert_wiphy(local->hw.wiphy);
1076
1077
/* Check that conf exists, even when clearing this function
1078
* must be called with the AP's channel context still there
1079
* as it would otherwise cause VLANs to have an invalid
1080
* channel context pointer for a while, possibly pointing
1081
* to a channel context that has already been freed.
1082
*/
1083
conf = rcu_dereference_protected(link_conf->chanctx_conf,
1084
lockdep_is_held(&local->hw.wiphy->mtx));
1085
WARN_ON(!conf);
1086
1087
if (clear)
1088
conf = NULL;
1089
1090
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
1091
struct ieee80211_bss_conf *vlan_conf;
1092
1093
vlan_conf = wiphy_dereference(local->hw.wiphy,
1094
vlan->vif.link_conf[link_id]);
1095
if (WARN_ON(!vlan_conf))
1096
continue;
1097
1098
rcu_assign_pointer(vlan_conf->chanctx_conf, conf);
1099
}
1100
}
1101
1102
void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
1103
bool clear)
1104
{
1105
struct ieee80211_local *local = link->sdata->local;
1106
1107
lockdep_assert_wiphy(local->hw.wiphy);
1108
1109
__ieee80211_link_copy_chanctx_to_vlans(link, clear);
1110
}
1111
1112
void ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link)
1113
{
1114
struct ieee80211_sub_if_data *sdata = link->sdata;
1115
struct ieee80211_chanctx *ctx = link->reserved_chanctx;
1116
1117
lockdep_assert_wiphy(sdata->local->hw.wiphy);
1118
1119
if (WARN_ON(!ctx))
1120
return;
1121
1122
list_del(&link->reserved_chanctx_list);
1123
link->reserved_chanctx = NULL;
1124
1125
if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) {
1126
if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) {
1127
if (WARN_ON(!ctx->replace_ctx))
1128
return;
1129
1130
WARN_ON(ctx->replace_ctx->replace_state !=
1131
IEEE80211_CHANCTX_WILL_BE_REPLACED);
1132
WARN_ON(ctx->replace_ctx->replace_ctx != ctx);
1133
1134
ctx->replace_ctx->replace_ctx = NULL;
1135
ctx->replace_ctx->replace_state =
1136
IEEE80211_CHANCTX_REPLACE_NONE;
1137
1138
list_del_rcu(&ctx->list);
1139
kfree_rcu(ctx, rcu_head);
1140
} else {
1141
ieee80211_free_chanctx(sdata->local, ctx, false);
1142
}
1143
}
1144
}
1145
1146
static struct ieee80211_chanctx *
1147
ieee80211_replace_chanctx(struct ieee80211_local *local,
1148
const struct ieee80211_chan_req *chanreq,
1149
enum ieee80211_chanctx_mode mode,
1150
struct ieee80211_chanctx *curr_ctx)
1151
{
1152
struct ieee80211_chanctx *new_ctx, *ctx;
1153
struct wiphy *wiphy = local->hw.wiphy;
1154
const struct wiphy_radio *radio;
1155
1156
if (!curr_ctx || (curr_ctx->replace_state ==
1157
IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
1158
!list_empty(&curr_ctx->reserved_links)) {
1159
/*
1160
* Another link already requested this context for a
1161
* reservation. Find another one hoping all links assigned
1162
* to it will also switch soon enough.
1163
*
1164
* TODO: This needs a little more work as some cases
1165
* (more than 2 chanctx capable devices) may fail which could
1166
* otherwise succeed provided some channel context juggling was
1167
* performed.
1168
*
1169
* Consider ctx1..3, link1..6, each ctx has 2 links. link1 and
1170
* link2 from ctx1 request new different chandefs starting 2
1171
* in-place reservations with ctx4 and ctx5 replacing ctx1 and
1172
* ctx2 respectively. Next link5 and link6 from ctx3 reserve
1173
* ctx4. If link3 and link4 remain on ctx2 as they are then this
1174
* fails unless `replace_ctx` from ctx5 is replaced with ctx3.
1175
*/
1176
list_for_each_entry(ctx, &local->chanctx_list, list) {
1177
if (ctx->replace_state !=
1178
IEEE80211_CHANCTX_REPLACE_NONE)
1179
continue;
1180
1181
if (!list_empty(&ctx->reserved_links))
1182
continue;
1183
1184
if (ctx->conf.radio_idx >= 0) {
1185
radio = &wiphy->radio[ctx->conf.radio_idx];
1186
if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
1187
continue;
1188
}
1189
1190
curr_ctx = ctx;
1191
break;
1192
}
1193
}
1194
1195
/*
1196
* If that's true then all available contexts already have reservations
1197
* and cannot be used.
1198
*/
1199
if (!curr_ctx || (curr_ctx->replace_state ==
1200
IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
1201
!list_empty(&curr_ctx->reserved_links))
1202
return ERR_PTR(-EBUSY);
1203
1204
new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
1205
if (!new_ctx)
1206
return ERR_PTR(-ENOMEM);
1207
1208
new_ctx->replace_ctx = curr_ctx;
1209
new_ctx->replace_state = IEEE80211_CHANCTX_REPLACES_OTHER;
1210
1211
curr_ctx->replace_ctx = new_ctx;
1212
curr_ctx->replace_state = IEEE80211_CHANCTX_WILL_BE_REPLACED;
1213
1214
list_add_rcu(&new_ctx->list, &local->chanctx_list);
1215
1216
return new_ctx;
1217
}
1218
1219
static bool
1220
ieee80211_find_available_radio(struct ieee80211_local *local,
1221
const struct ieee80211_chan_req *chanreq,
1222
u32 radio_mask, int *radio_idx)
1223
{
1224
struct wiphy *wiphy = local->hw.wiphy;
1225
const struct wiphy_radio *radio;
1226
int i;
1227
1228
*radio_idx = -1;
1229
if (!wiphy->n_radio)
1230
return true;
1231
1232
for (i = 0; i < wiphy->n_radio; i++) {
1233
if (!(radio_mask & BIT(i)))
1234
continue;
1235
1236
radio = &wiphy->radio[i];
1237
if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
1238
continue;
1239
1240
if (!ieee80211_can_create_new_chanctx(local, i))
1241
continue;
1242
1243
*radio_idx = i;
1244
return true;
1245
}
1246
1247
return false;
1248
}
1249
1250
int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
1251
const struct ieee80211_chan_req *chanreq,
1252
enum ieee80211_chanctx_mode mode,
1253
bool radar_required)
1254
{
1255
struct ieee80211_sub_if_data *sdata = link->sdata;
1256
struct ieee80211_local *local = sdata->local;
1257
struct ieee80211_chanctx *new_ctx, *curr_ctx;
1258
int radio_idx;
1259
1260
lockdep_assert_wiphy(local->hw.wiphy);
1261
1262
curr_ctx = ieee80211_link_get_chanctx(link);
1263
if (curr_ctx && !local->ops->switch_vif_chanctx)
1264
return -EOPNOTSUPP;
1265
1266
new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
1267
if (!new_ctx) {
1268
if (ieee80211_can_create_new_chanctx(local, -1) &&
1269
ieee80211_find_available_radio(local, chanreq,
1270
sdata->wdev.radio_mask,
1271
&radio_idx))
1272
new_ctx = ieee80211_new_chanctx(local, chanreq, mode,
1273
false, radio_idx);
1274
else
1275
new_ctx = ieee80211_replace_chanctx(local, chanreq,
1276
mode, curr_ctx);
1277
if (IS_ERR(new_ctx))
1278
return PTR_ERR(new_ctx);
1279
}
1280
1281
list_add(&link->reserved_chanctx_list, &new_ctx->reserved_links);
1282
link->reserved_chanctx = new_ctx;
1283
link->reserved = *chanreq;
1284
link->reserved_radar_required = radar_required;
1285
link->reserved_ready = false;
1286
1287
return 0;
1288
}
1289
1290
static void
1291
ieee80211_link_chanctx_reservation_complete(struct ieee80211_link_data *link)
1292
{
1293
struct ieee80211_sub_if_data *sdata = link->sdata;
1294
1295
switch (sdata->vif.type) {
1296
case NL80211_IFTYPE_ADHOC:
1297
case NL80211_IFTYPE_AP:
1298
case NL80211_IFTYPE_MESH_POINT:
1299
case NL80211_IFTYPE_OCB:
1300
wiphy_work_queue(sdata->local->hw.wiphy,
1301
&link->csa.finalize_work);
1302
break;
1303
case NL80211_IFTYPE_STATION:
1304
wiphy_delayed_work_queue(sdata->local->hw.wiphy,
1305
&link->u.mgd.csa.switch_work, 0);
1306
break;
1307
case NL80211_IFTYPE_UNSPECIFIED:
1308
case NL80211_IFTYPE_AP_VLAN:
1309
case NL80211_IFTYPE_WDS:
1310
case NL80211_IFTYPE_MONITOR:
1311
case NL80211_IFTYPE_P2P_CLIENT:
1312
case NL80211_IFTYPE_P2P_GO:
1313
case NL80211_IFTYPE_P2P_DEVICE:
1314
case NL80211_IFTYPE_NAN:
1315
case NUM_NL80211_IFTYPES:
1316
WARN_ON(1);
1317
break;
1318
}
1319
}
1320
1321
static void
1322
ieee80211_link_update_chanreq(struct ieee80211_link_data *link,
1323
const struct ieee80211_chan_req *chanreq)
1324
{
1325
struct ieee80211_sub_if_data *sdata = link->sdata;
1326
unsigned int link_id = link->link_id;
1327
struct ieee80211_sub_if_data *vlan;
1328
1329
link->conf->chanreq = *chanreq;
1330
1331
if (sdata->vif.type != NL80211_IFTYPE_AP)
1332
return;
1333
1334
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
1335
struct ieee80211_bss_conf *vlan_conf;
1336
1337
vlan_conf = wiphy_dereference(sdata->local->hw.wiphy,
1338
vlan->vif.link_conf[link_id]);
1339
if (WARN_ON(!vlan_conf))
1340
continue;
1341
1342
vlan_conf->chanreq = *chanreq;
1343
}
1344
}
1345
1346
static int
1347
ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
1348
{
1349
struct ieee80211_sub_if_data *sdata = link->sdata;
1350
struct ieee80211_bss_conf *link_conf = link->conf;
1351
struct ieee80211_local *local = sdata->local;
1352
struct ieee80211_vif_chanctx_switch vif_chsw[1] = {};
1353
struct ieee80211_chanctx *old_ctx, *new_ctx;
1354
const struct ieee80211_chan_req *chanreq;
1355
struct ieee80211_chan_req tmp;
1356
u64 changed = 0;
1357
int err;
1358
1359
lockdep_assert_wiphy(local->hw.wiphy);
1360
1361
new_ctx = link->reserved_chanctx;
1362
old_ctx = ieee80211_link_get_chanctx(link);
1363
1364
if (WARN_ON(!link->reserved_ready))
1365
return -EBUSY;
1366
1367
if (WARN_ON(!new_ctx))
1368
return -EINVAL;
1369
1370
if (WARN_ON(!old_ctx))
1371
return -EINVAL;
1372
1373
if (WARN_ON(new_ctx->replace_state ==
1374
IEEE80211_CHANCTX_REPLACES_OTHER))
1375
return -EINVAL;
1376
1377
chanreq = ieee80211_chanctx_non_reserved_chandef(local, new_ctx,
1378
&link->reserved,
1379
&tmp);
1380
if (WARN_ON(!chanreq))
1381
return -EINVAL;
1382
1383
if (link_conf->chanreq.oper.width != link->reserved.oper.width)
1384
changed = BSS_CHANGED_BANDWIDTH;
1385
1386
ieee80211_link_update_chanreq(link, &link->reserved);
1387
1388
_ieee80211_change_chanctx(local, new_ctx, old_ctx, chanreq, link);
1389
1390
vif_chsw[0].vif = &sdata->vif;
1391
vif_chsw[0].old_ctx = &old_ctx->conf;
1392
vif_chsw[0].new_ctx = &new_ctx->conf;
1393
vif_chsw[0].link_conf = link->conf;
1394
1395
list_del(&link->reserved_chanctx_list);
1396
link->reserved_chanctx = NULL;
1397
1398
err = drv_switch_vif_chanctx(local, vif_chsw, 1,
1399
CHANCTX_SWMODE_REASSIGN_VIF);
1400
if (err) {
1401
if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
1402
ieee80211_free_chanctx(local, new_ctx, false);
1403
1404
goto out;
1405
}
1406
1407
link->radar_required = link->reserved_radar_required;
1408
list_move(&link->assigned_chanctx_list, &new_ctx->assigned_links);
1409
rcu_assign_pointer(link_conf->chanctx_conf, &new_ctx->conf);
1410
1411
if (sdata->vif.type == NL80211_IFTYPE_AP)
1412
__ieee80211_link_copy_chanctx_to_vlans(link, false);
1413
1414
ieee80211_check_fast_xmit_iface(sdata);
1415
1416
if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
1417
ieee80211_free_chanctx(local, old_ctx, false);
1418
1419
ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL, false);
1420
ieee80211_recalc_smps_chanctx(local, new_ctx);
1421
ieee80211_recalc_radar_chanctx(local, new_ctx);
1422
1423
if (changed)
1424
ieee80211_link_info_change_notify(sdata, link, changed);
1425
1426
out:
1427
ieee80211_link_chanctx_reservation_complete(link);
1428
return err;
1429
}
1430
1431
static int
1432
ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link)
1433
{
1434
struct ieee80211_sub_if_data *sdata = link->sdata;
1435
struct ieee80211_local *local = sdata->local;
1436
struct ieee80211_chanctx *old_ctx, *new_ctx;
1437
const struct ieee80211_chan_req *chanreq;
1438
struct ieee80211_chan_req tmp;
1439
int err;
1440
1441
old_ctx = ieee80211_link_get_chanctx(link);
1442
new_ctx = link->reserved_chanctx;
1443
1444
if (WARN_ON(!link->reserved_ready))
1445
return -EINVAL;
1446
1447
if (WARN_ON(old_ctx))
1448
return -EINVAL;
1449
1450
if (WARN_ON(!new_ctx))
1451
return -EINVAL;
1452
1453
if (WARN_ON(new_ctx->replace_state ==
1454
IEEE80211_CHANCTX_REPLACES_OTHER))
1455
return -EINVAL;
1456
1457
chanreq = ieee80211_chanctx_non_reserved_chandef(local, new_ctx,
1458
&link->reserved,
1459
&tmp);
1460
if (WARN_ON(!chanreq))
1461
return -EINVAL;
1462
1463
ieee80211_change_chanctx(local, new_ctx, new_ctx, chanreq);
1464
1465
list_del(&link->reserved_chanctx_list);
1466
link->reserved_chanctx = NULL;
1467
1468
err = ieee80211_assign_link_chanctx(link, new_ctx, false);
1469
if (err) {
1470
if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
1471
ieee80211_free_chanctx(local, new_ctx, false);
1472
1473
goto out;
1474
}
1475
1476
out:
1477
ieee80211_link_chanctx_reservation_complete(link);
1478
return err;
1479
}
1480
1481
static bool
1482
ieee80211_link_has_in_place_reservation(struct ieee80211_link_data *link)
1483
{
1484
struct ieee80211_sub_if_data *sdata = link->sdata;
1485
struct ieee80211_chanctx *old_ctx, *new_ctx;
1486
1487
lockdep_assert_wiphy(sdata->local->hw.wiphy);
1488
1489
new_ctx = link->reserved_chanctx;
1490
old_ctx = ieee80211_link_get_chanctx(link);
1491
1492
if (!old_ctx)
1493
return false;
1494
1495
if (WARN_ON(!new_ctx))
1496
return false;
1497
1498
if (old_ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED)
1499
return false;
1500
1501
if (new_ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1502
return false;
1503
1504
return true;
1505
}
1506
1507
static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local,
1508
int n_vifs)
1509
{
1510
struct ieee80211_vif_chanctx_switch *vif_chsw;
1511
struct ieee80211_link_data *link;
1512
struct ieee80211_chanctx *ctx, *old_ctx;
1513
int i, err;
1514
1515
lockdep_assert_wiphy(local->hw.wiphy);
1516
1517
vif_chsw = kcalloc(n_vifs, sizeof(vif_chsw[0]), GFP_KERNEL);
1518
if (!vif_chsw)
1519
return -ENOMEM;
1520
1521
i = 0;
1522
list_for_each_entry(ctx, &local->chanctx_list, list) {
1523
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1524
continue;
1525
1526
if (WARN_ON(!ctx->replace_ctx)) {
1527
err = -EINVAL;
1528
goto out;
1529
}
1530
1531
list_for_each_entry(link, &ctx->reserved_links,
1532
reserved_chanctx_list) {
1533
if (!ieee80211_link_has_in_place_reservation(link))
1534
continue;
1535
1536
old_ctx = ieee80211_link_get_chanctx(link);
1537
vif_chsw[i].vif = &link->sdata->vif;
1538
vif_chsw[i].old_ctx = &old_ctx->conf;
1539
vif_chsw[i].new_ctx = &ctx->conf;
1540
vif_chsw[i].link_conf = link->conf;
1541
1542
i++;
1543
}
1544
}
1545
1546
err = drv_switch_vif_chanctx(local, vif_chsw, n_vifs,
1547
CHANCTX_SWMODE_SWAP_CONTEXTS);
1548
1549
out:
1550
kfree(vif_chsw);
1551
return err;
1552
}
1553
1554
static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local)
1555
{
1556
struct ieee80211_chanctx *ctx;
1557
int err;
1558
1559
lockdep_assert_wiphy(local->hw.wiphy);
1560
1561
list_for_each_entry(ctx, &local->chanctx_list, list) {
1562
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1563
continue;
1564
1565
if (!list_empty(&ctx->replace_ctx->assigned_links))
1566
continue;
1567
1568
ieee80211_del_chanctx(local, ctx->replace_ctx, false);
1569
err = ieee80211_add_chanctx(local, ctx);
1570
if (err)
1571
goto err;
1572
}
1573
1574
return 0;
1575
1576
err:
1577
WARN_ON(ieee80211_add_chanctx(local, ctx));
1578
list_for_each_entry_continue_reverse(ctx, &local->chanctx_list, list) {
1579
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1580
continue;
1581
1582
if (!list_empty(&ctx->replace_ctx->assigned_links))
1583
continue;
1584
1585
ieee80211_del_chanctx(local, ctx, false);
1586
WARN_ON(ieee80211_add_chanctx(local, ctx->replace_ctx));
1587
}
1588
1589
return err;
1590
}
1591
1592
static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
1593
{
1594
struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx;
1595
int err, n_assigned, n_reserved, n_ready;
1596
int n_ctx = 0, n_vifs_switch = 0, n_vifs_assign = 0, n_vifs_ctxless = 0;
1597
1598
lockdep_assert_wiphy(local->hw.wiphy);
1599
1600
/*
1601
* If there are 2 independent pairs of channel contexts performing
1602
* cross-switch of their vifs this code will still wait until both are
1603
* ready even though it could be possible to switch one before the
1604
* other is ready.
1605
*
1606
* For practical reasons and code simplicity just do a single huge
1607
* switch.
1608
*/
1609
1610
/*
1611
* Verify if the reservation is still feasible.
1612
* - if it's not then disconnect
1613
* - if it is but not all vifs necessary are ready then defer
1614
*/
1615
1616
list_for_each_entry(ctx, &local->chanctx_list, list) {
1617
struct ieee80211_link_data *link;
1618
1619
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1620
continue;
1621
1622
if (WARN_ON(!ctx->replace_ctx)) {
1623
err = -EINVAL;
1624
goto err;
1625
}
1626
1627
n_ctx++;
1628
1629
n_assigned = 0;
1630
n_reserved = 0;
1631
n_ready = 0;
1632
1633
list_for_each_entry(link, &ctx->replace_ctx->assigned_links,
1634
assigned_chanctx_list) {
1635
n_assigned++;
1636
if (link->reserved_chanctx) {
1637
n_reserved++;
1638
if (link->reserved_ready)
1639
n_ready++;
1640
}
1641
}
1642
1643
if (n_assigned != n_reserved) {
1644
if (n_ready == n_reserved) {
1645
wiphy_info(local->hw.wiphy,
1646
"channel context reservation cannot be finalized because some interfaces aren't switching\n");
1647
err = -EBUSY;
1648
goto err;
1649
}
1650
1651
return -EAGAIN;
1652
}
1653
1654
ctx->conf.radar_enabled = false;
1655
list_for_each_entry(link, &ctx->reserved_links,
1656
reserved_chanctx_list) {
1657
if (ieee80211_link_has_in_place_reservation(link) &&
1658
!link->reserved_ready)
1659
return -EAGAIN;
1660
1661
old_ctx = ieee80211_link_get_chanctx(link);
1662
if (old_ctx) {
1663
if (old_ctx->replace_state ==
1664
IEEE80211_CHANCTX_WILL_BE_REPLACED)
1665
n_vifs_switch++;
1666
else
1667
n_vifs_assign++;
1668
} else {
1669
n_vifs_ctxless++;
1670
}
1671
1672
if (link->reserved_radar_required)
1673
ctx->conf.radar_enabled = true;
1674
}
1675
}
1676
1677
if (WARN_ON(n_ctx == 0) ||
1678
WARN_ON(n_vifs_switch == 0 &&
1679
n_vifs_assign == 0 &&
1680
n_vifs_ctxless == 0)) {
1681
err = -EINVAL;
1682
goto err;
1683
}
1684
1685
/* update station rate control and min width before switch */
1686
list_for_each_entry(ctx, &local->chanctx_list, list) {
1687
struct ieee80211_link_data *link;
1688
1689
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1690
continue;
1691
1692
if (WARN_ON(!ctx->replace_ctx)) {
1693
err = -EINVAL;
1694
goto err;
1695
}
1696
1697
list_for_each_entry(link, &ctx->reserved_links,
1698
reserved_chanctx_list) {
1699
if (!ieee80211_link_has_in_place_reservation(link))
1700
continue;
1701
1702
ieee80211_chan_bw_change(local,
1703
ieee80211_link_get_chanctx(link),
1704
true, true);
1705
}
1706
1707
ieee80211_recalc_chanctx_min_def(local, ctx, NULL, true);
1708
}
1709
1710
/*
1711
* All necessary vifs are ready. Perform the switch now depending on
1712
* reservations and driver capabilities.
1713
*/
1714
1715
if (n_vifs_switch > 0) {
1716
err = ieee80211_chsw_switch_vifs(local, n_vifs_switch);
1717
if (err)
1718
goto err;
1719
}
1720
1721
if (n_vifs_assign > 0 || n_vifs_ctxless > 0) {
1722
err = ieee80211_chsw_switch_ctxs(local);
1723
if (err)
1724
goto err;
1725
}
1726
1727
/*
1728
* Update all structures, values and pointers to point to new channel
1729
* context(s).
1730
*/
1731
list_for_each_entry(ctx, &local->chanctx_list, list) {
1732
struct ieee80211_link_data *link, *link_tmp;
1733
1734
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1735
continue;
1736
1737
if (WARN_ON(!ctx->replace_ctx)) {
1738
err = -EINVAL;
1739
goto err;
1740
}
1741
1742
list_for_each_entry(link, &ctx->reserved_links,
1743
reserved_chanctx_list) {
1744
struct ieee80211_sub_if_data *sdata = link->sdata;
1745
struct ieee80211_bss_conf *link_conf = link->conf;
1746
u64 changed = 0;
1747
1748
if (!ieee80211_link_has_in_place_reservation(link))
1749
continue;
1750
1751
rcu_assign_pointer(link_conf->chanctx_conf,
1752
&ctx->conf);
1753
1754
if (sdata->vif.type == NL80211_IFTYPE_AP)
1755
__ieee80211_link_copy_chanctx_to_vlans(link,
1756
false);
1757
1758
ieee80211_check_fast_xmit_iface(sdata);
1759
1760
link->radar_required = link->reserved_radar_required;
1761
1762
if (link_conf->chanreq.oper.width != link->reserved.oper.width)
1763
changed = BSS_CHANGED_BANDWIDTH;
1764
1765
ieee80211_link_update_chanreq(link, &link->reserved);
1766
if (changed)
1767
ieee80211_link_info_change_notify(sdata,
1768
link,
1769
changed);
1770
1771
ieee80211_recalc_txpower(link, false);
1772
}
1773
1774
ieee80211_recalc_chanctx_chantype(local, ctx);
1775
ieee80211_recalc_smps_chanctx(local, ctx);
1776
ieee80211_recalc_radar_chanctx(local, ctx);
1777
ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
1778
1779
list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
1780
reserved_chanctx_list) {
1781
if (ieee80211_link_get_chanctx(link) != ctx)
1782
continue;
1783
1784
list_del(&link->reserved_chanctx_list);
1785
list_move(&link->assigned_chanctx_list,
1786
&ctx->assigned_links);
1787
link->reserved_chanctx = NULL;
1788
1789
ieee80211_link_chanctx_reservation_complete(link);
1790
ieee80211_chan_bw_change(local, ctx, false, false);
1791
}
1792
1793
/*
1794
* This context might have been a dependency for an already
1795
* ready re-assign reservation interface that was deferred. Do
1796
* not propagate error to the caller though. The in-place
1797
* reservation for originally requested interface has already
1798
* succeeded at this point.
1799
*/
1800
list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
1801
reserved_chanctx_list) {
1802
if (WARN_ON(ieee80211_link_has_in_place_reservation(link)))
1803
continue;
1804
1805
if (WARN_ON(link->reserved_chanctx != ctx))
1806
continue;
1807
1808
if (!link->reserved_ready)
1809
continue;
1810
1811
if (ieee80211_link_get_chanctx(link))
1812
err = ieee80211_link_use_reserved_reassign(link);
1813
else
1814
err = ieee80211_link_use_reserved_assign(link);
1815
1816
if (err) {
1817
link_info(link,
1818
"failed to finalize (re-)assign reservation (err=%d)\n",
1819
err);
1820
ieee80211_link_unreserve_chanctx(link);
1821
cfg80211_stop_iface(local->hw.wiphy,
1822
&link->sdata->wdev,
1823
GFP_KERNEL);
1824
}
1825
}
1826
}
1827
1828
/*
1829
* Finally free old contexts
1830
*/
1831
1832
list_for_each_entry_safe(ctx, ctx_tmp, &local->chanctx_list, list) {
1833
if (ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED)
1834
continue;
1835
1836
ctx->replace_ctx->replace_ctx = NULL;
1837
ctx->replace_ctx->replace_state =
1838
IEEE80211_CHANCTX_REPLACE_NONE;
1839
1840
list_del_rcu(&ctx->list);
1841
kfree_rcu(ctx, rcu_head);
1842
}
1843
1844
return 0;
1845
1846
err:
1847
list_for_each_entry(ctx, &local->chanctx_list, list) {
1848
struct ieee80211_link_data *link, *link_tmp;
1849
1850
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1851
continue;
1852
1853
list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
1854
reserved_chanctx_list) {
1855
ieee80211_link_unreserve_chanctx(link);
1856
ieee80211_link_chanctx_reservation_complete(link);
1857
}
1858
}
1859
1860
return err;
1861
}
1862
1863
void __ieee80211_link_release_channel(struct ieee80211_link_data *link,
1864
bool skip_idle_recalc)
1865
{
1866
struct ieee80211_sub_if_data *sdata = link->sdata;
1867
struct ieee80211_bss_conf *link_conf = link->conf;
1868
struct ieee80211_local *local = sdata->local;
1869
struct ieee80211_chanctx_conf *conf;
1870
struct ieee80211_chanctx *ctx;
1871
bool use_reserved_switch = false;
1872
1873
lockdep_assert_wiphy(local->hw.wiphy);
1874
1875
conf = rcu_dereference_protected(link_conf->chanctx_conf,
1876
lockdep_is_held(&local->hw.wiphy->mtx));
1877
if (!conf)
1878
return;
1879
1880
ctx = container_of(conf, struct ieee80211_chanctx, conf);
1881
1882
if (link->reserved_chanctx) {
1883
if (link->reserved_chanctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER &&
1884
ieee80211_chanctx_num_reserved(local, link->reserved_chanctx) > 1)
1885
use_reserved_switch = true;
1886
1887
ieee80211_link_unreserve_chanctx(link);
1888
}
1889
1890
ieee80211_assign_link_chanctx(link, NULL, false);
1891
if (ieee80211_chanctx_refcount(local, ctx) == 0)
1892
ieee80211_free_chanctx(local, ctx, skip_idle_recalc);
1893
1894
link->radar_required = false;
1895
1896
/* Unreserving may ready an in-place reservation. */
1897
if (use_reserved_switch)
1898
ieee80211_vif_use_reserved_switch(local);
1899
}
1900
1901
int _ieee80211_link_use_channel(struct ieee80211_link_data *link,
1902
const struct ieee80211_chan_req *chanreq,
1903
enum ieee80211_chanctx_mode mode,
1904
bool assign_on_failure)
1905
{
1906
struct ieee80211_sub_if_data *sdata = link->sdata;
1907
struct ieee80211_local *local = sdata->local;
1908
struct ieee80211_chanctx *ctx;
1909
u8 radar_detect_width = 0;
1910
bool reserved = false;
1911
int radio_idx;
1912
int ret;
1913
1914
lockdep_assert_wiphy(local->hw.wiphy);
1915
1916
if (!ieee80211_vif_link_active(&sdata->vif, link->link_id)) {
1917
ieee80211_link_update_chanreq(link, chanreq);
1918
return 0;
1919
}
1920
1921
ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
1922
&chanreq->oper,
1923
sdata->wdev.iftype);
1924
if (ret < 0)
1925
goto out;
1926
if (ret > 0)
1927
radar_detect_width = BIT(chanreq->oper.width);
1928
1929
link->radar_required = ret;
1930
1931
ret = ieee80211_check_combinations(sdata, &chanreq->oper, mode,
1932
radar_detect_width, -1);
1933
if (ret < 0)
1934
goto out;
1935
1936
if (!local->in_reconfig)
1937
__ieee80211_link_release_channel(link, false);
1938
1939
ctx = ieee80211_find_chanctx(local, link, chanreq, mode);
1940
/* Note: context is now reserved */
1941
if (ctx)
1942
reserved = true;
1943
else if (!ieee80211_find_available_radio(local, chanreq,
1944
sdata->wdev.radio_mask,
1945
&radio_idx))
1946
ctx = ERR_PTR(-EBUSY);
1947
else
1948
ctx = ieee80211_new_chanctx(local, chanreq, mode,
1949
assign_on_failure, radio_idx);
1950
if (IS_ERR(ctx)) {
1951
ret = PTR_ERR(ctx);
1952
goto out;
1953
}
1954
1955
ieee80211_link_update_chanreq(link, chanreq);
1956
1957
ret = ieee80211_assign_link_chanctx(link, ctx, assign_on_failure);
1958
1959
if (reserved) {
1960
/* remove reservation */
1961
WARN_ON(link->reserved_chanctx != ctx);
1962
link->reserved_chanctx = NULL;
1963
list_del(&link->reserved_chanctx_list);
1964
}
1965
1966
if (ret) {
1967
/* if assign fails refcount stays the same */
1968
if (ieee80211_chanctx_refcount(local, ctx) == 0)
1969
ieee80211_free_chanctx(local, ctx, false);
1970
goto out;
1971
}
1972
1973
ieee80211_recalc_smps_chanctx(local, ctx);
1974
ieee80211_recalc_radar_chanctx(local, ctx);
1975
out:
1976
if (ret)
1977
link->radar_required = false;
1978
1979
return ret;
1980
}
1981
1982
int ieee80211_link_use_reserved_context(struct ieee80211_link_data *link)
1983
{
1984
struct ieee80211_sub_if_data *sdata = link->sdata;
1985
struct ieee80211_local *local = sdata->local;
1986
struct ieee80211_chanctx *new_ctx;
1987
struct ieee80211_chanctx *old_ctx;
1988
int err;
1989
1990
lockdep_assert_wiphy(local->hw.wiphy);
1991
1992
new_ctx = link->reserved_chanctx;
1993
old_ctx = ieee80211_link_get_chanctx(link);
1994
1995
if (WARN_ON(!new_ctx))
1996
return -EINVAL;
1997
1998
if (WARN_ON(new_ctx->replace_state ==
1999
IEEE80211_CHANCTX_WILL_BE_REPLACED))
2000
return -EINVAL;
2001
2002
if (WARN_ON(link->reserved_ready))
2003
return -EINVAL;
2004
2005
link->reserved_ready = true;
2006
2007
if (new_ctx->replace_state == IEEE80211_CHANCTX_REPLACE_NONE) {
2008
if (old_ctx)
2009
return ieee80211_link_use_reserved_reassign(link);
2010
2011
return ieee80211_link_use_reserved_assign(link);
2012
}
2013
2014
/*
2015
* In-place reservation may need to be finalized now either if:
2016
* a) sdata is taking part in the swapping itself and is the last one
2017
* b) sdata has switched with a re-assign reservation to an existing
2018
* context readying in-place switching of old_ctx
2019
*
2020
* In case of (b) do not propagate the error up because the requested
2021
* sdata already switched successfully. Just spill an extra warning.
2022
* The ieee80211_vif_use_reserved_switch() already stops all necessary
2023
* interfaces upon failure.
2024
*/
2025
if ((old_ctx &&
2026
old_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
2027
new_ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) {
2028
err = ieee80211_vif_use_reserved_switch(local);
2029
if (err && err != -EAGAIN) {
2030
if (new_ctx->replace_state ==
2031
IEEE80211_CHANCTX_REPLACES_OTHER)
2032
return err;
2033
2034
wiphy_info(local->hw.wiphy,
2035
"depending in-place reservation failed (err=%d)\n",
2036
err);
2037
}
2038
}
2039
2040
return 0;
2041
}
2042
2043
/*
2044
* This is similar to ieee80211_chanctx_compatible(), but rechecks
2045
* against all the links actually using it (except the one that's
2046
* passed, since that one is changing).
2047
* This is done in order to allow changes to the AP's bandwidth for
2048
* wider bandwidth OFDMA purposes, which wouldn't be treated as
2049
* compatible by ieee80211_chanctx_recheck() but is OK if the link
2050
* requesting the update is the only one using it.
2051
*/
2052
static const struct ieee80211_chan_req *
2053
ieee80211_chanctx_recheck(struct ieee80211_local *local,
2054
struct ieee80211_link_data *skip_link,
2055
struct ieee80211_chanctx *ctx,
2056
const struct ieee80211_chan_req *req,
2057
struct ieee80211_chan_req *tmp)
2058
{
2059
const struct ieee80211_chan_req *ret = req;
2060
struct ieee80211_link_data *link;
2061
2062
lockdep_assert_wiphy(local->hw.wiphy);
2063
2064
for_each_sdata_link(local, link) {
2065
if (link == skip_link)
2066
continue;
2067
2068
if (rcu_access_pointer(link->conf->chanctx_conf) == &ctx->conf) {
2069
ret = ieee80211_chanreq_compatible(ret,
2070
&link->conf->chanreq,
2071
tmp);
2072
if (!ret)
2073
return NULL;
2074
}
2075
2076
if (link->reserved_chanctx == ctx) {
2077
ret = ieee80211_chanreq_compatible(ret,
2078
&link->reserved,
2079
tmp);
2080
if (!ret)
2081
return NULL;
2082
}
2083
}
2084
2085
*tmp = *ret;
2086
return tmp;
2087
}
2088
2089
int ieee80211_link_change_chanreq(struct ieee80211_link_data *link,
2090
const struct ieee80211_chan_req *chanreq,
2091
u64 *changed)
2092
{
2093
struct ieee80211_sub_if_data *sdata = link->sdata;
2094
struct ieee80211_bss_conf *link_conf = link->conf;
2095
struct ieee80211_local *local = sdata->local;
2096
struct ieee80211_chanctx_conf *conf;
2097
struct ieee80211_chanctx *ctx;
2098
const struct ieee80211_chan_req *compat;
2099
struct ieee80211_chan_req tmp;
2100
2101
lockdep_assert_wiphy(local->hw.wiphy);
2102
2103
if (!cfg80211_chandef_usable(sdata->local->hw.wiphy,
2104
&chanreq->oper,
2105
IEEE80211_CHAN_DISABLED))
2106
return -EINVAL;
2107
2108
/* for non-HT 20 MHz the rest doesn't matter */
2109
if (chanreq->oper.width == NL80211_CHAN_WIDTH_20_NOHT &&
2110
cfg80211_chandef_identical(&chanreq->oper, &link_conf->chanreq.oper))
2111
return 0;
2112
2113
/* but you cannot switch to/from it */
2114
if (chanreq->oper.width == NL80211_CHAN_WIDTH_20_NOHT ||
2115
link_conf->chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT)
2116
return -EINVAL;
2117
2118
conf = rcu_dereference_protected(link_conf->chanctx_conf,
2119
lockdep_is_held(&local->hw.wiphy->mtx));
2120
if (!conf)
2121
return -EINVAL;
2122
2123
ctx = container_of(conf, struct ieee80211_chanctx, conf);
2124
2125
compat = ieee80211_chanctx_recheck(local, link, ctx, chanreq, &tmp);
2126
if (!compat)
2127
return -EINVAL;
2128
2129
switch (ctx->replace_state) {
2130
case IEEE80211_CHANCTX_REPLACE_NONE:
2131
if (!ieee80211_chanctx_reserved_chanreq(local, ctx, compat,
2132
&tmp))
2133
return -EBUSY;
2134
break;
2135
case IEEE80211_CHANCTX_WILL_BE_REPLACED:
2136
/* TODO: Perhaps the bandwidth change could be treated as a
2137
* reservation itself? */
2138
return -EBUSY;
2139
case IEEE80211_CHANCTX_REPLACES_OTHER:
2140
/* channel context that is going to replace another channel
2141
* context doesn't really exist and shouldn't be assigned
2142
* anywhere yet */
2143
WARN_ON(1);
2144
break;
2145
}
2146
2147
ieee80211_link_update_chanreq(link, chanreq);
2148
2149
ieee80211_recalc_chanctx_chantype(local, ctx);
2150
2151
*changed |= BSS_CHANGED_BANDWIDTH;
2152
return 0;
2153
}
2154
2155
void ieee80211_link_release_channel(struct ieee80211_link_data *link)
2156
{
2157
struct ieee80211_sub_if_data *sdata = link->sdata;
2158
2159
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
2160
return;
2161
2162
lockdep_assert_wiphy(sdata->local->hw.wiphy);
2163
2164
if (rcu_access_pointer(link->conf->chanctx_conf))
2165
__ieee80211_link_release_channel(link, false);
2166
}
2167
2168
void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link)
2169
{
2170
struct ieee80211_sub_if_data *sdata = link->sdata;
2171
unsigned int link_id = link->link_id;
2172
struct ieee80211_bss_conf *link_conf = link->conf;
2173
struct ieee80211_bss_conf *ap_conf;
2174
struct ieee80211_local *local = sdata->local;
2175
struct ieee80211_sub_if_data *ap;
2176
struct ieee80211_chanctx_conf *conf;
2177
2178
lockdep_assert_wiphy(local->hw.wiphy);
2179
2180
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->bss))
2181
return;
2182
2183
ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
2184
2185
ap_conf = wiphy_dereference(local->hw.wiphy,
2186
ap->vif.link_conf[link_id]);
2187
conf = wiphy_dereference(local->hw.wiphy,
2188
ap_conf->chanctx_conf);
2189
rcu_assign_pointer(link_conf->chanctx_conf, conf);
2190
}
2191
2192
void ieee80211_iter_chan_contexts_atomic(
2193
struct ieee80211_hw *hw,
2194
void (*iter)(struct ieee80211_hw *hw,
2195
struct ieee80211_chanctx_conf *chanctx_conf,
2196
void *data),
2197
void *iter_data)
2198
{
2199
struct ieee80211_local *local = hw_to_local(hw);
2200
struct ieee80211_chanctx *ctx;
2201
2202
rcu_read_lock();
2203
list_for_each_entry_rcu(ctx, &local->chanctx_list, list)
2204
if (ctx->driver_present)
2205
iter(hw, &ctx->conf, iter_data);
2206
rcu_read_unlock();
2207
}
2208
EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic);
2209
2210
void ieee80211_iter_chan_contexts_mtx(
2211
struct ieee80211_hw *hw,
2212
void (*iter)(struct ieee80211_hw *hw,
2213
struct ieee80211_chanctx_conf *chanctx_conf,
2214
void *data),
2215
void *iter_data)
2216
{
2217
struct ieee80211_local *local = hw_to_local(hw);
2218
struct ieee80211_chanctx *ctx;
2219
2220
lockdep_assert_wiphy(hw->wiphy);
2221
2222
list_for_each_entry(ctx, &local->chanctx_list, list)
2223
if (ctx->driver_present)
2224
iter(hw, &ctx->conf, iter_data);
2225
}
2226
EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_mtx);
2227
2228