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