diff options
Diffstat (limited to 'net/mac80211/chan.c')
| -rw-r--r-- | net/mac80211/chan.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 03e8d2e3270e..3a4764b2869e 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
| @@ -410,6 +410,64 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
| 410 | return ret; | 410 | return ret; |
| 411 | } | 411 | } |
| 412 | 412 | ||
| 413 | int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | ||
| 414 | const struct cfg80211_chan_def *chandef, | ||
| 415 | u32 *changed) | ||
| 416 | { | ||
| 417 | struct ieee80211_local *local = sdata->local; | ||
| 418 | struct ieee80211_chanctx_conf *conf; | ||
| 419 | struct ieee80211_chanctx *ctx; | ||
| 420 | int ret; | ||
| 421 | u32 chanctx_changed = 0; | ||
| 422 | |||
| 423 | /* should never be called if not performing a channel switch. */ | ||
| 424 | if (WARN_ON(!sdata->vif.csa_active)) | ||
| 425 | return -EINVAL; | ||
| 426 | |||
| 427 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | ||
| 428 | IEEE80211_CHAN_DISABLED)) | ||
| 429 | return -EINVAL; | ||
| 430 | |||
| 431 | mutex_lock(&local->chanctx_mtx); | ||
| 432 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
| 433 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 434 | if (!conf) { | ||
| 435 | ret = -EINVAL; | ||
| 436 | goto out; | ||
| 437 | } | ||
| 438 | |||
| 439 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | ||
| 440 | if (ctx->refcount != 1) { | ||
| 441 | ret = -EINVAL; | ||
| 442 | goto out; | ||
| 443 | } | ||
| 444 | |||
| 445 | if (sdata->vif.bss_conf.chandef.width != chandef->width) { | ||
| 446 | chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH; | ||
| 447 | *changed |= BSS_CHANGED_BANDWIDTH; | ||
| 448 | } | ||
| 449 | |||
| 450 | sdata->vif.bss_conf.chandef = *chandef; | ||
| 451 | ctx->conf.def = *chandef; | ||
| 452 | |||
| 453 | chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; | ||
| 454 | drv_change_chanctx(local, ctx, chanctx_changed); | ||
| 455 | |||
| 456 | if (!local->use_chanctx) { | ||
| 457 | local->_oper_chandef = *chandef; | ||
| 458 | ieee80211_hw_config(local, 0); | ||
| 459 | } | ||
| 460 | |||
| 461 | ieee80211_recalc_chanctx_chantype(local, ctx); | ||
| 462 | ieee80211_recalc_smps_chanctx(local, ctx); | ||
| 463 | ieee80211_recalc_radar_chanctx(local, ctx); | ||
| 464 | |||
| 465 | ret = 0; | ||
| 466 | out: | ||
| 467 | mutex_unlock(&local->chanctx_mtx); | ||
| 468 | return ret; | ||
| 469 | } | ||
| 470 | |||
| 413 | int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | 471 | int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, |
| 414 | const struct cfg80211_chan_def *chandef, | 472 | const struct cfg80211_chan_def *chandef, |
| 415 | u32 *changed) | 473 | u32 *changed) |
