Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/mac80211/chan.c
29265 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
chan = link->conf->chanreq.oper.chan;
663
radio_idx = cfg80211_get_radio_idx_by_chan(wiphy, chan);
664
665
if (ieee80211_is_radio_idx_in_scan_req(wiphy, req,
666
radio_idx))
667
return true;
668
}
669
}
670
671
return false;
672
}
673
674
static bool
675
ieee80211_chanctx_radar_required(struct ieee80211_local *local,
676
struct ieee80211_chanctx *ctx)
677
{
678
struct ieee80211_chanctx_conf *conf = &ctx->conf;
679
struct ieee80211_link_data *link;
680
681
lockdep_assert_wiphy(local->hw.wiphy);
682
683
for_each_sdata_link(local, link) {
684
if (rcu_access_pointer(link->conf->chanctx_conf) != conf)
685
continue;
686
if (!link->radar_required)
687
continue;
688
return true;
689
}
690
691
return false;
692
}
693
694
static struct ieee80211_chanctx *
695
ieee80211_alloc_chanctx(struct ieee80211_local *local,
696
const struct ieee80211_chan_req *chanreq,
697
enum ieee80211_chanctx_mode mode,
698
int radio_idx)
699
{
700
struct ieee80211_chanctx *ctx;
701
702
lockdep_assert_wiphy(local->hw.wiphy);
703
704
ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
705
if (!ctx)
706
return NULL;
707
708
INIT_LIST_HEAD(&ctx->assigned_links);
709
INIT_LIST_HEAD(&ctx->reserved_links);
710
ctx->conf.def = chanreq->oper;
711
ctx->conf.ap = chanreq->ap;
712
ctx->conf.rx_chains_static = 1;
713
ctx->conf.rx_chains_dynamic = 1;
714
ctx->mode = mode;
715
ctx->conf.radar_enabled = false;
716
ctx->conf.radio_idx = radio_idx;
717
ctx->radar_detected = false;
718
_ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
719
720
return ctx;
721
}
722
723
static int ieee80211_add_chanctx(struct ieee80211_local *local,
724
struct ieee80211_chanctx *ctx)
725
{
726
u32 changed;
727
int err;
728
729
lockdep_assert_wiphy(local->hw.wiphy);
730
731
ieee80211_add_wbrf(local, &ctx->conf.def);
732
733
/* turn idle off *before* setting channel -- some drivers need that */
734
changed = ieee80211_idle_off(local);
735
if (changed)
736
ieee80211_hw_config(local, -1, changed);
737
738
err = drv_add_chanctx(local, ctx);
739
if (err) {
740
ieee80211_recalc_idle(local);
741
return err;
742
}
743
744
return 0;
745
}
746
747
static struct ieee80211_chanctx *
748
ieee80211_new_chanctx(struct ieee80211_local *local,
749
const struct ieee80211_chan_req *chanreq,
750
enum ieee80211_chanctx_mode mode,
751
bool assign_on_failure,
752
int radio_idx)
753
{
754
struct ieee80211_chanctx *ctx;
755
int err;
756
757
lockdep_assert_wiphy(local->hw.wiphy);
758
759
ctx = ieee80211_alloc_chanctx(local, chanreq, mode, radio_idx);
760
if (!ctx)
761
return ERR_PTR(-ENOMEM);
762
763
err = ieee80211_add_chanctx(local, ctx);
764
if (!assign_on_failure && err) {
765
kfree(ctx);
766
return ERR_PTR(err);
767
}
768
/* We ignored a driver error, see _ieee80211_set_active_links */
769
WARN_ON_ONCE(err && !local->in_reconfig);
770
771
list_add_rcu(&ctx->list, &local->chanctx_list);
772
return ctx;
773
}
774
775
static void ieee80211_del_chanctx(struct ieee80211_local *local,
776
struct ieee80211_chanctx *ctx,
777
bool skip_idle_recalc)
778
{
779
lockdep_assert_wiphy(local->hw.wiphy);
780
781
drv_remove_chanctx(local, ctx);
782
783
if (!skip_idle_recalc)
784
ieee80211_recalc_idle(local);
785
786
ieee80211_remove_wbrf(local, &ctx->conf.def);
787
}
788
789
static void ieee80211_free_chanctx(struct ieee80211_local *local,
790
struct ieee80211_chanctx *ctx,
791
bool skip_idle_recalc)
792
{
793
lockdep_assert_wiphy(local->hw.wiphy);
794
795
WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
796
797
list_del_rcu(&ctx->list);
798
ieee80211_del_chanctx(local, ctx, skip_idle_recalc);
799
kfree_rcu(ctx, rcu_head);
800
}
801
802
void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
803
struct ieee80211_chanctx *ctx)
804
{
805
struct ieee80211_chanctx_conf *conf = &ctx->conf;
806
const struct ieee80211_chan_req *compat = NULL;
807
struct ieee80211_link_data *link;
808
struct ieee80211_chan_req tmp;
809
struct sta_info *sta;
810
811
lockdep_assert_wiphy(local->hw.wiphy);
812
813
for_each_sdata_link(local, link) {
814
struct ieee80211_bss_conf *link_conf;
815
816
if (link->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
817
continue;
818
819
link_conf = link->conf;
820
821
if (rcu_access_pointer(link_conf->chanctx_conf) != conf)
822
continue;
823
824
if (!compat)
825
compat = &link_conf->chanreq;
826
827
compat = ieee80211_chanreq_compatible(&link_conf->chanreq,
828
compat, &tmp);
829
if (WARN_ON_ONCE(!compat))
830
return;
831
}
832
833
if (WARN_ON_ONCE(!compat))
834
return;
835
836
/* TDLS peers can sometimes affect the chandef width */
837
list_for_each_entry(sta, &local->sta_list, list) {
838
struct ieee80211_sub_if_data *sdata = sta->sdata;
839
struct ieee80211_chan_req tdls_chanreq = {};
840
int tdls_link_id;
841
842
if (!sta->uploaded ||
843
!test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW) ||
844
!test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
845
!sta->tdls_chandef.chan)
846
continue;
847
848
tdls_link_id = ieee80211_tdls_sta_link_id(sta);
849
link = sdata_dereference(sdata->link[tdls_link_id], sdata);
850
if (!link)
851
continue;
852
853
if (rcu_access_pointer(link->conf->chanctx_conf) != conf)
854
continue;
855
856
tdls_chanreq.oper = sta->tdls_chandef;
857
858
/* note this always fills and returns &tmp if compat */
859
compat = ieee80211_chanreq_compatible(&tdls_chanreq,
860
compat, &tmp);
861
if (WARN_ON_ONCE(!compat))
862
return;
863
}
864
865
ieee80211_change_chanctx(local, ctx, ctx, compat);
866
}
867
868
static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
869
struct ieee80211_chanctx *chanctx)
870
{
871
bool radar_enabled;
872
873
lockdep_assert_wiphy(local->hw.wiphy);
874
875
radar_enabled = ieee80211_chanctx_radar_required(local, chanctx);
876
877
if (radar_enabled == chanctx->conf.radar_enabled)
878
return;
879
880
chanctx->conf.radar_enabled = radar_enabled;
881
882
drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
883
}
884
885
static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
886
struct ieee80211_chanctx *new_ctx,
887
bool assign_on_failure)
888
{
889
struct ieee80211_sub_if_data *sdata = link->sdata;
890
struct ieee80211_local *local = sdata->local;
891
struct ieee80211_chanctx_conf *conf;
892
struct ieee80211_chanctx *curr_ctx = NULL;
893
bool new_idle;
894
int ret;
895
896
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN))
897
return -EOPNOTSUPP;
898
899
conf = rcu_dereference_protected(link->conf->chanctx_conf,
900
lockdep_is_held(&local->hw.wiphy->mtx));
901
902
if (conf && !local->in_reconfig) {
903
curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
904
905
drv_unassign_vif_chanctx(local, sdata, link->conf, curr_ctx);
906
conf = NULL;
907
list_del(&link->assigned_chanctx_list);
908
}
909
910
if (new_ctx) {
911
/* recalc considering the link we'll use it for now */
912
ieee80211_recalc_chanctx_min_def(local, new_ctx, link, false);
913
914
ret = drv_assign_vif_chanctx(local, sdata, link->conf, new_ctx);
915
if (assign_on_failure || !ret) {
916
/* Need to continue, see _ieee80211_set_active_links */
917
WARN_ON_ONCE(ret && !local->in_reconfig);
918
ret = 0;
919
920
/* succeeded, so commit it to the data structures */
921
conf = &new_ctx->conf;
922
if (!local->in_reconfig)
923
list_add(&link->assigned_chanctx_list,
924
&new_ctx->assigned_links);
925
}
926
} else {
927
ret = 0;
928
}
929
930
rcu_assign_pointer(link->conf->chanctx_conf, conf);
931
932
if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
933
ieee80211_recalc_chanctx_chantype(local, curr_ctx);
934
ieee80211_recalc_smps_chanctx(local, curr_ctx);
935
ieee80211_recalc_radar_chanctx(local, curr_ctx);
936
ieee80211_recalc_chanctx_min_def(local, curr_ctx, NULL, false);
937
}
938
939
if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
940
ieee80211_recalc_txpower(link, false);
941
ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL, false);
942
}
943
944
if (conf) {
945
new_idle = false;
946
} else {
947
struct ieee80211_link_data *tmp;
948
949
new_idle = true;
950
for_each_sdata_link(local, tmp) {
951
if (rcu_access_pointer(tmp->conf->chanctx_conf)) {
952
new_idle = false;
953
break;
954
}
955
}
956
}
957
958
if (new_idle != sdata->vif.cfg.idle) {
959
sdata->vif.cfg.idle = new_idle;
960
961
if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
962
sdata->vif.type != NL80211_IFTYPE_MONITOR)
963
ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_IDLE);
964
}
965
966
ieee80211_check_fast_xmit_iface(sdata);
967
968
return ret;
969
}
970
971
void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
972
struct ieee80211_chanctx *chanctx)
973
{
974
struct ieee80211_sub_if_data *sdata;
975
u8 rx_chains_static, rx_chains_dynamic;
976
struct ieee80211_link_data *link;
977
978
lockdep_assert_wiphy(local->hw.wiphy);
979
980
rx_chains_static = 1;
981
rx_chains_dynamic = 1;
982
983
for_each_sdata_link(local, link) {
984
u8 needed_static, needed_dynamic;
985
986
switch (link->sdata->vif.type) {
987
case NL80211_IFTYPE_STATION:
988
if (!link->sdata->u.mgd.associated)
989
continue;
990
break;
991
case NL80211_IFTYPE_MONITOR:
992
if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
993
continue;
994
break;
995
case NL80211_IFTYPE_AP:
996
case NL80211_IFTYPE_ADHOC:
997
case NL80211_IFTYPE_MESH_POINT:
998
case NL80211_IFTYPE_OCB:
999
break;
1000
default:
1001
continue;
1002
}
1003
1004
if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf)
1005
continue;
1006
1007
if (link->sdata->vif.type == NL80211_IFTYPE_MONITOR) {
1008
rx_chains_dynamic = rx_chains_static = local->rx_chains;
1009
break;
1010
}
1011
1012
switch (link->smps_mode) {
1013
default:
1014
WARN_ONCE(1, "Invalid SMPS mode %d\n",
1015
link->smps_mode);
1016
fallthrough;
1017
case IEEE80211_SMPS_OFF:
1018
needed_static = link->needed_rx_chains;
1019
needed_dynamic = link->needed_rx_chains;
1020
break;
1021
case IEEE80211_SMPS_DYNAMIC:
1022
needed_static = 1;
1023
needed_dynamic = link->needed_rx_chains;
1024
break;
1025
case IEEE80211_SMPS_STATIC:
1026
needed_static = 1;
1027
needed_dynamic = 1;
1028
break;
1029
}
1030
1031
rx_chains_static = max(rx_chains_static, needed_static);
1032
rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
1033
}
1034
1035
/* Disable SMPS for the monitor interface */
1036
sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata);
1037
if (sdata &&
1038
rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &chanctx->conf)
1039
rx_chains_dynamic = rx_chains_static = local->rx_chains;
1040
1041
if (rx_chains_static == chanctx->conf.rx_chains_static &&
1042
rx_chains_dynamic == chanctx->conf.rx_chains_dynamic)
1043
return;
1044
1045
chanctx->conf.rx_chains_static = rx_chains_static;
1046
chanctx->conf.rx_chains_dynamic = rx_chains_dynamic;
1047
drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
1048
}
1049
1050
static void
1051
__ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
1052
bool clear)
1053
{
1054
struct ieee80211_sub_if_data *sdata = link->sdata;
1055
unsigned int link_id = link->link_id;
1056
struct ieee80211_bss_conf *link_conf = link->conf;
1057
struct ieee80211_local *local __maybe_unused = sdata->local;
1058
struct ieee80211_sub_if_data *vlan;
1059
struct ieee80211_chanctx_conf *conf;
1060
1061
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
1062
return;
1063
1064
lockdep_assert_wiphy(local->hw.wiphy);
1065
1066
/* Check that conf exists, even when clearing this function
1067
* must be called with the AP's channel context still there
1068
* as it would otherwise cause VLANs to have an invalid
1069
* channel context pointer for a while, possibly pointing
1070
* to a channel context that has already been freed.
1071
*/
1072
conf = rcu_dereference_protected(link_conf->chanctx_conf,
1073
lockdep_is_held(&local->hw.wiphy->mtx));
1074
WARN_ON(!conf);
1075
1076
if (clear)
1077
conf = NULL;
1078
1079
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
1080
struct ieee80211_bss_conf *vlan_conf;
1081
1082
vlan_conf = wiphy_dereference(local->hw.wiphy,
1083
vlan->vif.link_conf[link_id]);
1084
if (WARN_ON(!vlan_conf))
1085
continue;
1086
1087
rcu_assign_pointer(vlan_conf->chanctx_conf, conf);
1088
}
1089
}
1090
1091
void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
1092
bool clear)
1093
{
1094
struct ieee80211_local *local = link->sdata->local;
1095
1096
lockdep_assert_wiphy(local->hw.wiphy);
1097
1098
__ieee80211_link_copy_chanctx_to_vlans(link, clear);
1099
}
1100
1101
void ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link)
1102
{
1103
struct ieee80211_sub_if_data *sdata = link->sdata;
1104
struct ieee80211_chanctx *ctx = link->reserved_chanctx;
1105
1106
lockdep_assert_wiphy(sdata->local->hw.wiphy);
1107
1108
if (WARN_ON(!ctx))
1109
return;
1110
1111
list_del(&link->reserved_chanctx_list);
1112
link->reserved_chanctx = NULL;
1113
1114
if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) {
1115
if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) {
1116
if (WARN_ON(!ctx->replace_ctx))
1117
return;
1118
1119
WARN_ON(ctx->replace_ctx->replace_state !=
1120
IEEE80211_CHANCTX_WILL_BE_REPLACED);
1121
WARN_ON(ctx->replace_ctx->replace_ctx != ctx);
1122
1123
ctx->replace_ctx->replace_ctx = NULL;
1124
ctx->replace_ctx->replace_state =
1125
IEEE80211_CHANCTX_REPLACE_NONE;
1126
1127
list_del_rcu(&ctx->list);
1128
kfree_rcu(ctx, rcu_head);
1129
} else {
1130
ieee80211_free_chanctx(sdata->local, ctx, false);
1131
}
1132
}
1133
}
1134
1135
static struct ieee80211_chanctx *
1136
ieee80211_replace_chanctx(struct ieee80211_local *local,
1137
const struct ieee80211_chan_req *chanreq,
1138
enum ieee80211_chanctx_mode mode,
1139
struct ieee80211_chanctx *curr_ctx)
1140
{
1141
struct ieee80211_chanctx *new_ctx, *ctx;
1142
struct wiphy *wiphy = local->hw.wiphy;
1143
const struct wiphy_radio *radio;
1144
1145
if (!curr_ctx || (curr_ctx->replace_state ==
1146
IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
1147
!list_empty(&curr_ctx->reserved_links)) {
1148
/*
1149
* Another link already requested this context for a
1150
* reservation. Find another one hoping all links assigned
1151
* to it will also switch soon enough.
1152
*
1153
* TODO: This needs a little more work as some cases
1154
* (more than 2 chanctx capable devices) may fail which could
1155
* otherwise succeed provided some channel context juggling was
1156
* performed.
1157
*
1158
* Consider ctx1..3, link1..6, each ctx has 2 links. link1 and
1159
* link2 from ctx1 request new different chandefs starting 2
1160
* in-place reservations with ctx4 and ctx5 replacing ctx1 and
1161
* ctx2 respectively. Next link5 and link6 from ctx3 reserve
1162
* ctx4. If link3 and link4 remain on ctx2 as they are then this
1163
* fails unless `replace_ctx` from ctx5 is replaced with ctx3.
1164
*/
1165
list_for_each_entry(ctx, &local->chanctx_list, list) {
1166
if (ctx->replace_state !=
1167
IEEE80211_CHANCTX_REPLACE_NONE)
1168
continue;
1169
1170
if (!list_empty(&ctx->reserved_links))
1171
continue;
1172
1173
if (ctx->conf.radio_idx >= 0) {
1174
radio = &wiphy->radio[ctx->conf.radio_idx];
1175
if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
1176
continue;
1177
}
1178
1179
curr_ctx = ctx;
1180
break;
1181
}
1182
}
1183
1184
/*
1185
* If that's true then all available contexts already have reservations
1186
* and cannot be used.
1187
*/
1188
if (!curr_ctx || (curr_ctx->replace_state ==
1189
IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
1190
!list_empty(&curr_ctx->reserved_links))
1191
return ERR_PTR(-EBUSY);
1192
1193
new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
1194
if (!new_ctx)
1195
return ERR_PTR(-ENOMEM);
1196
1197
new_ctx->replace_ctx = curr_ctx;
1198
new_ctx->replace_state = IEEE80211_CHANCTX_REPLACES_OTHER;
1199
1200
curr_ctx->replace_ctx = new_ctx;
1201
curr_ctx->replace_state = IEEE80211_CHANCTX_WILL_BE_REPLACED;
1202
1203
list_add_rcu(&new_ctx->list, &local->chanctx_list);
1204
1205
return new_ctx;
1206
}
1207
1208
static bool
1209
ieee80211_find_available_radio(struct ieee80211_local *local,
1210
const struct ieee80211_chan_req *chanreq,
1211
u32 radio_mask, int *radio_idx)
1212
{
1213
struct wiphy *wiphy = local->hw.wiphy;
1214
const struct wiphy_radio *radio;
1215
int i;
1216
1217
*radio_idx = -1;
1218
if (!wiphy->n_radio)
1219
return true;
1220
1221
for (i = 0; i < wiphy->n_radio; i++) {
1222
if (!(radio_mask & BIT(i)))
1223
continue;
1224
1225
radio = &wiphy->radio[i];
1226
if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
1227
continue;
1228
1229
if (!ieee80211_can_create_new_chanctx(local, i))
1230
continue;
1231
1232
*radio_idx = i;
1233
return true;
1234
}
1235
1236
return false;
1237
}
1238
1239
int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
1240
const struct ieee80211_chan_req *chanreq,
1241
enum ieee80211_chanctx_mode mode,
1242
bool radar_required)
1243
{
1244
struct ieee80211_sub_if_data *sdata = link->sdata;
1245
struct ieee80211_local *local = sdata->local;
1246
struct ieee80211_chanctx *new_ctx, *curr_ctx;
1247
int radio_idx;
1248
1249
lockdep_assert_wiphy(local->hw.wiphy);
1250
1251
curr_ctx = ieee80211_link_get_chanctx(link);
1252
if (curr_ctx && !local->ops->switch_vif_chanctx)
1253
return -EOPNOTSUPP;
1254
1255
new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
1256
if (!new_ctx) {
1257
if (ieee80211_can_create_new_chanctx(local, -1) &&
1258
ieee80211_find_available_radio(local, chanreq,
1259
sdata->wdev.radio_mask,
1260
&radio_idx))
1261
new_ctx = ieee80211_new_chanctx(local, chanreq, mode,
1262
false, radio_idx);
1263
else
1264
new_ctx = ieee80211_replace_chanctx(local, chanreq,
1265
mode, curr_ctx);
1266
if (IS_ERR(new_ctx))
1267
return PTR_ERR(new_ctx);
1268
}
1269
1270
list_add(&link->reserved_chanctx_list, &new_ctx->reserved_links);
1271
link->reserved_chanctx = new_ctx;
1272
link->reserved = *chanreq;
1273
link->reserved_radar_required = radar_required;
1274
link->reserved_ready = false;
1275
1276
return 0;
1277
}
1278
1279
static void
1280
ieee80211_link_chanctx_reservation_complete(struct ieee80211_link_data *link)
1281
{
1282
struct ieee80211_sub_if_data *sdata = link->sdata;
1283
1284
switch (sdata->vif.type) {
1285
case NL80211_IFTYPE_ADHOC:
1286
case NL80211_IFTYPE_AP:
1287
case NL80211_IFTYPE_MESH_POINT:
1288
case NL80211_IFTYPE_OCB:
1289
wiphy_work_queue(sdata->local->hw.wiphy,
1290
&link->csa.finalize_work);
1291
break;
1292
case NL80211_IFTYPE_STATION:
1293
wiphy_delayed_work_queue(sdata->local->hw.wiphy,
1294
&link->u.mgd.csa.switch_work, 0);
1295
break;
1296
case NL80211_IFTYPE_UNSPECIFIED:
1297
case NL80211_IFTYPE_AP_VLAN:
1298
case NL80211_IFTYPE_WDS:
1299
case NL80211_IFTYPE_MONITOR:
1300
case NL80211_IFTYPE_P2P_CLIENT:
1301
case NL80211_IFTYPE_P2P_GO:
1302
case NL80211_IFTYPE_P2P_DEVICE:
1303
case NL80211_IFTYPE_NAN:
1304
case NUM_NL80211_IFTYPES:
1305
WARN_ON(1);
1306
break;
1307
}
1308
}
1309
1310
static void
1311
ieee80211_link_update_chanreq(struct ieee80211_link_data *link,
1312
const struct ieee80211_chan_req *chanreq)
1313
{
1314
struct ieee80211_sub_if_data *sdata = link->sdata;
1315
unsigned int link_id = link->link_id;
1316
struct ieee80211_sub_if_data *vlan;
1317
1318
link->conf->chanreq = *chanreq;
1319
1320
if (sdata->vif.type != NL80211_IFTYPE_AP)
1321
return;
1322
1323
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
1324
struct ieee80211_bss_conf *vlan_conf;
1325
1326
vlan_conf = wiphy_dereference(sdata->local->hw.wiphy,
1327
vlan->vif.link_conf[link_id]);
1328
if (WARN_ON(!vlan_conf))
1329
continue;
1330
1331
vlan_conf->chanreq = *chanreq;
1332
}
1333
}
1334
1335
static int
1336
ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
1337
{
1338
struct ieee80211_sub_if_data *sdata = link->sdata;
1339
struct ieee80211_bss_conf *link_conf = link->conf;
1340
struct ieee80211_local *local = sdata->local;
1341
struct ieee80211_vif_chanctx_switch vif_chsw[1] = {};
1342
struct ieee80211_chanctx *old_ctx, *new_ctx;
1343
const struct ieee80211_chan_req *chanreq;
1344
struct ieee80211_chan_req tmp;
1345
u64 changed = 0;
1346
int err;
1347
1348
lockdep_assert_wiphy(local->hw.wiphy);
1349
1350
new_ctx = link->reserved_chanctx;
1351
old_ctx = ieee80211_link_get_chanctx(link);
1352
1353
if (WARN_ON(!link->reserved_ready))
1354
return -EBUSY;
1355
1356
if (WARN_ON(!new_ctx))
1357
return -EINVAL;
1358
1359
if (WARN_ON(!old_ctx))
1360
return -EINVAL;
1361
1362
if (WARN_ON(new_ctx->replace_state ==
1363
IEEE80211_CHANCTX_REPLACES_OTHER))
1364
return -EINVAL;
1365
1366
chanreq = ieee80211_chanctx_non_reserved_chandef(local, new_ctx,
1367
&link->reserved,
1368
&tmp);
1369
if (WARN_ON(!chanreq))
1370
return -EINVAL;
1371
1372
if (link_conf->chanreq.oper.width != link->reserved.oper.width)
1373
changed = BSS_CHANGED_BANDWIDTH;
1374
1375
ieee80211_link_update_chanreq(link, &link->reserved);
1376
1377
_ieee80211_change_chanctx(local, new_ctx, old_ctx, chanreq, link);
1378
1379
vif_chsw[0].vif = &sdata->vif;
1380
vif_chsw[0].old_ctx = &old_ctx->conf;
1381
vif_chsw[0].new_ctx = &new_ctx->conf;
1382
vif_chsw[0].link_conf = link->conf;
1383
1384
list_del(&link->reserved_chanctx_list);
1385
link->reserved_chanctx = NULL;
1386
1387
err = drv_switch_vif_chanctx(local, vif_chsw, 1,
1388
CHANCTX_SWMODE_REASSIGN_VIF);
1389
if (err) {
1390
if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
1391
ieee80211_free_chanctx(local, new_ctx, false);
1392
1393
goto out;
1394
}
1395
1396
link->radar_required = link->reserved_radar_required;
1397
list_move(&link->assigned_chanctx_list, &new_ctx->assigned_links);
1398
rcu_assign_pointer(link_conf->chanctx_conf, &new_ctx->conf);
1399
1400
if (sdata->vif.type == NL80211_IFTYPE_AP)
1401
__ieee80211_link_copy_chanctx_to_vlans(link, false);
1402
1403
ieee80211_check_fast_xmit_iface(sdata);
1404
1405
if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
1406
ieee80211_free_chanctx(local, old_ctx, false);
1407
1408
ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL, false);
1409
ieee80211_recalc_smps_chanctx(local, new_ctx);
1410
ieee80211_recalc_radar_chanctx(local, new_ctx);
1411
1412
if (changed)
1413
ieee80211_link_info_change_notify(sdata, link, changed);
1414
1415
out:
1416
ieee80211_link_chanctx_reservation_complete(link);
1417
return err;
1418
}
1419
1420
static int
1421
ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link)
1422
{
1423
struct ieee80211_sub_if_data *sdata = link->sdata;
1424
struct ieee80211_local *local = sdata->local;
1425
struct ieee80211_chanctx *old_ctx, *new_ctx;
1426
const struct ieee80211_chan_req *chanreq;
1427
struct ieee80211_chan_req tmp;
1428
int err;
1429
1430
old_ctx = ieee80211_link_get_chanctx(link);
1431
new_ctx = link->reserved_chanctx;
1432
1433
if (WARN_ON(!link->reserved_ready))
1434
return -EINVAL;
1435
1436
if (WARN_ON(old_ctx))
1437
return -EINVAL;
1438
1439
if (WARN_ON(!new_ctx))
1440
return -EINVAL;
1441
1442
if (WARN_ON(new_ctx->replace_state ==
1443
IEEE80211_CHANCTX_REPLACES_OTHER))
1444
return -EINVAL;
1445
1446
chanreq = ieee80211_chanctx_non_reserved_chandef(local, new_ctx,
1447
&link->reserved,
1448
&tmp);
1449
if (WARN_ON(!chanreq))
1450
return -EINVAL;
1451
1452
ieee80211_change_chanctx(local, new_ctx, new_ctx, chanreq);
1453
1454
list_del(&link->reserved_chanctx_list);
1455
link->reserved_chanctx = NULL;
1456
1457
err = ieee80211_assign_link_chanctx(link, new_ctx, false);
1458
if (err) {
1459
if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
1460
ieee80211_free_chanctx(local, new_ctx, false);
1461
1462
goto out;
1463
}
1464
1465
out:
1466
ieee80211_link_chanctx_reservation_complete(link);
1467
return err;
1468
}
1469
1470
static bool
1471
ieee80211_link_has_in_place_reservation(struct ieee80211_link_data *link)
1472
{
1473
struct ieee80211_sub_if_data *sdata = link->sdata;
1474
struct ieee80211_chanctx *old_ctx, *new_ctx;
1475
1476
lockdep_assert_wiphy(sdata->local->hw.wiphy);
1477
1478
new_ctx = link->reserved_chanctx;
1479
old_ctx = ieee80211_link_get_chanctx(link);
1480
1481
if (!old_ctx)
1482
return false;
1483
1484
if (WARN_ON(!new_ctx))
1485
return false;
1486
1487
if (old_ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED)
1488
return false;
1489
1490
if (new_ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1491
return false;
1492
1493
return true;
1494
}
1495
1496
static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local,
1497
int n_vifs)
1498
{
1499
struct ieee80211_vif_chanctx_switch *vif_chsw;
1500
struct ieee80211_link_data *link;
1501
struct ieee80211_chanctx *ctx, *old_ctx;
1502
int i, err;
1503
1504
lockdep_assert_wiphy(local->hw.wiphy);
1505
1506
vif_chsw = kcalloc(n_vifs, sizeof(vif_chsw[0]), GFP_KERNEL);
1507
if (!vif_chsw)
1508
return -ENOMEM;
1509
1510
i = 0;
1511
list_for_each_entry(ctx, &local->chanctx_list, list) {
1512
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1513
continue;
1514
1515
if (WARN_ON(!ctx->replace_ctx)) {
1516
err = -EINVAL;
1517
goto out;
1518
}
1519
1520
list_for_each_entry(link, &ctx->reserved_links,
1521
reserved_chanctx_list) {
1522
if (!ieee80211_link_has_in_place_reservation(link))
1523
continue;
1524
1525
old_ctx = ieee80211_link_get_chanctx(link);
1526
vif_chsw[i].vif = &link->sdata->vif;
1527
vif_chsw[i].old_ctx = &old_ctx->conf;
1528
vif_chsw[i].new_ctx = &ctx->conf;
1529
vif_chsw[i].link_conf = link->conf;
1530
1531
i++;
1532
}
1533
}
1534
1535
err = drv_switch_vif_chanctx(local, vif_chsw, n_vifs,
1536
CHANCTX_SWMODE_SWAP_CONTEXTS);
1537
1538
out:
1539
kfree(vif_chsw);
1540
return err;
1541
}
1542
1543
static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local)
1544
{
1545
struct ieee80211_chanctx *ctx;
1546
int err;
1547
1548
lockdep_assert_wiphy(local->hw.wiphy);
1549
1550
list_for_each_entry(ctx, &local->chanctx_list, list) {
1551
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1552
continue;
1553
1554
if (!list_empty(&ctx->replace_ctx->assigned_links))
1555
continue;
1556
1557
ieee80211_del_chanctx(local, ctx->replace_ctx, false);
1558
err = ieee80211_add_chanctx(local, ctx);
1559
if (err)
1560
goto err;
1561
}
1562
1563
return 0;
1564
1565
err:
1566
WARN_ON(ieee80211_add_chanctx(local, ctx));
1567
list_for_each_entry_continue_reverse(ctx, &local->chanctx_list, list) {
1568
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1569
continue;
1570
1571
if (!list_empty(&ctx->replace_ctx->assigned_links))
1572
continue;
1573
1574
ieee80211_del_chanctx(local, ctx, false);
1575
WARN_ON(ieee80211_add_chanctx(local, ctx->replace_ctx));
1576
}
1577
1578
return err;
1579
}
1580
1581
static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
1582
{
1583
struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx;
1584
int err, n_assigned, n_reserved, n_ready;
1585
int n_ctx = 0, n_vifs_switch = 0, n_vifs_assign = 0, n_vifs_ctxless = 0;
1586
1587
lockdep_assert_wiphy(local->hw.wiphy);
1588
1589
/*
1590
* If there are 2 independent pairs of channel contexts performing
1591
* cross-switch of their vifs this code will still wait until both are
1592
* ready even though it could be possible to switch one before the
1593
* other is ready.
1594
*
1595
* For practical reasons and code simplicity just do a single huge
1596
* switch.
1597
*/
1598
1599
/*
1600
* Verify if the reservation is still feasible.
1601
* - if it's not then disconnect
1602
* - if it is but not all vifs necessary are ready then defer
1603
*/
1604
1605
list_for_each_entry(ctx, &local->chanctx_list, list) {
1606
struct ieee80211_link_data *link;
1607
1608
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1609
continue;
1610
1611
if (WARN_ON(!ctx->replace_ctx)) {
1612
err = -EINVAL;
1613
goto err;
1614
}
1615
1616
n_ctx++;
1617
1618
n_assigned = 0;
1619
n_reserved = 0;
1620
n_ready = 0;
1621
1622
list_for_each_entry(link, &ctx->replace_ctx->assigned_links,
1623
assigned_chanctx_list) {
1624
n_assigned++;
1625
if (link->reserved_chanctx) {
1626
n_reserved++;
1627
if (link->reserved_ready)
1628
n_ready++;
1629
}
1630
}
1631
1632
if (n_assigned != n_reserved) {
1633
if (n_ready == n_reserved) {
1634
wiphy_info(local->hw.wiphy,
1635
"channel context reservation cannot be finalized because some interfaces aren't switching\n");
1636
err = -EBUSY;
1637
goto err;
1638
}
1639
1640
return -EAGAIN;
1641
}
1642
1643
ctx->conf.radar_enabled = false;
1644
list_for_each_entry(link, &ctx->reserved_links,
1645
reserved_chanctx_list) {
1646
if (ieee80211_link_has_in_place_reservation(link) &&
1647
!link->reserved_ready)
1648
return -EAGAIN;
1649
1650
old_ctx = ieee80211_link_get_chanctx(link);
1651
if (old_ctx) {
1652
if (old_ctx->replace_state ==
1653
IEEE80211_CHANCTX_WILL_BE_REPLACED)
1654
n_vifs_switch++;
1655
else
1656
n_vifs_assign++;
1657
} else {
1658
n_vifs_ctxless++;
1659
}
1660
1661
if (link->reserved_radar_required)
1662
ctx->conf.radar_enabled = true;
1663
}
1664
}
1665
1666
if (WARN_ON(n_ctx == 0) ||
1667
WARN_ON(n_vifs_switch == 0 &&
1668
n_vifs_assign == 0 &&
1669
n_vifs_ctxless == 0)) {
1670
err = -EINVAL;
1671
goto err;
1672
}
1673
1674
/* update station rate control and min width before switch */
1675
list_for_each_entry(ctx, &local->chanctx_list, list) {
1676
struct ieee80211_link_data *link;
1677
1678
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1679
continue;
1680
1681
if (WARN_ON(!ctx->replace_ctx)) {
1682
err = -EINVAL;
1683
goto err;
1684
}
1685
1686
list_for_each_entry(link, &ctx->reserved_links,
1687
reserved_chanctx_list) {
1688
if (!ieee80211_link_has_in_place_reservation(link))
1689
continue;
1690
1691
ieee80211_chan_bw_change(local,
1692
ieee80211_link_get_chanctx(link),
1693
true, true);
1694
}
1695
1696
ieee80211_recalc_chanctx_min_def(local, ctx, NULL, true);
1697
}
1698
1699
/*
1700
* All necessary vifs are ready. Perform the switch now depending on
1701
* reservations and driver capabilities.
1702
*/
1703
1704
if (n_vifs_switch > 0) {
1705
err = ieee80211_chsw_switch_vifs(local, n_vifs_switch);
1706
if (err)
1707
goto err;
1708
}
1709
1710
if (n_vifs_assign > 0 || n_vifs_ctxless > 0) {
1711
err = ieee80211_chsw_switch_ctxs(local);
1712
if (err)
1713
goto err;
1714
}
1715
1716
/*
1717
* Update all structures, values and pointers to point to new channel
1718
* context(s).
1719
*/
1720
list_for_each_entry(ctx, &local->chanctx_list, list) {
1721
struct ieee80211_link_data *link, *link_tmp;
1722
1723
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1724
continue;
1725
1726
if (WARN_ON(!ctx->replace_ctx)) {
1727
err = -EINVAL;
1728
goto err;
1729
}
1730
1731
list_for_each_entry(link, &ctx->reserved_links,
1732
reserved_chanctx_list) {
1733
struct ieee80211_sub_if_data *sdata = link->sdata;
1734
struct ieee80211_bss_conf *link_conf = link->conf;
1735
u64 changed = 0;
1736
1737
if (!ieee80211_link_has_in_place_reservation(link))
1738
continue;
1739
1740
rcu_assign_pointer(link_conf->chanctx_conf,
1741
&ctx->conf);
1742
1743
if (sdata->vif.type == NL80211_IFTYPE_AP)
1744
__ieee80211_link_copy_chanctx_to_vlans(link,
1745
false);
1746
1747
ieee80211_check_fast_xmit_iface(sdata);
1748
1749
link->radar_required = link->reserved_radar_required;
1750
1751
if (link_conf->chanreq.oper.width != link->reserved.oper.width)
1752
changed = BSS_CHANGED_BANDWIDTH;
1753
1754
ieee80211_link_update_chanreq(link, &link->reserved);
1755
if (changed)
1756
ieee80211_link_info_change_notify(sdata,
1757
link,
1758
changed);
1759
1760
ieee80211_recalc_txpower(link, false);
1761
}
1762
1763
ieee80211_recalc_chanctx_chantype(local, ctx);
1764
ieee80211_recalc_smps_chanctx(local, ctx);
1765
ieee80211_recalc_radar_chanctx(local, ctx);
1766
ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
1767
1768
list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
1769
reserved_chanctx_list) {
1770
if (ieee80211_link_get_chanctx(link) != ctx)
1771
continue;
1772
1773
list_del(&link->reserved_chanctx_list);
1774
list_move(&link->assigned_chanctx_list,
1775
&ctx->assigned_links);
1776
link->reserved_chanctx = NULL;
1777
1778
ieee80211_link_chanctx_reservation_complete(link);
1779
ieee80211_chan_bw_change(local, ctx, false, false);
1780
}
1781
1782
/*
1783
* This context might have been a dependency for an already
1784
* ready re-assign reservation interface that was deferred. Do
1785
* not propagate error to the caller though. The in-place
1786
* reservation for originally requested interface has already
1787
* succeeded at this point.
1788
*/
1789
list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
1790
reserved_chanctx_list) {
1791
if (WARN_ON(ieee80211_link_has_in_place_reservation(link)))
1792
continue;
1793
1794
if (WARN_ON(link->reserved_chanctx != ctx))
1795
continue;
1796
1797
if (!link->reserved_ready)
1798
continue;
1799
1800
if (ieee80211_link_get_chanctx(link))
1801
err = ieee80211_link_use_reserved_reassign(link);
1802
else
1803
err = ieee80211_link_use_reserved_assign(link);
1804
1805
if (err) {
1806
link_info(link,
1807
"failed to finalize (re-)assign reservation (err=%d)\n",
1808
err);
1809
ieee80211_link_unreserve_chanctx(link);
1810
cfg80211_stop_iface(local->hw.wiphy,
1811
&link->sdata->wdev,
1812
GFP_KERNEL);
1813
}
1814
}
1815
}
1816
1817
/*
1818
* Finally free old contexts
1819
*/
1820
1821
list_for_each_entry_safe(ctx, ctx_tmp, &local->chanctx_list, list) {
1822
if (ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED)
1823
continue;
1824
1825
ctx->replace_ctx->replace_ctx = NULL;
1826
ctx->replace_ctx->replace_state =
1827
IEEE80211_CHANCTX_REPLACE_NONE;
1828
1829
list_del_rcu(&ctx->list);
1830
kfree_rcu(ctx, rcu_head);
1831
}
1832
1833
return 0;
1834
1835
err:
1836
list_for_each_entry(ctx, &local->chanctx_list, list) {
1837
struct ieee80211_link_data *link, *link_tmp;
1838
1839
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1840
continue;
1841
1842
list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
1843
reserved_chanctx_list) {
1844
ieee80211_link_unreserve_chanctx(link);
1845
ieee80211_link_chanctx_reservation_complete(link);
1846
}
1847
}
1848
1849
return err;
1850
}
1851
1852
void __ieee80211_link_release_channel(struct ieee80211_link_data *link,
1853
bool skip_idle_recalc)
1854
{
1855
struct ieee80211_sub_if_data *sdata = link->sdata;
1856
struct ieee80211_bss_conf *link_conf = link->conf;
1857
struct ieee80211_local *local = sdata->local;
1858
struct ieee80211_chanctx_conf *conf;
1859
struct ieee80211_chanctx *ctx;
1860
bool use_reserved_switch = false;
1861
1862
lockdep_assert_wiphy(local->hw.wiphy);
1863
1864
conf = rcu_dereference_protected(link_conf->chanctx_conf,
1865
lockdep_is_held(&local->hw.wiphy->mtx));
1866
if (!conf)
1867
return;
1868
1869
ctx = container_of(conf, struct ieee80211_chanctx, conf);
1870
1871
if (link->reserved_chanctx) {
1872
if (link->reserved_chanctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER &&
1873
ieee80211_chanctx_num_reserved(local, link->reserved_chanctx) > 1)
1874
use_reserved_switch = true;
1875
1876
ieee80211_link_unreserve_chanctx(link);
1877
}
1878
1879
ieee80211_assign_link_chanctx(link, NULL, false);
1880
if (ieee80211_chanctx_refcount(local, ctx) == 0)
1881
ieee80211_free_chanctx(local, ctx, skip_idle_recalc);
1882
1883
link->radar_required = false;
1884
1885
/* Unreserving may ready an in-place reservation. */
1886
if (use_reserved_switch)
1887
ieee80211_vif_use_reserved_switch(local);
1888
}
1889
1890
int _ieee80211_link_use_channel(struct ieee80211_link_data *link,
1891
const struct ieee80211_chan_req *chanreq,
1892
enum ieee80211_chanctx_mode mode,
1893
bool assign_on_failure)
1894
{
1895
struct ieee80211_sub_if_data *sdata = link->sdata;
1896
struct ieee80211_local *local = sdata->local;
1897
struct ieee80211_chanctx *ctx;
1898
u8 radar_detect_width = 0;
1899
bool reserved = false;
1900
int radio_idx;
1901
int ret;
1902
1903
lockdep_assert_wiphy(local->hw.wiphy);
1904
1905
if (!ieee80211_vif_link_active(&sdata->vif, link->link_id)) {
1906
ieee80211_link_update_chanreq(link, chanreq);
1907
return 0;
1908
}
1909
1910
ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
1911
&chanreq->oper,
1912
sdata->wdev.iftype);
1913
if (ret < 0)
1914
goto out;
1915
if (ret > 0)
1916
radar_detect_width = BIT(chanreq->oper.width);
1917
1918
link->radar_required = ret;
1919
1920
ret = ieee80211_check_combinations(sdata, &chanreq->oper, mode,
1921
radar_detect_width, -1);
1922
if (ret < 0)
1923
goto out;
1924
1925
if (!local->in_reconfig)
1926
__ieee80211_link_release_channel(link, false);
1927
1928
ctx = ieee80211_find_chanctx(local, link, chanreq, mode);
1929
/* Note: context is now reserved */
1930
if (ctx)
1931
reserved = true;
1932
else if (!ieee80211_find_available_radio(local, chanreq,
1933
sdata->wdev.radio_mask,
1934
&radio_idx))
1935
ctx = ERR_PTR(-EBUSY);
1936
else
1937
ctx = ieee80211_new_chanctx(local, chanreq, mode,
1938
assign_on_failure, radio_idx);
1939
if (IS_ERR(ctx)) {
1940
ret = PTR_ERR(ctx);
1941
goto out;
1942
}
1943
1944
ieee80211_link_update_chanreq(link, chanreq);
1945
1946
ret = ieee80211_assign_link_chanctx(link, ctx, assign_on_failure);
1947
1948
if (reserved) {
1949
/* remove reservation */
1950
WARN_ON(link->reserved_chanctx != ctx);
1951
link->reserved_chanctx = NULL;
1952
list_del(&link->reserved_chanctx_list);
1953
}
1954
1955
if (ret) {
1956
/* if assign fails refcount stays the same */
1957
if (ieee80211_chanctx_refcount(local, ctx) == 0)
1958
ieee80211_free_chanctx(local, ctx, false);
1959
goto out;
1960
}
1961
1962
ieee80211_recalc_smps_chanctx(local, ctx);
1963
ieee80211_recalc_radar_chanctx(local, ctx);
1964
out:
1965
if (ret)
1966
link->radar_required = false;
1967
1968
return ret;
1969
}
1970
1971
int ieee80211_link_use_reserved_context(struct ieee80211_link_data *link)
1972
{
1973
struct ieee80211_sub_if_data *sdata = link->sdata;
1974
struct ieee80211_local *local = sdata->local;
1975
struct ieee80211_chanctx *new_ctx;
1976
struct ieee80211_chanctx *old_ctx;
1977
int err;
1978
1979
lockdep_assert_wiphy(local->hw.wiphy);
1980
1981
new_ctx = link->reserved_chanctx;
1982
old_ctx = ieee80211_link_get_chanctx(link);
1983
1984
if (WARN_ON(!new_ctx))
1985
return -EINVAL;
1986
1987
if (WARN_ON(new_ctx->replace_state ==
1988
IEEE80211_CHANCTX_WILL_BE_REPLACED))
1989
return -EINVAL;
1990
1991
if (WARN_ON(link->reserved_ready))
1992
return -EINVAL;
1993
1994
link->reserved_ready = true;
1995
1996
if (new_ctx->replace_state == IEEE80211_CHANCTX_REPLACE_NONE) {
1997
if (old_ctx)
1998
return ieee80211_link_use_reserved_reassign(link);
1999
2000
return ieee80211_link_use_reserved_assign(link);
2001
}
2002
2003
/*
2004
* In-place reservation may need to be finalized now either if:
2005
* a) sdata is taking part in the swapping itself and is the last one
2006
* b) sdata has switched with a re-assign reservation to an existing
2007
* context readying in-place switching of old_ctx
2008
*
2009
* In case of (b) do not propagate the error up because the requested
2010
* sdata already switched successfully. Just spill an extra warning.
2011
* The ieee80211_vif_use_reserved_switch() already stops all necessary
2012
* interfaces upon failure.
2013
*/
2014
if ((old_ctx &&
2015
old_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
2016
new_ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) {
2017
err = ieee80211_vif_use_reserved_switch(local);
2018
if (err && err != -EAGAIN) {
2019
if (new_ctx->replace_state ==
2020
IEEE80211_CHANCTX_REPLACES_OTHER)
2021
return err;
2022
2023
wiphy_info(local->hw.wiphy,
2024
"depending in-place reservation failed (err=%d)\n",
2025
err);
2026
}
2027
}
2028
2029
return 0;
2030
}
2031
2032
/*
2033
* This is similar to ieee80211_chanctx_compatible(), but rechecks
2034
* against all the links actually using it (except the one that's
2035
* passed, since that one is changing).
2036
* This is done in order to allow changes to the AP's bandwidth for
2037
* wider bandwidth OFDMA purposes, which wouldn't be treated as
2038
* compatible by ieee80211_chanctx_recheck() but is OK if the link
2039
* requesting the update is the only one using it.
2040
*/
2041
static const struct ieee80211_chan_req *
2042
ieee80211_chanctx_recheck(struct ieee80211_local *local,
2043
struct ieee80211_link_data *skip_link,
2044
struct ieee80211_chanctx *ctx,
2045
const struct ieee80211_chan_req *req,
2046
struct ieee80211_chan_req *tmp)
2047
{
2048
const struct ieee80211_chan_req *ret = req;
2049
struct ieee80211_link_data *link;
2050
2051
lockdep_assert_wiphy(local->hw.wiphy);
2052
2053
for_each_sdata_link(local, link) {
2054
if (link == skip_link)
2055
continue;
2056
2057
if (rcu_access_pointer(link->conf->chanctx_conf) == &ctx->conf) {
2058
ret = ieee80211_chanreq_compatible(ret,
2059
&link->conf->chanreq,
2060
tmp);
2061
if (!ret)
2062
return NULL;
2063
}
2064
2065
if (link->reserved_chanctx == ctx) {
2066
ret = ieee80211_chanreq_compatible(ret,
2067
&link->reserved,
2068
tmp);
2069
if (!ret)
2070
return NULL;
2071
}
2072
}
2073
2074
*tmp = *ret;
2075
return tmp;
2076
}
2077
2078
int ieee80211_link_change_chanreq(struct ieee80211_link_data *link,
2079
const struct ieee80211_chan_req *chanreq,
2080
u64 *changed)
2081
{
2082
struct ieee80211_sub_if_data *sdata = link->sdata;
2083
struct ieee80211_bss_conf *link_conf = link->conf;
2084
struct ieee80211_local *local = sdata->local;
2085
struct ieee80211_chanctx_conf *conf;
2086
struct ieee80211_chanctx *ctx;
2087
const struct ieee80211_chan_req *compat;
2088
struct ieee80211_chan_req tmp;
2089
2090
lockdep_assert_wiphy(local->hw.wiphy);
2091
2092
if (!cfg80211_chandef_usable(sdata->local->hw.wiphy,
2093
&chanreq->oper,
2094
IEEE80211_CHAN_DISABLED))
2095
return -EINVAL;
2096
2097
/* for non-HT 20 MHz the rest doesn't matter */
2098
if (chanreq->oper.width == NL80211_CHAN_WIDTH_20_NOHT &&
2099
cfg80211_chandef_identical(&chanreq->oper, &link_conf->chanreq.oper))
2100
return 0;
2101
2102
/* but you cannot switch to/from it */
2103
if (chanreq->oper.width == NL80211_CHAN_WIDTH_20_NOHT ||
2104
link_conf->chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT)
2105
return -EINVAL;
2106
2107
conf = rcu_dereference_protected(link_conf->chanctx_conf,
2108
lockdep_is_held(&local->hw.wiphy->mtx));
2109
if (!conf)
2110
return -EINVAL;
2111
2112
ctx = container_of(conf, struct ieee80211_chanctx, conf);
2113
2114
compat = ieee80211_chanctx_recheck(local, link, ctx, chanreq, &tmp);
2115
if (!compat)
2116
return -EINVAL;
2117
2118
switch (ctx->replace_state) {
2119
case IEEE80211_CHANCTX_REPLACE_NONE:
2120
if (!ieee80211_chanctx_reserved_chanreq(local, ctx, compat,
2121
&tmp))
2122
return -EBUSY;
2123
break;
2124
case IEEE80211_CHANCTX_WILL_BE_REPLACED:
2125
/* TODO: Perhaps the bandwidth change could be treated as a
2126
* reservation itself? */
2127
return -EBUSY;
2128
case IEEE80211_CHANCTX_REPLACES_OTHER:
2129
/* channel context that is going to replace another channel
2130
* context doesn't really exist and shouldn't be assigned
2131
* anywhere yet */
2132
WARN_ON(1);
2133
break;
2134
}
2135
2136
ieee80211_link_update_chanreq(link, chanreq);
2137
2138
ieee80211_recalc_chanctx_chantype(local, ctx);
2139
2140
*changed |= BSS_CHANGED_BANDWIDTH;
2141
return 0;
2142
}
2143
2144
void ieee80211_link_release_channel(struct ieee80211_link_data *link)
2145
{
2146
struct ieee80211_sub_if_data *sdata = link->sdata;
2147
2148
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
2149
return;
2150
2151
lockdep_assert_wiphy(sdata->local->hw.wiphy);
2152
2153
if (rcu_access_pointer(link->conf->chanctx_conf))
2154
__ieee80211_link_release_channel(link, false);
2155
}
2156
2157
void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link)
2158
{
2159
struct ieee80211_sub_if_data *sdata = link->sdata;
2160
unsigned int link_id = link->link_id;
2161
struct ieee80211_bss_conf *link_conf = link->conf;
2162
struct ieee80211_bss_conf *ap_conf;
2163
struct ieee80211_local *local = sdata->local;
2164
struct ieee80211_sub_if_data *ap;
2165
struct ieee80211_chanctx_conf *conf;
2166
2167
lockdep_assert_wiphy(local->hw.wiphy);
2168
2169
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->bss))
2170
return;
2171
2172
ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
2173
2174
ap_conf = wiphy_dereference(local->hw.wiphy,
2175
ap->vif.link_conf[link_id]);
2176
conf = wiphy_dereference(local->hw.wiphy,
2177
ap_conf->chanctx_conf);
2178
rcu_assign_pointer(link_conf->chanctx_conf, conf);
2179
}
2180
2181
void ieee80211_iter_chan_contexts_atomic(
2182
struct ieee80211_hw *hw,
2183
void (*iter)(struct ieee80211_hw *hw,
2184
struct ieee80211_chanctx_conf *chanctx_conf,
2185
void *data),
2186
void *iter_data)
2187
{
2188
struct ieee80211_local *local = hw_to_local(hw);
2189
struct ieee80211_chanctx *ctx;
2190
2191
rcu_read_lock();
2192
list_for_each_entry_rcu(ctx, &local->chanctx_list, list)
2193
if (ctx->driver_present)
2194
iter(hw, &ctx->conf, iter_data);
2195
rcu_read_unlock();
2196
}
2197
EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic);
2198
2199
void ieee80211_iter_chan_contexts_mtx(
2200
struct ieee80211_hw *hw,
2201
void (*iter)(struct ieee80211_hw *hw,
2202
struct ieee80211_chanctx_conf *chanctx_conf,
2203
void *data),
2204
void *iter_data)
2205
{
2206
struct ieee80211_local *local = hw_to_local(hw);
2207
struct ieee80211_chanctx *ctx;
2208
2209
lockdep_assert_wiphy(hw->wiphy);
2210
2211
list_for_each_entry(ctx, &local->chanctx_list, list)
2212
if (ctx->driver_present)
2213
iter(hw, &ctx->conf, iter_data);
2214
}
2215
EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_mtx);
2216
2217