Linux Audio

Check our new training course

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