Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

wifi: cfg80211: add initial UHR support

Add initial support for making UHR connections (or suppressing
that), adding UHR capable stations on the AP side, encoding
and decoding UHR MCSes (except rate calculation for the new
MCSes 17, 19, 20 and 23) as well as regulatory support.

Link: https://patch.msgid.link/20260130164259.54cc12fbb307.I26126bebd83c7ab17e99827489f946ceabb3521f@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

+265 -30
+55 -3
include/net/cfg80211.h
··· 7 7 * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> 8 8 * Copyright 2013-2014 Intel Mobile Communications GmbH 9 9 * Copyright 2015-2017 Intel Deutschland GmbH 10 - * Copyright (C) 2018-2025 Intel Corporation 10 + * Copyright (C) 2018-2026 Intel Corporation 11 11 */ 12 12 13 13 #include <linux/ethtool.h> ··· 126 126 * @IEEE80211_CHAN_NO_4MHZ: 4 MHz bandwidth is not permitted on this channel. 127 127 * @IEEE80211_CHAN_NO_8MHZ: 8 MHz bandwidth is not permitted on this channel. 128 128 * @IEEE80211_CHAN_NO_16MHZ: 16 MHz bandwidth is not permitted on this channel. 129 + * @IEEE80211_CHAN_NO_UHR: UHR operation is not permitted on this channel. 129 130 */ 130 131 enum ieee80211_channel_flags { 131 132 IEEE80211_CHAN_DISABLED = BIT(0), ··· 144 143 IEEE80211_CHAN_NO_10MHZ = BIT(12), 145 144 IEEE80211_CHAN_NO_HE = BIT(13), 146 145 /* can use free bits here */ 146 + IEEE80211_CHAN_NO_UHR = BIT(18), 147 147 IEEE80211_CHAN_NO_320MHZ = BIT(19), 148 148 IEEE80211_CHAN_NO_EHT = BIT(20), 149 149 IEEE80211_CHAN_DFS_CONCURRENT = BIT(21), ··· 431 429 u8 eht_ppe_thres[IEEE80211_EHT_PPE_THRES_MAX_LEN]; 432 430 }; 433 431 432 + /** 433 + * struct ieee80211_sta_uhr_cap - STA's UHR capabilities 434 + * @has_uhr: true iff UHR is supported and data is valid 435 + * @mac: fixed MAC capabilities 436 + * @phy: fixed PHY capabilities 437 + */ 438 + struct ieee80211_sta_uhr_cap { 439 + bool has_uhr; 440 + struct ieee80211_uhr_cap_mac mac; 441 + struct ieee80211_uhr_cap_phy phy; 442 + }; 443 + 434 444 /* sparse defines __CHECKER__; see Documentation/dev-tools/sparse.rst */ 435 445 #ifdef __CHECKER__ 436 446 /* ··· 468 454 * @he_6ghz_capa: HE 6 GHz capabilities, must be filled in for a 469 455 * 6 GHz band channel (and 0 may be valid value). 470 456 * @eht_cap: STA's EHT capabilities 457 + * @uhr_cap: STA's UHR capabilities 471 458 * @vendor_elems: vendor element(s) to advertise 472 459 * @vendor_elems.data: vendor element(s) data 473 460 * @vendor_elems.len: vendor element(s) length ··· 478 463 struct ieee80211_sta_he_cap he_cap; 479 464 struct ieee80211_he_6ghz_capa he_6ghz_capa; 480 465 struct ieee80211_sta_eht_cap eht_cap; 466 + struct ieee80211_sta_uhr_cap uhr_cap; 481 467 struct { 482 468 const u8 *data; 483 469 unsigned int len; ··· 716 700 717 701 if (data && data->eht_cap.has_eht) 718 702 return &data->eht_cap; 703 + 704 + return NULL; 705 + } 706 + 707 + /** 708 + * ieee80211_get_uhr_iftype_cap - return UHR capabilities for an sband's iftype 709 + * @sband: the sband to search for the iftype on 710 + * @iftype: enum nl80211_iftype 711 + * 712 + * Return: pointer to the struct ieee80211_sta_uhr_cap, or NULL is none found 713 + */ 714 + static inline const struct ieee80211_sta_uhr_cap * 715 + ieee80211_get_uhr_iftype_cap(const struct ieee80211_supported_band *sband, 716 + enum nl80211_iftype iftype) 717 + { 718 + const struct ieee80211_sband_iftype_data *data = 719 + ieee80211_get_sband_iftype_data(sband, iftype); 720 + 721 + if (data && data->uhr_cap.has_uhr) 722 + return &data->uhr_cap; 719 723 720 724 return NULL; 721 725 } ··· 1522 1486 * @he_cap: HE capabilities (or %NULL if HE isn't enabled) 1523 1487 * @eht_cap: EHT capabilities (or %NULL if EHT isn't enabled) 1524 1488 * @eht_oper: EHT operation IE (or %NULL if EHT isn't enabled) 1489 + * @uhr_oper: UHR operation (or %NULL if UHR isn't enabled) 1525 1490 * @ht_required: stations must support HT 1526 1491 * @vht_required: stations must support VHT 1527 1492 * @twt_responder: Enable Target Wait Time ··· 1562 1525 const struct ieee80211_he_operation *he_oper; 1563 1526 const struct ieee80211_eht_cap_elem *eht_cap; 1564 1527 const struct ieee80211_eht_operation *eht_oper; 1528 + const struct ieee80211_uhr_operation *uhr_oper; 1565 1529 bool ht_required, vht_required, he_required, sae_h2e_required; 1566 1530 bool twt_responder; 1567 1531 u32 flags; ··· 1736 1698 * @eht_capa: EHT capabilities of station 1737 1699 * @eht_capa_len: the length of the EHT capabilities 1738 1700 * @s1g_capa: S1G capabilities of station 1701 + * @uhr_capa: UHR capabilities of the station 1702 + * @uhr_capa_len: the length of the UHR capabilities 1739 1703 */ 1740 1704 struct link_station_parameters { 1741 1705 const u8 *mld_mac; ··· 1757 1717 const struct ieee80211_eht_cap_elem *eht_capa; 1758 1718 u8 eht_capa_len; 1759 1719 const struct ieee80211_s1g_cap *s1g_capa; 1720 + const struct ieee80211_uhr_cap *uhr_capa; 1721 + u8 uhr_capa_len; 1760 1722 }; 1761 1723 1762 1724 /** ··· 1940 1898 * @RATE_INFO_FLAGS_EXTENDED_SC_DMG: 60GHz extended SC MCS 1941 1899 * @RATE_INFO_FLAGS_EHT_MCS: EHT MCS information 1942 1900 * @RATE_INFO_FLAGS_S1G_MCS: MCS field filled with S1G MCS 1901 + * @RATE_INFO_FLAGS_UHR_MCS: UHR MCS information 1902 + * @RATE_INFO_FLAGS_UHR_ELR_MCS: UHR ELR MCS was used 1903 + * (set together with @RATE_INFO_FLAGS_UHR_MCS) 1904 + * @RATE_INFO_FLAGS_UHR_IM: UHR Interference Mitigation 1905 + * was used 1943 1906 */ 1944 1907 enum rate_info_flags { 1945 1908 RATE_INFO_FLAGS_MCS = BIT(0), ··· 1956 1909 RATE_INFO_FLAGS_EXTENDED_SC_DMG = BIT(6), 1957 1910 RATE_INFO_FLAGS_EHT_MCS = BIT(7), 1958 1911 RATE_INFO_FLAGS_S1G_MCS = BIT(8), 1912 + RATE_INFO_FLAGS_UHR_MCS = BIT(9), 1913 + RATE_INFO_FLAGS_UHR_ELR_MCS = BIT(10), 1914 + RATE_INFO_FLAGS_UHR_IM = BIT(11), 1959 1915 }; 1960 1916 1961 1917 /** ··· 1974 1924 * @RATE_INFO_BW_160: 160 MHz bandwidth 1975 1925 * @RATE_INFO_BW_HE_RU: bandwidth determined by HE RU allocation 1976 1926 * @RATE_INFO_BW_320: 320 MHz bandwidth 1977 - * @RATE_INFO_BW_EHT_RU: bandwidth determined by EHT RU allocation 1927 + * @RATE_INFO_BW_EHT_RU: bandwidth determined by EHT/UHR RU allocation 1978 1928 * @RATE_INFO_BW_1: 1 MHz bandwidth 1979 1929 * @RATE_INFO_BW_2: 2 MHz bandwidth 1980 1930 * @RATE_INFO_BW_4: 4 MHz bandwidth ··· 2005 1955 * 2006 1956 * @flags: bitflag of flags from &enum rate_info_flags 2007 1957 * @legacy: bitrate in 100kbit/s for 802.11abg 2008 - * @mcs: mcs index if struct describes an HT/VHT/HE/EHT/S1G rate 1958 + * @mcs: mcs index if struct describes an HT/VHT/HE/EHT/S1G/UHR rate 2009 1959 * @nss: number of streams (VHT & HE only) 2010 1960 * @bw: bandwidth (from &enum rate_info_bw) 2011 1961 * @he_gi: HE guard interval (from &enum nl80211_he_gi) ··· 3312 3262 * Drivers shall disable MLO features for the current association if this 3313 3263 * flag is not set. 3314 3264 * @ASSOC_REQ_SPP_AMSDU: SPP A-MSDUs will be used on this connection (if any) 3265 + * @ASSOC_REQ_DISABLE_UHR: Disable UHR 3315 3266 */ 3316 3267 enum cfg80211_assoc_req_flags { 3317 3268 ASSOC_REQ_DISABLE_HT = BIT(0), ··· 3323 3272 ASSOC_REQ_DISABLE_EHT = BIT(5), 3324 3273 CONNECT_REQ_MLO_SUPPORT = BIT(6), 3325 3274 ASSOC_REQ_SPP_AMSDU = BIT(7), 3275 + ASSOC_REQ_DISABLE_UHR = BIT(8), 3326 3276 }; 3327 3277 3328 3278 /**
+30
include/uapi/linux/nl80211.h
··· 2977 2977 * @NL80211_ATTR_EPP_PEER: A flag attribute to indicate if the peer is an EPP 2978 2978 * STA. Used with %NL80211_CMD_NEW_STA and %NL80211_CMD_ADD_LINK_STA 2979 2979 * 2980 + * @NL80211_ATTR_UHR_CAPABILITY: UHR Capability information element (from 2981 + * association request when used with NL80211_CMD_NEW_STATION). Can be set 2982 + * only if HE/EHT are also available. 2983 + * @NL80211_ATTR_DISABLE_UHR: Force UHR capable interfaces to disable 2984 + * this feature during association. This is a flag attribute. 2985 + * Currently only supported in mac80211 drivers. 2986 + * 2980 2987 * @NUM_NL80211_ATTR: total number of nl80211_attrs available 2981 2988 * @NL80211_ATTR_MAX: highest attribute number currently defined 2982 2989 * @__NL80211_ATTR_AFTER_LAST: internal use ··· 3554 3547 3555 3548 NL80211_ATTR_EPP_PEER, 3556 3549 3550 + NL80211_ATTR_UHR_CAPABILITY, 3551 + NL80211_ATTR_DISABLE_UHR, 3552 + 3557 3553 /* add attributes here, update the policy in nl80211.c */ 3558 3554 3559 3555 __NL80211_ATTR_AFTER_LAST, ··· 3909 3899 * @NL80211_RATE_INFO_4_MHZ_WIDTH: 4 MHz S1G rate 3910 3900 * @NL80211_RATE_INFO_8_MHZ_WIDTH: 8 MHz S1G rate 3911 3901 * @NL80211_RATE_INFO_16_MHZ_WIDTH: 16 MHz S1G rate 3902 + * @NL80211_RATE_INFO_UHR_MCS: UHR MCS index (u8, 0-15, 17, 19, 20, 23) 3903 + * Note that the other EHT attributes (such as @NL80211_RATE_INFO_EHT_NSS) 3904 + * are used in conjunction with this where applicable 3905 + * @NL80211_RATE_INFO_UHR_ELR: UHR ELR flag, which restricts NSS to 1, 3906 + * MCS to 0 or 1, and GI to %NL80211_RATE_INFO_EHT_GI_1_6. 3907 + * @NL80211_RATE_INFO_UHR_IM: UHR Interference Mitigation flag 3912 3908 * @__NL80211_RATE_INFO_AFTER_LAST: internal use 3913 3909 */ 3914 3910 enum nl80211_rate_info { ··· 3948 3932 NL80211_RATE_INFO_4_MHZ_WIDTH, 3949 3933 NL80211_RATE_INFO_8_MHZ_WIDTH, 3950 3934 NL80211_RATE_INFO_16_MHZ_WIDTH, 3935 + NL80211_RATE_INFO_UHR_MCS, 3936 + NL80211_RATE_INFO_UHR_ELR, 3937 + NL80211_RATE_INFO_UHR_IM, 3951 3938 3952 3939 /* keep last */ 3953 3940 __NL80211_RATE_INFO_AFTER_LAST, ··· 4273 4254 * capabilities element 4274 4255 * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE: EHT PPE thresholds information as 4275 4256 * defined in EHT capabilities element 4257 + * @NL80211_BAND_IFTYPE_ATTR_UHR_CAP_MAC: UHR MAC capabilities as in UHR 4258 + * capabilities element 4259 + * @NL80211_BAND_IFTYPE_ATTR_UHR_CAP_PHY: UHR PHY capabilities as in UHR 4260 + * capabilities element 4276 4261 * @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use 4277 4262 * @NL80211_BAND_IFTYPE_ATTR_MAX: highest band attribute currently defined 4278 4263 */ ··· 4294 4271 NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY, 4295 4272 NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET, 4296 4273 NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE, 4274 + NL80211_BAND_IFTYPE_ATTR_UHR_CAP_MAC, 4275 + NL80211_BAND_IFTYPE_ATTR_UHR_CAP_PHY, 4297 4276 4298 4277 /* keep last */ 4299 4278 __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST, ··· 4478 4453 * @NL80211_FREQUENCY_ATTR_S1G_NO_PRIMARY: Channel is not permitted for use 4479 4454 * as a primary channel. Does not prevent the channel from existing 4480 4455 * as a non-primary subchannel. Only applicable to S1G channels. 4456 + * @NL80211_FREQUENCY_ATTR_NO_UHR: UHR operation is not allowed on this channel 4457 + * in current regulatory domain. 4481 4458 * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number 4482 4459 * currently defined 4483 4460 * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use ··· 4529 4502 NL80211_FREQUENCY_ATTR_NO_8MHZ, 4530 4503 NL80211_FREQUENCY_ATTR_NO_16MHZ, 4531 4504 NL80211_FREQUENCY_ATTR_S1G_NO_PRIMARY, 4505 + NL80211_FREQUENCY_ATTR_NO_UHR, 4532 4506 4533 4507 /* keep last */ 4534 4508 __NL80211_FREQUENCY_ATTR_AFTER_LAST, ··· 4743 4715 * despite NO_IR configuration. 4744 4716 * @NL80211_RRF_ALLOW_20MHZ_ACTIVITY: Allow activity in 20 MHz bandwidth, 4745 4717 * despite NO_IR configuration. 4718 + * @NL80211_RRF_NO_UHR: UHR operation not allowed 4746 4719 */ 4747 4720 enum nl80211_reg_rule_flags { 4748 4721 NL80211_RRF_NO_OFDM = 1 << 0, ··· 4770 4741 NL80211_RRF_NO_6GHZ_AFC_CLIENT = 1 << 23, 4771 4742 NL80211_RRF_ALLOW_6GHZ_VLP_AP = 1 << 24, 4772 4743 NL80211_RRF_ALLOW_20MHZ_ACTIVITY = 1 << 25, 4744 + NL80211_RRF_NO_UHR = 1 << 26, 4773 4745 }; 4774 4746 4775 4747 #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
+98 -4
net/wireless/nl80211.c
··· 332 332 return 0; 333 333 } 334 334 335 + static int validate_uhr_capa(const struct nlattr *attr, 336 + struct netlink_ext_ack *extack) 337 + { 338 + const u8 *data = nla_data(attr); 339 + unsigned int len = nla_len(attr); 340 + 341 + return ieee80211_uhr_capa_size_ok(data, len, false); 342 + } 343 + 335 344 /* policy for the attributes */ 336 345 static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR]; 337 346 ··· 943 934 [NL80211_ATTR_BSS_PARAM] = { .type = NLA_FLAG }, 944 935 [NL80211_ATTR_S1G_PRIMARY_2MHZ] = { .type = NLA_FLAG }, 945 936 [NL80211_ATTR_EPP_PEER] = { .type = NLA_FLAG }, 937 + [NL80211_ATTR_UHR_CAPABILITY] = 938 + NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_uhr_capa, 255), 939 + [NL80211_ATTR_DISABLE_UHR] = { .type = NLA_FLAG }, 946 940 }; 947 941 948 942 /* policy for the key attributes */ ··· 1330 1318 goto nla_put_failure; 1331 1319 if ((chan->flags & IEEE80211_CHAN_S1G_NO_PRIMARY) && 1332 1320 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_S1G_NO_PRIMARY)) 1321 + goto nla_put_failure; 1322 + if ((chan->flags & IEEE80211_CHAN_NO_UHR) && 1323 + nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_UHR)) 1333 1324 goto nla_put_failure; 1334 1325 } 1335 1326 ··· 1969 1954 { 1970 1955 const struct ieee80211_sta_he_cap *he_cap = &iftdata->he_cap; 1971 1956 const struct ieee80211_sta_eht_cap *eht_cap = &iftdata->eht_cap; 1957 + const struct ieee80211_sta_uhr_cap *uhr_cap = &iftdata->uhr_cap; 1972 1958 1973 1959 if (nl80211_put_iftypes(msg, NL80211_BAND_IFTYPE_ATTR_IFTYPES, 1974 1960 iftdata->types_mask)) ··· 2018 2002 mcs_nss_size, &eht_cap->eht_mcs_nss_supp) || 2019 2003 nla_put(msg, NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE, 2020 2004 ppe_thresh_size, eht_cap->eht_ppe_thres)) 2005 + return -ENOBUFS; 2006 + } 2007 + 2008 + if (uhr_cap->has_uhr) { 2009 + if (nla_put(msg, NL80211_BAND_IFTYPE_ATTR_UHR_CAP_MAC, 2010 + sizeof(uhr_cap->mac), &uhr_cap->mac) || 2011 + nla_put(msg, NL80211_BAND_IFTYPE_ATTR_UHR_CAP_PHY, 2012 + sizeof(uhr_cap->phy), &uhr_cap->phy)) 2021 2013 return -ENOBUFS; 2022 2014 } 2023 2015 ··· 6486 6462 cap->datalen - 1)) 6487 6463 return -EINVAL; 6488 6464 } 6465 + 6466 + cap = cfg80211_find_ext_elem(WLAN_EID_EXT_UHR_OPER, ies, ies_len); 6467 + if (cap) { 6468 + if (!cap->datalen) 6469 + return -EINVAL; 6470 + params->uhr_oper = (void *)(cap->data + 1); 6471 + if (!ieee80211_uhr_oper_size_ok((const u8 *)params->uhr_oper, 6472 + cap->datalen - 1, true)) 6473 + return -EINVAL; 6474 + } 6475 + 6489 6476 return 0; 6490 6477 } 6491 6478 ··· 6626 6591 6627 6592 if ((params->eht_cap || params->eht_oper) && 6628 6593 (channel->flags & IEEE80211_CHAN_NO_EHT)) 6594 + return -EOPNOTSUPP; 6595 + 6596 + if (params->uhr_oper && (channel->flags & IEEE80211_CHAN_NO_UHR)) 6629 6597 return -EOPNOTSUPP; 6630 6598 6631 6599 return 0; ··· 7213 7175 break; 7214 7176 case RATE_INFO_BW_EHT_RU: 7215 7177 rate_flg = 0; 7216 - WARN_ON(!(info->flags & RATE_INFO_FLAGS_EHT_MCS)); 7178 + WARN_ON(!(info->flags & RATE_INFO_FLAGS_EHT_MCS) && 7179 + !(info->flags & RATE_INFO_FLAGS_UHR_MCS)); 7217 7180 break; 7218 7181 } 7219 7182 ··· 7266 7227 if (info->bw == RATE_INFO_BW_EHT_RU && 7267 7228 nla_put_u8(msg, NL80211_RATE_INFO_EHT_RU_ALLOC, 7268 7229 info->eht_ru_alloc)) 7230 + return false; 7231 + } else if (info->flags & RATE_INFO_FLAGS_UHR_MCS) { 7232 + if (nla_put_u8(msg, NL80211_RATE_INFO_UHR_MCS, info->mcs)) 7233 + return false; 7234 + if (nla_put_u8(msg, NL80211_RATE_INFO_EHT_NSS, info->nss)) 7235 + return false; 7236 + if (nla_put_u8(msg, NL80211_RATE_INFO_EHT_GI, info->eht_gi)) 7237 + return false; 7238 + if (info->bw == RATE_INFO_BW_EHT_RU && 7239 + nla_put_u8(msg, NL80211_RATE_INFO_EHT_RU_ALLOC, 7240 + info->eht_ru_alloc)) 7241 + return false; 7242 + if (info->flags & RATE_INFO_FLAGS_UHR_ELR_MCS && 7243 + nla_put_flag(msg, NL80211_RATE_INFO_UHR_ELR)) 7244 + return false; 7245 + if (info->flags & RATE_INFO_FLAGS_UHR_IM && 7246 + nla_put_flag(msg, NL80211_RATE_INFO_UHR_IM)) 7269 7247 return false; 7270 7248 } 7271 7249 ··· 8157 8101 if (params->ext_capab || params->link_sta_params.ht_capa || 8158 8102 params->link_sta_params.vht_capa || 8159 8103 params->link_sta_params.he_capa || 8160 - params->link_sta_params.eht_capa) 8104 + params->link_sta_params.eht_capa || 8105 + params->link_sta_params.uhr_capa) 8161 8106 return -EINVAL; 8162 8107 if (params->sta_flags_mask & BIT(NL80211_STA_FLAG_SPP_AMSDU)) 8163 8108 return -EINVAL; ··· 8376 8319 false)) 8377 8320 return -EINVAL; 8378 8321 } 8322 + } 8323 + 8324 + if (info->attrs[NL80211_ATTR_UHR_CAPABILITY]) { 8325 + if (!params->link_sta_params.eht_capa) 8326 + return -EINVAL; 8327 + 8328 + params->link_sta_params.uhr_capa = 8329 + nla_data(info->attrs[NL80211_ATTR_UHR_CAPABILITY]); 8330 + params->link_sta_params.uhr_capa_len = 8331 + nla_len(info->attrs[NL80211_ATTR_UHR_CAPABILITY]); 8379 8332 } 8380 8333 8381 8334 if (info->attrs[NL80211_ATTR_S1G_CAPABILITY]) ··· 8708 8641 } 8709 8642 } 8710 8643 8644 + if (info->attrs[NL80211_ATTR_UHR_CAPABILITY]) { 8645 + if (!params.link_sta_params.eht_capa) 8646 + return -EINVAL; 8647 + 8648 + params.link_sta_params.uhr_capa = 8649 + nla_data(info->attrs[NL80211_ATTR_UHR_CAPABILITY]); 8650 + params.link_sta_params.uhr_capa_len = 8651 + nla_len(info->attrs[NL80211_ATTR_UHR_CAPABILITY]); 8652 + } 8653 + 8711 8654 if (info->attrs[NL80211_ATTR_EML_CAPABILITY]) { 8712 8655 params.eml_cap_present = true; 8713 8656 params.eml_cap = ··· 8777 8700 params.link_sta_params.ht_capa = NULL; 8778 8701 params.link_sta_params.vht_capa = NULL; 8779 8702 8780 - /* HE and EHT require WME */ 8703 + /* HE, EHT and UHR require WME */ 8781 8704 if (params.link_sta_params.he_capa_len || 8782 8705 params.link_sta_params.he_6ghz_capa || 8783 - params.link_sta_params.eht_capa_len) 8706 + params.link_sta_params.eht_capa_len || 8707 + params.link_sta_params.uhr_capa_len) 8784 8708 return -EINVAL; 8785 8709 } 8786 8710 ··· 12454 12376 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_EHT])) 12455 12377 req.flags |= ASSOC_REQ_DISABLE_EHT; 12456 12378 12379 + if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_UHR])) 12380 + req.flags |= ASSOC_REQ_DISABLE_UHR; 12381 + 12457 12382 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) 12458 12383 memcpy(&req.vht_capa_mask, 12459 12384 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]), ··· 13328 13247 13329 13248 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_EHT])) 13330 13249 connect.flags |= ASSOC_REQ_DISABLE_EHT; 13250 + 13251 + if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_UHR])) 13252 + connect.flags |= ASSOC_REQ_DISABLE_UHR; 13331 13253 13332 13254 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) 13333 13255 memcpy(&connect.vht_capa_mask, ··· 17762 17678 false)) 17763 17679 return -EINVAL; 17764 17680 } 17681 + } 17682 + 17683 + if (info->attrs[NL80211_ATTR_UHR_CAPABILITY]) { 17684 + if (!params.eht_capa) 17685 + return -EINVAL; 17686 + 17687 + params.uhr_capa = 17688 + nla_data(info->attrs[NL80211_ATTR_UHR_CAPABILITY]); 17689 + params.uhr_capa_len = 17690 + nla_len(info->attrs[NL80211_ATTR_UHR_CAPABILITY]); 17765 17691 } 17766 17692 17767 17693 if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
+3 -1
net/wireless/reg.c
··· 5 5 * Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com> 6 6 * Copyright 2013-2014 Intel Mobile Communications GmbH 7 7 * Copyright 2017 Intel Deutschland GmbH 8 - * Copyright (C) 2018 - 2025 Intel Corporation 8 + * Copyright (C) 2018 - 2026 Intel Corporation 9 9 * 10 10 * Permission to use, copy, modify, and/or distribute this software for any 11 11 * purpose with or without fee is hereby granted, provided that the above ··· 1605 1605 channel_flags |= IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP; 1606 1606 if (rd_flags & NL80211_RRF_ALLOW_20MHZ_ACTIVITY) 1607 1607 channel_flags |= IEEE80211_CHAN_ALLOW_20MHZ_ACTIVITY; 1608 + if (rd_flags & NL80211_RRF_NO_UHR) 1609 + channel_flags |= IEEE80211_CHAN_NO_UHR; 1608 1610 return channel_flags; 1609 1611 } 1610 1612
+79 -22
net/wireless/util.c
··· 5 5 * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net> 6 6 * Copyright 2013-2014 Intel Mobile Communications GmbH 7 7 * Copyright 2017 Intel Deutschland GmbH 8 - * Copyright (C) 2018-2023, 2025 Intel Corporation 8 + * Copyright (C) 2018-2023, 2025-2026 Intel Corporation 9 9 */ 10 10 #include <linux/export.h> 11 11 #include <linux/bitops.h> ··· 1574 1574 return result / 10000; 1575 1575 } 1576 1576 1577 - static u32 cfg80211_calculate_bitrate_eht(struct rate_info *rate) 1577 + static u32 _cfg80211_calculate_bitrate_eht_uhr(struct rate_info *rate) 1578 1578 { 1579 1579 #define SCALE 6144 1580 - static const u32 mcs_divisors[16] = { 1581 - 102399, /* 16.666666... */ 1582 - 51201, /* 8.333333... */ 1583 - 34134, /* 5.555555... */ 1584 - 25599, /* 4.166666... */ 1585 - 17067, /* 2.777777... */ 1586 - 12801, /* 2.083333... */ 1587 - 11377, /* 1.851725... */ 1588 - 10239, /* 1.666666... */ 1589 - 8532, /* 1.388888... */ 1590 - 7680, /* 1.250000... */ 1591 - 6828, /* 1.111111... */ 1592 - 6144, /* 1.000000... */ 1593 - 5690, /* 0.926106... */ 1594 - 5120, /* 0.833333... */ 1595 - 409600, /* 66.666666... */ 1596 - 204800, /* 33.333333... */ 1580 + static const u32 mcs_divisors[] = { 1581 + [ 0] = 102399, /* 16.666666... */ 1582 + [ 1] = 51201, /* 8.333333... */ 1583 + [ 2] = 34134, /* 5.555555... */ 1584 + [ 3] = 25599, /* 4.166666... */ 1585 + [ 4] = 17067, /* 2.777777... */ 1586 + [ 5] = 12801, /* 2.083333... */ 1587 + [ 6] = 11377, /* 1.851725... */ 1588 + [ 7] = 10239, /* 1.666666... */ 1589 + [ 8] = 8532, /* 1.388888... */ 1590 + [ 9] = 7680, /* 1.250000... */ 1591 + [10] = 6828, /* 1.111111... */ 1592 + [11] = 6144, /* 1.000000... */ 1593 + [12] = 5690, /* 0.926106... */ 1594 + [13] = 5120, /* 0.833333... */ 1595 + [14] = 409600, /* 66.666666... */ 1596 + [15] = 204800, /* 33.333333... */ 1597 + [17] = 38400, /* 6.250180... */ 1598 + [19] = 19200, /* 3.125090... */ 1599 + [20] = 15360, /* 2.500000... */ 1600 + [23] = 9600, /* 1.562545... */ 1597 1601 }; 1598 1602 static const u32 rates_996[3] = { 480388888, 453700000, 408333333 }; 1599 1603 static const u32 rates_484[3] = { 229411111, 216666666, 195000000 }; ··· 1608 1604 u64 tmp; 1609 1605 u32 result; 1610 1606 1611 - if (WARN_ON_ONCE(rate->mcs > 15)) 1612 - return 0; 1613 1607 if (WARN_ON_ONCE(rate->eht_gi > NL80211_RATE_INFO_EHT_GI_3_2)) 1614 1608 return 0; 1615 1609 if (WARN_ON_ONCE(rate->eht_ru_alloc > ··· 1688 1686 rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_26) 1689 1687 result = rates_26[rate->eht_gi]; 1690 1688 else { 1691 - WARN(1, "invalid EHT MCS: bw:%d, ru:%d\n", 1689 + WARN(1, "invalid EHT or UHR MCS: bw:%d, ru:%d\n", 1692 1690 rate->bw, rate->eht_ru_alloc); 1693 1691 return 0; 1694 1692 } ··· 1702 1700 tmp *= rate->nss; 1703 1701 do_div(tmp, 8); 1704 1702 1703 + /* and handle interference mitigation - 0.9x */ 1704 + if (rate->flags & RATE_INFO_FLAGS_UHR_IM) { 1705 + if (WARN(rate->nss != 1 || rate->mcs == 15, 1706 + "invalid NSS or MCS for UHR IM\n")) 1707 + return 0; 1708 + tmp *= 9000; 1709 + do_div(tmp, 10000); 1710 + } 1711 + 1705 1712 result = tmp; 1706 1713 1707 1714 return result / 10000; 1715 + } 1716 + 1717 + static u32 cfg80211_calculate_bitrate_eht(struct rate_info *rate) 1718 + { 1719 + if (WARN_ONCE(rate->mcs > 15, "bad EHT MCS %d\n", rate->mcs)) 1720 + return 0; 1721 + 1722 + if (WARN_ONCE(rate->flags & (RATE_INFO_FLAGS_UHR_ELR_MCS | 1723 + RATE_INFO_FLAGS_UHR_IM), 1724 + "bad EHT MCS flags 0x%x\n", rate->flags)) 1725 + return 0; 1726 + 1727 + return _cfg80211_calculate_bitrate_eht_uhr(rate); 1728 + } 1729 + 1730 + static u32 cfg80211_calculate_bitrate_uhr(struct rate_info *rate) 1731 + { 1732 + if (rate->flags & RATE_INFO_FLAGS_UHR_ELR_MCS) { 1733 + WARN_ONCE(rate->eht_gi != NL80211_RATE_INFO_EHT_GI_1_6, 1734 + "bad UHR ELR guard interval %d\n", 1735 + rate->eht_gi); 1736 + WARN_ONCE(rate->mcs > 1, "bad UHR ELR MCS %d\n", rate->mcs); 1737 + WARN_ONCE(rate->nss != 1, "bad UHR ELR NSS %d\n", rate->nss); 1738 + WARN_ONCE(rate->bw != RATE_INFO_BW_20, 1739 + "bad UHR ELR bandwidth %d\n", 1740 + rate->bw); 1741 + WARN_ONCE(rate->flags & RATE_INFO_FLAGS_UHR_IM, 1742 + "bad UHR MCS flags 0x%x\n", rate->flags); 1743 + if (rate->mcs == 0) 1744 + return 17; 1745 + return 33; 1746 + } 1747 + 1748 + switch (rate->mcs) { 1749 + case 0 ... 15: 1750 + case 17: 1751 + case 19: 1752 + case 20: 1753 + case 23: 1754 + return _cfg80211_calculate_bitrate_eht_uhr(rate); 1755 + } 1756 + 1757 + WARN_ONCE(1, "bad UHR MCS %d\n", rate->mcs); 1758 + return 0; 1708 1759 } 1709 1760 1710 1761 static u32 cfg80211_calculate_bitrate_s1g(struct rate_info *rate) ··· 1884 1829 return cfg80211_calculate_bitrate_he(rate); 1885 1830 if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) 1886 1831 return cfg80211_calculate_bitrate_eht(rate); 1832 + if (rate->flags & RATE_INFO_FLAGS_UHR_MCS) 1833 + return cfg80211_calculate_bitrate_uhr(rate); 1887 1834 if (rate->flags & RATE_INFO_FLAGS_S1G_MCS) 1888 1835 return cfg80211_calculate_bitrate_s1g(rate); 1889 1836