From: Johannes Berg Date: Tue, 28 Apr 2026 09:25:38 +0000 (+0200) Subject: wifi: mac80211: mlme: use NPCA chandef if capable X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5af8f06349d85824a32aa15949cb66b174e0f713;p=thirdparty%2Fkernel%2Flinux.git wifi: mac80211: mlme: use NPCA chandef if capable If the device is capable, parse the AP chandef with NPCA. Also advertise the other NPCA operational parameters to the underlying driver and track if they change (though not with BSS critical update etc. yet) Since NPCA can only be enabled when the chanctx isn't shared, the channel context code needs to clear/set npca.enabled in the per-link configuration, except during association since we can't enable NPCA before having completed association. In this case, set npca.enabled during the association process. Link: https://patch.msgid.link/20260428112708.eb1e42c0b6d7.I0acd8445d4600363afb8430922531450399d0fab@changeid Signed-off-by: Johannes Berg --- diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ae7fd44e17b54..4fb579805e0fb 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -373,6 +373,7 @@ struct ieee80211_vif_chanctx_switch { * @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, @@ -411,6 +412,7 @@ enum ieee80211_bss_change { 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 */ }; @@ -596,6 +598,26 @@ struct ieee80211_parsed_tpe { 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 * @@ -770,6 +792,7 @@ struct ieee80211_parsed_tpe { * (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; @@ -873,6 +896,8 @@ struct ieee80211_bss_conf { u8 bss_param_ch_cnt_link_id; u8 s1g_long_beacon_period; + + struct ieee80211_bss_npca_params npca; }; #define IEEE80211_NAN_MAX_CHANNELS 3 diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 5e24988ef5614..b9d563f927daa 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -770,6 +770,38 @@ void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local, _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, @@ -845,10 +877,16 @@ static void _ieee80211_change_chanctx(struct ieee80211_local *local, 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, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5be390de67564..3db8a499a1c82 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -401,6 +401,7 @@ check_uhr: 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); @@ -411,6 +412,14 @@ check_uhr: "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; @@ -1320,6 +1329,7 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, .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; @@ -1403,8 +1413,55 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, } } - 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", @@ -1451,6 +1508,24 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, } 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; } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 24537794256c3..3184007f40c1e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2147,6 +2147,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) 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 |