diff options
Diffstat (limited to 'net/mac80211/chan.c')
-rw-r--r-- | net/mac80211/chan.c | 130 |
1 files changed, 40 insertions, 90 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index f84b86028a9..53f03120db5 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -8,93 +8,47 @@ #include "ieee80211_i.h" #include "driver-ops.h" -static bool -ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, - enum nl80211_channel_type chantype2, - enum nl80211_channel_type *compat) +static void ieee80211_change_chandef(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx, + const struct cfg80211_chan_def *chandef) { - /* - * start out with chantype1 being the result, - * overwriting later if needed - */ - if (compat) - *compat = chantype1; - - switch (chantype1) { - case NL80211_CHAN_NO_HT: - if (compat) - *compat = chantype2; - break; - case NL80211_CHAN_HT20: - /* - * allow any change that doesn't go to no-HT - * (if it already is no-HT no change is needed) - */ - if (chantype2 == NL80211_CHAN_NO_HT) - break; - if (compat) - *compat = chantype2; - break; - case NL80211_CHAN_HT40PLUS: - case NL80211_CHAN_HT40MINUS: - /* allow smaller bandwidth and same */ - if (chantype2 == NL80211_CHAN_NO_HT) - break; - if (chantype2 == NL80211_CHAN_HT20) - break; - if (chantype2 == chantype1) - break; - return false; - } - - return true; -} - -static void ieee80211_change_chantype(struct ieee80211_local *local, - struct ieee80211_chanctx *ctx, - enum nl80211_channel_type chantype) -{ - if (chantype == ctx->conf.channel_type) + if (cfg80211_chandef_identical(&ctx->conf.def, chandef)) return; - ctx->conf.channel_type = chantype; - drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE); + WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef)); + + ctx->conf.def = *chandef; + drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH); if (!local->use_chanctx) { - local->_oper_channel_type = chantype; + local->_oper_channel_type = cfg80211_get_chandef_type(chandef); ieee80211_hw_config(local, 0); } } static struct ieee80211_chanctx * ieee80211_find_chanctx(struct ieee80211_local *local, - struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type, + const struct cfg80211_chan_def *chandef, enum ieee80211_chanctx_mode mode) { struct ieee80211_chanctx *ctx; - enum nl80211_channel_type compat_type; lockdep_assert_held(&local->chanctx_mtx); if (mode == IEEE80211_CHANCTX_EXCLUSIVE) return NULL; - if (WARN_ON(!channel)) - return NULL; list_for_each_entry(ctx, &local->chanctx_list, list) { - compat_type = ctx->conf.channel_type; + const struct cfg80211_chan_def *compat; if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) continue; - if (ctx->conf.channel != channel) - continue; - if (!ieee80211_channel_types_are_compatible(ctx->conf.channel_type, - channel_type, - &compat_type)) + + compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef); + if (!compat) continue; - ieee80211_change_chantype(local, ctx, compat_type); + ieee80211_change_chandef(local, ctx, compat); return ctx; } @@ -104,8 +58,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local, static struct ieee80211_chanctx * ieee80211_new_chanctx(struct ieee80211_local *local, - struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type, + const struct cfg80211_chan_def *chandef, enum ieee80211_chanctx_mode mode) { struct ieee80211_chanctx *ctx; @@ -117,15 +70,15 @@ ieee80211_new_chanctx(struct ieee80211_local *local, if (!ctx) return ERR_PTR(-ENOMEM); - ctx->conf.channel = channel; - ctx->conf.channel_type = channel_type; + ctx->conf.def = *chandef; ctx->conf.rx_chains_static = 1; ctx->conf.rx_chains_dynamic = 1; ctx->mode = mode; if (!local->use_chanctx) { - local->_oper_channel_type = channel_type; - local->_oper_channel = channel; + local->_oper_channel_type = + cfg80211_get_chandef_type(chandef); + local->_oper_channel = chandef->chan; ieee80211_hw_config(local, 0); } else { err = drv_add_chanctx(local, ctx); @@ -173,44 +126,42 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); ctx->refcount++; + ieee80211_recalc_txpower(sdata); + return 0; } -static enum nl80211_channel_type -ieee80211_calc_chantype(struct ieee80211_local *local, - struct ieee80211_chanctx *ctx) +static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) { struct ieee80211_chanctx_conf *conf = &ctx->conf; struct ieee80211_sub_if_data *sdata; - enum nl80211_channel_type result = NL80211_CHAN_NO_HT; + const struct cfg80211_chan_def *compat = NULL; lockdep_assert_held(&local->chanctx_mtx); rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!ieee80211_sdata_running(sdata)) continue; if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) continue; - WARN_ON_ONCE(!ieee80211_channel_types_are_compatible( - sdata->vif.bss_conf.channel_type, - result, &result)); + if (!compat) + compat = &sdata->vif.bss_conf.chandef; + + compat = cfg80211_chandef_compatible( + &sdata->vif.bss_conf.chandef, compat); + if (!compat) + break; } rcu_read_unlock(); - return result; -} - -static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, - struct ieee80211_chanctx *ctx) -{ - enum nl80211_channel_type chantype; - - lockdep_assert_held(&local->chanctx_mtx); + if (WARN_ON_ONCE(!compat)) + return; - chantype = ieee80211_calc_chantype(local, ctx); - ieee80211_change_chantype(local, ctx, chantype); + ieee80211_change_chandef(local, ctx, compat); } static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, @@ -335,8 +286,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, } int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type, + const struct cfg80211_chan_def *chandef, enum ieee80211_chanctx_mode mode) { struct ieee80211_local *local = sdata->local; @@ -348,15 +298,15 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->chanctx_mtx); __ieee80211_vif_release_channel(sdata); - ctx = ieee80211_find_chanctx(local, channel, channel_type, mode); + ctx = ieee80211_find_chanctx(local, chandef, mode); if (!ctx) - ctx = ieee80211_new_chanctx(local, channel, channel_type, mode); + ctx = ieee80211_new_chanctx(local, chandef, mode); if (IS_ERR(ctx)) { ret = PTR_ERR(ctx); goto out; } - sdata->vif.bss_conf.channel_type = channel_type; + sdata->vif.bss_conf.chandef = *chandef; ret = ieee80211_assign_vif_chanctx(sdata, ctx); if (ret) { |