[PATCH v2 5/7] initial UHR support
Johannes Berg
johannes at sipsolutions.net
Tue Mar 17 09:35:53 PDT 2026
From: Johannes Berg <johannes.berg at intel.com>
Add initial UHR support, based on a very "superficial"
reading of D1.3 (it's incomplete and not well-specified
in quite a few places.)
Reviewed-by: Benjamin Berg <benjamin.berg at intel.com>
Signed-off-by: Johannes Berg <johannes.berg at intel.com>
---
hostapd/Android.mk | 6 ++
hostapd/Makefile | 6 ++
hostapd/config_file.c | 8 ++
hostapd/hostapd.conf | 13 +++
src/ap/ap_config.h | 6 ++
src/ap/ap_drv_ops.c | 4 +
src/ap/ap_drv_ops.h | 2 +
src/ap/beacon.c | 42 +++++++++
src/ap/ctrl_iface_ap.c | 16 ++++
src/ap/hostapd.h | 6 ++
src/ap/ieee802_11.c | 53 ++++++++++-
src/ap/ieee802_11.h | 13 +++
src/ap/ieee802_11_uhr.c | 145 ++++++++++++++++++++++++++++++
src/ap/sta_info.c | 10 ++-
src/ap/sta_info.h | 65 +++++++-------
src/common/ieee802_11_common.c | 16 ++++
src/common/ieee802_11_common.h | 4 +
src/common/ieee802_11_defs.h | 36 ++++++++
src/drivers/driver.h | 28 ++++++
src/drivers/driver_common.c | 6 ++
wpa_supplicant/Android.mk | 3 +
wpa_supplicant/Makefile | 7 ++
wpa_supplicant/config.c | 1 +
wpa_supplicant/config_file.c | 1 +
wpa_supplicant/config_ssid.h | 8 ++
wpa_supplicant/ctrl_iface.c | 8 +-
wpa_supplicant/events.c | 13 +++
wpa_supplicant/sme.c | 1 +
wpa_supplicant/wpa_cli.c | 1 +
wpa_supplicant/wpa_supplicant.c | 17 +++-
wpa_supplicant/wpa_supplicant_i.h | 4 +
31 files changed, 508 insertions(+), 41 deletions(-)
create mode 100644 src/ap/ieee802_11_uhr.c
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 042f51280427..69c1edbf9bc4 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -299,6 +299,12 @@ ifdef CONFIG_IEEE80211AC
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211BN
+CONFIG_IEEE80211BE=y
+L_CFLAGS += -DCONFIG_IEEE80211BN
+OBJS += src/ap/ieee802_11_uhr.c
+endif
+
ifdef CONFIG_IEEE80211BE
CONFIG_IEEE80211AX=y
L_CFLAGS += -DCONFIG_IEEE80211BE
diff --git a/hostapd/Makefile b/hostapd/Makefile
index c67f874dac4b..a5bdb28a5f62 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -344,6 +344,12 @@ ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211BN
+CONFIG_IEEE80211BE=y
+CFLAGS += -DCONFIG_IEEE80211BN
+OBJS += ../src/ap/ieee802_11_uhr.o
+endif
+
ifdef CONFIG_IEEE80211BE
CONFIG_IEEE80211AX=y
CFLAGS += -DCONFIG_IEEE80211BE
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 545683871a15..1d5fa9ee7a8d 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -4876,6 +4876,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->disable_11ax = !!atoi(pos);
} else if (os_strcmp(buf, "disable_11be") == 0) {
bss->disable_11be = !!atoi(pos);
+ } else if (os_strcmp(buf, "disable_11bn") == 0) {
+ bss->disable_11bn = !!atoi(pos);
#ifdef CONFIG_PASN
#ifdef CONFIG_TESTING_OPTIONS
} else if (os_strcmp(buf, "force_kdk_derivation") == 0) {
@@ -4973,6 +4975,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->mld_indicate_disabled = atoi(pos);
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_IEEE80211BE */
+#ifdef CONFIG_IEEE80211BN
+ } else if (os_strcmp(buf, "ieee80211bn") == 0) {
+ conf->ieee80211bn = atoi(pos);
+ } else if (os_strcmp(buf, "require_uhr") == 0) {
+ conf->require_uhr = atoi(pos);
+#endif /* CONFIG_IEEE80211BN */
} else if (os_strcmp(buf, "i2r_lmr_policy") == 0) {
conf->i2r_lmr_policy = atoi(pos);
} else {
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 9e3f9d4d524c..27d5a5a39053 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1125,6 +1125,19 @@ wmm_ac_vo_acm=0
# will be used as the AP MLD MAC address.
#mld_addr=02:03:04:05:06:07
+##### IEEE 802.11bn related configuration #####################################
+
+#ieee80211bn: Whether IEEE 802.11bn (UHR) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+#ieee80211bn=1
+
+#disable_11bn: Boolean (0/1) to disable UHR for a specific BSS
+#disable_11bn=0
+
+# Require stations to support UHR PHY (reject association if they do not)
+#require_uhr=0
+
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 15bee01b5ca2..c3ed1893f8af 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -569,6 +569,7 @@ struct hostapd_bss_config {
bool disable_11ac;
bool disable_11ax;
bool disable_11be;
+ bool disable_11bn;
/* IEEE 802.11v */
int time_advertisement;
@@ -1233,6 +1234,11 @@ struct hostapd_config {
int require_eht;
#endif /* CONFIG_IEEE80211BE */
+ int ieee80211bn;
+#ifdef CONFIG_IEEE80211BN
+ bool require_uhr;
+#endif
+
/* EHT enable/disable config from CHAN_SWITCH */
#define CH_SWITCH_EHT_ENABLED BIT(0)
#define CH_SWITCH_EHT_DISABLED BIT(1)
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 61b823abe138..7234eb316f98 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -477,6 +477,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
size_t he_capab_len,
const struct ieee80211_eht_capabilities *eht_capab,
size_t eht_capab_len,
+ const struct ieee80211_uhr_capabilities *uhr_capab,
+ size_t uhr_capab_len,
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set, const u8 *link_addr, bool mld_link_sta,
@@ -502,6 +504,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.he_capab_len = he_capab_len;
params.eht_capab = eht_capab;
params.eht_capab_len = eht_capab_len;
+ params.uhr_capab = uhr_capab;
+ params.uhr_capab_len = uhr_capab_len;
params.he_6ghz_capab = he_6ghz_capab;
params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
params.vht_opmode = vht_opmode;
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 66913ed0fca7..f09b3ad9a306 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -47,6 +47,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
size_t he_capab_len,
const struct ieee80211_eht_capabilities *eht_capab,
size_t eht_capab_len,
+ const struct ieee80211_uhr_capabilities *uhr_capab,
+ size_t uhr_capab_len,
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set, const u8 *link_addr, bool mld_link_sta,
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index f16ff1fdcb06..f6ac012787e2 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -805,6 +805,13 @@ static size_t hostapd_probe_resp_elems_len(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211BE */
+#ifdef CONFIG_IEEE80211BN
+ if (hostapd_is_uhr_enabled(hapd)) {
+ buflen += hostapd_eid_uhr_capab_len(hapd, IEEE80211_MODE_AP);
+ buflen += 3 + IEEE80211_UHR_OPER_MAX_SIZE;
+ }
+#endif /* CONFIG_IEEE80211BN */
+
buflen += hostapd_eid_mbssid_len(hapd_probed, WLAN_FC_STYPE_PROBE_RESP,
NULL,
params->known_bss,
@@ -977,6 +984,13 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211BE */
+#ifdef CONFIG_IEEE80211BN
+ if (hostapd_is_uhr_enabled(hapd)) {
+ pos = hostapd_eid_uhr_capab(hapd, pos, IEEE80211_MODE_AP);
+ pos = hostapd_eid_uhr_operation(hapd, pos, false);
+ }
+#endif /* CONFIG_IEEE80211BN */
+
#ifdef CONFIG_IEEE80211AC
if (hapd->conf->vendor_vht)
pos = hostapd_eid_vendor_vht(hapd, pos);
@@ -2295,6 +2309,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211BE */
+#ifdef CONFIG_IEEE80211BN
+ if (hostapd_is_uhr_enabled(hapd))
+ tail_len += 3 + sizeof(struct ieee80211_uhr_operation);
+#endif /* CONFIG_IEEE80211BN */
+
if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
hapd == hostapd_mbssid_get_tx_bss(hapd))
tail_len += 5; /* Multiple BSSID Configuration element */
@@ -2477,6 +2496,25 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211BE */
+#ifdef CONFIG_IEEE80211BN
+ if (hostapd_is_uhr_enabled(hapd)) {
+ u8 *uhr_oper;
+
+ tailpos = hostapd_eid_uhr_operation(hapd, tailpos, true);
+ params->uhr_oper = os_zalloc(3 + IEEE80211_UHR_OPER_MAX_SIZE);
+ if (!params->uhr_oper)
+ goto error;
+
+ uhr_oper = hostapd_eid_uhr_operation(hapd, params->uhr_oper,
+ false);
+ /* check that it was filled */
+ if (uhr_oper == params->uhr_oper) {
+ os_free(params->uhr_oper);
+ params->uhr_oper = NULL;
+ }
+ }
+#endif /* CONFIG_IEEE80211BN */
+
#ifdef CONFIG_IEEE80211AC
if (hapd->conf->vendor_vht)
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
@@ -2683,6 +2721,8 @@ error:
os_free(head);
os_free(tail);
os_free(resp);
+ os_free(params->uhr_oper);
+ params->uhr_oper = NULL;
return -1;
#endif /* CONFIG_SAE || NEED_AP_MLME */
}
@@ -2714,6 +2754,8 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
#endif /* CONFIG_IEEE80211AX */
os_free(params->allowed_freqs);
params->allowed_freqs = NULL;
+ os_free(params->uhr_oper);
+ params->uhr_oper = NULL;
}
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index f2093018b939..57aa05e1dccc 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -405,6 +405,20 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211BE */
+#ifdef CONFIG_IEEE80211BN
+ if ((sta->flags & WLAN_STA_UHR) && sta->uhr_capab) {
+ res = os_snprintf(buf + len, buflen - len, "uhr_capab=");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ len += wpa_snprintf_hex(buf + len, buflen - len,
+ (const u8 *) sta->uhr_capab,
+ sta->uhr_capab_len);
+ res = os_snprintf(buf + len, buflen - len, "\n");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ }
+#endif /* CONFIG_IEEE80211BN */
+
#ifdef CONFIG_IEEE80211AC
if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
res = os_snprintf(buf + len, buflen - len,
@@ -885,6 +899,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
"ieee80211ac=%d\n"
"ieee80211ax=%d\n"
"ieee80211be=%d\n"
+ "ieee80211bn=%d\n"
"beacon_int=%u\n"
"dtim_period=%d\n",
iface->conf->channel,
@@ -896,6 +911,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
hostapd_is_vht_enabled(hapd),
hostapd_is_he_enabled(hapd),
hostapd_is_eht_enabled(hapd),
+ hostapd_is_uhr_enabled(hapd),
iface->conf->beacon_int,
hapd->conf->dtim_period);
if (os_snprintf_error(buflen - len, ret))
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index be09bb36c93b..11ef777bcbd8 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -944,4 +944,10 @@ hostapd_is_eht_enabled(struct hostapd_data *hapd)
return hapd->iconf->ieee80211be && !hapd->conf->disable_11be;
}
+static inline bool
+hostapd_is_uhr_enabled(struct hostapd_data *hapd)
+{
+ return hapd->iconf->ieee80211bn && !hapd->conf->disable_11bn;
+}
+
#endif /* HOSTAPD_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index bb8defeb6c7e..acaead60be50 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -151,6 +151,11 @@ static size_t hostapd_supp_rates(struct hostapd_data *hapd, u8 *buf)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_EHT_PHY;
#endif /* CONFIG_IEEE80211BE */
+#ifdef CONFIG_IEEE80211BN
+ if (hapd->iconf->ieee80211bn && hapd->iconf->require_uhr)
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_UHR_PHY;
+#endif /* CONFIG_IEEE80211BN */
+
#ifdef CONFIG_SAE
if ((hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
@@ -4667,6 +4672,24 @@ static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
}
}
#endif /* CONFIG_IEEE80211BE */
+#ifdef CONFIG_IEEE80211BN
+ if (hostapd_is_uhr_enabled(hapd)) {
+ resp = copy_sta_uhr_capab(hapd, sta, IEEE80211_MODE_AP,
+ elems->uhr_capabilities,
+ elems->uhr_capabilities_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+
+ if (hapd->iconf->require_uhr && !(sta->flags & WLAN_STA_UHR)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Station does not support mandatory UHR PHY - reject association");
+ /* FIXME - need assignment from spec */
+ return WLAN_STATUS_DENIED_EHT_NOT_SUPPORTED;
+ }
+ }
+#endif /* CONFIG_IEEE80211BN */
#ifdef CONFIG_P2P
if (elems->p2p && ies && ies_len) {
@@ -5254,6 +5277,13 @@ void ieee80211_ml_build_assoc_resp(struct hostapd_data *hapd,
}
}
+#ifdef CONFIG_IEEE80211BN
+ if (hostapd_is_uhr_enabled(hapd)) {
+ p = hostapd_eid_uhr_capab(hapd, p, IEEE80211_MODE_AP);
+ p = hostapd_eid_uhr_operation(hapd, p, false);
+ }
+#endif /* CONFIG_IEEE80211BN */
+
p = hostapd_eid_ext_capab(hapd, p, false);
p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
p = hostapd_eid_wmm(hapd, p);
@@ -5525,6 +5555,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
struct ieee80211_vht_capabilities vht_cap;
struct ieee80211_he_capabilities he_cap;
struct ieee80211_eht_capabilities eht_cap;
+ struct ieee80211_uhr_capabilities uhr_cap;
int set = 1;
const u8 *mld_link_addr = NULL;
bool mld_link_sta = false, epp_sta = false;
@@ -5606,6 +5637,11 @@ static int add_associated_sta(struct hostapd_data *hapd,
hostapd_get_eht_capab(hapd, sta->eht_capab, &eht_cap,
sta->eht_capab_len);
#endif /* CONFIG_IEEE80211BE */
+#ifdef CONFIG_IEEE80211BN
+ if (sta->flags & WLAN_STA_UHR)
+ hostapd_get_uhr_capab(hapd, sta->uhr_capab, &uhr_cap,
+ sta->uhr_capab_len);
+#endif /* CONFIG_IEEE80211BN */
/*
* Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
@@ -5621,6 +5657,8 @@ static int add_associated_sta(struct hostapd_data *hapd,
sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
sta->flags & WLAN_STA_EHT ? &eht_cap : NULL,
sta->flags & WLAN_STA_EHT ? sta->eht_capab_len : 0,
+ sta->flags & WLAN_STA_UHR ? &uhr_cap : NULL,
+ sta->flags & WLAN_STA_UHR ? sta->uhr_capab_len : 0,
sta->he_6ghz_capab,
sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
sta->vht_opmode, sta->p2p_ie ? 1 : 0,
@@ -5682,6 +5720,12 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
buflen += hostapd_eid_eht_ml_tid_to_link_map_len(hapd);
}
#endif /* CONFIG_IEEE80211BE */
+#ifdef CONFIG_IEEE80211BN
+ if (hostapd_is_uhr_enabled(hapd)) {
+ buflen += hostapd_eid_uhr_capab_len(hapd, IEEE80211_MODE_AP);
+ buflen += 3 + IEEE80211_UHR_OPER_MAX_SIZE;
+ }
+#endif /* CONFIG_IEEE80211BN */
buf = os_zalloc(buflen);
if (!buf) {
@@ -5844,6 +5888,13 @@ rsnxe_done:
}
#endif /* CONFIG_IEEE80211BE */
+#ifdef CONFIG_IEEE80211BN
+ if (hostapd_is_uhr_enabled(hapd)) {
+ p = hostapd_eid_uhr_capab(hapd, p, IEEE80211_MODE_AP);
+ p = hostapd_eid_uhr_operation(hapd, p, false);
+ }
+#endif /* CONFIG_IEEE80211BN */
+
#ifdef CONFIG_OWE
if (((hapd->conf->wpa_key_mgmt | hapd->conf->rsn_override_key_mgmt |
hapd->conf->rsn_override_key_mgmt_2) & WPA_KEY_MGMT_OWE) &&
@@ -6345,7 +6396,7 @@ static void handle_assoc(struct hostapd_data *hapd,
hostapd_logger(hapd, mgmt->sa,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
- "Station tried to associate before authentication (aid=%d flags=0x%x)",
+ "Station tried to associate before authentication (aid=%d flags=0x%llx)",
sta ? sta->aid : -1,
sta ? sta->flags : 0);
send_deauth(hapd, mgmt->sa,
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 991377c1c483..82c471e92725 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -328,4 +328,17 @@ void hostapd_link_reconf_resp_tx_status(struct hostapd_data *hapd,
size_t hostapd_eid_eht_ml_tid_to_link_map_len(struct hostapd_data *hapd);
u8 * hostapd_eid_eht_ml_tid_to_link_map(struct hostapd_data *hapd, u8 *eid);
+size_t hostapd_eid_uhr_capab_len(struct hostapd_data *hapd,
+ enum ieee80211_op_mode opmode);
+u8 * hostapd_eid_uhr_capab(struct hostapd_data *hapd, u8 *eid,
+ enum ieee80211_op_mode opmode);
+u8 * hostapd_eid_uhr_operation(struct hostapd_data *hapd, u8 *eid, bool beacon);
+u16 copy_sta_uhr_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ enum ieee80211_op_mode opmode,
+ const u8 *uhr_capab, size_t uhr_capab_len);
+void hostapd_get_uhr_capab(struct hostapd_data *hapd,
+ const struct ieee80211_uhr_capabilities *src,
+ struct ieee80211_uhr_capabilities *dest,
+ size_t len);
+
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_uhr.c b/src/ap/ieee802_11_uhr.c
new file mode 100644
index 000000000000..d7b00746bd93
--- /dev/null
+++ b/src/ap/ieee802_11_uhr.c
@@ -0,0 +1,145 @@
+/*
+ * hostapd / IEEE 802.11bn UHR
+ * Copyright (C) 2025 Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "common/ocv.h"
+#include "common/wpa_ctrl.h"
+#include "crypto/crypto.h"
+#include "crypto/dh_groups.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_drv_ops.h"
+#include "wpa_auth.h"
+#include "ieee802_11.h"
+
+
+size_t hostapd_eid_uhr_capab_len(struct hostapd_data *hapd,
+ enum ieee80211_op_mode opmode)
+{
+ struct hostapd_hw_modes *mode;
+ struct uhr_capabilities *uhr_cap;
+
+ mode = hapd->iface->current_mode;
+ if (!mode)
+ return 0;
+
+ uhr_cap = &mode->uhr_capab[opmode];
+ if (!uhr_cap->uhr_supported)
+ return 0;
+
+ return 6;
+}
+
+
+u8 * hostapd_eid_uhr_capab(struct hostapd_data *hapd, u8 *eid,
+ enum ieee80211_op_mode opmode)
+{
+ struct hostapd_hw_modes *mode;
+ struct uhr_capabilities *uhr_cap;
+ struct ieee80211_uhr_capabilities *cap;
+ u8 *pos = eid, *length_pos;
+
+ mode = hapd->iface->current_mode;
+ if (!mode)
+ return eid;
+
+ uhr_cap = &mode->uhr_capab[opmode];
+ if (!uhr_cap->uhr_supported)
+ return eid;
+
+ *pos++ = WLAN_EID_EXTENSION;
+ length_pos = pos++;
+ *pos++ = WLAN_EID_EXT_UHR_CAPABILITIES;
+
+ cap = (struct ieee80211_uhr_capabilities *) pos;
+ os_memcpy(cap->mac, uhr_cap->mac, sizeof(cap->mac));
+ os_memcpy(cap->phy, uhr_cap->phy, sizeof(cap->phy));
+ pos += sizeof(*cap);
+
+ *length_pos = pos - (eid + 2);
+ return pos;
+}
+
+
+u8 * hostapd_eid_uhr_operation(struct hostapd_data *hapd, u8 *eid, bool beacon)
+{
+ struct ieee80211_uhr_operation *oper;
+ u8 *pos = eid;
+
+ if (!hapd->iface->current_mode)
+ return eid;
+
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 1 + sizeof(*oper);
+ *pos++ = WLAN_EID_EXT_UHR_OPERATION;
+
+ oper = (void *) pos;
+ oper->oper_params = 0;
+
+ /* TODO: Fill in appropriate UHR-MCS max Nss information */
+ oper->basic_uhr_mcs_nss_set[0] = 0x11;
+ oper->basic_uhr_mcs_nss_set[1] = 0x00;
+ oper->basic_uhr_mcs_nss_set[2] = 0x00;
+ oper->basic_uhr_mcs_nss_set[3] = 0x00;
+
+ return pos + sizeof(*oper);
+}
+
+
+static bool ieee80211_invalid_uhr_cap_size(enum hostapd_hw_mode mode,
+ const u8 *uhr_cap, size_t len)
+{
+ return len < sizeof(struct ieee80211_uhr_capabilities);
+}
+
+
+u16 copy_sta_uhr_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ enum ieee80211_op_mode opmode,
+ const u8 *uhr_capab, size_t uhr_capab_len)
+{
+ struct hostapd_hw_modes *c_mode = hapd->iface->current_mode;
+ enum hostapd_hw_mode mode = c_mode ? c_mode->mode : NUM_HOSTAPD_MODES;
+
+ if (!hostapd_is_uhr_enabled(hapd) || !uhr_capab ||
+ ieee80211_invalid_uhr_cap_size(mode, uhr_capab, uhr_capab_len)) {
+ sta->flags &= ~WLAN_STA_UHR;
+ os_free(sta->uhr_capab);
+ sta->uhr_capab = NULL;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ os_free(sta->uhr_capab);
+ sta->uhr_capab = os_memdup(uhr_capab, uhr_capab_len);
+ if (!sta->uhr_capab) {
+ sta->uhr_capab_len = 0;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->flags |= WLAN_STA_UHR;
+ sta->uhr_capab_len = uhr_capab_len;
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+void hostapd_get_uhr_capab(struct hostapd_data *hapd,
+ const struct ieee80211_uhr_capabilities *src,
+ struct ieee80211_uhr_capabilities *dest,
+ size_t len)
+{
+ if (!src || !dest)
+ return;
+
+ if (len > sizeof(*dest))
+ len = sizeof(*dest);
+ /* TODO: mask out unsupported features */
+
+ os_memset(dest, 0, sizeof(*dest));
+ os_memcpy(dest, src, len);
+}
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index fc16b1a426bd..386cd24b21c6 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -474,6 +474,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->he_capab);
os_free(sta->he_6ghz_capab);
os_free(sta->eht_capab);
+ os_free(sta->uhr_capab);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
@@ -596,7 +597,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
int reason;
int max_inactivity = hapd->conf->ap_max_inactivity;
- wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
+ wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%llx timeout_next=%d",
hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
sta->timeout_next);
if (sta->timeout_next == STA_REMOVE) {
@@ -1958,13 +1959,13 @@ void ap_sta_clear_assoc_timeout(struct hostapd_data *hapd,
}
-int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
+int ap_sta_flags_txt(unsigned long long flags, char *buf, size_t buflen)
{
int res;
buf[0] = '\0';
res = os_snprintf(buf, buflen,
- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1985,6 +1986,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
(flags & WLAN_STA_HE ? "[HE]" : ""),
(flags & WLAN_STA_EHT ? "[EHT]" : ""),
+ (flags & WLAN_STA_UHR ? "[UHR]" : ""),
(flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""),
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_SPP_AMSDU ? "[SPP-A-MSDU]" : ""),
@@ -2109,7 +2111,7 @@ int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
if (hostapd_sta_add(hapd, sta->addr, 0, 0,
sta->supported_rates,
sta->supported_rates_len,
- 0, NULL, NULL, NULL, 0, NULL, 0, NULL,
+ 0, NULL, NULL, NULL, 0, NULL, 0, NULL, 0, NULL,
sta->flags, 0, 0, 0, 0,
mld_link_addr, mld_link_sta, eml_cap, epp_sta)) {
hostapd_logger(hapd, sta->addr,
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index a7d6c280167d..4154739bb005 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -20,35 +20,36 @@
#include "hostapd.h"
/* STA flags */
-#define WLAN_STA_AUTH BIT(0)
-#define WLAN_STA_ASSOC BIT(1)
-#define WLAN_STA_SPP_AMSDU BIT(2)
-#define WLAN_STA_AUTHORIZED BIT(5)
-#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
-#define WLAN_STA_SHORT_PREAMBLE BIT(7)
-#define WLAN_STA_PREAUTH BIT(8)
-#define WLAN_STA_WMM BIT(9)
-#define WLAN_STA_MFP BIT(10)
-#define WLAN_STA_HT BIT(11)
-#define WLAN_STA_WPS BIT(12)
-#define WLAN_STA_MAYBE_WPS BIT(13)
-#define WLAN_STA_WDS BIT(14)
-#define WLAN_STA_ASSOC_REQ_OK BIT(15)
-#define WLAN_STA_WPS2 BIT(16)
-#define WLAN_STA_GAS BIT(17)
-#define WLAN_STA_VHT BIT(18)
-#define WLAN_STA_WNM_SLEEP_MODE BIT(19)
-#define WLAN_STA_VHT_OPMODE_ENABLED BIT(20)
-#define WLAN_STA_VENDOR_VHT BIT(21)
-#define WLAN_STA_PENDING_FILS_ERP BIT(22)
-#define WLAN_STA_MULTI_AP BIT(23)
-#define WLAN_STA_HE BIT(24)
-#define WLAN_STA_6GHZ BIT(25)
-#define WLAN_STA_PENDING_PASN_FILS_ERP BIT(26)
-#define WLAN_STA_EHT BIT(27)
-#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
-#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
-#define WLAN_STA_NONERP BIT(31)
+#define WLAN_STA_AUTH BIT_ULL(0)
+#define WLAN_STA_ASSOC BIT_ULL(1)
+#define WLAN_STA_SPP_AMSDU BIT_ULL(2)
+#define WLAN_STA_AUTHORIZED BIT_ULL(5)
+#define WLAN_STA_PENDING_POLL BIT_ULL(6) /* pending activity poll not ACKed */
+#define WLAN_STA_SHORT_PREAMBLE BIT_ULL(7)
+#define WLAN_STA_PREAUTH BIT_ULL(8)
+#define WLAN_STA_WMM BIT_ULL(9)
+#define WLAN_STA_MFP BIT_ULL(10)
+#define WLAN_STA_HT BIT_ULL(11)
+#define WLAN_STA_WPS BIT_ULL(12)
+#define WLAN_STA_MAYBE_WPS BIT_ULL(13)
+#define WLAN_STA_WDS BIT_ULL(14)
+#define WLAN_STA_ASSOC_REQ_OK BIT_ULL(15)
+#define WLAN_STA_WPS2 BIT_ULL(16)
+#define WLAN_STA_GAS BIT_ULL(17)
+#define WLAN_STA_VHT BIT_ULL(18)
+#define WLAN_STA_WNM_SLEEP_MODE BIT_ULL(19)
+#define WLAN_STA_VHT_OPMODE_ENABLED BIT_ULL(20)
+#define WLAN_STA_VENDOR_VHT BIT_ULL(21)
+#define WLAN_STA_PENDING_FILS_ERP BIT_ULL(22)
+#define WLAN_STA_MULTI_AP BIT_ULL(23)
+#define WLAN_STA_HE BIT_ULL(24)
+#define WLAN_STA_6GHZ BIT_ULL(25)
+#define WLAN_STA_PENDING_PASN_FILS_ERP BIT_ULL(26)
+#define WLAN_STA_EHT BIT_ULL(27)
+#define WLAN_STA_PENDING_DISASSOC_CB BIT_ULL(29)
+#define WLAN_STA_PENDING_DEAUTH_CB BIT_ULL(30)
+#define WLAN_STA_NONERP BIT_ULL(31)
+#define WLAN_STA_UHR BIT_ULL(32)
/* Maximum number of supported rates (from both Supported Rates and Extended
* Supported Rates IEs). */
@@ -93,7 +94,7 @@ struct sta_info {
struct dl_list ip6addr; /* list head for struct ip6addr */
u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
u16 disconnect_reason_code; /* RADIUS server override */
- u32 flags; /* Bitfield of WLAN_STA_* */
+ unsigned long long flags; /* Bitfield of WLAN_STA_* */
u16 capability;
u16 listen_interval; /* or beacon_int for APs */
u8 supported_rates[WLAN_SUPP_RATES_MAX];
@@ -207,6 +208,8 @@ struct sta_info {
struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
struct ieee80211_eht_capabilities *eht_capab;
size_t eht_capab_len;
+ struct ieee80211_uhr_capabilities *uhr_capab;
+ size_t uhr_capab_len;
int sa_query_count; /* number of pending SA Query requests;
* 0 = no SA Query in progress */
@@ -418,7 +421,7 @@ void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
void ap_sta_clear_assoc_timeout(struct hostapd_data *hapd,
struct sta_info *sta);
-int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
+int ap_sta_flags_txt(unsigned long long flags, char *buf, size_t buflen);
void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta,
unsigned timeout);
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 0fd15603c7b7..9b2e8823a7b8 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -434,6 +434,14 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
elems->pasn_encrypted_data = pos;
elems->pasn_encrypted_data_len = elen;
break;
+ case WLAN_EID_EXT_UHR_CAPABILITIES:
+ elems->uhr_capabilities = pos;
+ elems->uhr_capabilities_len = elen;
+ break;
+ case WLAN_EID_EXT_UHR_OPERATION:
+ elems->uhr_operation = pos;
+ elems->uhr_operation_len = elen;
+ break;
default:
if (show_errors) {
wpa_printf(MSG_MSGDUMP,
@@ -1008,6 +1016,14 @@ void ieee802_11_elems_clear_ext_ids(struct ieee802_11_elems *elems,
elems->eht_operation = NULL;
elems->eht_operation_len = 0;
break;
+ case WLAN_EID_EXT_UHR_CAPABILITIES:
+ elems->uhr_capabilities = NULL;
+ elems->uhr_capabilities_len = 0;
+ break;
+ case WLAN_EID_EXT_UHR_OPERATION:
+ elems->uhr_operation = NULL;
+ elems->uhr_operation_len = 0;
+ break;
}
}
}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 438f70dd57b5..a2cdaf41898e 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -128,6 +128,8 @@ struct ieee802_11_elems {
const u8 *rsn_selection;
const u8 *wfa_capab;
const u8 *proximity_ranging;
+ const u8 *uhr_capabilities;
+ const u8 *uhr_operation;
u8 ssid_len;
u8 supp_rates_len;
@@ -198,6 +200,8 @@ struct ieee802_11_elems {
size_t rsn_selection_len;
u8 wfa_capab_len;
size_t proximity_ranging_len;
+ u8 uhr_capabilities_len;
+ u8 uhr_operation_len;
struct mb_ies_info mb_ies;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 55e74f93ac08..17bd3d8d2946 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -541,6 +541,8 @@
#define WLAN_EID_EXT_BANDWIDTH_INDICATION 135
#define WLAN_EID_EXT_KNOWN_STA_IDENTIFICATION 136
#define WLAN_EID_EXT_PASN_ENCRYPTED_DATA 140
+#define WLAN_EID_EXT_UHR_OPERATION 151
+#define WLAN_EID_EXT_UHR_CAPABILITIES 152
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -1412,6 +1414,7 @@ struct ieee80211_ampe_ie {
#define HT_OPER_PARAM_PCO_PHASE ((u16) BIT(11))
/* B36..B39 - Reserved */
+#define BSS_MEMBERSHIP_SELECTOR_UHR_PHY 120
#define BSS_MEMBERSHIP_SELECTOR_EHT_PHY 121
#define BSS_MEMBERSHIP_SELECTOR_HE_PHY 122
#define BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY 123
@@ -3292,6 +3295,39 @@ struct ieee80211_s1g_beacon_compat {
le32 tsf_completion;
} STRUCT_PACKED;
+/* UHR Capabilities element format */
+struct ieee80211_uhr_capabilities {
+ /* UHR MAC Capabilities Information */
+ u8 mac[5];
+ /* UHR PHY Capabilities Information */
+ u8 phy[1];
+} STRUCT_PACKED;
+
+#define UHR_OPER_PARAMS_DPS_ENA 0x0001
+#define UHR_OPER_PARAMS_NPCA_ENA 0x0002
+#define UHR_OPER_PARAMS_PEDCA_ENA 0x0004
+#define UHR_OPER_PARAMS_DBE_ENA 0x0008
+
+/* UHR Operation element format */
+struct ieee80211_uhr_operation {
+ le16 oper_params; /* UHR Operation Parameters: UHR_OPER_* bits */
+ u8 basic_uhr_mcs_nss_set[4];
+ /* FIXME: DPS, P-EDCA, DBE */
+} STRUCT_PACKED;
+
+/* Max size in Draft P802.11bn D1.3 with DPS, NPCA, P-EDCA, DBE */
+#define IEEE80211_UHR_OPER_MAX_SIZE \
+ (sizeof(struct ieee80211_uhr_operation) + 4 + 6 + 3 + 3)
+
+/* IEEE P802.11bn/D1.3, Figure 9-aa4 */
+#define UHR_OPER_PARAMS_NPCA_PRIM_CHAN_OFFS 0x0000000F
+#define UHR_OPER_PARAMS_NPCA_NPCA_MIN_DUR_THRESH 0x000000F0
+#define UHR_OPER_PARAMS_NPCA_NPCA_SWITCH_DELAY 0x00003F00
+#define UHR_OPER_PARAMS_NPCA_NPCA_SWITCH_BACK_DELAY 0x000FC000
+#define UHR_OPER_PARAMS_NPCA_INIT_NPCA_QRSC 0x00300000
+#define UHR_OPER_PARAMS_NPCA_MOPLEN_NPCA 0x00400000
+#define UHR_OPER_PARAMS_NPCA_DIS_SUBCH_BITMAP_PRES 0x00800000
+
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index cefc73942ea6..d437dc7d58c5 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -216,6 +216,13 @@ struct eht_capabilities {
u8 ppet[EHT_PPE_THRESH_CAPAB_LEN];
};
+/* struct uhr_capabilities - IEEE 802.11bn UHR capabilities */
+struct uhr_capabilities {
+ bool uhr_supported;
+ u8 mac[5];
+ u8 phy[1];
+};
+
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
#define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1)
#define HOSTAPD_MODE_FLAG_HE_INFO_KNOWN BIT(2)
@@ -326,6 +333,11 @@ struct hostapd_hw_modes {
* eht_capab - EHT (IEEE 802.11be) capabilities
*/
struct eht_capabilities eht_capab[IEEE80211_MODE_NUM];
+
+ /**
+ * uhr_capab - UHR (IEEE 802.11bb) capabilities
+ */
+ struct uhr_capabilities uhr_capab[IEEE80211_MODE_NUM];
};
@@ -1403,6 +1415,11 @@ struct wpa_driver_associate_params {
*/
int disable_eht;
+ /**
+ * disable_uhr - Disable UHR for this connection
+ */
+ int disable_uhr;
+
/*
* mld_params - MLD association parameters
*/
@@ -1928,6 +1945,12 @@ struct wpa_driver_ap_params {
* sae_password - SAE password for SAE offload
*/
const char *sae_password;
+
+ /**
+ * uhr_oper - Full UHR operation (beacon only has abridged data),
+ * includes the extended element header
+ */
+ u8 *uhr_oper;
};
struct wpa_driver_mesh_bss_params {
@@ -2702,6 +2725,9 @@ struct hostapd_sta_add_params {
s8 mld_link_id;
const u8 *mld_link_addr;
u16 eml_cap;
+
+ const struct ieee80211_uhr_capabilities *uhr_capab;
+ size_t uhr_capab_len;
};
struct mac_address {
@@ -7380,6 +7406,8 @@ bool he_supported(const struct hostapd_hw_modes *hw_mode,
enum ieee80211_op_mode op_mode);
bool eht_supported(const struct hostapd_hw_modes *hw_mode,
enum ieee80211_op_mode op_mode);
+bool uhr_supported(const struct hostapd_hw_modes *hw_mode,
+ enum ieee80211_op_mode op_mode);
struct wowlan_triggers *
wpa_get_wowlan_triggers(const char *wowlan_triggers,
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 3653c639e843..97ddaa1670f8 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -220,6 +220,12 @@ bool eht_supported(const struct hostapd_hw_modes *hw_mode,
return hw_mode->eht_capab[op_mode].eht_supported;
}
+bool uhr_supported(const struct hostapd_hw_modes *hw_mode,
+ enum ieee80211_op_mode op_mode)
+{
+ return hw_mode->uhr_capab[op_mode].uhr_supported;
+}
+
static int wpa_check_wowlan_trigger(const char *start, const char *trigger,
int capa_trigger, u8 *param_trigger)
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index b8c7152c5b54..b63ab7a45cf8 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -975,6 +975,9 @@ endif
ifdef CONFIG_IEEE80211BE
OBJS += src/ap/ieee802_11_eht.c
endif
+ifdef CONFIG_IEEE80211BN
+OBJS += src/ap/ieee802_11_uhr.c
+endif
ifdef CONFIG_WNM_AP
L_CFLAGS += -DCONFIG_WNM_AP
OBJS += src/ap/wnm_ap.c
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index fbfc7307f93a..c6f3378ca9b5 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1049,6 +1049,9 @@ endif
ifdef CONFIG_IEEE80211BE
OBJS += ../src/ap/ieee802_11_eht.o
endif
+ifdef CONFIG_IEEE80211BN
+OBJS += ../src/ap/ieee802_11_uhr.o
+endif
ifdef CONFIG_WNM_AP
CFLAGS += -DCONFIG_WNM_AP
OBJS += ../src/ap/wnm_ap.o
@@ -1071,6 +1074,10 @@ OBJS += ../src/eap_server/eap_server_methods.o
ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211BN
+CONFIG_IEEE80211BE=y
+CFLAGS += -DCONFIG_IEEE80211BN
+endif
ifdef CONFIG_IEEE80211BE
CONFIG_IEEE80211AX=y
CFLAGS += -DCONFIG_IEEE80211BE
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 20dd4eaf3c9e..65a26bc4b719 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2835,6 +2835,7 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(transition_disable, 0, 255) },
{ INT_RANGE(sae_pk, 0, 2) },
{ INT_RANGE(disable_eht, 0, 1)},
+ { INT_RANGE(disable_uhr, 0, 1)},
{ INT_RANGE(enable_4addr_mode, 0, 1)},
{ INT_RANGE(max_idle, 0, 65535)},
{ INT_RANGE(ssid_protection, 0, 1)},
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 2f62e6cee167..e54b2dd4b598 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1019,6 +1019,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid,
INT(disable_he);
#endif /* CONFIG_HE_OVERRIDES */
INT(disable_eht);
+ INT(disable_uhr);
INT(enable_4addr_mode);
INT(max_idle);
INT(ssid_protection);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 43a13053090d..b1083fbacf75 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -1300,6 +1300,14 @@ struct wpa_ssid {
*/
int disable_eht;
+ /**
+ * disable_uhr - Disable UHR (IEEE 802.11bn) for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_uhr;
+
/**
* enable_4addr_mode - Set 4addr mode after association
* 0 = Do not attempt to set 4addr mode
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index f2125b0b44fc..727d2573a053 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2379,12 +2379,14 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
if (wpa_s->connection_set &&
(wpa_s->connection_ht || wpa_s->connection_vht ||
- wpa_s->connection_he || wpa_s->connection_eht)) {
+ wpa_s->connection_he || wpa_s->connection_eht ||
+ wpa_s->connection_uhr)) {
ret = os_snprintf(pos, end - pos,
"wifi_generation=%u\n",
+ wpa_s->connection_uhr ? 8 :
wpa_s->connection_eht ? 7 :
- (wpa_s->connection_he ? 6 :
- (wpa_s->connection_vht ? 5 : 4)));
+ wpa_s->connection_he ? 6 :
+ wpa_s->connection_vht ? 5 : 4);
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index c241ea2cf827..75fca81f3e91 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1063,6 +1063,17 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
continue;
}
+ if (flagged && ((rate_ie[j] & 0x7f) ==
+ BSS_MEMBERSHIP_SELECTOR_UHR_PHY)) {
+ if (!uhr_supported(mode, IEEE80211_MODE_INFRA)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " hardware does not support UHR PHY");
+ return 0;
+ }
+ continue;
+ }
+
#ifdef CONFIG_SAE
if (flagged && ((rate_ie[j] & 0x7f) ==
BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY)) {
@@ -3555,6 +3566,8 @@ static void wpas_parse_connection_info(struct wpa_supplicant *wpa_s,
resp_elems.eht_capabilities;
if (req_elems.rrm_enabled)
wpa_s->rrm.rrm_used = 1;
+ wpa_s->connection_uhr = req_elems.uhr_capabilities &&
+ resp_elems.uhr_capabilities;
#ifdef CONFIG_PMKSA_PRIVACY
if (wpa_s->assoc_resp_encrypted && resp_elems.nonce) {
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 8c6bc23e644d..005b498eebc4 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -2984,6 +2984,7 @@ mscs_fail:
wpa_supplicant_apply_he_overrides(wpa_s, ssid, ¶ms);
#endif /* CONFIG_HE_OVERRIDES */
wpa_supplicant_apply_eht_overrides(wpa_s, ssid, ¶ms);
+ wpa_supplicant_apply_uhr_overrides(wpa_s, ssid, ¶ms);
#ifdef CONFIG_IEEE80211R
if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies &&
get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len,
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 098ada6ceb6f..7542586e3caf 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1497,6 +1497,7 @@ static const char *network_fields[] = {
"disable_he",
#endif /* CONFIG_HE_OVERRIDES */
"disable_eht",
+ "disable_uhr",
"ap_max_inactivity", "dtim_period", "beacon_int",
#ifdef CONFIG_MACSEC
"macsec_policy",
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 937a26265e5b..d0756ade8e64 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -2258,7 +2258,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, 0);
}
- /* Mark WMM enabled for any HT/VHT/HE/EHT association to get more
+ /* Mark WMM enabled for any HT/VHT/HE/EHT/UHR association to get more
* appropriate advertisement of the supported number of PTKSA receive
* counters. In theory, this could be based on a driver capability, but
* in practice all cases using WMM support at least eight replay
@@ -2269,7 +2269,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
* is far more likely for any current device to support WMM. */
wmm = wpa_s->connection_set &&
(wpa_s->connection_ht || wpa_s->connection_vht ||
- wpa_s->connection_he || wpa_s->connection_eht);
+ wpa_s->connection_he || wpa_s->connection_eht ||
+ wpa_s->connection_uhr);
if (!wmm && bss)
wmm = !!wpa_bss_get_vendor_ie(bss, WMM_IE_VENDOR_TYPE);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_WMM_ENABLED, wmm);
@@ -4930,6 +4931,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_supplicant_apply_he_overrides(wpa_s, ssid, ¶ms);
#endif /* CONFIG_HE_OVERRIDES */
wpa_supplicant_apply_eht_overrides(wpa_s, ssid, ¶ms);
+ wpa_supplicant_apply_uhr_overrides(wpa_s, ssid, ¶ms);
#ifdef CONFIG_P2P
/*
@@ -6885,6 +6887,17 @@ void wpa_supplicant_apply_eht_overrides(
}
+void wpa_supplicant_apply_uhr_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params)
+{
+ if (!ssid)
+ return;
+
+ params->disable_uhr = ssid->disable_uhr;
+}
+
+
static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
{
#ifdef PCSC_FUNCS
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 4148e94ea06d..175a043b0b3a 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1011,6 +1011,7 @@ struct wpa_supplicant {
unsigned int connection_vht:1;
unsigned int connection_he:1;
unsigned int connection_eht:1;
+ unsigned int connection_uhr:1;
unsigned int disable_mbo_oce:1;
u8 connection_max_nss_rx;
u8 connection_max_nss_tx;
@@ -1710,6 +1711,9 @@ void wpa_supplicant_apply_he_overrides(
void wpa_supplicant_apply_eht_overrides(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_driver_associate_params *params);
+void wpa_supplicant_apply_uhr_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params);
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
--
2.53.0
More information about the Hostap
mailing list