* bandwidth) OFDMA settings need to be changed
* @IEEE80211_CHANCTX_CHANGE_PUNCTURING: The punctured channel(s) bitmap
* was changed.
+ * @IEEE80211_CHANCTX_CHANGE_NPCA: NPCA configuration changed
+ * @IEEE80211_CHANCTX_CHANGE_NPCA_PUNCT: NPCA puncturing changed
*/
enum ieee80211_chanctx_change {
IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(0),
IEEE80211_CHANCTX_CHANGE_MIN_DEF = BIT(4),
IEEE80211_CHANCTX_CHANGE_AP = BIT(5),
IEEE80211_CHANCTX_CHANGE_PUNCTURING = BIT(6),
+ IEEE80211_CHANCTX_CHANGE_NPCA = BIT(7),
+ IEEE80211_CHANCTX_CHANGE_NPCA_PUNCT = BIT(8),
};
/**
* @oper: channel definition to use for operation
* @ap: the channel definition of the AP, if any
* (otherwise the chan member is %NULL)
+ * @require_npca: If NPCA is configured, require it to
+ * remain, this is used by AP interfaces
*/
struct ieee80211_chan_req {
struct cfg80211_chan_def oper;
struct cfg80211_chan_def ap;
+ bool require_npca;
};
/**
unsigned int link_id = params->beacon.link_id;
struct ieee80211_link_data *link;
struct ieee80211_bss_conf *link_conf;
- struct ieee80211_chan_req chanreq = { .oper = params->chandef };
+ struct ieee80211_chan_req chanreq = {
+ .oper = params->chandef,
+ .require_npca = true,
+ };
u64 tsf;
lockdep_assert_wiphy(local->hw.wiphy);
struct cfg80211_csa_settings *params)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_chan_req chanreq = { .oper = params->chandef };
+ struct ieee80211_chan_req chanreq = {
+ .oper = params->chandef,
+ .require_npca = true,
+ };
struct ieee80211_local *local = sdata->local;
struct ieee80211_channel_switch ch_switch = {
.link_id = params->link_id,
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_link_data *link;
- struct ieee80211_chan_req chanreq = { .oper = *chandef };
+ struct ieee80211_chan_req chanreq = {
+ .oper = *chandef,
+ .require_npca = true,
+ };
int ret;
u64 changed = 0;
const struct ieee80211_chan_req *b,
struct ieee80211_chan_req *tmp)
{
+ struct ieee80211_chan_req _a = *a, _b = *b;
const struct cfg80211_chan_def *compat;
if (a->ap.chan && b->ap.chan &&
!cfg80211_chandef_identical(&a->ap, &b->ap))
return NULL;
- compat = cfg80211_chandef_compatible(&a->oper, &b->oper);
+ /*
+ * Remove NPCA if it's not required, so that interfaces
+ * sharing a channel context will not use NPCA while the
+ * channel context is shared.
+ * If both sides are AP interfaces requiring NPC, there's
+ * an assumption that userspace will set them up with
+ * identical configurations and the same BSS color
+ * (if the config is not identical, sharing will fail due
+ * to cfg80211_chandef_compatible() failing below.)
+ */
+ if (!_a.require_npca) {
+ _a.oper.npca_chan = NULL;
+ _a.oper.npca_punctured = 0;
+ }
+
+ if (!_b.require_npca) {
+ _b.oper.npca_chan = NULL;
+ _b.oper.npca_punctured = 0;
+ }
+
+ compat = cfg80211_chandef_compatible(&_a.oper, &_b.oper);
if (!compat)
return NULL;
/* Note: later code assumes this always fills & returns tmp if compat */
tmp->oper = *compat;
tmp->ap = a->ap.chan ? a->ap : b->ap;
+ tmp->require_npca = a->require_npca && b->require_npca;
return tmp;
}
const struct ieee80211_chan_req *chanreq,
struct ieee80211_link_data *rsvd_for)
{
- const struct cfg80211_chan_def *chandef = &chanreq->oper;
struct ieee80211_chan_req ctx_req = {
.oper = ctx->conf.def,
.ap = ctx->conf.ap,
u32 changed = 0;
/* 5/10 MHz not handled here */
- switch (chandef->width) {
+ switch (chanreq->oper.width) {
case NL80211_CHAN_WIDTH_1:
case NL80211_CHAN_WIDTH_2:
case NL80211_CHAN_WIDTH_4:
changed |= IEEE80211_CHANCTX_CHANGE_WIDTH;
if (ctx->conf.def.punctured != chanreq->oper.punctured)
changed |= IEEE80211_CHANCTX_CHANGE_PUNCTURING;
+ if (ctx->conf.def.npca_chan != chanreq->oper.npca_chan)
+ changed |= IEEE80211_CHANCTX_CHANGE_NPCA;
+ if (chanreq->oper.npca_chan &&
+ ctx->conf.def.npca_punctured != chanreq->oper.npca_punctured)
+ changed |= IEEE80211_CHANCTX_CHANGE_NPCA_PUNCT;
}
if (!cfg80211_chandef_identical(&ctx->conf.ap, &chanreq->ap))
changed |= IEEE80211_CHANCTX_CHANGE_AP;
- ctx->conf.def = *chandef;
+ ctx->conf.def = chanreq->oper;
ctx->conf.ap = chanreq->ap;
/* check if min chanctx also changed */