Allow userspace to disable UHR mode during association via NL80211_ATTR_DISABLE_UHR. This attribute provides a mechanism for userspace applications to explicitly opt out of UHR operation during association. It is necessary because certain regulatory or deployment scenarios may require disabling UHR features on specific channels or devices. By exposing this control to userspace, we ensure flexibility and compliance without relying on static kernel configurations. Signed-off-by: Karthikeyan Kathirvel --- include/net/cfg80211.h | 2 ++ include/uapi/linux/nl80211.h | 4 ++++ net/mac80211/mlme.c | 9 ++++++++- net/wireless/nl80211.c | 7 +++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 85321948b7ec..a72247b05cf5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3307,6 +3307,7 @@ struct cfg80211_ml_reconf_req { * Drivers shall disable MLO features for the current association if this * flag is not set. * @ASSOC_REQ_SPP_AMSDU: SPP A-MSDUs will be used on this connection (if any) + * @ASSOC_REQ_DISABLE_UHR: Disable UHR */ enum cfg80211_assoc_req_flags { ASSOC_REQ_DISABLE_HT = BIT(0), @@ -3317,6 +3318,7 @@ enum cfg80211_assoc_req_flags { ASSOC_REQ_DISABLE_EHT = BIT(5), CONNECT_REQ_MLO_SUPPORT = BIT(6), ASSOC_REQ_SPP_AMSDU = BIT(7), + ASSOC_REQ_DISABLE_UHR = BIT(8), }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 9e957378f43b..1bda6a379bbc 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2976,6 +2976,9 @@ enum nl80211_commands { * @NL80211_ATTR_UHR_CAPABILITY: UHR Capability information element (from * association request when used with NL80211_CMD_NEW_STATION). Can be set * only if %NL80211_STA_FLAG_WME is set. + * @NL80211_ATTR_DISABLE_UHR: Force UHR capable interfaces to disable + * this feature during association. This is a flag attribute. + * Currently only supported in mac80211 drivers. * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined @@ -3546,6 +3549,7 @@ enum nl80211_attrs { NL80211_ATTR_S1G_PRIMARY_2MHZ, NL80211_ATTR_UHR_CAPABILITY, + NL80211_ATTR_DISABLE_UHR, /* add attributes here, update the policy in nl80211.c */ diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 9b730aa5fc3a..9d5906682a1f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -6020,6 +6020,12 @@ ieee80211_determine_our_sta_mode(struct ieee80211_sub_if_data *sdata, mlme_link_id_dbg(sdata, link_id, "no EHT 320 MHz cap in 6 GHz, limiting to 160 MHz\n"); + if (req && req->flags & ASSOC_REQ_DISABLE_UHR) { + mlme_link_id_dbg(sdata, link_id, + "UHR disabled by flag, limiting to EHT\n"); + goto out; + } + uhr_cap = ieee80211_get_uhr_iftype_cap_vif(sband, &sdata->vif); if (!uhr_cap) { mlme_link_id_dbg(sdata, link_id, @@ -9727,7 +9733,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, if (req->flags & (ASSOC_REQ_DISABLE_HT | ASSOC_REQ_DISABLE_VHT | ASSOC_REQ_DISABLE_HE | - ASSOC_REQ_DISABLE_EHT)) { + ASSOC_REQ_DISABLE_EHT | + ASSOC_REQ_DISABLE_UHR)) { err = -EINVAL; goto err_free; } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cb0592c292b4..1e18606c5e44 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -935,6 +935,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_UHR_CAPABILITY] = NLA_POLICY_RANGE(NLA_BINARY, NL80211_UHR_MIN_CAPABILITY_LEN, NL80211_UHR_MAX_CAPABILITY_LEN), + [NL80211_ATTR_DISABLE_UHR] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -12399,6 +12400,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_EHT])) req.flags |= ASSOC_REQ_DISABLE_EHT; + if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_UHR])) + req.flags |= ASSOC_REQ_DISABLE_UHR; + if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) memcpy(&req.vht_capa_mask, nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]), @@ -13278,6 +13282,9 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_EHT])) connect.flags |= ASSOC_REQ_DISABLE_EHT; + if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_UHR])) + connect.flags |= ASSOC_REQ_DISABLE_UHR; + if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) memcpy(&connect.vht_capa_mask, nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]), -- 2.34.1