* @BSS_CHANGED_MLD_TTLM: negotiated TID to link mapping was changed
* @BSS_CHANGED_TPE: transmit power envelope changed
* @BSS_CHANGED_NAN_LOCAL_SCHED: NAN local schedule changed (NAN mode only)
+ * @BSS_CHANGED_NPCA: NPCA parameters changed
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
BSS_CHANGED_MLD_TTLM = BIT_ULL(34),
BSS_CHANGED_TPE = BIT_ULL(35),
BSS_CHANGED_NAN_LOCAL_SCHED = BIT_ULL(36),
+ BSS_CHANGED_NPCA = BIT_ULL(37),
/* when adding here, make sure to change ieee80211_reconfig */
};
struct ieee80211_parsed_tpe_psd psd_local[2], psd_reg_client[2];
};
+/**
+ * struct ieee80211_bss_npca_params - NPCA parameters
+ * @min_dur_thresh: NPCA minimum duration threshold (512 + 128*n usec)
+ * @switch_delay: NPCA switch delay (units of 4 usec)
+ * @switch_back_delay: NPCA switch back delay (units of 4 usec)
+ * @init_qsrc: initial QSRC value
+ * @moplen: indicates MOPLEN NPCA is permitted in the BSS
+ * @enabled: NPCA is enabled for this link
+ *
+ * Note: the individual values (except @enabled) are in spec representation.
+ */
+struct ieee80211_bss_npca_params {
+ u32 min_dur_thresh:4,
+ switch_delay:6,
+ switch_back_delay:6,
+ init_qsrc:2,
+ moplen:1,
+ enabled:1;
+};
+
/**
* struct ieee80211_bss_conf - holds the BSS's changing parameters
*
* (as opposed to hearing its value from another link's beacon).
* @s1g_long_beacon_period: number of beacon intervals between each long
* beacon transmission.
+ * @npca: NPCA parameters
*/
struct ieee80211_bss_conf {
struct ieee80211_vif *vif;
u8 bss_param_ch_cnt_link_id;
u8 s1g_long_beacon_period;
+
+ struct ieee80211_bss_npca_params npca;
};
#define IEEE80211_NAN_MAX_CHANNELS 3
_ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
}
+static void
+ieee80211_chanctx_update_npca_links(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx,
+ bool enable)
+{
+ struct ieee80211_chanctx_user_iter iter;
+
+ if (!!ctx->conf.def.npca_chan != enable)
+ return;
+
+ for_each_chanctx_user_assigned(local, ctx, &iter) {
+ if (!iter.link)
+ continue;
+ if (!iter.sdata->vif.cfg.assoc)
+ continue;
+
+ if (enable) {
+ if (!iter.link->conf->chanreq.oper.npca_chan)
+ continue;
+ } else {
+ if (!iter.link->conf->npca.enabled)
+ continue;
+ }
+
+ iter.link->conf->npca.enabled = enable;
+ drv_link_info_changed(local, iter.sdata,
+ iter.link->conf,
+ iter.link->link_id,
+ BSS_CHANGED_NPCA);
+ }
+}
+
static void _ieee80211_change_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
struct ieee80211_chanctx *old_ctx,
ieee80211_add_wbrf(local, &ctx->conf.def);
+ /* disable NPCA on the link using it */
+ ieee80211_chanctx_update_npca_links(local, ctx, false);
+
drv_change_chanctx(local, ctx, changed);
/* check if BW is wider */
ieee80211_chan_bw_change(local, old_ctx, false, false);
+
+ /* enable NPCA on the link that requested it */
+ ieee80211_chanctx_update_npca_links(local, ctx, true);
}
static void ieee80211_change_chanctx(struct ieee80211_local *local,
elems->uhr_operation_len,
false)) {
struct cfg80211_chan_def npca_chandef = *chandef;
+ const struct ieee80211_sta_uhr_cap *uhr_cap;
const struct ieee80211_uhr_npca_info *npca;
npca = ieee80211_uhr_npca_info(uhr_oper);
"AP UHR NPCA settings invalid, disabling UHR\n");
return IEEE80211_CONN_MODE_EHT;
}
+
+ uhr_cap = ieee80211_get_uhr_iftype_cap_vif(sband, &sdata->vif);
+ /* can't happen since we must have UHR to parse the elems */
+ if (WARN_ON(!uhr_cap))
+ return IEEE80211_CONN_MODE_EHT;
+
+ if (uhr_cap->mac.mac_cap[0] & IEEE80211_UHR_MAC_CAP0_NPCA_SUPP)
+ *chandef = npca_chandef;
}
return IEEE80211_CONN_MODE_UHR;
.conn = &link->u.mgd.conn,
};
struct ieee80211_sub_if_data *sdata = link->sdata;
+ struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_chan_req chanreq = {};
enum ieee80211_conn_mode ap_mode;
const char *frame;
}
}
- if (ieee80211_chanreq_identical(&chanreq, &link->conf->chanreq))
+ /*
+ * Beacons don't have the full information - we need to track
+ * critical updates for NPCA parameters etc. For now only handle
+ * association and link reconfiguration response.
+ */
+ if (stype != IEEE80211_STYPE_BEACON &&
+ chanreq.oper.npca_chan && elems->uhr_operation &&
+ ieee80211_uhr_oper_size_ok((const void *)elems->uhr_operation,
+ elems->uhr_operation_len,
+ false)) {
+ const struct ieee80211_uhr_npca_info *npca;
+ struct ieee80211_bss_npca_params params = {};
+
+ npca = ieee80211_uhr_npca_info(elems->uhr_operation);
+ if (!npca) {
+ chanreq.oper.npca_chan = NULL;
+ chanreq.oper.npca_punctured = 0;
+ } else {
+ params.min_dur_thresh =
+ le32_get_bits(npca->params,
+ IEEE80211_UHR_NPCA_PARAMS_MIN_DUR_THRESH);
+ params.switch_delay =
+ le32_get_bits(npca->params,
+ IEEE80211_UHR_NPCA_PARAMS_SWITCH_DELAY);
+ params.switch_back_delay =
+ le32_get_bits(npca->params,
+ IEEE80211_UHR_NPCA_PARAMS_SWITCH_BACK_DELAY);
+ params.init_qsrc =
+ le32_get_bits(npca->params,
+ IEEE80211_UHR_NPCA_PARAMS_INIT_QSRC);
+ params.moplen =
+ le32_get_bits(npca->params,
+ IEEE80211_UHR_NPCA_PARAMS_MOPLEN);
+ /* don't change the enabled bit yet */
+ params.enabled = link->conf->npca.enabled;
+ }
+
+ if (memcmp(¶ms, &link->conf->npca, sizeof(params)) ||
+ !update) {
+ link->conf->npca = params;
+ *changed |= BSS_CHANGED_NPCA;
+ }
+ }
+
+ if (ieee80211_chanreq_identical(&chanreq, &link->conf->chanreq)) {
+ if (update)
+ goto update_npca;
return 0;
+ }
link_info(link,
"AP %pM changed bandwidth in %s, new used config is %d.%03d MHz, width %d (%d.%03d/%d MHz)\n",
}
cfg80211_schedule_channels_check(&sdata->wdev);
+
+update_npca:
+ chanctx_conf = sdata_dereference(link->conf->chanctx_conf, sdata);
+ /* must be non-NULL when update is true */
+ if (WARN_ON(!chanctx_conf))
+ return -EINVAL;
+
+ /*
+ * If we're not associated yet (i.e. in the process associating)
+ * then the chanctx code won't have enabled NPCA in the link, so
+ * if the channel context was set up with NPCA for us, enable it.
+ */
+ if (chanreq.oper.npca_chan && chanctx_conf->def.npca_chan &&
+ !link->conf->npca.enabled && !sdata->vif.cfg.assoc) {
+ link->conf->npca.enabled = true;
+ *changed |= BSS_CHANGED_NPCA;
+ }
+
return 0;
}
ieee80211_bss_info_change_notify(sdata,
changed);
} else if (!WARN_ON(!link)) {
+ if (link->conf->npca.enabled)
+ changed |= BSS_CHANGED_NPCA;
+
ieee80211_link_info_change_notify(sdata, link,
changed);
changed = BSS_CHANGED_ASSOC |