diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2abf9e20cc22..6461a7bd0169 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -900,6 +900,7 @@ struct cfg80211_bitrate_mask { enum nl80211_eht_gi eht_gi; enum nl80211_he_ltf he_ltf; enum nl80211_eht_ltf eht_ltf; + bool nonht_dup_6ghz; } control[NUM_NL80211_BANDS]; }; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 020387d76412..d8fefefc11a9 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -5900,6 +5900,9 @@ enum nl80211_key_attributes { * see &struct nl80211_txrate_eht * @NL80211_TXRATE_EHT_GI: configure EHT GI, (u8, see &enum nl80211_eht_gi) * @NL80211_TXRATE_EHT_LTF: configure EHT LTF, (u8, see &enum nl80211_eht_ltf) + * @NL80211_TXRATE_6GHZ_NON_HT_DUP: configure 6 GHz non-HT duplicate Beacon + * transmission. This flag is applicable only in Beacon TX rate setting + * and must be accompanied by a non-HT (legacy) Beacon rate. * @__NL80211_TXRATE_AFTER_LAST: internal * @NL80211_TXRATE_MAX: highest TX rate attribute */ @@ -5915,6 +5918,7 @@ enum nl80211_tx_rate_attributes { NL80211_TXRATE_EHT, NL80211_TXRATE_EHT_GI, NL80211_TXRATE_EHT_LTF, + NL80211_TXRATE_6GHZ_NON_HT_DUP, /* keep last */ __NL80211_TXRATE_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8f022bb1413c..e585da1d79c9 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -569,6 +569,7 @@ static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { [NL80211_TXRATE_EHT_LTF] = NLA_POLICY_RANGE(NLA_U8, NL80211_RATE_INFO_EHT_1XLTF, NL80211_RATE_INFO_EHT_8XLTF), + [NL80211_TXRATE_6GHZ_NON_HT_DUP] = { .type = NLA_FLAG }, }; @@ -6303,6 +6304,14 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, mask->control[band].eht_ltf = nla_get_u8(tb[NL80211_TXRATE_EHT_LTF]); + if (tb[NL80211_TXRATE_6GHZ_NON_HT_DUP]) { + if (band != NL80211_BAND_6GHZ || + (wdev->iftype != NL80211_IFTYPE_AP && + wdev->iftype != NL80211_IFTYPE_P2P_GO)) + return -EINVAL; + mask->control[band].nonht_dup_6ghz = true; + } + if (mask->control[band].legacy == 0) { /* don't allow empty legacy rates if HT, VHT, HE or EHT * are not even supported. @@ -6344,6 +6353,7 @@ static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev, { u32 count_ht, count_vht, count_he, count_eht, i; u32 rate = beacon_rate->control[band].legacy; + bool nonht_dup = beacon_rate->control[band].nonht_dup_6ghz; /* Allow only one rate */ if (hweight32(rate) > 1) @@ -6405,6 +6415,9 @@ static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev, (!rate && !count_ht && !count_vht && !count_he && !count_eht)) return -EINVAL; + if (nonht_dup && !rate) + return -EINVAL; + if (rate && !wiphy_ext_feature_isset(&rdev->wiphy, NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))