mirror of
https://git.FreeBSD.org/src.git
synced 2024-10-18 02:19:39 +00:00
wpa: Import 2.11
Following is a changelog of new features and fixes to wpa: hostapd: * Wi-Fi Easy Connect - add support for DPP release 3 - allow Configurator parameters to be provided during config exchange * HE/IEEE 802.11ax/Wi-Fi 6 - various fixes * EHT/IEEE 802.11be/Wi-Fi 7 - add preliminary support * SAE: add support for fetching the password from a RADIUS server * support OpenSSL 3.0 API changes * support background radar detection and CAC with some additional drivers * support RADIUS ACL/PSK check during 4-way handshake (wpa_psk_radius=3) * EAP-SIM/AKA: support IMSI privacy * improve 4-way handshake operations - use Secure=1 in message 3 during PTK rekeying * OCV: do not check Frequency Segment 1 Channel Number for 160 MHz cases to avoid interoperability issues * support new SAE AKM suites with variable length keys * support new AKM for 802.1X/EAP with SHA384 * extend PASN support for secure ranging * FT: Use SHA256 to derive PMKID for AKM 00-0F-AC:3 (FT-EAP) - this is based on additional details being added in the IEEE 802.11 standard - the new implementation is not backwards compatible * improved ACS to cover additional channel types/bandwidths * extended Multiple BSSID support * fix beacon protection with FT protocol (incorrect BIGTK was provided) * support unsynchronized service discovery (USD) * add preliminary support for RADIUS/TLS * add support for explicit SSID protection in 4-way handshake (a mitigation for CVE-2023-52424; disabled by default for now, can be enabled with ssid_protection=1) * fix SAE H2E rejected groups validation to avoid downgrade attacks * use stricter validation for some RADIUS messages * a large number of other fixes, cleanup, and extensions wpa_supplicant: * Wi-Fi Easy Connect - add support for DPP release 3 - allow Configurator parameters to be provided during config exchange * MACsec - add support for GCM-AES-256 cipher suite - remove incorrect EAP Session-Id length constraint - add hardware offload support for additional drivers * HE/IEEE 802.11ax/Wi-Fi 6 - support BSS color updates - various fixes * EHT/IEEE 802.11be/Wi-Fi 7 - add preliminary support * support OpenSSL 3.0 API changes * improve EAP-TLS support for TLSv1.3 * EAP-SIM/AKA: support IMSI privacy * improve mitigation against DoS attacks when PMF is used * improve 4-way handshake operations - discard unencrypted EAPOL frames in additional cases - use Secure=1 in message 2 during PTK rekeying * OCV: do not check Frequency Segment 1 Channel Number for 160 MHz cases to avoid interoperability issues * support new SAE AKM suites with variable length keys * support new AKM for 802.1X/EAP with SHA384 * improve cross-AKM roaming with driver-based SME/BSS selection * PASN - extend support for secure ranging - allow PASN implementation to be used with external programs for Wi-Fi Aware * FT: Use SHA256 to derive PMKID for AKM 00-0F-AC:3 (FT-EAP) - this is based on additional details being added in the IEEE 802.11 standard - the new implementation is not backwards compatible, but PMKSA caching with FT-EAP was, and still is, disabled by default * support a pregenerated MAC (mac_addr=3) as an alternative mechanism for using per-network random MAC addresses * EAP-PEAP: require Phase 2 authentication by default (phase2_auth=1) to improve security for still unfortunately common invalid configurations that do not set ca_cert * extend SCS support for QoS Characteristics * extend MSCS support * support unsynchronized service discovery (USD) * add support for explicit SSID protection in 4-way handshake (a mitigation for CVE-2023-52424; disabled by default for now, can be enabled with ssid_protection=1) - in addition, verify SSID after key setup when beacon protection is used * fix SAE H2E rejected groups validation to avoid downgrade attacks * a large number of other fixes, cleanup, and extensions MFC after: 2 months Merge commit '6377230b3cf4f238dcd0dc2d76ff25943d3040e5'
This commit is contained in:
commit
a90b9d0159
@ -37,7 +37,7 @@ without moderation. You can subscribe to the list at this address:
|
||||
http://lists.infradead.org/mailman/listinfo/hostap
|
||||
|
||||
The message should contain an inlined patch against the current
|
||||
development branch (i.e., the master branch of
|
||||
development branch (i.e., the main branch of
|
||||
git://w1.fi/hostap.git). Please make sure the software you use for
|
||||
sending the patch does not corrupt whitespace. If that cannot be fixed
|
||||
for some reason, it is better to include an attached version of the
|
||||
|
@ -1,7 +1,7 @@
|
||||
wpa_supplicant and hostapd
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2024, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
These programs are licensed under the BSD license (the one with
|
||||
|
@ -154,6 +154,7 @@ OBJS += src/utils/crc32.c
|
||||
OBJS += src/common/ieee802_11_common.c
|
||||
OBJS += src/common/wpa_common.c
|
||||
OBJS += src/common/hw_features_common.c
|
||||
OBJS += src/common/ptksa_cache.c
|
||||
|
||||
OBJS += src/eapol_auth/eapol_auth_sm.c
|
||||
|
||||
@ -237,6 +238,8 @@ L_CFLAGS += -DCONFIG_OCV
|
||||
OBJS += src/common/ocv.c
|
||||
endif
|
||||
|
||||
NEED_AES_UNWRAP=y
|
||||
|
||||
ifdef CONFIG_IEEE80211R
|
||||
L_CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP
|
||||
OBJS += src/ap/wpa_auth_ft.c
|
||||
@ -256,6 +259,7 @@ L_CFLAGS += -DCONFIG_SAE
|
||||
OBJS += src/common/sae.c
|
||||
ifdef CONFIG_SAE_PK
|
||||
L_CFLAGS += -DCONFIG_SAE_PK
|
||||
NEED_AES_SIV=y
|
||||
OBJS += src/common/sae_pk.c
|
||||
endif
|
||||
NEED_ECC=y
|
||||
@ -294,6 +298,12 @@ ifdef CONFIG_IEEE80211AC
|
||||
L_CFLAGS += -DCONFIG_IEEE80211AC
|
||||
endif
|
||||
|
||||
ifdef CONFIG_IEEE80211BE
|
||||
CONFIG_IEEE80211AX=y
|
||||
L_CFLAGS += -DCONFIG_IEEE80211BE
|
||||
OBJS += src/ap/ieee802_11_eht.c
|
||||
endif
|
||||
|
||||
ifdef CONFIG_IEEE80211AX
|
||||
L_CFLAGS += -DCONFIG_IEEE80211AX
|
||||
endif
|
||||
@ -572,6 +582,12 @@ L_CFLAGS += -DCONFIG_DPP3
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CONFIG_NAN_USD
|
||||
OBJS += src/common/nan_de.c
|
||||
OBJS += src/ap/nan_usd_ap.c
|
||||
L_CFLAGS += -DCONFIG_NAN_USD
|
||||
endif
|
||||
|
||||
ifdef CONFIG_PASN
|
||||
L_CFLAGS += -DCONFIG_PASN
|
||||
L_CFLAGS += -DCONFIG_PTKSA_CACHE
|
||||
@ -579,7 +595,6 @@ NEED_HMAC_SHA256_KDF=y
|
||||
NEED_HMAC_SHA384_KDF=y
|
||||
NEED_SHA256=y
|
||||
NEED_SHA384=y
|
||||
OBJS += src/common/ptksa_cache.c
|
||||
endif
|
||||
|
||||
ifdef CONFIG_EAP_IKEV2
|
||||
@ -632,6 +647,11 @@ ifdef CHAP
|
||||
OBJS += src/eap_common/chap.c
|
||||
endif
|
||||
|
||||
ifdef CONFIG_RADIUS_TLS
|
||||
TLS_FUNCS=y
|
||||
L_CFLAGS += -DCONFIG_RADIUS_TLS
|
||||
endif
|
||||
|
||||
ifdef TLS_FUNCS
|
||||
NEED_DES=y
|
||||
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
|
||||
@ -653,6 +673,7 @@ L_CFLAGS += -DCONFIG_TLSV12
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_TLS), openssl)
|
||||
L_CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
|
||||
ifdef TLS_FUNCS
|
||||
OBJS += src/crypto/tls_openssl.c
|
||||
OBJS += src/crypto/tls_openssl_ocsp.c
|
||||
@ -825,7 +846,9 @@ endif
|
||||
ifdef NEED_AES_ENCBLOCK
|
||||
AESOBJS += src/crypto/aes-encblock.c
|
||||
endif
|
||||
ifneq ($(CONFIG_TLS), openssl)
|
||||
AESOBJS += src/crypto/aes-omac1.c
|
||||
endif
|
||||
ifdef NEED_AES_UNWRAP
|
||||
ifneq ($(CONFIG_TLS), openssl)
|
||||
NEED_AES_DEC=y
|
||||
@ -1026,6 +1049,9 @@ endif
|
||||
ifdef NEED_AP_MLME
|
||||
OBJS += src/ap/wmm.c
|
||||
OBJS += src/ap/ap_list.c
|
||||
OBJS += src/ap/comeback_token.c
|
||||
OBJS += src/pasn/pasn_responder.c
|
||||
OBJS += src/pasn/pasn_common.c
|
||||
OBJS += src/ap/ieee802_11.c
|
||||
OBJS += src/ap/hw_features.c
|
||||
OBJS += src/ap/dfs.c
|
||||
|
@ -1,5 +1,42 @@
|
||||
ChangeLog for hostapd
|
||||
|
||||
2024-07-20 - v2.11
|
||||
* Wi-Fi Easy Connect
|
||||
- add support for DPP release 3
|
||||
- allow Configurator parameters to be provided during config exchange
|
||||
* HE/IEEE 802.11ax/Wi-Fi 6
|
||||
- various fixes
|
||||
* EHT/IEEE 802.11be/Wi-Fi 7
|
||||
- add preliminary support
|
||||
* SAE: add support for fetching the password from a RADIUS server
|
||||
* support OpenSSL 3.0 API changes
|
||||
* support background radar detection and CAC with some additional
|
||||
drivers
|
||||
* support RADIUS ACL/PSK check during 4-way handshake (wpa_psk_radius=3)
|
||||
* EAP-SIM/AKA: support IMSI privacy
|
||||
* improve 4-way handshake operations
|
||||
- use Secure=1 in message 3 during PTK rekeying
|
||||
* OCV: do not check Frequency Segment 1 Channel Number for 160 MHz cases
|
||||
to avoid interoperability issues
|
||||
* support new SAE AKM suites with variable length keys
|
||||
* support new AKM for 802.1X/EAP with SHA384
|
||||
* extend PASN support for secure ranging
|
||||
* FT: Use SHA256 to derive PMKID for AKM 00-0F-AC:3 (FT-EAP)
|
||||
- this is based on additional details being added in the IEEE 802.11
|
||||
standard
|
||||
- the new implementation is not backwards compatible
|
||||
* improved ACS to cover additional channel types/bandwidths
|
||||
* extended Multiple BSSID support
|
||||
* fix beacon protection with FT protocol (incorrect BIGTK was provided)
|
||||
* support unsynchronized service discovery (USD)
|
||||
* add preliminary support for RADIUS/TLS
|
||||
* add support for explicit SSID protection in 4-way handshake
|
||||
(a mitigation for CVE-2023-52424; disabled by default for now, can be
|
||||
enabled with ssid_protection=1)
|
||||
* fix SAE H2E rejected groups validation to avoid downgrade attacks
|
||||
* use stricter validation for some RADIUS messages
|
||||
* a large number of other fixes, cleanup, and extensions
|
||||
|
||||
2022-01-16 - v2.10
|
||||
* SAE changes
|
||||
- improved protection against side channel attacks
|
||||
|
@ -84,6 +84,7 @@ OBJS += ../src/ap/beacon.o
|
||||
OBJS += ../src/ap/bss_load.o
|
||||
OBJS += ../src/ap/neighbor_db.o
|
||||
OBJS += ../src/ap/rrm.o
|
||||
OBJS += ../src/common/ptksa_cache.o
|
||||
|
||||
OBJS_c = hostapd_cli.o
|
||||
OBJS_c += ../src/common/wpa_ctrl.o
|
||||
@ -167,7 +168,7 @@ OBJS += ../src/eapol_auth/eapol_auth_sm.o
|
||||
|
||||
|
||||
ifdef CONFIG_CODE_COVERAGE
|
||||
CFLAGS += -O0 -fprofile-arcs -ftest-coverage
|
||||
CFLAGS += -O0 -fprofile-arcs -ftest-coverage -U_FORTIFY_SOURCE
|
||||
LIBS += -lgcov
|
||||
LIBS_c += -lgcov
|
||||
LIBS_h += -lgcov
|
||||
@ -276,6 +277,8 @@ CFLAGS += -DCONFIG_OCV
|
||||
OBJS += ../src/common/ocv.o
|
||||
endif
|
||||
|
||||
NEED_AES_UNWRAP=y
|
||||
|
||||
ifdef CONFIG_IEEE80211R
|
||||
CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP
|
||||
OBJS += ../src/ap/wpa_auth_ft.o
|
||||
@ -295,6 +298,7 @@ CFLAGS += -DCONFIG_SAE
|
||||
OBJS += ../src/common/sae.o
|
||||
ifdef CONFIG_SAE_PK
|
||||
CFLAGS += -DCONFIG_SAE_PK
|
||||
NEED_AES_SIV=y
|
||||
OBJS += ../src/common/sae_pk.o
|
||||
endif
|
||||
NEED_ECC=y
|
||||
@ -339,6 +343,12 @@ ifdef CONFIG_IEEE80211AC
|
||||
CFLAGS += -DCONFIG_IEEE80211AC
|
||||
endif
|
||||
|
||||
ifdef CONFIG_IEEE80211BE
|
||||
CONFIG_IEEE80211AX=y
|
||||
CFLAGS += -DCONFIG_IEEE80211BE
|
||||
OBJS += ../src/ap/ieee802_11_eht.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_IEEE80211AX
|
||||
CFLAGS += -DCONFIG_IEEE80211AX
|
||||
OBJS += ../src/ap/ieee802_11_he.o
|
||||
@ -598,6 +608,12 @@ CFLAGS += -DCONFIG_DPP3
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CONFIG_NAN_USD
|
||||
OBJS += ../src/common/nan_de.o
|
||||
OBJS += ../src/ap/nan_usd_ap.o
|
||||
CFLAGS += -DCONFIG_NAN_USD
|
||||
endif
|
||||
|
||||
ifdef CONFIG_PASN
|
||||
CFLAGS += -DCONFIG_PASN
|
||||
CFLAGS += -DCONFIG_PTKSA_CACHE
|
||||
@ -605,7 +621,6 @@ NEED_HMAC_SHA256_KDF=y
|
||||
NEED_HMAC_SHA384_KDF=y
|
||||
NEED_SHA256=y
|
||||
NEED_SHA384=y
|
||||
OBJS += ../src/common/ptksa_cache.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_EAP_IKEV2
|
||||
@ -667,6 +682,11 @@ ifdef CHAP
|
||||
OBJS += ../src/eap_common/chap.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_RADIUS_TLS
|
||||
TLS_FUNCS=y
|
||||
CFLAGS += -DCONFIG_RADIUS_TLS
|
||||
endif
|
||||
|
||||
ifdef TLS_FUNCS
|
||||
NEED_DES=y
|
||||
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
|
||||
@ -708,6 +728,7 @@ endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_TLS), openssl)
|
||||
CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
|
||||
CONFIG_CRYPTO=openssl
|
||||
ifdef TLS_FUNCS
|
||||
OBJS += ../src/crypto/tls_openssl.o
|
||||
@ -932,11 +953,13 @@ endif
|
||||
ifdef NEED_AES_ENCBLOCK
|
||||
AESOBJS += ../src/crypto/aes-encblock.o
|
||||
endif
|
||||
ifneq ($(CONFIG_TLS), openssl)
|
||||
ifneq ($(CONFIG_TLS), linux)
|
||||
ifneq ($(CONFIG_TLS), wolfssl)
|
||||
AESOBJS += ../src/crypto/aes-omac1.o
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
ifdef NEED_AES_UNWRAP
|
||||
ifneq ($(CONFIG_TLS), openssl)
|
||||
ifneq ($(CONFIG_TLS), linux)
|
||||
@ -1172,6 +1195,9 @@ endif
|
||||
ifdef NEED_AP_MLME
|
||||
OBJS += ../src/ap/wmm.o
|
||||
OBJS += ../src/ap/ap_list.o
|
||||
OBJS += ../src/ap/comeback_token.o
|
||||
OBJS += ../src/pasn/pasn_responder.o
|
||||
OBJS += ../src/pasn/pasn_common.o
|
||||
OBJS += ../src/ap/ieee802_11.o
|
||||
OBJS += ../src/ap/hw_features.o
|
||||
OBJS += ../src/ap/dfs.o
|
||||
|
@ -2,7 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
|
||||
Authenticator and RADIUS authentication server
|
||||
================================================================
|
||||
|
||||
Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2024, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
This program is licensed under the BSD license (the one with
|
||||
|
@ -121,6 +121,9 @@ CONFIG_PKCS12=y
|
||||
# Build IPv6 support for RADIUS operations
|
||||
CONFIG_IPV6=y
|
||||
|
||||
# Include support fo RADIUS/TLS into the RADIUS client
|
||||
#CONFIG_RADIUS_TLS=y
|
||||
|
||||
# IEEE Std 802.11r-2008 (Fast BSS Transition)
|
||||
#CONFIG_IEEE80211R=y
|
||||
|
||||
@ -212,3 +215,6 @@ CONFIG_NO_RANDOM_POOL=y
|
||||
# release under this optional build parameter. This functionality is subject to
|
||||
# be completely removed in a future release.
|
||||
CONFIG_WEP=y
|
||||
|
||||
# Wi-Fi Aware unsynchronized service discovery (NAN USD)
|
||||
#CONFIG_NAN_USD=y
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / Configuration file parser
|
||||
* Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2003-2024, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -118,52 +118,6 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
|
||||
int hostapd_acl_comp(const void *a, const void *b)
|
||||
{
|
||||
const struct mac_acl_entry *aa = a;
|
||||
const struct mac_acl_entry *bb = b;
|
||||
return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
|
||||
}
|
||||
|
||||
|
||||
int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
|
||||
int vlan_id, const u8 *addr)
|
||||
{
|
||||
struct mac_acl_entry *newacl;
|
||||
|
||||
newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
|
||||
if (!newacl) {
|
||||
wpa_printf(MSG_ERROR, "MAC list reallocation failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*acl = newacl;
|
||||
os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
|
||||
os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id));
|
||||
(*acl)[*num].vlan_id.untagged = vlan_id;
|
||||
(*acl)[*num].vlan_id.notempty = !!vlan_id;
|
||||
(*num)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
|
||||
const u8 *addr)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (i < *num) {
|
||||
if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == 0) {
|
||||
os_remove_in_array(*acl, *num, sizeof(**acl), i);
|
||||
(*num)--;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_config_read_maclist(const char *fname,
|
||||
struct mac_acl_entry **acl, int *num)
|
||||
{
|
||||
@ -713,6 +667,10 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
|
||||
val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
|
||||
#endif /* CONFIG_SHA384 */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_SHA384
|
||||
else if (os_strcmp(start, "WPA-EAP-SHA384") == 0)
|
||||
val |= WPA_KEY_MGMT_IEEE8021X_SHA384;
|
||||
#endif /* CONFIG_SHA384 */
|
||||
else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
|
||||
val |= WPA_KEY_MGMT_PSK_SHA256;
|
||||
else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
|
||||
@ -720,8 +678,12 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
|
||||
#ifdef CONFIG_SAE
|
||||
else if (os_strcmp(start, "SAE") == 0)
|
||||
val |= WPA_KEY_MGMT_SAE;
|
||||
else if (os_strcmp(start, "SAE-EXT-KEY") == 0)
|
||||
val |= WPA_KEY_MGMT_SAE_EXT_KEY;
|
||||
else if (os_strcmp(start, "FT-SAE") == 0)
|
||||
val |= WPA_KEY_MGMT_FT_SAE;
|
||||
else if (os_strcmp(start, "FT-SAE-EXT-KEY") == 0)
|
||||
val |= WPA_KEY_MGMT_FT_SAE_EXT_KEY;
|
||||
#endif /* CONFIG_SAE */
|
||||
#ifdef CONFIG_SUITEB
|
||||
else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
|
||||
@ -1058,6 +1020,78 @@ static int add_r1kh(struct hostapd_bss_config *bss, char *value)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_config_read_rxkh_file(struct hostapd_bss_config *conf,
|
||||
const char *fname)
|
||||
{
|
||||
FILE *f;
|
||||
char buf[256], *pos;
|
||||
int line = 0, errors = 0;
|
||||
|
||||
if (!fname)
|
||||
return 0;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if (!f) {
|
||||
wpa_printf(MSG_ERROR, "rxkh file '%s' not found.", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
line++;
|
||||
|
||||
if (buf[0] == '#')
|
||||
continue;
|
||||
pos = buf;
|
||||
while (*pos != '\0') {
|
||||
if (*pos == '\n') {
|
||||
*pos = '\0';
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
if (buf[0] == '\0')
|
||||
continue;
|
||||
|
||||
pos = os_strchr(buf, '=');
|
||||
if (!pos) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Invalid line '%s'",
|
||||
line, buf);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
*pos = '\0';
|
||||
pos++;
|
||||
|
||||
if (os_strcmp(buf, "r0kh") == 0) {
|
||||
if (add_r0kh(conf, pos) < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid r0kh '%s'",
|
||||
line, pos);
|
||||
errors++;
|
||||
}
|
||||
} else if (os_strcmp(buf, "r1kh") == 0) {
|
||||
if (add_r1kh(conf, pos) < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid r1kh '%s'",
|
||||
line, pos);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
if (errors) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"%d errors in configuring RxKHs from '%s'",
|
||||
errors, fname);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
|
||||
@ -1644,6 +1678,8 @@ static int parse_anqp_elem(struct hostapd_bss_config *bss, char *buf, int line)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_INTERWORKING */
|
||||
|
||||
|
||||
static int parse_qos_map_set(struct hostapd_bss_config *bss,
|
||||
char *buf, int line)
|
||||
@ -1685,8 +1721,6 @@ static int parse_qos_map_set(struct hostapd_bss_config *bss,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_INTERWORKING */
|
||||
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
static int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf,
|
||||
@ -2197,6 +2231,7 @@ static int add_airtime_weight(struct hostapd_bss_config *bss, char *value)
|
||||
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
|
||||
static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
|
||||
{
|
||||
struct sae_password_entry *pw;
|
||||
@ -2300,6 +2335,40 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
|
||||
os_free(pw);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int parse_sae_password_file(struct hostapd_bss_config *bss,
|
||||
const char *fname)
|
||||
{
|
||||
FILE *f;
|
||||
char buf[500], *pos;
|
||||
unsigned int line = 0;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if (!f) {
|
||||
wpa_printf(MSG_ERROR, "sae_password_file '%s' not found.",
|
||||
fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
pos = os_strchr(buf, '\n');
|
||||
if (pos)
|
||||
*pos = '\0';
|
||||
line++;
|
||||
if (parse_sae_password(bss, buf)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Invalid SAE password at line %d in '%s'",
|
||||
line, fname);
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
|
||||
@ -2349,6 +2418,24 @@ static int get_hex_config(u8 *buf, size_t max_len, int line,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
static int get_u16(const char *pos, int line, u16 *ret_val)
|
||||
{
|
||||
char *end;
|
||||
long int val = strtol(pos, &end, 0);
|
||||
|
||||
if (*end || val < 0 || val > 0xffff) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Invalid value '%s'",
|
||||
line, pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ret_val = val;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
|
||||
static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
struct hostapd_bss_config *bss,
|
||||
const char *buf, char *pos, int line)
|
||||
@ -2358,6 +2445,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
sizeof(conf->bss[0]->iface));
|
||||
} else if (os_strcmp(buf, "bridge") == 0) {
|
||||
os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
|
||||
} else if (os_strcmp(buf, "bridge_hairpin") == 0) {
|
||||
bss->bridge_hairpin = atoi(pos);
|
||||
} else if (os_strcmp(buf, "vlan_bridge") == 0) {
|
||||
os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge));
|
||||
} else if (os_strcmp(buf, "wds_bridge") == 0) {
|
||||
@ -2407,7 +2496,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
}
|
||||
os_memcpy(ssid->ssid, pos, ssid->ssid_len);
|
||||
ssid->ssid_set = 1;
|
||||
ssid->short_ssid = crc32(ssid->ssid, ssid->ssid_len);
|
||||
ssid->short_ssid = ieee80211_crc32(ssid->ssid, ssid->ssid_len);
|
||||
} else if (os_strcmp(buf, "ssid2") == 0) {
|
||||
struct hostapd_ssid *ssid = &bss->ssid;
|
||||
size_t slen;
|
||||
@ -2421,7 +2510,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
os_memcpy(ssid->ssid, str, slen);
|
||||
ssid->ssid_len = slen;
|
||||
ssid->ssid_set = 1;
|
||||
ssid->short_ssid = crc32(ssid->ssid, ssid->ssid_len);
|
||||
ssid->short_ssid = ieee80211_crc32(ssid->ssid, ssid->ssid_len);
|
||||
os_free(str);
|
||||
} else if (os_strcmp(buf, "utf8_ssid") == 0) {
|
||||
bss->ssid.utf8_ssid = atoi(pos) > 0;
|
||||
@ -2460,6 +2549,30 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->ap_max_inactivity = atoi(pos);
|
||||
} else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
|
||||
bss->skip_inactivity_poll = atoi(pos);
|
||||
} else if (os_strcmp(buf, "bss_max_idle") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < 0 || val > 2) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid bss_max_idle value", line);
|
||||
return 1;
|
||||
}
|
||||
bss->bss_max_idle = val;
|
||||
} else if (os_strcmp(buf, "max_acceptable_idle_period") == 0) {
|
||||
bss->max_acceptable_idle_period = atoi(pos);
|
||||
} else if (os_strcmp(buf, "no_disconnect_on_group_keyerror") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < 0 || val > 1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid no_disconnect_on_group_keyerror",
|
||||
line);
|
||||
return 1;
|
||||
}
|
||||
bss->no_disconnect_on_group_keyerror = val;
|
||||
} else if (os_strcmp(buf, "config_id") == 0) {
|
||||
os_free(bss->config_id);
|
||||
bss->config_id = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "country_code") == 0) {
|
||||
if (pos[0] < 'A' || pos[0] > 'Z' ||
|
||||
pos[1] < 'A' || pos[1] > 'Z') {
|
||||
@ -2624,6 +2737,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->eap_teap_separate_result = atoi(pos);
|
||||
} else if (os_strcmp(buf, "eap_teap_id") == 0) {
|
||||
bss->eap_teap_id = atoi(pos);
|
||||
} else if (os_strcmp(buf, "eap_teap_method_sequence") == 0) {
|
||||
bss->eap_teap_method_sequence = atoi(pos);
|
||||
#endif /* EAP_SERVER_TEAP */
|
||||
#ifdef EAP_SERVER_SIM
|
||||
} else if (os_strcmp(buf, "eap_sim_db") == 0) {
|
||||
@ -2635,6 +2750,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->eap_sim_aka_result_ind = atoi(pos);
|
||||
} else if (os_strcmp(buf, "eap_sim_id") == 0) {
|
||||
bss->eap_sim_id = atoi(pos);
|
||||
} else if (os_strcmp(buf, "imsi_privacy_key") == 0) {
|
||||
os_free(bss->imsi_privacy_key);
|
||||
bss->imsi_privacy_key = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "eap_sim_aka_fast_reauth_limit") == 0) {
|
||||
bss->eap_sim_aka_fast_reauth_limit = atoi(pos);
|
||||
#endif /* EAP_SERVER_SIM */
|
||||
#ifdef EAP_SERVER_TNC
|
||||
} else if (os_strcmp(buf, "tnc") == 0) {
|
||||
@ -2770,6 +2890,37 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
os_free(bss->radius->auth_server->shared_secret);
|
||||
bss->radius->auth_server->shared_secret = (u8 *) os_strdup(pos);
|
||||
bss->radius->auth_server->shared_secret_len = len;
|
||||
} else if (bss->radius->auth_server &&
|
||||
os_strcmp(buf, "auth_server_type") == 0) {
|
||||
if (os_strcmp(pos, "UDP") == 0) {
|
||||
bss->radius->auth_server->tls = false;
|
||||
#ifdef CONFIG_RADIUS_TLS
|
||||
} else if (os_strcmp(pos, "TLS") == 0) {
|
||||
bss->radius->auth_server->tls = true;
|
||||
#endif /* CONFIG_RADIUS_TLS */
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Line %d: unsupported RADIUS type '%s'",
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
#ifdef CONFIG_RADIUS_TLS
|
||||
} else if (bss->radius->auth_server &&
|
||||
os_strcmp(buf, "auth_server_ca_cert") == 0) {
|
||||
os_free(bss->radius->auth_server->ca_cert);
|
||||
bss->radius->auth_server->ca_cert = os_strdup(pos);
|
||||
} else if (bss->radius->auth_server &&
|
||||
os_strcmp(buf, "auth_server_client_cert") == 0) {
|
||||
os_free(bss->radius->auth_server->client_cert);
|
||||
bss->radius->auth_server->client_cert = os_strdup(pos);
|
||||
} else if (bss->radius->auth_server &&
|
||||
os_strcmp(buf, "auth_server_private_key") == 0) {
|
||||
os_free(bss->radius->auth_server->private_key);
|
||||
bss->radius->auth_server->private_key = os_strdup(pos);
|
||||
} else if (bss->radius->auth_server &&
|
||||
os_strcmp(buf, "auth_server_private_key_passwd") == 0) {
|
||||
os_free(bss->radius->auth_server->private_key_passwd);
|
||||
bss->radius->auth_server->private_key_passwd = os_strdup(pos);
|
||||
#endif /* CONFIG_RADIUS_TLS */
|
||||
} else if (os_strcmp(buf, "acct_server_addr") == 0) {
|
||||
if (hostapd_config_read_radius_addr(
|
||||
&bss->radius->acct_servers,
|
||||
@ -2804,8 +2955,42 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
os_free(bss->radius->acct_server->shared_secret);
|
||||
bss->radius->acct_server->shared_secret = (u8 *) os_strdup(pos);
|
||||
bss->radius->acct_server->shared_secret_len = len;
|
||||
} else if (bss->radius->acct_server &&
|
||||
os_strcmp(buf, "acct_server_type") == 0) {
|
||||
if (os_strcmp(pos, "UDP") == 0) {
|
||||
bss->radius->acct_server->tls = false;
|
||||
#ifdef CONFIG_RADIUS_TLS
|
||||
} else if (os_strcmp(pos, "TLS") == 0) {
|
||||
bss->radius->acct_server->tls = true;
|
||||
#endif /* CONFIG_RADIUS_TLS */
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Line %d: unsupported RADIUS type '%s'",
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
#ifdef CONFIG_RADIUS_TLS
|
||||
} else if (bss->radius->acct_server &&
|
||||
os_strcmp(buf, "acct_server_ca_cert") == 0) {
|
||||
os_free(bss->radius->acct_server->ca_cert);
|
||||
bss->radius->acct_server->ca_cert = os_strdup(pos);
|
||||
} else if (bss->radius->acct_server &&
|
||||
os_strcmp(buf, "acct_server_client_cert") == 0) {
|
||||
os_free(bss->radius->acct_server->client_cert);
|
||||
bss->radius->acct_server->client_cert = os_strdup(pos);
|
||||
} else if (bss->radius->acct_server &&
|
||||
os_strcmp(buf, "acct_server_private_key") == 0) {
|
||||
os_free(bss->radius->acct_server->private_key);
|
||||
bss->radius->acct_server->private_key = os_strdup(pos);
|
||||
} else if (bss->radius->acct_server &&
|
||||
os_strcmp(buf, "acct_server_private_key_passwd") == 0) {
|
||||
os_free(bss->radius->acct_server->private_key_passwd);
|
||||
bss->radius->acct_server->private_key_passwd = os_strdup(pos);
|
||||
#endif /* CONFIG_RADIUS_TLS */
|
||||
} else if (os_strcmp(buf, "radius_retry_primary_interval") == 0) {
|
||||
bss->radius->retry_primary_interval = atoi(pos);
|
||||
} else if (os_strcmp(buf,
|
||||
"radius_require_message_authenticator") == 0) {
|
||||
bss->radius_require_message_authenticator = atoi(pos);
|
||||
} else if (os_strcmp(buf, "radius_acct_interim_interval") == 0) {
|
||||
bss->acct_interim_interval = atoi(pos);
|
||||
} else if (os_strcmp(buf, "radius_request_cui") == 0) {
|
||||
@ -2975,7 +3160,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->wpa_psk_radius = atoi(pos);
|
||||
if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
|
||||
bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
|
||||
bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
|
||||
bss->wpa_psk_radius != PSK_RADIUS_REQUIRED &&
|
||||
bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: unknown wpa_psk_radius %d",
|
||||
line, bss->wpa_psk_radius);
|
||||
@ -3072,6 +3258,21 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
} else if (os_strcmp(buf, "rxkh_file") == 0) {
|
||||
os_free(bss->rxkh_file);
|
||||
bss->rxkh_file = os_strdup(pos);
|
||||
if (!bss->rxkh_file) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: allocation failed",
|
||||
line);
|
||||
return 1;
|
||||
}
|
||||
if (hostapd_config_read_rxkh_file(bss, pos)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Line %d: failed to read rxkh_file '%s'",
|
||||
line, pos);
|
||||
/* Allow the file to be created later and read into
|
||||
* already operating AP context. */
|
||||
}
|
||||
} else if (os_strcmp(buf, "pmk_r1_push") == 0) {
|
||||
bss->pmk_r1_push = atoi(pos);
|
||||
} else if (os_strcmp(buf, "ft_over_ds") == 0) {
|
||||
@ -3139,6 +3340,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
conf->hw_mode_set = true;
|
||||
} else if (os_strcmp(buf, "wps_rf_bands") == 0) {
|
||||
if (os_strcmp(pos, "ad") == 0)
|
||||
bss->wps_rf_bands = WPS_RF_60GHZ;
|
||||
@ -3193,6 +3395,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
conf->acs_freq_list_present = 1;
|
||||
} else if (os_strcmp(buf, "acs_exclude_6ghz_non_psc") == 0) {
|
||||
conf->acs_exclude_6ghz_non_psc = atoi(pos);
|
||||
} else if (os_strcmp(buf, "enable_background_radar") == 0) {
|
||||
conf->enable_background_radar = atoi(pos);
|
||||
} else if (os_strcmp(buf, "min_tx_power") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
@ -3484,6 +3688,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
}
|
||||
} else if (os_strcmp(buf, "require_ht") == 0) {
|
||||
conf->require_ht = atoi(pos);
|
||||
} else if (os_strcmp(buf, "ht_vht_twt_responder") == 0) {
|
||||
conf->ht_vht_twt_responder = atoi(pos);
|
||||
} else if (os_strcmp(buf, "obss_interval") == 0) {
|
||||
conf->obss_interval = atoi(pos);
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
@ -3511,6 +3717,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
} else if (os_strcmp(buf, "ieee80211ax") == 0) {
|
||||
conf->ieee80211ax = atoi(pos);
|
||||
} else if (os_strcmp(buf, "require_he") == 0) {
|
||||
conf->require_he = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_su_beamformer") == 0) {
|
||||
conf->he_phy_capab.he_su_beamformer = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_su_beamformee") == 0) {
|
||||
@ -3642,6 +3850,20 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
} else if (os_strcmp(buf, "he_6ghz_reg_pwr_type") == 0) {
|
||||
conf->he_6ghz_reg_pwr_type = atoi(pos);
|
||||
if (conf->he_6ghz_reg_pwr_type > HE_REG_INFO_6GHZ_AP_TYPE_MAX) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: invalid he_6ghz_reg_pwr_type value",
|
||||
line);
|
||||
return 1;
|
||||
}
|
||||
} else if (os_strcmp(buf, "reg_def_cli_eirp_psd") == 0) {
|
||||
conf->reg_def_cli_eirp_psd = atoi(pos);
|
||||
} else if (os_strcmp(buf, "reg_sub_cli_eirp_psd") == 0) {
|
||||
conf->reg_sub_cli_eirp_psd = atoi(pos);
|
||||
} else if (os_strcmp(buf, "reg_def_cli_eirp") == 0) {
|
||||
conf->reg_def_cli_eirp = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_oper_chwidth") == 0) {
|
||||
conf->he_oper_chwidth = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_oper_centr_freq_seg0_idx") == 0) {
|
||||
@ -3666,6 +3888,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
return 1;
|
||||
}
|
||||
bss->unsol_bcast_probe_resp_interval = val;
|
||||
} else if (os_strcmp(buf, "mbssid") == 0) {
|
||||
int mbssid = atoi(pos);
|
||||
if (mbssid < 0 || mbssid > ENHANCED_MBSSID_ENABLED) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: invalid mbssid (%d): '%s'.",
|
||||
line, mbssid, pos);
|
||||
return 1;
|
||||
}
|
||||
conf->mbssid = mbssid;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
|
||||
bss->max_listen_interval = atoi(pos);
|
||||
@ -4053,10 +4284,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->gas_frag_limit = val;
|
||||
} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
|
||||
bss->gas_comeback_delay = atoi(pos);
|
||||
#endif /* CONFIG_INTERWORKING */
|
||||
} else if (os_strcmp(buf, "qos_map_set") == 0) {
|
||||
if (parse_qos_map_set(bss, pos, line) < 0)
|
||||
return 1;
|
||||
#endif /* CONFIG_INTERWORKING */
|
||||
#ifdef CONFIG_RADIUS_TEST
|
||||
} else if (os_strcmp(buf, "dump_msk_file") == 0) {
|
||||
os_free(bss->dump_msk_file);
|
||||
@ -4297,6 +4528,23 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->oci_freq_override_fils_assoc = atoi(pos);
|
||||
} else if (os_strcmp(buf, "oci_freq_override_wnm_sleep") == 0) {
|
||||
bss->oci_freq_override_wnm_sleep = atoi(pos);
|
||||
} else if (os_strcmp(buf, "eap_skip_prot_success") == 0) {
|
||||
bss->eap_skip_prot_success = atoi(pos);
|
||||
} else if (os_strcmp(buf, "delay_eapol_tx") == 0) {
|
||||
conf->delay_eapol_tx = atoi(pos);
|
||||
} else if (os_strcmp(buf, "eapol_m1_elements") == 0) {
|
||||
if (parse_wpabuf_hex(line, buf, &bss->eapol_m1_elements, pos))
|
||||
return 1;
|
||||
} else if (os_strcmp(buf, "eapol_m3_elements") == 0) {
|
||||
if (parse_wpabuf_hex(line, buf, &bss->eapol_m3_elements, pos))
|
||||
return 1;
|
||||
} else if (os_strcmp(buf, "eapol_m3_no_encrypt") == 0) {
|
||||
bss->eapol_m3_no_encrypt = atoi(pos);
|
||||
} else if (os_strcmp(buf, "test_assoc_comeback_type") == 0) {
|
||||
bss->test_assoc_comeback_type = atoi(pos);
|
||||
} else if (os_strcmp(buf, "presp_elements") == 0) {
|
||||
if (parse_wpabuf_hex(line, buf, &bss->presp_elements, pos))
|
||||
return 1;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#ifdef CONFIG_SAE
|
||||
} else if (os_strcmp(buf, "sae_password") == 0) {
|
||||
@ -4305,6 +4553,13 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
line);
|
||||
return 1;
|
||||
}
|
||||
} else if (os_strcmp(buf, "sae_password_file") == 0) {
|
||||
if (parse_sae_password_file(bss, pos) < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid sae_password in file",
|
||||
line);
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
} else if (os_strcmp(buf, "vendor_elements") == 0) {
|
||||
if (parse_wpabuf_hex(line, buf, &bss->vendor_elements, pos))
|
||||
@ -4436,6 +4691,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
|
||||
WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE |
|
||||
WLAN_RRM_CAPS_BEACON_REPORT_TABLE;
|
||||
} else if (os_strcmp(buf, "rrm_link_measurement_report") == 0) {
|
||||
if (atoi(pos))
|
||||
bss->radio_measurements[0] |=
|
||||
WLAN_RRM_CAPS_LINK_MEASUREMENT;
|
||||
} else if (os_strcmp(buf, "gas_address3") == 0) {
|
||||
bss->gas_address3 = atoi(pos);
|
||||
} else if (os_strcmp(buf, "stationary_ap") == 0) {
|
||||
@ -4480,6 +4739,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
#endif /* CONFIG_FILS */
|
||||
} else if (os_strcmp(buf, "multicast_to_unicast") == 0) {
|
||||
bss->multicast_to_unicast = atoi(pos);
|
||||
} else if (os_strcmp(buf, "bridge_multicast_to_unicast") == 0) {
|
||||
bss->bridge_multicast_to_unicast = atoi(pos);
|
||||
} else if (os_strcmp(buf, "broadcast_deauth") == 0) {
|
||||
bss->broadcast_deauth = atoi(pos);
|
||||
} else if (os_strcmp(buf, "notify_mgmt_frames") == 0) {
|
||||
@ -4491,6 +4752,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "dpp_mud_url") == 0) {
|
||||
os_free(bss->dpp_mud_url);
|
||||
bss->dpp_mud_url = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "dpp_extra_conf_req_name") == 0) {
|
||||
os_free(bss->dpp_extra_conf_req_name);
|
||||
bss->dpp_extra_conf_req_name = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "dpp_extra_conf_req_value") == 0) {
|
||||
os_free(bss->dpp_extra_conf_req_value);
|
||||
bss->dpp_extra_conf_req_value = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "dpp_connector") == 0) {
|
||||
os_free(bss->dpp_connector);
|
||||
bss->dpp_connector = os_strdup(pos);
|
||||
@ -4506,6 +4773,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "dpp_controller") == 0) {
|
||||
if (hostapd_dpp_controller_parse(bss, pos))
|
||||
return 1;
|
||||
} else if (os_strcmp(buf, "dpp_relay_port") == 0) {
|
||||
bss->dpp_relay_port = atoi(pos);
|
||||
} else if (os_strcmp(buf, "dpp_configurator_connectivity") == 0) {
|
||||
bss->dpp_configurator_connectivity = atoi(pos);
|
||||
} else if (os_strcmp(buf, "dpp_pfs") == 0) {
|
||||
@ -4566,6 +4835,36 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
}
|
||||
|
||||
bss->multi_ap = val;
|
||||
} else if (os_strcmp(buf, "multi_ap_profile") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < MULTI_AP_PROFILE_1 || val > MULTI_AP_PROFILE_MAX) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid multi_ap_profile '%s'",
|
||||
line, buf);
|
||||
return -1;
|
||||
}
|
||||
bss->multi_ap_profile = val;
|
||||
} else if (os_strcmp(buf, "multi_ap_client_disallow") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < 0 || val > 3) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid multi_ap_client_allow '%s'",
|
||||
line, buf);
|
||||
return -1;
|
||||
}
|
||||
bss->multi_ap_client_disallow = val;
|
||||
} else if (os_strcmp(buf, "multi_ap_vlanid") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < 0 || val > MAX_VLAN_ID) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid multi_ap_vlan_id '%s'",
|
||||
line, buf);
|
||||
return -1;
|
||||
}
|
||||
bss->multi_ap_vlanid = val;
|
||||
} else if (os_strcmp(buf, "rssi_reject_assoc_rssi") == 0) {
|
||||
conf->rssi_reject_assoc_rssi = atoi(pos);
|
||||
} else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) {
|
||||
@ -4641,6 +4940,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->macsec_replay_protect = macsec_replay_protect;
|
||||
} else if (os_strcmp(buf, "macsec_replay_window") == 0) {
|
||||
bss->macsec_replay_window = atoi(pos);
|
||||
} else if (os_strcmp(buf, "macsec_offload") == 0) {
|
||||
int macsec_offload = atoi(pos);
|
||||
|
||||
if (macsec_offload < 0 || macsec_offload > 2) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: invalid macsec_offload (%d): '%s'.",
|
||||
line, macsec_offload, pos);
|
||||
return 1;
|
||||
}
|
||||
bss->macsec_offload = macsec_offload;
|
||||
} else if (os_strcmp(buf, "macsec_port") == 0) {
|
||||
int macsec_port = atoi(pos);
|
||||
|
||||
@ -4661,6 +4970,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
return 1;
|
||||
}
|
||||
bss->mka_priority = mka_priority;
|
||||
} else if (os_strcmp(buf, "macsec_csindex") == 0) {
|
||||
int macsec_csindex = atoi(pos);
|
||||
|
||||
if (macsec_csindex < 0 || macsec_csindex > 1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: invalid macsec_csindex (%d): '%s'.",
|
||||
line, macsec_csindex, pos);
|
||||
return 1;
|
||||
}
|
||||
bss->macsec_csindex = macsec_csindex;
|
||||
} else if (os_strcmp(buf, "mka_cak") == 0) {
|
||||
size_t len = os_strlen(pos);
|
||||
|
||||
@ -4697,6 +5016,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->disable_11ac = !!atoi(pos);
|
||||
} else if (os_strcmp(buf, "disable_11ax") == 0) {
|
||||
bss->disable_11ax = !!atoi(pos);
|
||||
} else if (os_strcmp(buf, "disable_11be") == 0) {
|
||||
bss->disable_11be = !!atoi(pos);
|
||||
#ifdef CONFIG_PASN
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
} else if (os_strcmp(buf, "force_kdk_derivation") == 0) {
|
||||
@ -4713,6 +5034,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
}
|
||||
} else if (os_strcmp(buf, "pasn_comeback_after") == 0) {
|
||||
bss->pasn_comeback_after = atoi(pos);
|
||||
} else if (os_strcmp(buf, "pasn_noauth") == 0) {
|
||||
bss->pasn_noauth = atoi(pos);
|
||||
#endif /* CONFIG_PASN */
|
||||
} else if (os_strcmp(buf, "ext_capa_mask") == 0) {
|
||||
if (get_hex_config(bss->ext_capa_mask, EXT_CAPA_MAX_LEN,
|
||||
@ -4724,6 +5047,58 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
return 1;
|
||||
} else if (os_strcmp(buf, "rnr") == 0) {
|
||||
bss->rnr = atoi(pos);
|
||||
} else if (os_strcmp(buf, "ssid_protection") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < 0 || val > 1)
|
||||
return 1;
|
||||
bss->ssid_protection = val;
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
} else if (os_strcmp(buf, "ieee80211be") == 0) {
|
||||
conf->ieee80211be = atoi(pos);
|
||||
} else if (os_strcmp(buf, "eht_oper_chwidth") == 0) {
|
||||
conf->eht_oper_chwidth = atoi(pos);
|
||||
} else if (os_strcmp(buf, "eht_oper_centr_freq_seg0_idx") == 0) {
|
||||
conf->eht_oper_centr_freq_seg0_idx = atoi(pos);
|
||||
} else if (os_strcmp(buf, "eht_su_beamformer") == 0) {
|
||||
conf->eht_phy_capab.su_beamformer = atoi(pos);
|
||||
} else if (os_strcmp(buf, "eht_su_beamformee") == 0) {
|
||||
conf->eht_phy_capab.su_beamformee = atoi(pos);
|
||||
} else if (os_strcmp(buf, "eht_mu_beamformer") == 0) {
|
||||
conf->eht_phy_capab.mu_beamformer = atoi(pos);
|
||||
} else if (os_strcmp(buf, "eht_default_pe_duration") == 0) {
|
||||
conf->eht_default_pe_duration = atoi(pos);
|
||||
} else if (os_strcmp(buf, "punct_bitmap") == 0) {
|
||||
if (get_u16(pos, line, &conf->punct_bitmap))
|
||||
return 1;
|
||||
} else if (os_strcmp(buf, "punct_acs_threshold") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < 0 || val > 100) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: punct_acs_threshold must be between 0 and 100",
|
||||
line);
|
||||
return 1;
|
||||
}
|
||||
conf->punct_acs_threshold = val;
|
||||
} else if (os_strcmp(buf, "mld_ap") == 0) {
|
||||
bss->mld_ap = !!atoi(pos);
|
||||
} else if (os_strcmp(buf, "mld_addr") == 0) {
|
||||
if (hwaddr_aton(pos, bss->mld_addr)) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Invalid mld_addr",
|
||||
line);
|
||||
return 1;
|
||||
}
|
||||
} else if (os_strcmp(buf, "eht_bw320_offset") == 0) {
|
||||
conf->eht_bw320_offset = atoi(pos);
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
} else if (os_strcmp(buf, "eht_oper_puncturing_override") == 0) {
|
||||
if (get_u16(pos, line, &bss->eht_oper_puncturing_override))
|
||||
return 1;
|
||||
} else if (os_strcmp(buf, "mld_indicate_disabled") == 0) {
|
||||
bss->mld_indicate_disabled = atoi(pos);
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: unknown configuration item '%s'",
|
||||
|
@ -10,13 +10,10 @@
|
||||
#define CONFIG_FILE_H
|
||||
|
||||
struct hostapd_config * hostapd_config_read(const char *fname);
|
||||
int hostapd_config_read_rxkh_file(struct hostapd_bss_config *conf,
|
||||
const char *fname);
|
||||
int hostapd_set_iface(struct hostapd_config *conf,
|
||||
struct hostapd_bss_config *bss, const char *field,
|
||||
char *value);
|
||||
int hostapd_acl_comp(const void *a, const void *b);
|
||||
int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
|
||||
int vlan_id, const u8 *addr);
|
||||
void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
|
||||
const u8 *addr);
|
||||
|
||||
#endif /* CONFIG_FILE_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -141,6 +141,9 @@ CONFIG_PKCS12=y
|
||||
# Build IPv6 support for RADIUS operations
|
||||
CONFIG_IPV6=y
|
||||
|
||||
# Include support fo RADIUS/TLS into the RADIUS client
|
||||
#CONFIG_RADIUS_TLS=y
|
||||
|
||||
# IEEE Std 802.11r-2008 (Fast BSS Transition)
|
||||
#CONFIG_IEEE80211R=y
|
||||
|
||||
@ -156,10 +159,20 @@ CONFIG_IPV6=y
|
||||
#CONFIG_IEEE80211AC=y
|
||||
|
||||
# IEEE 802.11ax HE support
|
||||
#CONFIG_IEEE80211AX=y
|
||||
|
||||
# IEEE 802.11be EHT support
|
||||
# CONFIG_IEEE80211AX is mandatory for setting CONFIG_IEEE80211BE.
|
||||
# Note: This is experimental and work in progress. The definitions are still
|
||||
# subject to change and this should not be expected to interoperate with the
|
||||
# final IEEE 802.11ax version.
|
||||
#CONFIG_IEEE80211AX=y
|
||||
# final IEEE 802.11be version.
|
||||
#CONFIG_IEEE80211BE=y
|
||||
|
||||
# Simultaneous Authentication of Equals (SAE), WPA3-Personal
|
||||
#CONFIG_SAE=y
|
||||
|
||||
# SAE Public Key, WPA3-Personal
|
||||
#CONFIG_SAE_PK=y
|
||||
|
||||
# Remove debugging code that is printing out debug messages to stdout.
|
||||
# This can be used to reduce the size of the hostapd considerably if debugging
|
||||
@ -400,7 +413,6 @@ CONFIG_IPV6=y
|
||||
# Experimental implementation based on IEEE P802.11z/D2.6 and the protocol
|
||||
# design is still subject to change. As such, this should not yet be enabled in
|
||||
# production use.
|
||||
# This requires CONFIG_IEEE80211W=y to be enabled, too.
|
||||
#CONFIG_PASN=y
|
||||
|
||||
# Device Provisioning Protocol (DPP) (also known as Wi-Fi Easy Connect)
|
||||
@ -410,3 +422,6 @@ CONFIG_DPP2=y
|
||||
# DPP version 3 support (experimental and still changing; do not enable for
|
||||
# production use)
|
||||
#CONFIG_DPP3=y
|
||||
|
||||
# Wi-Fi Aware unsynchronized service discovery (NAN USD)
|
||||
#CONFIG_NAN_USD=y
|
||||
|
@ -225,6 +225,16 @@ channel=1
|
||||
# Default behavior is to include all PSC and non-PSC channels.
|
||||
#acs_exclude_6ghz_non_psc=1
|
||||
|
||||
# Enable background radar feature
|
||||
# This feature allows CAC to be run on dedicated radio RF chains while the
|
||||
# radio(s) are otherwise running normal AP activities on other channels.
|
||||
# This requires that the driver and the radio support it before feature will
|
||||
# actually be enabled, i.e., this parameter value is ignored with drivers that
|
||||
# do not advertise support for the capability.
|
||||
# 0: Leave disabled (default)
|
||||
# 1: Enable it.
|
||||
#enable_background_radar=1
|
||||
|
||||
# Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection.
|
||||
# (default 0, i.e., not constraint)
|
||||
#min_tx_power=20
|
||||
@ -512,6 +522,25 @@ wmm_ac_vo_acm=0
|
||||
# even if they are still in range of the AP. This can be done by setting
|
||||
# skip_inactivity_poll to 1 (default 0).
|
||||
#skip_inactivity_poll=0
|
||||
#
|
||||
# BSS max idle period management
|
||||
# 0 = disabled (do not advertise and manage BSS max idle period)
|
||||
# 1 = enabled (advertise and manage BSS max idle period; default)
|
||||
# 2 = enabled requiring protected frames (advertise and manage BSS max idle
|
||||
# period and require STAs to use protected keep-alive frames)
|
||||
#bss_max_idle=1
|
||||
#
|
||||
# Maximum acceptable BSS maximum idle period
|
||||
# If this is set to a nonzero value, the AP allows STAs to request different
|
||||
# maximum idle period values. This is in the units to 1000 TUs (1.024 s)
|
||||
#max_acceptable_idle_period=600
|
||||
#
|
||||
# Allow STA to skip group key handshake without getting disconnection when
|
||||
# BSS max idle period management is enabled.
|
||||
# 0 = disconnect STA if it does not reply to group key handshake (default)
|
||||
# 1 = do not disconnect STA if it does not reply to group key handshake and
|
||||
# if BSS max idle period management is enabled
|
||||
#no_disconnect_on_group_keyerror=0
|
||||
|
||||
# Disassociate stations based on excessive transmission failures or other
|
||||
# indications of connection loss. This depends on the driver capabilities and
|
||||
@ -636,6 +665,12 @@ wmm_ac_vo_acm=0
|
||||
# no co-existence issues with neighboring devices are found.
|
||||
#obss_interval=0
|
||||
|
||||
# ht_vht_twt_responder: Whether TWT responder is enabled in HT and VHT modes
|
||||
# 0 = disable; Disable TWT responder support in HT and VHT modes (default).
|
||||
# 1 = enable; Enable TWT responder support in HT and VHT modes if supported by
|
||||
# the driver.
|
||||
#ht_vht_twt_responder=0
|
||||
|
||||
##### IEEE 802.11ac related configuration #####################################
|
||||
|
||||
# ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled
|
||||
@ -802,6 +837,9 @@ wmm_ac_vo_acm=0
|
||||
# 1 = enabled
|
||||
#ieee80211ax=1
|
||||
|
||||
# Require stations to support HE PHY (reject association if they do not)
|
||||
#require_he=1
|
||||
|
||||
# disable_11ax: Boolean (0/1) to disable HE for a specific BSS
|
||||
#disable_11ax=0
|
||||
|
||||
@ -861,7 +899,7 @@ wmm_ac_vo_acm=0
|
||||
# he_oper_chwidth is ignored, and the channel width is derived from the
|
||||
# configured operating class or center frequency indexes (see
|
||||
# IEEE P802.11ax/D6.1 Annex E, Table E-4).
|
||||
#he_oper_chwidth
|
||||
#he_oper_chwidth (see vht_oper_chwidth)
|
||||
#he_oper_centr_freq_seg0_idx
|
||||
#he_oper_centr_freq_seg1_idx
|
||||
|
||||
@ -965,6 +1003,25 @@ wmm_ac_vo_acm=0
|
||||
# (default)
|
||||
#he_6ghz_tx_ant_pat=1
|
||||
|
||||
# 6 GHz Access Point type
|
||||
# This config is to set the 6 GHz Access Point type. Possible options are:
|
||||
# 0 = Indoor AP
|
||||
# 1 = Standard power AP
|
||||
# 2 = Very low power AP (default)
|
||||
# 3 = Indoor enabled AP
|
||||
# 4 = Indoor standard power AP
|
||||
# This has no impact for operation on other bands.
|
||||
# See IEEE P802.11-REVme/D4.0, Table E-12 (Regulatory Info subfield encoding)
|
||||
# for more details.
|
||||
#he_6ghz_reg_pwr_type=0
|
||||
#
|
||||
# 6 GHz Maximum Tx Power used in Transmit Power Envelope elements, where the
|
||||
# "Transmit Power Interpretation" is set to "Regulatory client EIRP PSD".
|
||||
# For Maximum Transmit Power Category subfield encoding set to default (0):
|
||||
#reg_def_cli_eirp_psd=-1
|
||||
# For Maximum Transmit Power Category subfield encoding set to subordinate (1):
|
||||
#reg_sub_cli_eirp_psd=-1
|
||||
|
||||
# Unsolicited broadcast Probe Response transmission settings
|
||||
# This is for the 6 GHz band only. If the interval is set to a non-zero value,
|
||||
# the AP schedules unsolicited broadcast Probe Response frames to be
|
||||
@ -973,6 +1030,78 @@ wmm_ac_vo_acm=0
|
||||
# Valid range: 0..20 TUs; default is 0 (disabled)
|
||||
#unsol_bcast_probe_resp_interval=0
|
||||
|
||||
##### IEEE 802.11be related configuration #####################################
|
||||
|
||||
#ieee80211be: Whether IEEE 802.11be (EHT) is enabled
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#ieee80211be=1
|
||||
|
||||
#disable_11be: Boolean (0/1) to disable EHT for a specific BSS
|
||||
#disable_11be=0
|
||||
|
||||
#eht_su_beamformer: EHT single user beamformer support
|
||||
# 0 = not supported (default)
|
||||
# 1 = supported
|
||||
#eht_su_beamformer=1
|
||||
|
||||
#eht_su_beamformee: EHT single user beamformee support
|
||||
# 0 = not supported (default)
|
||||
# 1 = supported
|
||||
#eht_su_beamformee=1
|
||||
|
||||
#eht_mu_beamformer: EHT multiple user beamformer support
|
||||
# 0 = not supported (default)
|
||||
# 1 = supported
|
||||
#eht_mu_beamformer=1
|
||||
|
||||
# EHT operating channel information; see matching he_* parameters for details.
|
||||
# The field eht_oper_centr_freq_seg0_idx field is used to indicate center
|
||||
# frequency of 40, 80, and 160 MHz bandwidth operation.
|
||||
# In the 6 GHz band, eht_oper_chwidth is ignored and the channel width is
|
||||
# derived from the configured operating class (IEEE P802.11be/D1.5,
|
||||
# Annex E.1 - Country information and operating classes).
|
||||
#eht_oper_chwidth (see vht_oper_chwidth)
|
||||
#eht_oper_centr_freq_seg0_idx
|
||||
|
||||
#eht_default_pe_duration: The duration of PE field in EHT TB PPDU
|
||||
# 0 = PE field duration is the same as he_default_pe_duration (default)
|
||||
# 1 = PE field duration is 20 us
|
||||
#eht_default_pe_duration=0
|
||||
|
||||
#eht_bw320_offset: For automatic channel selection (ACS) to indicate a preferred
|
||||
# 320 MHz channelization in EHT mode.
|
||||
# If the channel is decided or the bandwidth is not 320 MHz, this option is
|
||||
# meaningless.
|
||||
# 0 = auto-detect by hostapd
|
||||
# 1 = 320 MHz-1 (channel center frequency 31, 95, 159)
|
||||
# 2 = 320 MHz-2 (channel center frequency 63, 127, 191)
|
||||
#eht_bw320_offset=0
|
||||
|
||||
# Disabled subchannel bitmap (16 bits) as per IEEE P802.11be/3.0,
|
||||
# Figure 9-1002c (EHT Operation Information field format). Each bit corresponds
|
||||
# to a 20 MHz channel, the lowest bit corresponds to the lowest frequency. A
|
||||
# bit set to 1 indicates that the channel is punctured (disabled). The default
|
||||
# value is 0 indicating that all channels are active.
|
||||
#punct_bitmap=0
|
||||
|
||||
# Preamble puncturing threshold in automatic channel selection (ACS).
|
||||
# The value indicates the percentage of ideal channel average interference
|
||||
# factor above which a channel should be punctured.
|
||||
# Default is 0, indicates that ACS algorithm should not puncture any channel.
|
||||
#punct_acs_threshold=75
|
||||
|
||||
# AP MLD - Whether this AP is a part of an AP MLD
|
||||
# 0 = no (no MLO)
|
||||
# 1 = yes (MLO)
|
||||
#mld_ap=0
|
||||
|
||||
# AP MLD MAC address
|
||||
# The configured address will be set as the interface hardware address and used
|
||||
# as the AP MLD MAC address. If not set, the current interface hardware address
|
||||
# will be used as the AP MLD MAC address.
|
||||
#mld_addr=02:03:04:05:06:07
|
||||
|
||||
##### IEEE 802.1X-2004 related configuration ##################################
|
||||
|
||||
# Require IEEE 802.1X authorization
|
||||
@ -1063,6 +1192,14 @@ eapol_key_index_workaround=0
|
||||
# 0: No replay window, strict check (default)
|
||||
# 1..2^32-1: number of packets that could be misordered
|
||||
#
|
||||
# macsec_offload: IEEE 802.1X/MACsec hardware offload
|
||||
# This setting applies only when MACsec is in use, i.e.,
|
||||
# - macsec_policy is enabled
|
||||
# - the key server has decided to enable MACsec
|
||||
# 0 = MACSEC_OFFLOAD_OFF (default)
|
||||
# 1 = MACSEC_OFFLOAD_PHY
|
||||
# 2 = MACSEC_OFFLOAD_MAC
|
||||
#
|
||||
# macsec_port: IEEE 802.1X/MACsec port
|
||||
# Port component of the SCI
|
||||
# Range: 1-65534 (default: 1)
|
||||
@ -1070,6 +1207,10 @@ eapol_key_index_workaround=0
|
||||
# mka_priority (Priority of MKA Actor)
|
||||
# Range: 0..255 (default: 255)
|
||||
#
|
||||
# macsec_csindex: IEEE 802.1X/MACsec cipher suite
|
||||
# 0 = GCM-AES-128 (default)
|
||||
# 1 = GCM-AES-256 (default)
|
||||
#
|
||||
# mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode
|
||||
# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
|
||||
# In this mode, instances of hostapd can act as MACsec peers. The peer
|
||||
@ -1243,12 +1384,11 @@ eap_server=0
|
||||
|
||||
# dh_file: File path to DH/DSA parameters file (in PEM format)
|
||||
# This is an optional configuration file for setting parameters for an
|
||||
# ephemeral DH key exchange. In most cases, the default RSA authentication does
|
||||
# not use this configuration. However, it is possible setup RSA to use
|
||||
# ephemeral DH key exchange. In addition, ciphers with DSA keys always use
|
||||
# ephemeral DH keys. This can be used to achieve forward secrecy. If the file
|
||||
# is in DSA parameters format, it will be automatically converted into DH
|
||||
# params. This parameter is required if anonymous EAP-FAST is used.
|
||||
# ephemeral DH key exchange. If the file is in DSA parameters format, it will
|
||||
# be automatically converted into DH params. If the used TLS library supports
|
||||
# automatic DH parameter selection, that functionality will be used if this
|
||||
# parameter is not set. DH parameters are required if anonymous EAP-FAST is
|
||||
# used.
|
||||
# You can generate DH parameters file with OpenSSL, e.g.,
|
||||
# "openssl dhparam -out /etc/hostapd.dh.pem 2048"
|
||||
#dh_file=/etc/hostapd.dh.pem
|
||||
@ -1358,6 +1498,12 @@ eap_server=0
|
||||
# 5 = require both user and machine identity
|
||||
#eap_teap_id=0
|
||||
|
||||
# EAP-TEAP tunneled EAP method behavior
|
||||
# 0 = minimize roundtrips by merging start of the next EAP method with the
|
||||
# crypto-binding of the previous one.
|
||||
# 1 = complete crypto-binding before starting the next EAP method
|
||||
#eap_teap_method_sequence=0
|
||||
|
||||
# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
|
||||
# (default: 0 = disabled).
|
||||
#eap_sim_aka_result_ind=1
|
||||
@ -1367,8 +1513,25 @@ eap_server=0
|
||||
# 1 = use pseudonyms, but not fast reauthentication
|
||||
# 2 = do not use pseudonyms, but use fast reauthentication
|
||||
# 3 = use pseudonyms and use fast reauthentication (default)
|
||||
# 4 = do not use pseudonyms or fast reauthentication and allow
|
||||
# EAP-Response/Identity to be used without method specific identity exchange
|
||||
# 5 = use pseudonyms, but not fast reauthentication and allow
|
||||
# EAP-Response/Identity to be used without method specific identity exchange
|
||||
# 6 = do not use pseudonyms, but use fast reauthentication and allow
|
||||
# EAP-Response/Identity to be used without method specific identity exchange
|
||||
# 7 = use pseudonyms and use fast reauthentication and allow
|
||||
# EAP-Response/Identity to be used without method specific identity exchange
|
||||
#eap_sim_id=3
|
||||
|
||||
# IMSI privacy key (PEM encoded RSA 2048-bit private key) for decrypting
|
||||
# permanent identity when using EAP-SIM/AKA/AKA'.
|
||||
#imsi_privacy_key=imsi-privacy-key.pem
|
||||
|
||||
# EAP-SIM and EAP-AKA fast re-authentication limit
|
||||
# Maximum number of fast re-authentications allowed after each full
|
||||
# authentication.
|
||||
#eap_sim_aka_fast_reauth_limit=1000
|
||||
|
||||
# Trusted Network Connect (TNC)
|
||||
# If enabled, TNC validation will be required before the peer is allowed to
|
||||
# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
|
||||
@ -1440,6 +1603,16 @@ own_ip_addr=127.0.0.1
|
||||
#acct_server_port=1813
|
||||
#acct_server_shared_secret=secret2
|
||||
|
||||
# RADIUS/TLS instead of RADIUS/UDP
|
||||
#auth_server_addr=127.0.0.1
|
||||
#auth_server_port=2083
|
||||
#auth_server_type=TLS
|
||||
#auth_server_shared_secret=radsec
|
||||
#auth_server_ca_cert=<path to trusted CA certificate(s)>
|
||||
#auth_server_client_cert=<path to client certificate>
|
||||
#auth_server_private_key=<path to private key>
|
||||
#auth_server_private_key_passwd=<password for decrypting private key>
|
||||
|
||||
# Retry interval for trying to return to the primary RADIUS server (in
|
||||
# seconds). RADIUS client code will automatically try to use the next server
|
||||
# when the current server is not replying to requests. If this interval is set,
|
||||
@ -1447,6 +1620,17 @@ own_ip_addr=127.0.0.1
|
||||
# currently used secondary server is still working.
|
||||
#radius_retry_primary_interval=600
|
||||
|
||||
# Message-Authenticator attribute requirement for non-EAP cases
|
||||
# hostapd requires Message-Authenticator attribute to be included in all cases
|
||||
# where RADIUS is used for EAP authentication. This is also required for cases
|
||||
# where RADIUS is used for MAC ACL (macaddr_acl=2) by default, but that case
|
||||
# can be configured to not require this for compatibility with RADIUS servers
|
||||
# that do not include the attribute. This is not recommended due to potential
|
||||
# security concerns, but can be used as a temporary workaround in networks where
|
||||
# the connection to the RADIUS server is secure.
|
||||
# 0 = Do not require Message-Authenticator in MAC ACL response
|
||||
# 1 = Require Message-Authenticator in all authentication cases (default)
|
||||
#radius_require_message_authenticator=1
|
||||
|
||||
# Interim accounting update interval
|
||||
# If this is set (larger than 0) and acct_server is configured, hostapd will
|
||||
@ -1651,12 +1835,19 @@ own_ip_addr=127.0.0.1
|
||||
#wpa_psk_file=/etc/hostapd.wpa_psk
|
||||
|
||||
# Optionally, WPA passphrase can be received from RADIUS authentication server
|
||||
# This requires macaddr_acl to be set to 2 (RADIUS)
|
||||
# This requires macaddr_acl to be set to 2 (RADIUS) for wpa_psk_radius values
|
||||
# 1 and 2.
|
||||
# 0 = disabled (default)
|
||||
# 1 = optional; use default passphrase/psk if RADIUS server does not include
|
||||
# Tunnel-Password
|
||||
# 2 = required; reject authentication if RADIUS server does not include
|
||||
# Tunnel-Password
|
||||
# 3 = ask RADIUS server during 4-way handshake if there is no locally
|
||||
# configured PSK/passphrase for the STA
|
||||
#
|
||||
# The Tunnel-Password attribute in Access-Accept can contain either the
|
||||
# 8..63 character ASCII passphrase or a 64 hex character encoding of the PSK.
|
||||
#
|
||||
#wpa_psk_radius=0
|
||||
|
||||
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
|
||||
@ -1914,6 +2105,10 @@ own_ip_addr=127.0.0.1
|
||||
#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff
|
||||
#sae_password=example secret|mac=02:03:04:05:06:07|id=pw identifier
|
||||
#sae_password=example secret|vlanid=3|id=pw identifier
|
||||
#
|
||||
# SAE passwords can also be read from a separate file in which each line
|
||||
# contains and entry in the same format as sae_password uses.
|
||||
#sae_password_file=/tc/hostapd.sae_passwords
|
||||
|
||||
# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
|
||||
# This parameter defines how many open SAE instances can be in progress at the
|
||||
@ -1924,7 +2119,7 @@ own_ip_addr=127.0.0.1
|
||||
# Maximum number of SAE synchronization errors (dot11RSNASAESync)
|
||||
# The offending SAE peer will be disconnected if more than this many
|
||||
# synchronization errors happen.
|
||||
#sae_sync=5
|
||||
#sae_sync=3
|
||||
|
||||
# Enabled SAE finite cyclic groups
|
||||
# SAE implementation are required to support group 19 (ECC group defined over a
|
||||
@ -2042,6 +2237,8 @@ own_ip_addr=127.0.0.1
|
||||
# If fils_discovery_max_interval is non-zero, the AP enables FILS Discovery
|
||||
# frame transmission. These values use TUs as the unit and have allowed range
|
||||
# of 0-10000. fils_discovery_min_interval defaults to 20.
|
||||
# This feature is currently supported only when ieee80211ax is enabled for
|
||||
# the radio and disable_11ax is not set for the BSS.
|
||||
#fils_discovery_min_interval=20
|
||||
#fils_discovery_max_interval=0
|
||||
|
||||
@ -2077,6 +2274,30 @@ own_ip_addr=127.0.0.1
|
||||
# (default: 10 TUs)
|
||||
#pasn_comeback_after=10
|
||||
|
||||
# Unauthenticated PASN activated (dot11NoAuthPASNActivated)
|
||||
# This indicates whether PASN without mutual authentication is allowed.
|
||||
# (default: 1 = activated)
|
||||
#pasn_noauth=1
|
||||
|
||||
# SSID protection in 4-way handshake
|
||||
# The IEEE 802.11i-2004 RSN design did not provide means for protecting the
|
||||
# SSID in the general case. IEEE P802.11REVme/D6.0 added support for this in
|
||||
# 4-way handshake. This capability allows a STA to confirm that the AP has the
|
||||
# same understanding on which SSID is being used for an association in a
|
||||
# protected manner in cases where both the AP and the STA has this capability.
|
||||
# This can be used to mitigate CVE-2023-52424 (a.k.a. the SSID Confusion
|
||||
# Attack).
|
||||
#
|
||||
# Ideally, this capability would be enabled by default on the AP, but since this
|
||||
# is new functionality with limited testing, the default is to disable this for
|
||||
# now and require explicitly configuration to enable. The default behavior is
|
||||
# like to change once this capability has received more testing.
|
||||
#
|
||||
# 0 = SSID protection in 4-way handshake disabled (default)
|
||||
# 1 = SSID protection in 4-way handshake enabled
|
||||
#
|
||||
#ssid_protection=0
|
||||
|
||||
##### IEEE 802.11r configuration ##############################################
|
||||
|
||||
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
|
||||
@ -2136,6 +2357,12 @@ own_ip_addr=127.0.0.1
|
||||
# list and thus will receive push notifications.
|
||||
#r1kh=00:00:00:00:00:00 00:00:00:00:00:00 00112233445566778899aabbccddeeff
|
||||
|
||||
# Optionally, the list of RxKHs can be read from a text file. Format is the same
|
||||
# as specified above. File shall contain both r0kh and r1kh. Once this variable
|
||||
# is set, RxKHs can be reloaded at runtime without bringing down an interface
|
||||
# using the RELOAD_RXKHS command.
|
||||
#rxkh_file=<path>
|
||||
|
||||
# Timeout (seconds) for newly discovered R0KH/R1KH (see wildcard entries above)
|
||||
# Special values: 0 -> do not expire
|
||||
# Warning: do not cache implies no sequence number validation with wildcards
|
||||
@ -2390,6 +2617,23 @@ own_ip_addr=127.0.0.1
|
||||
#multi_ap_backhaul_wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
||||
#multi_ap_backhaul_wpa_passphrase=secret passphrase
|
||||
|
||||
# Multi-AP Profile
|
||||
# Indicate the supported Multi-AP profile (default: 2)
|
||||
# 1 = Supports Multi-AP profile 1 as defined in Wi-Fi EasyMesh specification
|
||||
# 2 = Supports Multi-AP profile 2 as defined in Wi-Fi EasyMesh specification
|
||||
#multi_ap_profile=2
|
||||
|
||||
# Multi-AP client disallow
|
||||
# Used to disallow profile specific backhaul STA association
|
||||
# Bitmap of the disallowed Profile-X profiles
|
||||
# 1 = Profile-1 Backhaul STA association disallowed
|
||||
# 2 = Profile-2 Backhaul STA association disallowed
|
||||
#multi_ap_client_disallow=0
|
||||
|
||||
# Multi-AP VLAN ID
|
||||
# A valid non-zero VLAN ID will be used to update Default IEEE 802.1Q Setting
|
||||
#multi_ap_vlanid=0
|
||||
|
||||
# WPS UPnP interface
|
||||
# If set, support for external Registrars is enabled.
|
||||
#upnp_iface=br0
|
||||
@ -2453,12 +2697,24 @@ own_ip_addr=127.0.0.1
|
||||
# MUD URL for Enrollee's DPP Configuration Request (optional)
|
||||
#dpp_mud_url=https://example.com/mud
|
||||
|
||||
# JSON node name of additional data for Enrollee's DPP Configuration Request
|
||||
#dpp_extra_conf_req_name=org.example
|
||||
|
||||
# JSON node data of additional data for Enrollee's DPP Configuration Request
|
||||
#dpp_extra_conf_req_value="abc":123
|
||||
|
||||
#dpp_connector
|
||||
#dpp_netaccesskey
|
||||
#dpp_netaccesskey_expiry
|
||||
#dpp_csign
|
||||
#dpp_controller
|
||||
|
||||
# DPP Relay port number
|
||||
# TCP port to listen to for incoming connections from a Controller. This can be
|
||||
# used to allow Controller initiated exchanges in addition to the
|
||||
# Controller-as-responder cases covered by the dpp_controller parameter.
|
||||
#dpp_relay_port=12345
|
||||
|
||||
# Configurator Connectivity indication
|
||||
# 0: no Configurator is currently connected (default)
|
||||
# 1: advertise that a Configurator is available
|
||||
@ -2726,7 +2982,12 @@ own_ip_addr=127.0.0.1
|
||||
# If the RADIUS server indicates that the station is not allowed to connect to
|
||||
# the BSS/ESS, the AP can allow the station some time to download a
|
||||
# notification page (URL included in the message). This parameter sets that
|
||||
# timeout in seconds.
|
||||
# timeout in seconds. If the RADIUS server provides no URL, this value is
|
||||
# reduced to two seconds with an additional trigger for immediate
|
||||
# deauthentication when the STA acknowledges reception of the deauthentication
|
||||
# imminent indication. Note that setting this value to 0 will prevent delivery
|
||||
# of the notification to the STA, so a value of at least 1 should be used here
|
||||
# for normal use cases.
|
||||
#hs20_deauth_req_timeout=60
|
||||
|
||||
# Operator Friendly Name
|
||||
@ -2906,6 +3167,9 @@ own_ip_addr=127.0.0.1
|
||||
# Enable neighbor report via radio measurements
|
||||
#rrm_neighbor_report=1
|
||||
|
||||
# Enable link measurement report via radio measurements
|
||||
#rrm_link_measurement_report=1
|
||||
|
||||
# Enable beacon report via radio measurements
|
||||
#rrm_beacon_report=1
|
||||
|
||||
@ -3002,6 +3266,18 @@ own_ip_addr=127.0.0.1
|
||||
# Include only ECSA IE without CSA IE where possible
|
||||
# (channel switch operating class is needed)
|
||||
#ecsa_ie_only=0
|
||||
#
|
||||
# Delay EAPOL-Key messages 1/4 and 3/4 by not sending the frame until the last
|
||||
# attempt (wpa_pairwise_update_count). This will trigger a timeout on all
|
||||
# previous attempts and thus delays the frame. (testing only)
|
||||
#delay_eapol_tx=0
|
||||
#
|
||||
# Additional elements for Probe Response frames.
|
||||
# This parameter can be used to add additional element(s) to the end of the
|
||||
# Probe Response frames. The format for these element(s) is a hexdump of the
|
||||
# raw information elements (id+len+payload for one or more elements).
|
||||
# These elements are added after the 'vendor_elements'.
|
||||
#presp_elements=
|
||||
|
||||
##### Multiple BSSID support ##################################################
|
||||
#
|
||||
@ -3045,3 +3321,63 @@ own_ip_addr=127.0.0.1
|
||||
#bss=wlan0_1
|
||||
#bssid=00:13:10:95:fe:0b
|
||||
# ...
|
||||
#
|
||||
# Multiple BSSID Advertisement in IEEE 802.11ax
|
||||
# IEEE Std 802.11ax-2021 added a feature where instead of multiple interfaces
|
||||
# on a common radio transmitting individual Beacon frames, those interfaces can
|
||||
# form a set with a common Beacon frame transmitted for all. The interface
|
||||
# which is brought up first is called the transmitting profile of the MBSSID
|
||||
# set which transmits the Beacon frames. The remaining interfaces are called
|
||||
# the non-transmitting profiles and these are advertised inside the Multiple
|
||||
# BSSID element in the Beacon and Probe Response frames from the first
|
||||
# interface.
|
||||
#
|
||||
# The transmitting interface is visible to all stations in the vicinity, however
|
||||
# the stations that do not support parsing of the Multiple BSSID element will
|
||||
# not be able to connect to the non-transmitting interfaces.
|
||||
#
|
||||
# Enhanced Multiple BSSID Advertisements (EMA)
|
||||
# When enabled, the non-transmitting interfaces are split into multiple
|
||||
# Beacon frames. The number of Beacon frames required to cover all the
|
||||
# non-transmitting profiles is called the profile periodicity.
|
||||
#
|
||||
# Refer to IEEE Std 802.11-2020 for details regarding the procedure and
|
||||
# required MAC address assignment.
|
||||
#
|
||||
# Following configuration is per radio.
|
||||
# 0 = Disabled (default)
|
||||
# 1 = Multiple BSSID advertisement enabled.
|
||||
# 2 = Enhanced multiple BSSID advertisement enabled.
|
||||
#mbssid=0
|
||||
#
|
||||
# The transmitting interface should be added with the 'interface' option while
|
||||
# the non-transmitting interfaces should be added using the 'bss' option.
|
||||
# Security configuration should be added separately per interface, if required.
|
||||
#
|
||||
# Example:
|
||||
#mbssid=2
|
||||
#interface=wlan2
|
||||
#ctrl_interface=/var/run/hostapd
|
||||
#wpa_passphrase=0123456789
|
||||
#ieee80211w=2
|
||||
#sae_pwe=1
|
||||
#auth_algs=1
|
||||
#wpa=2
|
||||
#wpa_pairwise=CCMP
|
||||
#ssid=<SSID-0>
|
||||
#bridge=br-lan
|
||||
#wpa_key_mgmt=SAE
|
||||
#bssid=00:03:7f:12:84:84
|
||||
#
|
||||
#bss=wlan2-1
|
||||
#ctrl_interface=/var/run/hostapd
|
||||
#wpa_passphrase=0123456789
|
||||
#ieee80211w=2
|
||||
#sae_pwe=1
|
||||
#auth_algs=1
|
||||
#wpa=2
|
||||
#wpa_pairwise=CCMP
|
||||
#ssid=<SSID-1>
|
||||
#bridge=br-lan
|
||||
#wpa_key_mgmt=SAE
|
||||
#bssid=00:03:7f:12:84:85
|
||||
|
@ -52,8 +52,8 @@
|
||||
# Arbitrary RADIUS attributes can be added into Access-Accept packets similarly
|
||||
# to the way radius_auth_req_attr is used for Access-Request packet in
|
||||
# hostapd.conf. For EAP server, this is configured separately for each user
|
||||
# entry with radius_accept_attr=<value> line(s) following the main user entry
|
||||
# line.
|
||||
# entry with radius_accept_attr=<attr_id>[:<syntax:value>] line(s) following
|
||||
# the main user entry line.
|
||||
|
||||
# Phase 1 users
|
||||
"user" MD5 "password"
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
static const char *const hostapd_cli_version =
|
||||
"hostapd_cli v" VERSION_STR "\n"
|
||||
"Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi> and contributors";
|
||||
"Copyright (c) 2004-2024, Jouni Malinen <j@w1.fi> and contributors";
|
||||
|
||||
static struct wpa_ctrl *ctrl_conn;
|
||||
static int hostapd_cli_quit = 0;
|
||||
@ -252,6 +252,13 @@ static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_close_log(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "CLOSE_LOG");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
|
||||
@ -307,6 +314,12 @@ static void hostapd_cli_action_process(char *msg, size_t len)
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_action_cb(char *msg, size_t len)
|
||||
{
|
||||
hostapd_cli_action_process(msg, len);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
char buf[64];
|
||||
@ -1155,6 +1168,15 @@ static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
static int hostapd_cli_cmd_color_change(struct wpa_ctrl *ctrl,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "COLOR_CHANGE", 1, argc, argv);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
@ -1169,7 +1191,7 @@ static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
|
||||
"arguments (count and freq)\n"
|
||||
"usage: <cs_count> <freq> [sec_channel_offset=] "
|
||||
"[center_freq1=] [center_freq2=] [bandwidth=] "
|
||||
"[blocktx] [ht|vht]\n");
|
||||
"[blocktx] [ht|vht|he|eht]\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1194,34 +1216,76 @@ static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_notify_cw_change(struct wpa_ctrl *ctrl,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "NOTIFY_CW_CHANGE", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "ENABLE");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "RELOAD");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
|
||||
static int hostapd_cli_cmd_reload_bss(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "RELOAD_BSS");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_reload_config(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "RELOAD_CONFIG");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "DISABLE");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc,
|
||||
static int hostapd_cli_cmd_enable_mld(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "ENABLE_MLD");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_disable_mld(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "DISABLE_MLD");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "UPDATE_BEACON");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_stop_ap(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "STOP_AP");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
char cmd[256];
|
||||
@ -1366,6 +1430,13 @@ static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_driver_flags2(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "DRIVER_FLAGS2");
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
|
||||
static int hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc,
|
||||
@ -1478,7 +1549,7 @@ static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
|
||||
static int hostapd_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_CONTROLLER_START", 1, argc, argv);
|
||||
return hostapd_cli_cmd(ctrl, "DPP_CONTROLLER_START", 0, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
@ -1503,6 +1574,15 @@ static int hostapd_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP3
|
||||
static int hostapd_cli_cmd_dpp_push_button(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_PUSH_BUTTON", 0, argc, argv);
|
||||
}
|
||||
#endif /* CONFIG_DPP3 */
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
|
||||
@ -1534,6 +1614,13 @@ static int hostapd_cli_cmd_req_beacon(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_req_link_measurement(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "REQ_LINK_MEASUREMENT", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
@ -1541,6 +1628,24 @@ static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
|
||||
static int hostapd_cli_cmd_get_rxkhs(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "GET_RXKHS");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_reload_rxkhs(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "RELOAD_RXKHS");
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
|
||||
#ifdef ANDROID
|
||||
static int hostapd_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
@ -1563,6 +1668,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
"= get MIB variables (dot1x, dot11, radius)" },
|
||||
{ "relog", hostapd_cli_cmd_relog, NULL,
|
||||
"= reload/truncate debug log output file" },
|
||||
{ "close_log", hostapd_cli_cmd_close_log, NULL,
|
||||
"= disable debug log output file" },
|
||||
{ "status", hostapd_cli_cmd_status, NULL,
|
||||
"= show interface status info" },
|
||||
{ "sta", hostapd_cli_cmd_sta, hostapd_complete_stations,
|
||||
@ -1648,6 +1755,13 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
"<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n"
|
||||
" [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n"
|
||||
" = initiate channel switch announcement" },
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
{ "color_change", hostapd_cli_cmd_color_change, NULL,
|
||||
"<color> = initiate BSS color change to set the specified color\n"
|
||||
"Value 0 will disable the color.\n"},
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
{ "notify_cw_change", hostapd_cli_cmd_notify_cw_change, NULL,
|
||||
"<channel_width> = 0 - 20 MHz, 1 - 40 MHz, 2 - 80 MHz, 3 - 160 MHz" },
|
||||
{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL,
|
||||
"<addr> <url>\n"
|
||||
" = send WNM-Notification Subscription Remediation Request" },
|
||||
@ -1661,10 +1775,20 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
"= enable hostapd on current interface" },
|
||||
{ "reload", hostapd_cli_cmd_reload, NULL,
|
||||
"= reload configuration for current interface" },
|
||||
{ "reload_bss", hostapd_cli_cmd_reload_bss, NULL,
|
||||
"= reload configuration for current BSS" },
|
||||
{ "reload_config", hostapd_cli_cmd_reload_config, NULL,
|
||||
"= reload configuration for current interface" },
|
||||
{ "disable", hostapd_cli_cmd_disable, NULL,
|
||||
"= disable hostapd on current interface" },
|
||||
{ "enable_mld", hostapd_cli_cmd_enable_mld, NULL,
|
||||
"= enable AP MLD to which the interface is affiliated" },
|
||||
{ "disable_mld", hostapd_cli_cmd_disable_mld, NULL,
|
||||
"= disable AP MLD to which the interface is affiliated" },
|
||||
{ "update_beacon", hostapd_cli_cmd_update_beacon, NULL,
|
||||
"= update Beacon frame contents\n"},
|
||||
{ "stop_ap", hostapd_cli_cmd_stop_ap, NULL,
|
||||
"= stop AP\n"},
|
||||
{ "erp_flush", hostapd_cli_cmd_erp_flush, NULL,
|
||||
"= drop all ERP keys"},
|
||||
{ "log_level", hostapd_cli_cmd_log_level, NULL,
|
||||
@ -1686,6 +1810,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
" = send FTM range request"},
|
||||
{ "driver_flags", hostapd_cli_cmd_driver_flags, NULL,
|
||||
" = show supported driver flags"},
|
||||
{ "driver_flags2", hostapd_cli_cmd_driver_flags2, NULL,
|
||||
" = show supported driver flags2"},
|
||||
#ifdef CONFIG_DPP
|
||||
{ "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL,
|
||||
"report a scanned DPP URI from a QR Code" },
|
||||
@ -1729,6 +1855,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
{ "dpp_stop_chirp", hostapd_cli_cmd_dpp_stop_chirp, NULL,
|
||||
"= stop DPP chirp" },
|
||||
#endif /* CONFIG_DPP2 */
|
||||
#ifdef CONFIG_DPP3
|
||||
{ "dpp_push_button", hostapd_cli_cmd_dpp_push_button, NULL,
|
||||
"= press DPP push button" },
|
||||
#endif /* CONFIG_DPP3 */
|
||||
#endif /* CONFIG_DPP */
|
||||
{ "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
|
||||
"=Add/Delete/Show/Clear accept MAC ACL" },
|
||||
@ -1738,8 +1868,16 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
"<addr> = poll a STA to check connectivity with a QoS null frame" },
|
||||
{ "req_beacon", hostapd_cli_cmd_req_beacon, NULL,
|
||||
"<addr> [req_mode=] <measurement request hexdump> = send a Beacon report request to a station" },
|
||||
{ "req_link_measurement", hostapd_cli_cmd_req_link_measurement, NULL,
|
||||
"<addr> = send a link measurement report request to a station"},
|
||||
{ "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL,
|
||||
"= reload wpa_psk_file only" },
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
{ "reload_rxkhs", hostapd_cli_cmd_reload_rxkhs, NULL,
|
||||
"= reload R0KHs and R1KHs" },
|
||||
{ "get_rxkhs", hostapd_cli_cmd_get_rxkhs, NULL,
|
||||
"= get R0KHs and R1KHs" },
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef ANDROID
|
||||
{ "driver", hostapd_cli_cmd_driver, NULL,
|
||||
"<driver sub command> [<hex formatted data>] = send driver command data" },
|
||||
@ -2002,7 +2140,6 @@ static void hostapd_cli_interactive(void)
|
||||
os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
|
||||
}
|
||||
|
||||
eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
|
||||
edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
|
||||
hostapd_cli_edit_completion_cb, NULL, hfile, NULL);
|
||||
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
|
||||
@ -2026,40 +2163,46 @@ static void hostapd_cli_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_action(struct wpa_ctrl *ctrl)
|
||||
static void hostapd_cli_action_ping(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
fd_set rfds;
|
||||
int fd, res;
|
||||
struct timeval tv;
|
||||
struct wpa_ctrl *ctrl = eloop_ctx;
|
||||
char buf[256];
|
||||
size_t len;
|
||||
|
||||
fd = wpa_ctrl_get_fd(ctrl);
|
||||
|
||||
while (!hostapd_cli_quit) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(fd, &rfds);
|
||||
tv.tv_sec = ping_interval;
|
||||
tv.tv_usec = 0;
|
||||
res = select(fd + 1, &rfds, NULL, NULL, &tv);
|
||||
if (res < 0 && errno != EINTR) {
|
||||
perror("select");
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(fd, &rfds))
|
||||
hostapd_cli_recv_pending(ctrl, 0, 1);
|
||||
else {
|
||||
len = sizeof(buf) - 1;
|
||||
if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
|
||||
hostapd_cli_action_process) < 0 ||
|
||||
len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
|
||||
printf("hostapd did not reply to PING "
|
||||
"command - exiting\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* verify that connection is still working */
|
||||
len = sizeof(buf) - 1;
|
||||
if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
|
||||
hostapd_cli_action_cb) < 0 ||
|
||||
len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
|
||||
printf("hostapd did not reply to PING command - exiting\n");
|
||||
eloop_terminate();
|
||||
return;
|
||||
}
|
||||
eloop_register_timeout(ping_interval, 0, hostapd_cli_action_ping,
|
||||
ctrl, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_action_receive(int sock, void *eloop_ctx,
|
||||
void *sock_ctx)
|
||||
{
|
||||
struct wpa_ctrl *ctrl = eloop_ctx;
|
||||
|
||||
hostapd_cli_recv_pending(ctrl, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_action(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = wpa_ctrl_get_fd(ctrl);
|
||||
eloop_register_timeout(ping_interval, 0, hostapd_cli_action_ping,
|
||||
ctrl, NULL);
|
||||
eloop_register_read_sock(fd, hostapd_cli_action_receive, ctrl, NULL);
|
||||
eloop_run();
|
||||
eloop_cancel_timeout(hostapd_cli_action_ping, ctrl, NULL);
|
||||
eloop_unregister_read_sock(fd);
|
||||
}
|
||||
|
||||
|
||||
@ -2162,6 +2305,8 @@ int main(int argc, char *argv[])
|
||||
continue;
|
||||
}
|
||||
|
||||
eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
|
||||
|
||||
if (action_file && !hostapd_cli_attached)
|
||||
return -1;
|
||||
if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
|
||||
|
@ -1,65 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Logwatch script for hostapd
|
||||
#
|
||||
# Copyright 2005 Henrik Brix Andersen <brix@gentoo.org>
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
# Alternatively, this file may be distributed under the terms of the BSD License
|
||||
|
||||
use strict;
|
||||
|
||||
my $debug = $ENV{'LOGWATCH_DEBUG'} || 0;
|
||||
my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
|
||||
my $debugcounter = 1;
|
||||
|
||||
my %hostapd;
|
||||
my @unmatched;
|
||||
|
||||
if ($debug >= 5) {
|
||||
print STDERR "\n\nDEBUG: Inside HOSTAPD Filter\n\n";
|
||||
}
|
||||
|
||||
while (defined(my $line = <STDIN>)) {
|
||||
if ($debug >= 5) {
|
||||
print STDERR "DEBUG($debugcounter): $line";
|
||||
$debugcounter++;
|
||||
}
|
||||
chomp($line);
|
||||
|
||||
if (my ($iface,$mac,$layer,$details) = ($line =~ /(.*?): STA (.*?) (.*?): (.*?)$/i)) {
|
||||
unless ($detail == 10) {
|
||||
# collapse association events
|
||||
$details =~ s/^(associated) .*$/$1/i;
|
||||
}
|
||||
$hostapd{$iface}->{$mac}->{$layer}->{$details}++;
|
||||
} else {
|
||||
push @unmatched, "$line\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (keys %hostapd) {
|
||||
foreach my $iface (sort keys %hostapd) {
|
||||
print "Interface $iface:\n";
|
||||
foreach my $mac (sort keys %{$hostapd{$iface}}) {
|
||||
print " Client MAC Address $mac:\n";
|
||||
foreach my $layer (sort keys %{$hostapd{$iface}->{$mac}}) {
|
||||
print " $layer:\n";
|
||||
foreach my $details (sort keys %{$hostapd{$iface}->{$mac}->{$layer}}) {
|
||||
print " $details";
|
||||
my $count = $hostapd{$iface}->{$mac}->{$layer}->{$details};
|
||||
if ($count > 1) {
|
||||
print ": " . $count . " Times";
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($#unmatched >= 0) {
|
||||
print "\n**Unmatched Entries**\n";
|
||||
print @unmatched;
|
||||
}
|
||||
|
||||
exit(0);
|
@ -15,6 +15,7 @@
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "utils/uuid.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/random.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "common/version.h"
|
||||
@ -157,14 +158,50 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
|
||||
struct hostapd_bss_config *conf = hapd->conf;
|
||||
u8 *b = conf->bssid;
|
||||
struct wpa_driver_capa capa;
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
struct hostapd_data *h_hapd = NULL;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
|
||||
wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (conf->mld_ap)
|
||||
h_hapd = hostapd_mld_get_first_bss(hapd);
|
||||
|
||||
if (h_hapd) {
|
||||
hapd->drv_priv = h_hapd->drv_priv;
|
||||
hapd->interface_added = h_hapd->interface_added;
|
||||
|
||||
/*
|
||||
* All interfaces participating in the AP MLD would have
|
||||
* the same MLD address, which is the interface hardware
|
||||
* address, while the interface address would be
|
||||
* derived from the original interface address if BSSID
|
||||
* is not configured, and otherwise it would be the
|
||||
* configured BSSID.
|
||||
*/
|
||||
if (is_zero_ether_addr(b)) {
|
||||
os_memcpy(hapd->own_addr, h_hapd->mld->mld_addr,
|
||||
ETH_ALEN);
|
||||
random_mac_addr_keep_oui(hapd->own_addr);
|
||||
} else {
|
||||
os_memcpy(hapd->own_addr, b, ETH_ALEN);
|
||||
}
|
||||
|
||||
hostapd_mld_add_link(hapd);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Setup of non first link (%d) BSS of MLD %s",
|
||||
hapd->mld_link_id, hapd->conf->iface);
|
||||
|
||||
goto setup_mld;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
/* Initialize the driver interface */
|
||||
if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
|
||||
if (is_zero_ether_addr(b))
|
||||
b = NULL;
|
||||
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
@ -188,6 +225,19 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
|
||||
break;
|
||||
}
|
||||
params.bssid = b;
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
/*
|
||||
* Use the configured MLD MAC address as the interface hardware address
|
||||
* if this AP is a part of an AP MLD.
|
||||
*/
|
||||
if (hapd->conf->mld_ap) {
|
||||
if (!is_zero_ether_addr(hapd->conf->mld_addr))
|
||||
params.bssid = hapd->conf->mld_addr;
|
||||
else
|
||||
params.bssid = NULL;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
params.ifname = hapd->conf->iface;
|
||||
params.driver_params = hapd->iconf->driver_params;
|
||||
params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
|
||||
@ -213,12 +263,36 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
/*
|
||||
* This is the first interface added to the AP MLD, so have the
|
||||
* interface hardware address be the MLD address, while the link address
|
||||
* would be derived from the original interface address if BSSID is not
|
||||
* configured, and otherwise it would be the configured BSSID.
|
||||
*/
|
||||
if (hapd->conf->mld_ap) {
|
||||
os_memcpy(hapd->mld->mld_addr, hapd->own_addr, ETH_ALEN);
|
||||
|
||||
if (!b)
|
||||
random_mac_addr_keep_oui(hapd->own_addr);
|
||||
else
|
||||
os_memcpy(hapd->own_addr, b, ETH_ALEN);
|
||||
|
||||
hostapd_mld_add_link(hapd);
|
||||
wpa_printf(MSG_DEBUG, "Setup of first link (%d) BSS of MLD %s",
|
||||
hapd->mld_link_id, hapd->conf->iface);
|
||||
}
|
||||
|
||||
setup_mld:
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
if (hapd->driver->get_capa &&
|
||||
hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
|
||||
struct wowlan_triggers *triggs;
|
||||
|
||||
iface->drv_flags = capa.flags;
|
||||
iface->drv_flags2 = capa.flags2;
|
||||
iface->drv_rrm_flags = capa.rrm_flags;
|
||||
iface->probe_resp_offloads = capa.probe_resp_offloads;
|
||||
/*
|
||||
* Use default extended capa values from per-radio information
|
||||
@ -234,14 +308,41 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
|
||||
*/
|
||||
hostapd_get_ext_capa(iface);
|
||||
|
||||
hostapd_get_mld_capa(iface);
|
||||
|
||||
triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
|
||||
if (triggs && hapd->driver->set_wowlan) {
|
||||
if (hapd->driver->set_wowlan(hapd->drv_priv, triggs))
|
||||
wpa_printf(MSG_ERROR, "set_wowlan failed");
|
||||
}
|
||||
os_free(triggs);
|
||||
|
||||
iface->mbssid_max_interfaces = capa.mbssid_max_interfaces;
|
||||
iface->ema_max_periodicity = capa.ema_max_periodicity;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hapd->conf->mld_ap) {
|
||||
if (!(iface->drv_flags2 & WPA_DRIVER_FLAGS2_MLO)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"MLD: Not supported by the driver");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize the BSS parameter change to 1 */
|
||||
hapd->eht_mld_bss_param_change = 1;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MLD: Set link_id=%u, mld_addr=" MACSTR
|
||||
", own_addr=" MACSTR,
|
||||
hapd->mld_link_id, MAC2STR(hapd->mld->mld_addr),
|
||||
MAC2STR(hapd->own_addr));
|
||||
|
||||
hostapd_drv_link_add(hapd, hapd->mld_link_id,
|
||||
hapd->own_addr);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -454,7 +555,7 @@ static void show_version(void)
|
||||
"hostapd v%s\n"
|
||||
"User space daemon for IEEE 802.11 AP management,\n"
|
||||
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
|
||||
"Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi> "
|
||||
"Copyright (c) 2002-2024, Jouni Malinen <j@w1.fi> "
|
||||
"and contributors\n",
|
||||
VERSION_STR);
|
||||
}
|
||||
@ -465,7 +566,7 @@ static void usage(void)
|
||||
show_version();
|
||||
fprintf(stderr,
|
||||
"\n"
|
||||
"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
|
||||
"usage: hostapd [-hdBKtvq] [-P <PID file>] [-e <entropy file>] "
|
||||
"\\\n"
|
||||
" [-g <global ctrl_iface>] [-G <group>]\\\n"
|
||||
" [-i <comma-separated list of interface names>]\\\n"
|
||||
@ -493,7 +594,8 @@ static void usage(void)
|
||||
#endif /* CONFIG_DEBUG_SYSLOG */
|
||||
" -S start all the interfaces synchronously\n"
|
||||
" -t include timestamps in some debug messages\n"
|
||||
" -v show hostapd version\n");
|
||||
" -v show hostapd version\n"
|
||||
" -q show less debug messages (-qq for even less)\n");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
@ -634,6 +736,29 @@ static void hostapd_periodic(void *eloop_ctx, void *timeout_ctx)
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_global_cleanup_mld(struct hapd_interfaces *interfaces)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
size_t i;
|
||||
|
||||
if (!interfaces || !interfaces->mld)
|
||||
return;
|
||||
|
||||
for (i = 0; i < interfaces->mld_count; i++) {
|
||||
if (!interfaces->mld[i])
|
||||
continue;
|
||||
|
||||
os_free(interfaces->mld[i]);
|
||||
interfaces->mld[i] = NULL;
|
||||
}
|
||||
|
||||
os_free(interfaces->mld);
|
||||
interfaces->mld = NULL;
|
||||
interfaces->mld_count = 0;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct hapd_interfaces interfaces;
|
||||
@ -684,7 +809,7 @@ int main(int argc, char *argv[])
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
for (;;) {
|
||||
c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:");
|
||||
c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:q");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch (c) {
|
||||
@ -723,7 +848,6 @@ int main(int argc, char *argv[])
|
||||
case 'v':
|
||||
show_version();
|
||||
exit(1);
|
||||
break;
|
||||
case 'g':
|
||||
if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
|
||||
return -1;
|
||||
@ -758,6 +882,9 @@ int main(int argc, char *argv[])
|
||||
&if_names_size, optarg))
|
||||
goto out;
|
||||
break;
|
||||
case 'q':
|
||||
wpa_debug_level++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
@ -912,6 +1039,8 @@ int main(int argc, char *argv[])
|
||||
interfaces.iface = NULL;
|
||||
interfaces.count = 0;
|
||||
|
||||
hostapd_global_cleanup_mld(&interfaces);
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
dpp_global_deinit(interfaces.dpp);
|
||||
#endif /* CONFIG_DPP */
|
||||
@ -934,6 +1063,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
fst_global_deinit();
|
||||
|
||||
crypto_unload();
|
||||
os_program_deinit();
|
||||
|
||||
return ret;
|
||||
|
@ -60,6 +60,10 @@ L_CFLAGS += -DEAP_TLS_OPENSSL
|
||||
|
||||
L_CFLAGS += -Wno-unused-parameter
|
||||
|
||||
ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0)
|
||||
L_CFLAGS += -DCONFIG_ANDROID_LOG
|
||||
L_CFLAGS += -DANDROID_LOG_NAME='"hs20-osu-client"'
|
||||
endif
|
||||
|
||||
########################
|
||||
include $(CLEAR_VARS)
|
||||
@ -68,9 +72,15 @@ LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := libc libcutils
|
||||
LOCAL_SHARED_LIBRARIES += libcrypto libssl
|
||||
ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
LOCAL_SHARED_LIBRARIES += libxml2
|
||||
LOCAL_SHARED_LIBRARIES += liblog
|
||||
else
|
||||
#LOCAL_SHARED_LIBRARIES += libxml2
|
||||
LOCAL_STATIC_LIBRARIES += libxml2
|
||||
LOCAL_SHARED_LIBRARIES += libicuuc
|
||||
endif # End of check for platform version
|
||||
LOCAL_SHARED_LIBRARIES += libcurl
|
||||
|
||||
LOCAL_CFLAGS := $(L_CFLAGS)
|
||||
|
@ -11,15 +11,12 @@
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
#include <openssl/buf.h>
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
#include <openssl/buffer.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "utils/base64.h"
|
||||
@ -220,7 +217,7 @@ typedef struct {
|
||||
} d;
|
||||
} AttrOrOID;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
DEFINE_STACK_OF(AttrOrOID)
|
||||
#endif
|
||||
|
||||
@ -340,30 +337,13 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
|
||||
if (!csrattrs || ! csrattrs->attrs)
|
||||
return;
|
||||
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
num = sk_num(CHECKED_CAST(_STACK *, STACK_OF(AttrOrOID) *,
|
||||
csrattrs->attrs));
|
||||
for (i = 0; i < num; i++) {
|
||||
AttrOrOID *ao = sk_value(
|
||||
CHECKED_CAST(_STACK *, const STACK_OF(AttrOrOID) *,
|
||||
csrattrs->attrs), i);
|
||||
switch (ao->type) {
|
||||
case 0:
|
||||
add_csrattrs_oid(ctx, ao->d.oid, exts);
|
||||
break;
|
||||
case 1:
|
||||
add_csrattrs_attr(ctx, ao->d.attribute, exts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else /* OPENSSL_IS_BORINGSSL */
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
num = sk_AttrOrOID_num(csrattrs->attrs);
|
||||
#else
|
||||
num = SKM_sk_num(AttrOrOID, csrattrs->attrs);
|
||||
#endif
|
||||
for (i = 0; i < num; i++) {
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
AttrOrOID *ao = sk_AttrOrOID_value(csrattrs->attrs, i);
|
||||
#else
|
||||
AttrOrOID *ao = SKM_sk_value(AttrOrOID, csrattrs->attrs, i);
|
||||
@ -377,7 +357,6 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
}
|
||||
|
||||
|
||||
@ -387,7 +366,6 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
|
||||
{
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
RSA *rsa;
|
||||
X509_REQ *req = NULL;
|
||||
int ret = -1;
|
||||
unsigned int val;
|
||||
@ -415,16 +393,11 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
pctx = NULL;
|
||||
|
||||
rsa = EVP_PKEY_get1_RSA(pkey);
|
||||
if (rsa == NULL)
|
||||
goto fail;
|
||||
|
||||
if (key_pem) {
|
||||
FILE *f = fopen(key_pem, "wb");
|
||||
if (f == NULL)
|
||||
goto fail;
|
||||
if (!PEM_write_RSAPrivateKey(f, rsa, NULL, NULL, 0, NULL,
|
||||
NULL)) {
|
||||
if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
|
||||
wpa_printf(MSG_INFO, "Could not write private key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
fclose(f);
|
||||
|
@ -1231,12 +1231,13 @@ static void set_pps_cred_home_sp_oi(struct hs20_osu_client *ctx, int id,
|
||||
homeoi, required);
|
||||
|
||||
if (required) {
|
||||
if (set_cred(ctx->ifname, id, "required_roaming_consortium",
|
||||
homeoi) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to set cred required_roaming_consortium");
|
||||
if (set_cred_quoted(ctx->ifname, id, "required_home_ois",
|
||||
homeoi) < 0)
|
||||
wpa_printf(MSG_INFO,
|
||||
"Failed to set cred required_home_ois");
|
||||
} else {
|
||||
if (set_cred(ctx->ifname, id, "roaming_consortium", homeoi) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to set cred roaming_consortium");
|
||||
if (set_cred_quoted(ctx->ifname, id, "home_ois", homeoi) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to set cred home_ois");
|
||||
}
|
||||
|
||||
xml_node_get_text_free(ctx->xml, homeoi);
|
||||
@ -2018,6 +2019,7 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
|
||||
struct osu_data *osu = NULL, *last = NULL;
|
||||
size_t osu_count = 0;
|
||||
char *pos, *end;
|
||||
int res;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if (f == NULL) {
|
||||
@ -2037,15 +2039,20 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
|
||||
osu = last;
|
||||
last = &osu[osu_count++];
|
||||
memset(last, 0, sizeof(*last));
|
||||
snprintf(last->bssid, sizeof(last->bssid), "%s",
|
||||
buf + 13);
|
||||
res = os_snprintf(last->bssid, sizeof(last->bssid),
|
||||
"%s", buf + 13);
|
||||
if (os_snprintf_error(sizeof(last->bssid), res))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (!last)
|
||||
continue;
|
||||
|
||||
if (strncmp(buf, "uri=", 4) == 0) {
|
||||
snprintf(last->url, sizeof(last->url), "%s", buf + 4);
|
||||
res = os_snprintf(last->url, sizeof(last->url),
|
||||
"%s", buf + 4);
|
||||
if (os_snprintf_error(sizeof(last->url), res))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -2055,26 +2062,37 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
|
||||
}
|
||||
|
||||
if (strncmp(buf, "osu_ssid=", 9) == 0) {
|
||||
snprintf(last->osu_ssid, sizeof(last->osu_ssid),
|
||||
"%s", buf + 9);
|
||||
res = os_snprintf(last->osu_ssid,
|
||||
sizeof(last->osu_ssid),
|
||||
"%s", buf + 9);
|
||||
if (os_snprintf_error(sizeof(last->osu_ssid), res))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(buf, "osu_ssid2=", 10) == 0) {
|
||||
snprintf(last->osu_ssid2, sizeof(last->osu_ssid2),
|
||||
"%s", buf + 10);
|
||||
res = os_snprintf(last->osu_ssid2,
|
||||
sizeof(last->osu_ssid2),
|
||||
"%s", buf + 10);
|
||||
if (os_snprintf_error(sizeof(last->osu_ssid2), res))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (os_strncmp(buf, "osu_nai=", 8) == 0) {
|
||||
os_snprintf(last->osu_nai, sizeof(last->osu_nai),
|
||||
"%s", buf + 8);
|
||||
res = os_snprintf(last->osu_nai, sizeof(last->osu_nai),
|
||||
"%s", buf + 8);
|
||||
if (os_snprintf_error(sizeof(last->osu_nai), res))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (os_strncmp(buf, "osu_nai2=", 9) == 0) {
|
||||
os_snprintf(last->osu_nai2, sizeof(last->osu_nai2),
|
||||
"%s", buf + 9);
|
||||
res = os_snprintf(last->osu_nai2,
|
||||
sizeof(last->osu_nai2),
|
||||
"%s", buf + 9);
|
||||
if (os_snprintf_error(sizeof(last->osu_nai2), res))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -2087,8 +2105,14 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
|
||||
continue;
|
||||
*pos++ = '\0';
|
||||
txt = &last->friendly_name[last->friendly_name_count++];
|
||||
snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 14);
|
||||
snprintf(txt->text, sizeof(txt->text), "%s", pos);
|
||||
res = os_snprintf(txt->lang, sizeof(txt->lang),
|
||||
"%s", buf + 14);
|
||||
if (os_snprintf_error(sizeof(txt->lang), res))
|
||||
break;
|
||||
res = os_snprintf(txt->text, sizeof(txt->text),
|
||||
"%s", pos);
|
||||
if (os_snprintf_error(sizeof(txt->text), res))
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(buf, "desc=", 5) == 0) {
|
||||
@ -2100,8 +2124,14 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
|
||||
continue;
|
||||
*pos++ = '\0';
|
||||
txt = &last->serv_desc[last->serv_desc_count++];
|
||||
snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 5);
|
||||
snprintf(txt->text, sizeof(txt->text), "%s", pos);
|
||||
res = os_snprintf(txt->lang, sizeof(txt->lang),
|
||||
"%s", buf + 5);
|
||||
if (os_snprintf_error(sizeof(txt->lang), res))
|
||||
break;
|
||||
res = os_snprintf(txt->text, sizeof(txt->text),
|
||||
"%s", pos);
|
||||
if (os_snprintf_error(sizeof(txt->text), res))
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(buf, "icon=", 5) == 0) {
|
||||
@ -2124,23 +2154,30 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
|
||||
if (!end)
|
||||
continue;
|
||||
*end = '\0';
|
||||
snprintf(icon->lang, sizeof(icon->lang), "%s", pos);
|
||||
res = os_snprintf(icon->lang, sizeof(icon->lang),
|
||||
"%s", pos);
|
||||
if (os_snprintf_error(sizeof(icon->lang), res))
|
||||
break;
|
||||
pos = end + 1;
|
||||
|
||||
end = strchr(pos, ':');
|
||||
if (end)
|
||||
*end = '\0';
|
||||
snprintf(icon->mime_type, sizeof(icon->mime_type),
|
||||
"%s", pos);
|
||||
if (!pos)
|
||||
res = os_snprintf(icon->mime_type,
|
||||
sizeof(icon->mime_type), "%s", pos);
|
||||
if (os_snprintf_error(sizeof(icon->mime_type), res))
|
||||
break;
|
||||
if (!end)
|
||||
continue;
|
||||
pos = end + 1;
|
||||
|
||||
end = strchr(pos, ':');
|
||||
if (end)
|
||||
*end = '\0';
|
||||
snprintf(icon->filename, sizeof(icon->filename),
|
||||
"%s", pos);
|
||||
res = os_snprintf(icon->filename,
|
||||
sizeof(icon->filename), "%s", pos);
|
||||
if (os_snprintf_error(sizeof(icon->filename), res))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -2911,20 +2948,27 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
|
||||
int found;
|
||||
char *host = NULL;
|
||||
|
||||
wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s)",
|
||||
!ctx->no_osu_cert_validation, ctx->server_url);
|
||||
wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s server_url=%s)",
|
||||
!ctx->no_osu_cert_validation, cert->url ? cert->url : "N/A",
|
||||
ctx->server_url);
|
||||
|
||||
host = get_hostname(ctx->server_url);
|
||||
if (ctx->no_osu_cert_validation && cert->url)
|
||||
host = get_hostname(cert->url);
|
||||
else
|
||||
host = get_hostname(ctx->server_url);
|
||||
|
||||
for (i = 0; i < ctx->server_dnsname_count; i++)
|
||||
os_free(ctx->server_dnsname[i]);
|
||||
os_free(ctx->server_dnsname);
|
||||
ctx->server_dnsname = os_calloc(cert->num_dnsname, sizeof(char *));
|
||||
ctx->server_dnsname_count = 0;
|
||||
if (!ctx->no_osu_cert_validation) {
|
||||
for (i = 0; i < ctx->server_dnsname_count; i++)
|
||||
os_free(ctx->server_dnsname[i]);
|
||||
os_free(ctx->server_dnsname);
|
||||
ctx->server_dnsname = os_calloc(cert->num_dnsname,
|
||||
sizeof(char *));
|
||||
ctx->server_dnsname_count = 0;
|
||||
}
|
||||
|
||||
found = 0;
|
||||
for (i = 0; i < cert->num_dnsname; i++) {
|
||||
if (ctx->server_dnsname) {
|
||||
if (!ctx->no_osu_cert_validation && ctx->server_dnsname) {
|
||||
ctx->server_dnsname[ctx->server_dnsname_count] =
|
||||
os_strdup(cert->dnsname[i]);
|
||||
if (ctx->server_dnsname[ctx->server_dnsname_count])
|
||||
@ -3249,7 +3293,6 @@ int main(int argc, char *argv[])
|
||||
default:
|
||||
usage();
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -564,7 +564,6 @@ static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec,
|
||||
free(id);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcasecmp(name, "uploadMO") == 0) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p pae radius rsn_supp tls utils wps
|
||||
SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p pae pasn radius rsn_supp tls utils wps
|
||||
SUBDIRS += fst
|
||||
|
||||
all:
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/list.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/hw_features_common.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
@ -75,7 +76,7 @@
|
||||
*
|
||||
* This corresponds to:
|
||||
* ---
|
||||
* (busy time - tx time) / (active time - tx time) * 2^(chan_nf + band_min_nf)
|
||||
* (busy time - tx time) / (active time - tx time) * 2^(chan_nf - band_min_nf)
|
||||
* ---
|
||||
*
|
||||
* The coefficient of 2 reflects the way power in "far-field"
|
||||
@ -92,7 +93,7 @@
|
||||
* calculated easily.
|
||||
* ---
|
||||
* (busy time - tx time) / (active time - tx time) *
|
||||
* 2^(10^(chan_nf/10) + 10^(band_min_nf/10))
|
||||
* 2^(10^(chan_nf/10) - 10^(band_min_nf/10))
|
||||
* ---
|
||||
*
|
||||
* However to account for cases where busy/rx time is 0 (channel load is then
|
||||
@ -100,7 +101,7 @@
|
||||
* channel with lower noise floor is preferred. The equation becomes:
|
||||
* ---
|
||||
* 10^(chan_nf/5) + (busy time - tx time) / (active time - tx time) *
|
||||
* 2^(10^(chan_nf/10) + 10^(band_min_nf/10))
|
||||
* 2^(10^(chan_nf/10) - 10^(band_min_nf/10))
|
||||
* ---
|
||||
*
|
||||
* All this "interference factor" is purely subjective and only time
|
||||
@ -241,9 +242,73 @@
|
||||
* [1] http://en.wikipedia.org/wiki/Near_and_far_field
|
||||
*/
|
||||
|
||||
enum bw_type {
|
||||
ACS_BW40,
|
||||
ACS_BW80,
|
||||
ACS_BW160,
|
||||
ACS_BW320_1,
|
||||
ACS_BW320_2,
|
||||
};
|
||||
|
||||
struct bw_item {
|
||||
int first;
|
||||
int last;
|
||||
int center_chan;
|
||||
};
|
||||
|
||||
static const struct bw_item bw_40[] = {
|
||||
{ 5180, 5200, 38 }, { 5220, 5240, 46 }, { 5260, 5280, 54 },
|
||||
{ 5300, 5320, 62 }, { 5500, 5520, 102 }, { 5540, 5560, 110 },
|
||||
{ 5580, 5600, 118 }, { 5620, 5640, 126 }, { 5660, 5680, 134 },
|
||||
{ 5700, 5720, 142 }, { 5745, 5765, 151 }, { 5785, 5805, 159 },
|
||||
{ 5825, 5845, 167 }, { 5865, 5885, 175 },
|
||||
{ 5955, 5975, 3 }, { 5995, 6015, 11 }, { 6035, 6055, 19 },
|
||||
{ 6075, 6095, 27 }, { 6115, 6135, 35 }, { 6155, 6175, 43 },
|
||||
{ 6195, 6215, 51 }, { 6235, 6255, 59 }, { 6275, 6295, 67 },
|
||||
{ 6315, 6335, 75 }, { 6355, 6375, 83 }, { 6395, 6415, 91 },
|
||||
{ 6435, 6455, 99 }, { 6475, 6495, 107 }, { 6515, 6535, 115 },
|
||||
{ 6555, 6575, 123 }, { 6595, 6615, 131 }, { 6635, 6655, 139 },
|
||||
{ 6675, 6695, 147 }, { 6715, 6735, 155 }, { 6755, 6775, 163 },
|
||||
{ 6795, 6815, 171 }, { 6835, 6855, 179 }, { 6875, 6895, 187 },
|
||||
{ 6915, 6935, 195 }, { 6955, 6975, 203 }, { 6995, 7015, 211 },
|
||||
{ 7035, 7055, 219 }, { 7075, 7095, 227}, { -1, -1, -1 }
|
||||
};
|
||||
static const struct bw_item bw_80[] = {
|
||||
{ 5180, 5240, 42 }, { 5260, 5320, 58 }, { 5500, 5560, 106 },
|
||||
{ 5580, 5640, 122 }, { 5660, 5720, 138 }, { 5745, 5805, 155 },
|
||||
{ 5825, 5885, 171},
|
||||
{ 5955, 6015, 7 }, { 6035, 6095, 23 }, { 6115, 6175, 39 },
|
||||
{ 6195, 6255, 55 }, { 6275, 6335, 71 }, { 6355, 6415, 87 },
|
||||
{ 6435, 6495, 103 }, { 6515, 6575, 119 }, { 6595, 6655, 135 },
|
||||
{ 6675, 6735, 151 }, { 6755, 6815, 167 }, { 6835, 6895, 183 },
|
||||
{ 6915, 6975, 199 }, { 6995, 7055, 215 }, { -1, -1, -1 }
|
||||
};
|
||||
static const struct bw_item bw_160[] = {
|
||||
{ 5180, 5320, 50 }, { 5500, 5640, 114 }, { 5745, 5885, 163 },
|
||||
{ 5955, 6095, 15 }, { 6115, 6255, 47 }, { 6275, 6415, 79 },
|
||||
{ 6435, 6575, 111 }, { 6595, 6735, 143 },
|
||||
{ 6755, 6895, 175 }, { 6915, 7055, 207 }, { -1, -1, -1 }
|
||||
};
|
||||
static const struct bw_item bw_320_1[] = {
|
||||
{ 5955, 6255, 31 }, { 6275, 6575, 95 }, { 6595, 6895, 159 },
|
||||
{ -1, -1, -1 }
|
||||
};
|
||||
static const struct bw_item bw_320_2[] = {
|
||||
{ 6115, 6415, 63 }, { 6435, 6735, 127 }, { 6755, 7055, 191 },
|
||||
{ -1, -1, -1 }
|
||||
};
|
||||
static const struct bw_item *bw_desc[] = {
|
||||
[ACS_BW40] = bw_40,
|
||||
[ACS_BW80] = bw_80,
|
||||
[ACS_BW160] = bw_160,
|
||||
[ACS_BW320_1] = bw_320_1,
|
||||
[ACS_BW320_2] = bw_320_2,
|
||||
};
|
||||
|
||||
|
||||
static int acs_request_scan(struct hostapd_iface *iface);
|
||||
static int acs_survey_is_sufficient(struct freq_survey *survey);
|
||||
static void acs_scan_retry(void *eloop_data, void *user_data);
|
||||
|
||||
|
||||
static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
|
||||
@ -275,6 +340,7 @@ static void acs_cleanup_mode(struct hostapd_hw_modes *mode)
|
||||
dl_list_init(&chan->survey_list);
|
||||
chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
|
||||
chan->min_nf = 0;
|
||||
chan->punct_bitmap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,6 +354,8 @@ void acs_cleanup(struct hostapd_iface *iface)
|
||||
|
||||
iface->chans_surveyed = 0;
|
||||
iface->acs_num_completed_scans = 0;
|
||||
iface->acs_num_retries = 0;
|
||||
eloop_cancel_timeout(acs_scan_retry, iface, NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -370,48 +438,31 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
|
||||
static int acs_usable_bw40_chan(const struct hostapd_channel_data *chan)
|
||||
static bool acs_usable_bw_chan(const struct hostapd_channel_data *chan,
|
||||
enum bw_type bw)
|
||||
{
|
||||
const int allowed[] = { 5180, 5220, 5260, 5300, 5500, 5540, 5580, 5620,
|
||||
5660, 5745, 5785, 4920, 4960, 5955, 5995, 6035,
|
||||
6075, 6115, 6155, 6195, 6235, 6275, 6315, 6355,
|
||||
6395, 6435, 6475, 6515, 6555, 6595, 6635, 6675,
|
||||
6715, 6755, 6795, 6835, 6875, 6915, 6955, 6995,
|
||||
7035, 7075 };
|
||||
unsigned int i;
|
||||
unsigned int i = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(allowed); i++)
|
||||
if (chan->freq == allowed[i])
|
||||
return 1;
|
||||
while (bw_desc[bw][i].first != -1) {
|
||||
if (chan->freq == bw_desc[bw][i].first)
|
||||
return true;
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static int acs_usable_bw80_chan(const struct hostapd_channel_data *chan)
|
||||
static int acs_get_bw_center_chan(int freq, enum bw_type bw)
|
||||
{
|
||||
const int allowed[] = { 5180, 5260, 5500, 5580, 5660, 5745, 5955, 6035,
|
||||
6115, 6195, 6275, 6355, 6435, 6515, 6595, 6675,
|
||||
6755, 6835, 6915, 6995 };
|
||||
unsigned int i;
|
||||
unsigned int i = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(allowed); i++)
|
||||
if (chan->freq == allowed[i])
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int acs_usable_bw160_chan(const struct hostapd_channel_data *chan)
|
||||
{
|
||||
const int allowed[] = { 5180, 5500, 5955, 6115, 6275, 6435, 6595, 6755,
|
||||
6915 };
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(allowed); i++)
|
||||
if (chan->freq == allowed[i])
|
||||
return 1;
|
||||
while (bw_desc[bw][i].first != -1) {
|
||||
if (freq >= bw_desc[bw][i].first &&
|
||||
freq <= bw_desc[bw][i].last)
|
||||
return bw_desc[bw][i].center_chan;
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -420,19 +471,24 @@ static int acs_usable_bw160_chan(const struct hostapd_channel_data *chan)
|
||||
static int acs_survey_is_sufficient(struct freq_survey *survey)
|
||||
{
|
||||
if (!(survey->filled & SURVEY_HAS_NF)) {
|
||||
wpa_printf(MSG_INFO, "ACS: Survey is missing noise floor");
|
||||
wpa_printf(MSG_INFO,
|
||||
"ACS: Survey for freq %d is missing noise floor",
|
||||
survey->freq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) {
|
||||
wpa_printf(MSG_INFO, "ACS: Survey is missing channel time");
|
||||
wpa_printf(MSG_INFO,
|
||||
"ACS: Survey for freq %d is missing channel time",
|
||||
survey->freq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) &&
|
||||
!(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"ACS: Survey is missing RX and busy time (at least one is required)");
|
||||
"ACS: Survey for freq %d is missing RX and busy time (at least one is required)",
|
||||
survey->freq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -455,7 +511,7 @@ static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan)
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
ret = 1; /* no survey list entries */
|
||||
ret = 0; /* no survey list entries */
|
||||
|
||||
if (!ret) {
|
||||
wpa_printf(MSG_INFO,
|
||||
@ -540,6 +596,10 @@ static void acs_survey_mode_interference_factor(
|
||||
if (!acs_usable_chan(chan))
|
||||
continue;
|
||||
|
||||
if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
|
||||
iface->conf->acs_exclude_dfs)
|
||||
continue;
|
||||
|
||||
if (!is_in_chanlist(iface, chan))
|
||||
continue;
|
||||
|
||||
@ -549,6 +609,10 @@ static void acs_survey_mode_interference_factor(
|
||||
if (chan->max_tx_power < iface->conf->min_tx_power)
|
||||
continue;
|
||||
|
||||
if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
|
||||
iface->conf->country[2] == 0x4f)
|
||||
continue;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)",
|
||||
chan->chan, chan->freq);
|
||||
|
||||
@ -594,6 +658,26 @@ acs_find_chan_mode(struct hostapd_hw_modes *mode, int freq)
|
||||
}
|
||||
|
||||
|
||||
static enum hostapd_hw_mode
|
||||
acs_find_mode(struct hostapd_iface *iface, int freq)
|
||||
{
|
||||
int i;
|
||||
struct hostapd_hw_modes *mode;
|
||||
struct hostapd_channel_data *chan;
|
||||
|
||||
for (i = 0; i < iface->num_hw_features; i++) {
|
||||
mode = &iface->hw_features[i];
|
||||
if (!hostapd_hw_skip_mode(iface, mode)) {
|
||||
chan = acs_find_chan_mode(mode, freq);
|
||||
if (chan)
|
||||
return mode->mode;
|
||||
}
|
||||
}
|
||||
|
||||
return HOSTAPD_MODE_IEEE80211ANY;
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_channel_data *
|
||||
acs_find_chan(struct hostapd_iface *iface, int freq)
|
||||
{
|
||||
@ -644,6 +728,98 @@ static int is_common_24ghz_chan(int chan)
|
||||
#define ACS_24GHZ_PREFER_1_6_11 0.8
|
||||
#endif /* ACS_24GHZ_PREFER_1_6_11 */
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
static void acs_update_puncturing_bitmap(struct hostapd_iface *iface,
|
||||
struct hostapd_hw_modes *mode, u32 bw,
|
||||
int n_chans,
|
||||
struct hostapd_channel_data *chan,
|
||||
long double factor,
|
||||
int index_primary)
|
||||
{
|
||||
struct hostapd_config *conf = iface->conf;
|
||||
struct hostapd_channel_data *adj_chan = NULL, *first_chan = chan;
|
||||
int i;
|
||||
long double threshold;
|
||||
|
||||
/*
|
||||
* If threshold is 0 or user configured puncturing pattern is
|
||||
* available then don't add additional puncturing.
|
||||
*/
|
||||
if (!conf->punct_acs_threshold || conf->punct_bitmap)
|
||||
return;
|
||||
|
||||
if (is_24ghz_mode(mode->mode) || bw < 80)
|
||||
return;
|
||||
|
||||
threshold = factor * conf->punct_acs_threshold / 100;
|
||||
for (i = 0; i < n_chans; i++) {
|
||||
int adj_freq;
|
||||
|
||||
if (i == index_primary)
|
||||
continue; /* Cannot puncture primary channel */
|
||||
|
||||
if (i > index_primary)
|
||||
adj_freq = chan->freq + (i - index_primary) * 20;
|
||||
else
|
||||
adj_freq = chan->freq - (index_primary - i) * 20;
|
||||
|
||||
adj_chan = acs_find_chan(iface, adj_freq);
|
||||
if (!adj_chan) {
|
||||
chan->punct_bitmap = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
first_chan = adj_chan;
|
||||
|
||||
if (adj_chan->interference_factor > threshold)
|
||||
chan->punct_bitmap |= BIT(i);
|
||||
}
|
||||
|
||||
if (!is_punct_bitmap_valid(bw, (chan->freq - first_chan->freq) / 20,
|
||||
chan->punct_bitmap))
|
||||
chan->punct_bitmap = 0;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
|
||||
static bool
|
||||
acs_usable_bw320_chan(struct hostapd_iface *iface,
|
||||
struct hostapd_channel_data *chan, int *bw320_offset)
|
||||
{
|
||||
const char *bw320_str[] = { "320 MHz", "320 MHz-1", "320 MHz-2" };
|
||||
int conf_bw320_offset = hostapd_get_bw320_offset(iface->conf);
|
||||
|
||||
*bw320_offset = 0;
|
||||
switch (conf_bw320_offset) {
|
||||
case 1:
|
||||
if (acs_usable_bw_chan(chan, ACS_BW320_1))
|
||||
*bw320_offset = 1;
|
||||
break;
|
||||
case 2:
|
||||
if (acs_usable_bw_chan(chan, ACS_BW320_2))
|
||||
*bw320_offset = 2;
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
conf_bw320_offset = 0;
|
||||
if (acs_usable_bw_chan(chan, ACS_BW320_1))
|
||||
*bw320_offset = 1;
|
||||
else if (acs_usable_bw_chan(chan, ACS_BW320_2))
|
||||
*bw320_offset = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!*bw320_offset)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Channel %d: not allowed as primary channel for %s bandwidth",
|
||||
chan->chan, bw320_str[conf_bw320_offset]);
|
||||
|
||||
return *bw320_offset != 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
struct hostapd_hw_modes *mode,
|
||||
@ -652,13 +828,21 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
struct hostapd_channel_data **ideal_chan,
|
||||
long double *ideal_factor)
|
||||
{
|
||||
struct hostapd_channel_data *chan, *adj_chan = NULL;
|
||||
struct hostapd_channel_data *chan, *adj_chan = NULL, *best;
|
||||
long double factor;
|
||||
int i, j;
|
||||
int bw320_offset = 0, ideal_bw320_offset = 0;
|
||||
unsigned int k;
|
||||
int secondary_channel = 1, freq_offset;
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
int index_primary = 0;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
if (is_24ghz_mode(mode->mode))
|
||||
secondary_channel = iface->conf->secondary_channel;
|
||||
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
double total_weight;
|
||||
double total_weight = 0;
|
||||
struct acs_bias *bias, tmp_bias;
|
||||
|
||||
chan = &mode->channels[i];
|
||||
@ -666,10 +850,20 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
/* Since in the current ACS implementation the first channel is
|
||||
* always a primary channel, skip channels not available as
|
||||
* primary until more sophisticated channel selection is
|
||||
* implemented. */
|
||||
* implemented.
|
||||
*
|
||||
* If this implementation is changed to allow any channel in
|
||||
* the bandwidth to be the primary one, the last parameter to
|
||||
* acs_update_puncturing_bitmap() should be changed to the index
|
||||
* of the primary channel
|
||||
*/
|
||||
if (!chan_pri_allowed(chan))
|
||||
continue;
|
||||
|
||||
if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
|
||||
iface->conf->acs_exclude_dfs)
|
||||
continue;
|
||||
|
||||
if (!is_in_chanlist(iface, chan))
|
||||
continue;
|
||||
|
||||
@ -679,7 +873,11 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
if (chan->max_tx_power < iface->conf->min_tx_power)
|
||||
continue;
|
||||
|
||||
if (!chan_bw_allowed(chan, bw, 1, 1)) {
|
||||
if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
|
||||
iface->conf->country[2] == 0x4f)
|
||||
continue;
|
||||
|
||||
if (!chan_bw_allowed(chan, bw, secondary_channel != -1, 1)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Channel %d: BW %u is not supported",
|
||||
chan->chan, bw);
|
||||
@ -692,7 +890,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
((iface->conf->ieee80211n &&
|
||||
iface->conf->secondary_channel) ||
|
||||
is_6ghz_freq(chan->freq)) &&
|
||||
!acs_usable_bw40_chan(chan)) {
|
||||
!acs_usable_bw_chan(chan, ACS_BW40)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Channel %d: not allowed as primary channel for 40 MHz bandwidth",
|
||||
chan->chan);
|
||||
@ -700,10 +898,11 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
|
||||
(iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
|
||||
(iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
|
||||
iface->conf->ieee80211be)) {
|
||||
if (hostapd_get_oper_chwidth(iface->conf) ==
|
||||
CHANWIDTH_80MHZ &&
|
||||
!acs_usable_bw80_chan(chan)) {
|
||||
CONF_OPER_CHWIDTH_80MHZ &&
|
||||
!acs_usable_bw_chan(chan, ACS_BW80)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Channel %d: not allowed as primary channel for 80 MHz bandwidth",
|
||||
chan->chan);
|
||||
@ -711,8 +910,8 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
if (hostapd_get_oper_chwidth(iface->conf) ==
|
||||
CHANWIDTH_160MHZ &&
|
||||
!acs_usable_bw160_chan(chan)) {
|
||||
CONF_OPER_CHWIDTH_160MHZ &&
|
||||
!acs_usable_bw_chan(chan, ACS_BW160)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Channel %d: not allowed as primary channel for 160 MHz bandwidth",
|
||||
chan->chan);
|
||||
@ -720,13 +919,25 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
}
|
||||
}
|
||||
|
||||
if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
|
||||
iface->conf->ieee80211be) {
|
||||
if (hostapd_get_oper_chwidth(iface->conf) ==
|
||||
CONF_OPER_CHWIDTH_320MHZ &&
|
||||
!acs_usable_bw320_chan(iface, chan, &bw320_offset))
|
||||
continue;
|
||||
}
|
||||
|
||||
factor = 0;
|
||||
if (acs_usable_chan(chan))
|
||||
best = NULL;
|
||||
if (acs_usable_chan(chan)) {
|
||||
factor = chan->interference_factor;
|
||||
total_weight = 1;
|
||||
total_weight = 1;
|
||||
best = chan;
|
||||
}
|
||||
|
||||
for (j = 1; j < n_chans; j++) {
|
||||
adj_chan = acs_find_chan(iface, chan->freq + (j * 20));
|
||||
adj_chan = acs_find_chan(iface, chan->freq +
|
||||
j * secondary_channel * 20);
|
||||
if (!adj_chan)
|
||||
break;
|
||||
|
||||
@ -737,10 +948,16 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
break;
|
||||
}
|
||||
|
||||
if (acs_usable_chan(adj_chan)) {
|
||||
factor += adj_chan->interference_factor;
|
||||
total_weight += 1;
|
||||
}
|
||||
if (!acs_usable_chan(adj_chan))
|
||||
continue;
|
||||
|
||||
factor += adj_chan->interference_factor;
|
||||
total_weight += 1;
|
||||
|
||||
/* find the best channel in this segment */
|
||||
if (!best || adj_chan->interference_factor <
|
||||
best->interference_factor)
|
||||
best = adj_chan;
|
||||
}
|
||||
|
||||
if (j != n_chans) {
|
||||
@ -749,12 +966,29 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the AP is in the 5 GHz or 6 GHz band, lets prefer a less
|
||||
* crowded primary channel if one was found in the segment */
|
||||
if (iface->current_mode &&
|
||||
iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
|
||||
best && chan != best) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: promoting channel %d over %d (less interference %Lg/%Lg)",
|
||||
best->chan, chan->chan,
|
||||
chan->interference_factor,
|
||||
best->interference_factor);
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
index_primary = (chan->freq - best->freq) / 20;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
chan = best;
|
||||
}
|
||||
|
||||
/* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
|
||||
* channel interference factor. */
|
||||
if (is_24ghz_mode(mode->mode)) {
|
||||
for (j = 0; j < n_chans; j++) {
|
||||
freq_offset = j * 20 * secondary_channel;
|
||||
adj_chan = acs_find_chan(iface, chan->freq +
|
||||
(j * 20) - 5);
|
||||
freq_offset - 5);
|
||||
if (adj_chan && acs_usable_chan(adj_chan)) {
|
||||
factor += ACS_ADJ_WEIGHT *
|
||||
adj_chan->interference_factor;
|
||||
@ -762,7 +996,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
adj_chan = acs_find_chan(iface, chan->freq +
|
||||
(j * 20) - 10);
|
||||
freq_offset - 10);
|
||||
if (adj_chan && acs_usable_chan(adj_chan)) {
|
||||
factor += ACS_NEXT_ADJ_WEIGHT *
|
||||
adj_chan->interference_factor;
|
||||
@ -770,7 +1004,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
adj_chan = acs_find_chan(iface, chan->freq +
|
||||
(j * 20) + 5);
|
||||
freq_offset + 5);
|
||||
if (adj_chan && acs_usable_chan(adj_chan)) {
|
||||
factor += ACS_ADJ_WEIGHT *
|
||||
adj_chan->interference_factor;
|
||||
@ -778,7 +1012,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
adj_chan = acs_find_chan(iface, chan->freq +
|
||||
(j * 20) + 10);
|
||||
freq_offset + 10);
|
||||
if (adj_chan && acs_usable_chan(adj_chan)) {
|
||||
factor += ACS_NEXT_ADJ_WEIGHT *
|
||||
adj_chan->interference_factor;
|
||||
@ -787,6 +1021,9 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
}
|
||||
}
|
||||
|
||||
if (total_weight == 0)
|
||||
continue;
|
||||
|
||||
factor /= total_weight;
|
||||
|
||||
bias = NULL;
|
||||
@ -817,14 +1054,32 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
|
||||
if (acs_usable_chan(chan) &&
|
||||
(!*ideal_chan || factor < *ideal_factor)) {
|
||||
/* Reset puncturing bitmap for the previous ideal
|
||||
* channel */
|
||||
if (*ideal_chan)
|
||||
(*ideal_chan)->punct_bitmap = 0;
|
||||
|
||||
*ideal_factor = factor;
|
||||
*ideal_chan = chan;
|
||||
ideal_bw320_offset = bw320_offset;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (iface->conf->ieee80211be)
|
||||
acs_update_puncturing_bitmap(iface, mode, bw,
|
||||
n_chans, chan,
|
||||
factor,
|
||||
index_primary);
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
}
|
||||
|
||||
/* This channel would at least be usable */
|
||||
if (!(*rand_chan))
|
||||
if (!(*rand_chan)) {
|
||||
*rand_chan = chan;
|
||||
ideal_bw320_offset = bw320_offset;
|
||||
}
|
||||
}
|
||||
|
||||
hostapd_set_and_check_bw320_offset(iface->conf, ideal_bw320_offset);
|
||||
}
|
||||
|
||||
|
||||
@ -851,26 +1106,24 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
goto bw_selected;
|
||||
}
|
||||
|
||||
/* TODO: HT40- support */
|
||||
|
||||
if (iface->conf->ieee80211n &&
|
||||
iface->conf->secondary_channel == -1) {
|
||||
wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (iface->conf->ieee80211n &&
|
||||
iface->conf->secondary_channel)
|
||||
n_chans = 2;
|
||||
|
||||
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
|
||||
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
|
||||
iface->conf->ieee80211be) {
|
||||
switch (hostapd_get_oper_chwidth(iface->conf)) {
|
||||
case CHANWIDTH_80MHZ:
|
||||
case CONF_OPER_CHWIDTH_80MHZ:
|
||||
n_chans = 4;
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
case CONF_OPER_CHWIDTH_160MHZ:
|
||||
n_chans = 8;
|
||||
break;
|
||||
case CONF_OPER_CHWIDTH_320MHZ:
|
||||
n_chans = 16;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -893,6 +1146,13 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
if (ideal_chan) {
|
||||
wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg",
|
||||
ideal_chan->chan, ideal_chan->freq, ideal_factor);
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (iface->conf->punct_acs_threshold)
|
||||
wpa_printf(MSG_DEBUG, "ACS: RU puncturing bitmap 0x%x",
|
||||
ideal_chan->punct_bitmap);
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
return ideal_chan;
|
||||
}
|
||||
|
||||
@ -900,32 +1160,78 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
static void acs_adjust_secondary(struct hostapd_iface *iface)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* When working with bandwidth over 20 MHz on the 5 GHz or 6 GHz band,
|
||||
* ACS can return a secondary channel which is not the first channel of
|
||||
* the segment and we need to adjust. */
|
||||
if (!iface->conf->secondary_channel ||
|
||||
acs_find_mode(iface, iface->freq) != HOSTAPD_MODE_IEEE80211A)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Adjusting HT/VHT/HE/EHT secondary frequency");
|
||||
|
||||
for (i = 0; bw_desc[ACS_BW40][i].first != -1; i++) {
|
||||
if (iface->freq == bw_desc[ACS_BW40][i].first)
|
||||
iface->conf->secondary_channel = 1;
|
||||
else if (iface->freq == bw_desc[ACS_BW40][i].last)
|
||||
iface->conf->secondary_channel = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void acs_adjust_center_freq(struct hostapd_iface *iface)
|
||||
{
|
||||
int offset;
|
||||
int center;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency");
|
||||
wpa_printf(MSG_DEBUG, "ACS: Adjusting center frequency");
|
||||
|
||||
switch (hostapd_get_oper_chwidth(iface->conf)) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
offset = 2 * iface->conf->secondary_channel;
|
||||
case CONF_OPER_CHWIDTH_USE_HT:
|
||||
if (iface->conf->secondary_channel &&
|
||||
iface->freq >= 2400 && iface->freq < 2500)
|
||||
center = iface->conf->channel +
|
||||
2 * iface->conf->secondary_channel;
|
||||
else if (iface->conf->secondary_channel)
|
||||
center = acs_get_bw_center_chan(iface->freq, ACS_BW40);
|
||||
else
|
||||
center = iface->conf->channel;
|
||||
break;
|
||||
case CHANWIDTH_80MHZ:
|
||||
offset = 6;
|
||||
case CONF_OPER_CHWIDTH_80MHZ:
|
||||
center = acs_get_bw_center_chan(iface->freq, ACS_BW80);
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
offset = 14;
|
||||
case CONF_OPER_CHWIDTH_160MHZ:
|
||||
center = acs_get_bw_center_chan(iface->freq, ACS_BW160);
|
||||
break;
|
||||
case CONF_OPER_CHWIDTH_320MHZ:
|
||||
switch (hostapd_get_bw320_offset(iface->conf)) {
|
||||
case 1:
|
||||
center = acs_get_bw_center_chan(iface->freq,
|
||||
ACS_BW320_1);
|
||||
break;
|
||||
case 2:
|
||||
center = acs_get_bw_center_chan(iface->freq,
|
||||
ACS_BW320_2);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_INFO,
|
||||
"ACS: BW320 offset is not selected");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
/* TODO: How can this be calculated? Adjust
|
||||
* acs_find_ideal_chan() */
|
||||
wpa_printf(MSG_INFO,
|
||||
"ACS: Only VHT20/40/80/160 is supported now");
|
||||
"ACS: Only VHT20/40/80/160/320 is supported now");
|
||||
return;
|
||||
}
|
||||
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
|
||||
iface->conf->channel + offset);
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, center);
|
||||
}
|
||||
|
||||
|
||||
@ -980,9 +1286,24 @@ static void acs_study(struct hostapd_iface *iface)
|
||||
|
||||
iface->conf->channel = ideal_chan->chan;
|
||||
iface->freq = ideal_chan->freq;
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
iface->conf->punct_bitmap = ideal_chan->punct_bitmap;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax)
|
||||
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
|
||||
iface->conf->ieee80211be) {
|
||||
acs_adjust_secondary(iface);
|
||||
acs_adjust_center_freq(iface);
|
||||
}
|
||||
|
||||
err = hostapd_select_hw_mode(iface);
|
||||
if (err) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"ACS: Could not (err: %d) select hw_mode for freq=%d channel=%d",
|
||||
err, iface->freq, iface->conf->channel);
|
||||
err = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
fail:
|
||||
@ -1007,6 +1328,7 @@ static void acs_scan_complete(struct hostapd_iface *iface)
|
||||
int err;
|
||||
|
||||
iface->scan_cb = NULL;
|
||||
iface->acs_num_retries = 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "ACS: Using survey based algorithm (acs_num_scans=%d)",
|
||||
iface->conf->acs_num_scans);
|
||||
@ -1019,7 +1341,7 @@ static void acs_scan_complete(struct hostapd_iface *iface)
|
||||
|
||||
if (++iface->acs_num_completed_scans < iface->conf->acs_num_scans) {
|
||||
err = acs_request_scan(iface);
|
||||
if (err) {
|
||||
if (err && err != -EBUSY) {
|
||||
wpa_printf(MSG_ERROR, "ACS: Failed to request scan");
|
||||
goto fail;
|
||||
}
|
||||
@ -1044,7 +1366,9 @@ static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
|
||||
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
chan = &mode->channels[i];
|
||||
if (chan->flag & HOSTAPD_CHAN_DISABLED)
|
||||
if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
|
||||
((chan->flag & HOSTAPD_CHAN_RADAR) &&
|
||||
iface->conf->acs_exclude_dfs))
|
||||
continue;
|
||||
|
||||
if (!is_in_chanlist(iface, chan))
|
||||
@ -1056,6 +1380,10 @@ static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
|
||||
if (chan->max_tx_power < iface->conf->min_tx_power)
|
||||
continue;
|
||||
|
||||
if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
|
||||
iface->conf->country[2] == 0x4f)
|
||||
continue;
|
||||
|
||||
*freq++ = chan->freq;
|
||||
}
|
||||
|
||||
@ -1066,7 +1394,7 @@ static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
|
||||
static int acs_request_scan(struct hostapd_iface *iface)
|
||||
{
|
||||
struct wpa_driver_scan_params params;
|
||||
int i, *freq;
|
||||
int i, *freq, ret;
|
||||
int num_channels;
|
||||
struct hostapd_hw_modes *mode;
|
||||
|
||||
@ -1099,32 +1427,78 @@ static int acs_request_scan(struct hostapd_iface *iface)
|
||||
return -1;
|
||||
}
|
||||
|
||||
iface->scan_cb = acs_scan_complete;
|
||||
if (!iface->acs_num_retries)
|
||||
wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
|
||||
iface->acs_num_completed_scans + 1,
|
||||
iface->conf->acs_num_scans);
|
||||
else
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Re-try scanning attempt %d (%d / %d)",
|
||||
iface->acs_num_retries,
|
||||
iface->acs_num_completed_scans + 1,
|
||||
iface->conf->acs_num_scans);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
|
||||
iface->acs_num_completed_scans + 1,
|
||||
iface->conf->acs_num_scans);
|
||||
ret = hostapd_driver_scan(iface->bss[0], ¶ms);
|
||||
os_free(params.freqs);
|
||||
|
||||
if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) {
|
||||
if (ret == -EBUSY) {
|
||||
iface->acs_num_retries++;
|
||||
if (iface->acs_num_retries >= ACS_SCAN_RETRY_MAX_COUNT) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"ACS: Failed to request initial scan (all re-attempts failed)");
|
||||
acs_fail(iface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_INFO,
|
||||
"Failed to request acs scan ret=%d (%s) - try to scan after %d seconds",
|
||||
ret, strerror(-ret), ACS_SCAN_RETRY_INTERVAL);
|
||||
eloop_cancel_timeout(acs_scan_retry, iface, NULL);
|
||||
eloop_register_timeout(ACS_SCAN_RETRY_INTERVAL, 0,
|
||||
acs_scan_retry, iface, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
wpa_printf(MSG_ERROR, "ACS: Failed to request initial scan");
|
||||
acs_cleanup(iface);
|
||||
os_free(params.freqs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_free(params.freqs);
|
||||
iface->scan_cb = acs_scan_complete;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void acs_scan_retry(void *eloop_data, void *user_data)
|
||||
{
|
||||
struct hostapd_iface *iface = eloop_data;
|
||||
|
||||
if (acs_request_scan(iface)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"ACS: Failed to request re-try of initial scan");
|
||||
acs_fail(iface);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
|
||||
{
|
||||
int err;
|
||||
|
||||
wpa_printf(MSG_INFO, "ACS: Automatic channel selection started, this may take a bit");
|
||||
|
||||
if (iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) {
|
||||
wpa_printf(MSG_INFO, "ACS: Offloading to driver");
|
||||
if (hostapd_drv_do_acs(iface->bss[0]))
|
||||
|
||||
err = hostapd_drv_do_acs(iface->bss[0]);
|
||||
if (err) {
|
||||
if (err == 1)
|
||||
return HOSTAPD_CHAN_INVALID_NO_IR;
|
||||
return HOSTAPD_CHAN_INVALID;
|
||||
}
|
||||
|
||||
return HOSTAPD_CHAN_ACS;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,9 @@
|
||||
enum hostapd_chan_status acs_init(struct hostapd_iface *iface);
|
||||
void acs_cleanup(struct hostapd_iface *iface);
|
||||
|
||||
#define ACS_SCAN_RETRY_MAX_COUNT 15
|
||||
#define ACS_SCAN_RETRY_INTERVAL 5
|
||||
|
||||
#else /* CONFIG_ACS */
|
||||
|
||||
static inline enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
|
||||
|
@ -232,7 +232,7 @@ static int get_weight_for_sta(struct hostapd_data *hapd, const u8 *sta)
|
||||
struct airtime_sta_weight *wt;
|
||||
|
||||
wt = hapd->conf->airtime_weight_list;
|
||||
while (wt && os_memcmp(wt->addr, sta, ETH_ALEN) != 0)
|
||||
while (wt && !ether_addr_equal(wt->addr, sta))
|
||||
wt = wt->next;
|
||||
|
||||
return wt ? wt->weight : hapd->conf->airtime_weight;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / Configuration helper functions
|
||||
* Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2003-2024, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -90,7 +90,9 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
bss->radius_server_auth_port = 1812;
|
||||
bss->eap_sim_db_timeout = 1;
|
||||
bss->eap_sim_id = 3;
|
||||
bss->eap_sim_aka_fast_reauth_limit = 1000;
|
||||
bss->ap_max_inactivity = AP_MAX_INACTIVITY;
|
||||
bss->bss_max_idle = 1;
|
||||
bss->eapol_version = EAPOL_VERSION;
|
||||
|
||||
bss->max_listen_interval = 65535;
|
||||
@ -120,9 +122,10 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
bss->radius_das_time_window = 300;
|
||||
bss->radius_require_message_authenticator = 1;
|
||||
|
||||
bss->anti_clogging_threshold = 5;
|
||||
bss->sae_sync = 5;
|
||||
bss->sae_sync = 3;
|
||||
|
||||
bss->gas_frag_limit = 1400;
|
||||
|
||||
@ -162,13 +165,17 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
/* Default to strict CRL checking. */
|
||||
bss->check_crl_strict = 1;
|
||||
|
||||
bss->multi_ap_profile = MULTI_AP_PROFILE_2;
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
bss->sae_commit_status = -1;
|
||||
bss->test_assoc_comeback_type = -1;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#ifdef CONFIG_PASN
|
||||
/* comeback after 10 TUs */
|
||||
bss->pasn_comeback_after = 10;
|
||||
bss->pasn_noauth = 1;
|
||||
#endif /* CONFIG_PASN */
|
||||
}
|
||||
|
||||
@ -279,6 +286,10 @@ struct hostapd_config * hostapd_config_defaults(void)
|
||||
conf->he_6ghz_max_ampdu_len_exp = 7;
|
||||
conf->he_6ghz_rx_ant_pat = 1;
|
||||
conf->he_6ghz_tx_ant_pat = 1;
|
||||
conf->he_6ghz_reg_pwr_type = HE_REG_INFO_6GHZ_AP_TYPE_VLP;
|
||||
conf->reg_def_cli_eirp_psd = -1;
|
||||
conf->reg_sub_cli_eirp_psd = -1;
|
||||
conf->reg_def_cli_eirp = -1;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
/* The third octet of the country string uses an ASCII space character
|
||||
@ -293,6 +304,8 @@ struct hostapd_config * hostapd_config_defaults(void)
|
||||
conf->airtime_update_interval = AIRTIME_DEFAULT_UPDATE_INTERVAL;
|
||||
#endif /* CONFIG_AIRTIME_POLICY */
|
||||
|
||||
hostapd_set_and_check_bw320_offset(conf, 0);
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
@ -461,9 +474,12 @@ static int hostapd_derive_psk(struct hostapd_ssid *ssid)
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)",
|
||||
(u8 *) ssid->wpa_passphrase,
|
||||
os_strlen(ssid->wpa_passphrase));
|
||||
pbkdf2_sha1(ssid->wpa_passphrase,
|
||||
ssid->ssid, ssid->ssid_len,
|
||||
4096, ssid->wpa_psk->psk, PMK_LEN);
|
||||
if (pbkdf2_sha1(ssid->wpa_passphrase,
|
||||
ssid->ssid, ssid->ssid_len,
|
||||
4096, ssid->wpa_psk->psk, PMK_LEN) != 0) {
|
||||
wpa_printf(MSG_ERROR, "Error in pbkdf2_sha1()");
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)",
|
||||
ssid->wpa_psk->psk, PMK_LEN);
|
||||
return 0;
|
||||
@ -476,9 +492,11 @@ int hostapd_setup_sae_pt(struct hostapd_bss_config *conf)
|
||||
struct hostapd_ssid *ssid = &conf->ssid;
|
||||
struct sae_password_entry *pw;
|
||||
|
||||
if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf) &&
|
||||
if ((conf->sae_pwe == SAE_PWE_HUNT_AND_PECK &&
|
||||
!hostapd_sae_pw_id_in_use(conf) &&
|
||||
!wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt) &&
|
||||
!hostapd_sae_pk_in_use(conf)) ||
|
||||
conf->sae_pwe == 3 ||
|
||||
conf->sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK ||
|
||||
!wpa_key_mgmt_sae(conf->wpa_key_mgmt))
|
||||
return 0; /* PT not needed */
|
||||
|
||||
@ -541,6 +559,10 @@ static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
|
||||
|
||||
for (i = 0; i < num_servers; i++) {
|
||||
os_free(servers[i].shared_secret);
|
||||
os_free(servers[i].ca_cert);
|
||||
os_free(servers[i].client_cert);
|
||||
os_free(servers[i].private_key);
|
||||
os_free(servers[i].private_key_passwd);
|
||||
}
|
||||
os_free(servers);
|
||||
}
|
||||
@ -686,6 +708,33 @@ void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
|
||||
void hostapd_config_clear_rxkhs(struct hostapd_bss_config *conf)
|
||||
{
|
||||
struct ft_remote_r0kh *r0kh, *r0kh_prev;
|
||||
struct ft_remote_r1kh *r1kh, *r1kh_prev;
|
||||
|
||||
r0kh = conf->r0kh_list;
|
||||
conf->r0kh_list = NULL;
|
||||
while (r0kh) {
|
||||
r0kh_prev = r0kh;
|
||||
r0kh = r0kh->next;
|
||||
os_free(r0kh_prev);
|
||||
}
|
||||
|
||||
r1kh = conf->r1kh_list;
|
||||
conf->r1kh_list = NULL;
|
||||
while (r1kh) {
|
||||
r1kh_prev = r1kh;
|
||||
r1kh = r1kh->next;
|
||||
os_free(r1kh_prev);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
|
||||
static void hostapd_config_free_anqp_elem(struct hostapd_bss_config *conf)
|
||||
{
|
||||
struct anqp_element *elem;
|
||||
@ -792,6 +841,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(conf->radius_req_attr_sqlite);
|
||||
os_free(conf->rsn_preauth_interfaces);
|
||||
os_free(conf->ctrl_interface);
|
||||
os_free(conf->config_id);
|
||||
os_free(conf->ca_cert);
|
||||
os_free(conf->server_cert);
|
||||
os_free(conf->server_cert2);
|
||||
@ -809,6 +859,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(conf->eap_fast_a_id);
|
||||
os_free(conf->eap_fast_a_id_info);
|
||||
os_free(conf->eap_sim_db);
|
||||
os_free(conf->imsi_privacy_key);
|
||||
os_free(conf->radius_server_clients);
|
||||
os_free(conf->radius);
|
||||
os_free(conf->radius_das_shared_secret);
|
||||
@ -816,26 +867,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(conf->time_zone);
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
{
|
||||
struct ft_remote_r0kh *r0kh, *r0kh_prev;
|
||||
struct ft_remote_r1kh *r1kh, *r1kh_prev;
|
||||
|
||||
r0kh = conf->r0kh_list;
|
||||
conf->r0kh_list = NULL;
|
||||
while (r0kh) {
|
||||
r0kh_prev = r0kh;
|
||||
r0kh = r0kh->next;
|
||||
os_free(r0kh_prev);
|
||||
}
|
||||
|
||||
r1kh = conf->r1kh_list;
|
||||
conf->r1kh_list = NULL;
|
||||
while (r1kh) {
|
||||
r1kh_prev = r1kh;
|
||||
r1kh = r1kh->next;
|
||||
os_free(r1kh_prev);
|
||||
}
|
||||
}
|
||||
hostapd_config_clear_rxkhs(conf);
|
||||
os_free(conf->rxkh_file);
|
||||
conf->rxkh_file = NULL;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
@ -933,6 +967,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
wpabuf_free(conf->rsnxe_override_ft);
|
||||
wpabuf_free(conf->gtk_rsc_override);
|
||||
wpabuf_free(conf->igtk_rsc_override);
|
||||
wpabuf_free(conf->eapol_m1_elements);
|
||||
wpabuf_free(conf->eapol_m3_elements);
|
||||
wpabuf_free(conf->presp_elements);
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
os_free(conf->no_probe_resp_if_seen_on);
|
||||
@ -943,6 +980,8 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
#ifdef CONFIG_DPP
|
||||
os_free(conf->dpp_name);
|
||||
os_free(conf->dpp_mud_url);
|
||||
os_free(conf->dpp_extra_conf_req_name);
|
||||
os_free(conf->dpp_extra_conf_req_value);
|
||||
os_free(conf->dpp_connector);
|
||||
wpabuf_free(conf->dpp_netaccesskey);
|
||||
wpabuf_free(conf->dpp_csign);
|
||||
@ -1118,10 +1157,9 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
|
||||
for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
|
||||
if (next_ok &&
|
||||
(psk->group ||
|
||||
(addr && os_memcmp(psk->addr, addr, ETH_ALEN) == 0) ||
|
||||
(addr && ether_addr_equal(psk->addr, addr)) ||
|
||||
(!addr && p2p_dev_addr &&
|
||||
os_memcmp(psk->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
|
||||
0))) {
|
||||
ether_addr_equal(psk->p2p_dev_addr, p2p_dev_addr)))) {
|
||||
if (vlan_id)
|
||||
*vlan_id = psk->vlan_id;
|
||||
return psk->psk;
|
||||
@ -1202,6 +1240,14 @@ static bool hostapd_config_check_bss_6g(struct hostapd_bss_config *bss)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
if (wpa_key_mgmt_sae(bss->wpa_key_mgmt) &&
|
||||
bss->sae_pwe == SAE_PWE_HUNT_AND_PECK) {
|
||||
wpa_printf(MSG_INFO, "SAE: Enabling SAE H2E on 6 GHz");
|
||||
bss->sae_pwe = SAE_PWE_BOTH;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1243,15 +1289,18 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
|
||||
if (full_config && bss->wpa &&
|
||||
bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
|
||||
bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS &&
|
||||
bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
|
||||
wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
|
||||
"RADIUS checking (macaddr_acl=2) enabled.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (full_config && bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
|
||||
if (full_config && bss->wpa &&
|
||||
wpa_key_mgmt_wpa_psk_no_sae(bss->wpa_key_mgmt) &&
|
||||
bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
|
||||
bss->ssid.wpa_psk_file == NULL &&
|
||||
bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS &&
|
||||
(bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
|
||||
bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
|
||||
wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
|
||||
@ -1424,7 +1473,14 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
if (full_config && bss->fils_discovery_min_int &&
|
||||
if (full_config && bss->fils_discovery_max_int &&
|
||||
(!conf->ieee80211ax || bss->disable_11ax)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Currently IEEE 802.11ax support is mandatory to enable FILS discovery transmission.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (full_config && bss->fils_discovery_max_int &&
|
||||
bss->unsol_bcast_probe_resp_interval) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Cannot enable both FILS discovery and unsolicited broadcast Probe Response at the same time");
|
||||
@ -1432,6 +1488,20 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (full_config && !bss->disable_11be && bss->disable_11ax) {
|
||||
bss->disable_11be = true;
|
||||
wpa_printf(MSG_INFO,
|
||||
"Disabling IEEE 802.11be as IEEE 802.11ax is disabled for this BSS");
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
if (full_config && bss->ignore_broadcast_ssid && conf->mbssid) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Hidden SSID is not suppored when MBSSID is enabled");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1463,6 +1533,13 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (full_config && is_6ghz_op_class(conf->op_class) &&
|
||||
!conf->hw_mode_set) {
|
||||
/* Use the appropriate hw_mode value automatically when the
|
||||
* op_class parameter has been set, but hw_mode was not. */
|
||||
conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
if (full_config && conf->ieee80211d &&
|
||||
(!conf->country[0] || !conf->country[1])) {
|
||||
wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
|
||||
@ -1500,6 +1577,24 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (full_config && conf->ieee80211be && !conf->ieee80211ax) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Cannot set ieee80211be without ieee80211ax");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (full_config)
|
||||
hostapd_set_and_check_bw320_offset(conf,
|
||||
conf->eht_bw320_offset);
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
if (full_config && conf->mbssid && !conf->ieee80211ax) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Cannot enable multiple BSSID support without ieee80211ax");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < conf->num_bss; i++) {
|
||||
if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
|
||||
return -1;
|
||||
@ -1646,3 +1741,49 @@ bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf)
|
||||
return with_pk;
|
||||
}
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
|
||||
|
||||
int hostapd_acl_comp(const void *a, const void *b)
|
||||
{
|
||||
const struct mac_acl_entry *aa = a;
|
||||
const struct mac_acl_entry *bb = b;
|
||||
return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
|
||||
}
|
||||
|
||||
|
||||
int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
|
||||
int vlan_id, const u8 *addr)
|
||||
{
|
||||
struct mac_acl_entry *newacl;
|
||||
|
||||
newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
|
||||
if (!newacl) {
|
||||
wpa_printf(MSG_ERROR, "MAC list reallocation failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*acl = newacl;
|
||||
os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
|
||||
os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id));
|
||||
(*acl)[*num].vlan_id.untagged = vlan_id;
|
||||
(*acl)[*num].vlan_id.notempty = !!vlan_id;
|
||||
(*num)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
|
||||
const u8 *addr)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (i < *num) {
|
||||
if (ether_addr_equal((*acl)[i].addr, addr)) {
|
||||
os_remove_in_array(*acl, *num, sizeof(**acl), i);
|
||||
(*num)--;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / Configuration definitions and helpers functions
|
||||
* Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2003-2024, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -20,6 +20,12 @@
|
||||
#include "fst/fst.h"
|
||||
#include "vlan.h"
|
||||
|
||||
enum macaddr_acl {
|
||||
ACCEPT_UNLESS_DENIED = 0,
|
||||
DENY_UNLESS_ACCEPTED = 1,
|
||||
USE_EXTERNAL_RADIUS_AUTH = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* mesh_conf - local MBSS state and settings
|
||||
*/
|
||||
@ -278,6 +284,7 @@ struct hostapd_bss_config {
|
||||
char bridge[IFNAMSIZ + 1];
|
||||
char vlan_bridge[IFNAMSIZ + 1];
|
||||
char wds_bridge[IFNAMSIZ + 1];
|
||||
int bridge_hairpin; /* hairpin_mode on bridge members */
|
||||
|
||||
enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
|
||||
|
||||
@ -302,6 +309,7 @@ struct hostapd_bss_config {
|
||||
struct hostapd_ip_addr own_ip_addr;
|
||||
char *nas_identifier;
|
||||
struct hostapd_radius_servers *radius;
|
||||
int radius_require_message_authenticator;
|
||||
int acct_interim_interval;
|
||||
int radius_request_cui;
|
||||
struct hostapd_radius_attr *radius_auth_req_attr;
|
||||
@ -331,12 +339,11 @@ struct hostapd_bss_config {
|
||||
int eap_reauth_period;
|
||||
int erp_send_reauth_start;
|
||||
char *erp_domain;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
bool eap_skip_prot_success;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
enum macaddr_acl {
|
||||
ACCEPT_UNLESS_DENIED = 0,
|
||||
DENY_UNLESS_ACCEPTED = 1,
|
||||
USE_EXTERNAL_RADIUS_AUTH = 2
|
||||
} macaddr_acl;
|
||||
enum macaddr_acl macaddr_acl;
|
||||
struct mac_acl_entry *accept_mac;
|
||||
int num_accept_mac;
|
||||
struct mac_acl_entry *deny_mac;
|
||||
@ -364,7 +371,8 @@ struct hostapd_bss_config {
|
||||
enum {
|
||||
PSK_RADIUS_IGNORED = 0,
|
||||
PSK_RADIUS_ACCEPTED = 1,
|
||||
PSK_RADIUS_REQUIRED = 2
|
||||
PSK_RADIUS_REQUIRED = 2,
|
||||
PSK_RADIUS_DURING_4WAY_HS = 3,
|
||||
} wpa_psk_radius;
|
||||
int wpa_pairwise;
|
||||
int group_cipher; /* wpa_group value override from configuation */
|
||||
@ -398,6 +406,7 @@ struct hostapd_bss_config {
|
||||
int ft_over_ds;
|
||||
int ft_psk_generate_local;
|
||||
int r1_max_key_lifetime;
|
||||
char *rxkh_file;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
char *ctrl_interface; /* directory for UNIX domain sockets */
|
||||
@ -437,8 +446,11 @@ struct hostapd_bss_config {
|
||||
int eap_teap_pac_no_inner;
|
||||
int eap_teap_separate_result;
|
||||
int eap_teap_id;
|
||||
int eap_teap_method_sequence;
|
||||
int eap_sim_aka_result_ind;
|
||||
int eap_sim_id;
|
||||
char *imsi_privacy_key;
|
||||
int eap_sim_aka_fast_reauth_limit;
|
||||
int tnc;
|
||||
int fragment_size;
|
||||
u16 pwd_group;
|
||||
@ -454,6 +466,9 @@ struct hostapd_bss_config {
|
||||
*/
|
||||
|
||||
int ap_max_inactivity;
|
||||
int bss_max_idle;
|
||||
int max_acceptable_idle_period;
|
||||
bool no_disconnect_on_group_keyerror;
|
||||
int ignore_broadcast_ssid;
|
||||
int no_probe_resp_if_max_sta;
|
||||
|
||||
@ -537,6 +552,7 @@ struct hostapd_bss_config {
|
||||
bool disable_11n;
|
||||
bool disable_11ac;
|
||||
bool disable_11ax;
|
||||
bool disable_11be;
|
||||
|
||||
/* IEEE 802.11v */
|
||||
int time_advertisement;
|
||||
@ -662,7 +678,7 @@ struct hostapd_bss_config {
|
||||
unsigned int sae_sync;
|
||||
int sae_require_mfp;
|
||||
int sae_confirm_immediate;
|
||||
int sae_pwe;
|
||||
enum sae_pwe sae_pwe;
|
||||
int *sae_groups;
|
||||
struct sae_password_entry *sae_passwords;
|
||||
|
||||
@ -693,6 +709,15 @@ struct hostapd_bss_config {
|
||||
unsigned int oci_freq_override_ft_assoc;
|
||||
unsigned int oci_freq_override_fils_assoc;
|
||||
unsigned int oci_freq_override_wnm_sleep;
|
||||
struct wpabuf *eapol_m1_elements;
|
||||
struct wpabuf *eapol_m3_elements;
|
||||
bool eapol_m3_no_encrypt;
|
||||
int test_assoc_comeback_type;
|
||||
struct wpabuf *presp_elements;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
u16 eht_oper_puncturing_override;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#define MESH_ENABLED BIT(0)
|
||||
@ -739,6 +764,7 @@ struct hostapd_bss_config {
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
int multicast_to_unicast;
|
||||
int bridge_multicast_to_unicast;
|
||||
|
||||
int broadcast_deauth;
|
||||
|
||||
@ -747,12 +773,15 @@ struct hostapd_bss_config {
|
||||
#ifdef CONFIG_DPP
|
||||
char *dpp_name;
|
||||
char *dpp_mud_url;
|
||||
char *dpp_extra_conf_req_name;
|
||||
char *dpp_extra_conf_req_value;
|
||||
char *dpp_connector;
|
||||
struct wpabuf *dpp_netaccesskey;
|
||||
unsigned int dpp_netaccesskey_expiry;
|
||||
struct wpabuf *dpp_csign;
|
||||
#ifdef CONFIG_DPP2
|
||||
struct dpp_controller_conf *dpp_controller;
|
||||
int dpp_relay_port;
|
||||
int dpp_configurator_connectivity;
|
||||
int dpp_pfs;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
@ -776,6 +805,14 @@ struct hostapd_bss_config {
|
||||
#define BACKHAUL_BSS 1
|
||||
#define FRONTHAUL_BSS 2
|
||||
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
|
||||
int multi_ap_profile;
|
||||
/* Multi-AP Profile-1 clients not allowed to connect */
|
||||
#define PROFILE1_CLIENT_ASSOC_DISALLOW BIT(0)
|
||||
/* Multi-AP Profile-2 clients not allowed to connect */
|
||||
#define PROFILE2_CLIENT_ASSOC_DISALLOW BIT(1)
|
||||
unsigned int multi_ap_client_disallow;
|
||||
/* Primary VLAN ID to use in Multi-AP */
|
||||
int multi_ap_vlanid;
|
||||
|
||||
#ifdef CONFIG_AIRTIME_POLICY
|
||||
unsigned int airtime_weight;
|
||||
@ -832,6 +869,19 @@ struct hostapd_bss_config {
|
||||
*/
|
||||
u32 macsec_replay_window;
|
||||
|
||||
/**
|
||||
* macsec_offload - Enable MACsec offload
|
||||
*
|
||||
* This setting applies only when MACsec is in use, i.e.,
|
||||
* - macsec_policy is enabled
|
||||
* - the key server has decided to enable MACsec
|
||||
*
|
||||
* 0 = MACSEC_OFFLOAD_OFF (default)
|
||||
* 1 = MACSEC_OFFLOAD_PHY
|
||||
* 2 = MACSEC_OFFLOAD_MAC
|
||||
*/
|
||||
int macsec_offload;
|
||||
|
||||
/**
|
||||
* macsec_port - MACsec port (in SCI)
|
||||
*
|
||||
@ -848,6 +898,13 @@ struct hostapd_bss_config {
|
||||
*/
|
||||
int mka_priority;
|
||||
|
||||
/**
|
||||
* macsec_csindex - Cipher suite index for MACsec
|
||||
*
|
||||
* Range: 0-1 (default: 0)
|
||||
*/
|
||||
int macsec_csindex;
|
||||
|
||||
/**
|
||||
* mka_ckn - MKA pre-shared CKN
|
||||
*/
|
||||
@ -872,6 +929,9 @@ struct hostapd_bss_config {
|
||||
#endif /* CONFIG_MACSEC */
|
||||
|
||||
#ifdef CONFIG_PASN
|
||||
/* Whether to allow PASN-UNAUTH */
|
||||
int pasn_noauth;
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
/*
|
||||
* Normally, KDK should be derived if and only if both sides support
|
||||
@ -898,6 +958,29 @@ struct hostapd_bss_config {
|
||||
u8 ext_capa[EXT_CAPA_MAX_LEN];
|
||||
|
||||
u8 rnr;
|
||||
char *config_id;
|
||||
bool xrates_supported;
|
||||
|
||||
bool ssid_protection;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
/* The AP is part of an AP MLD */
|
||||
u8 mld_ap;
|
||||
|
||||
/* The MLD ID to which the AP MLD is affiliated with */
|
||||
u8 mld_id;
|
||||
|
||||
/* The AP's MLD MAC address within the AP MLD */
|
||||
u8 mld_addr[ETH_ALEN];
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
/*
|
||||
* If set indicate the AP as disabled in the RNR element included in the
|
||||
* other APs in the AP MLD.
|
||||
*/
|
||||
bool mld_indicate_disabled;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -936,6 +1019,15 @@ struct spatial_reuse {
|
||||
u8 srg_partial_bssid_bitmap[8];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct eht_phy_capabilities_info - EHT PHY capabilities
|
||||
*/
|
||||
struct eht_phy_capabilities_info {
|
||||
bool su_beamformer;
|
||||
bool su_beamformee;
|
||||
bool mu_beamformer;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hostapd_config - Per-radio interface configuration
|
||||
*/
|
||||
@ -957,7 +1049,9 @@ struct hostapd_config {
|
||||
int acs_exclude_dfs;
|
||||
u8 min_tx_power;
|
||||
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
|
||||
bool hw_mode_set;
|
||||
int acs_exclude_6ghz_non_psc;
|
||||
int enable_background_radar;
|
||||
enum {
|
||||
LONG_PREAMBLE = 0,
|
||||
SHORT_PREAMBLE = 1
|
||||
@ -1022,7 +1116,7 @@ struct hostapd_config {
|
||||
u32 vht_capab;
|
||||
int ieee80211ac;
|
||||
int require_vht;
|
||||
u8 vht_oper_chwidth;
|
||||
enum oper_chan_width vht_oper_chwidth;
|
||||
u8 vht_oper_centr_freq_seg0_idx;
|
||||
u8 vht_oper_centr_freq_seg1_idx;
|
||||
u8 ht40_plus_minus_allowed;
|
||||
@ -1045,6 +1139,7 @@ struct hostapd_config {
|
||||
double ignore_reassoc_probability;
|
||||
double corrupt_gtk_rekey_mic_probability;
|
||||
int ecsa_ie_only;
|
||||
bool delay_eapol_tx;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#ifdef CONFIG_ACS
|
||||
@ -1066,13 +1161,28 @@ struct hostapd_config {
|
||||
struct he_operation he_op;
|
||||
struct ieee80211_he_mu_edca_parameter_set he_mu_edca;
|
||||
struct spatial_reuse spr;
|
||||
u8 he_oper_chwidth;
|
||||
enum oper_chan_width he_oper_chwidth;
|
||||
u8 he_oper_centr_freq_seg0_idx;
|
||||
u8 he_oper_centr_freq_seg1_idx;
|
||||
u8 he_6ghz_max_mpdu;
|
||||
u8 he_6ghz_max_ampdu_len_exp;
|
||||
u8 he_6ghz_rx_ant_pat;
|
||||
u8 he_6ghz_tx_ant_pat;
|
||||
u8 he_6ghz_reg_pwr_type;
|
||||
|
||||
int reg_def_cli_eirp_psd;
|
||||
int reg_sub_cli_eirp_psd;
|
||||
|
||||
/*
|
||||
* This value should be used when regulatory client EIRP PSD values
|
||||
* advertised by an AP that is an SP AP or an indoor SP AP are
|
||||
* insufficient to ensure that regulatory client limits on total EIRP
|
||||
* are always met for all transmission bandwidths within the bandwidth
|
||||
* of the AP’s BSS.
|
||||
*/
|
||||
int reg_def_cli_eirp;
|
||||
|
||||
bool require_he;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
/* VHT enable/disable config from CHAN_SWITCH */
|
||||
@ -1100,11 +1210,41 @@ struct hostapd_config {
|
||||
unsigned int airtime_update_interval;
|
||||
#define AIRTIME_MODE_MAX (__AIRTIME_MODE_MAX - 1)
|
||||
#endif /* CONFIG_AIRTIME_POLICY */
|
||||
|
||||
int ieee80211be;
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
enum oper_chan_width eht_oper_chwidth;
|
||||
u8 eht_oper_centr_freq_seg0_idx;
|
||||
struct eht_phy_capabilities_info eht_phy_capab;
|
||||
u16 punct_bitmap; /* a bitmap of disabled 20 MHz channels */
|
||||
u8 punct_acs_threshold;
|
||||
u8 eht_default_pe_duration;
|
||||
u8 eht_bw320_offset;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
/* EHT enable/disable config from CHAN_SWITCH */
|
||||
#define CH_SWITCH_EHT_ENABLED BIT(0)
|
||||
#define CH_SWITCH_EHT_DISABLED BIT(1)
|
||||
unsigned int ch_switch_eht_config;
|
||||
|
||||
enum mbssid {
|
||||
MBSSID_DISABLED = 0,
|
||||
MBSSID_ENABLED = 1,
|
||||
ENHANCED_MBSSID_ENABLED = 2,
|
||||
} mbssid;
|
||||
|
||||
/* Whether to enable TWT responder in HT and VHT modes */
|
||||
bool ht_vht_twt_responder;
|
||||
};
|
||||
|
||||
|
||||
static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf)
|
||||
static inline enum oper_chan_width
|
||||
hostapd_get_oper_chwidth(struct hostapd_config *conf)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (conf->ieee80211be)
|
||||
return conf->eht_oper_chwidth;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (conf->ieee80211ax)
|
||||
return conf->he_oper_chwidth;
|
||||
@ -1113,8 +1253,15 @@ static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf)
|
||||
}
|
||||
|
||||
static inline void
|
||||
hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth)
|
||||
hostapd_set_oper_chwidth(struct hostapd_config *conf,
|
||||
enum oper_chan_width oper_chwidth)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (conf->ieee80211be)
|
||||
conf->eht_oper_chwidth = oper_chwidth;
|
||||
if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ)
|
||||
oper_chwidth = CONF_OPER_CHWIDTH_160MHZ;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (conf->ieee80211ax)
|
||||
conf->he_oper_chwidth = oper_chwidth;
|
||||
@ -1125,6 +1272,10 @@ hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth)
|
||||
static inline u8
|
||||
hostapd_get_oper_centr_freq_seg0_idx(struct hostapd_config *conf)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (conf->ieee80211be)
|
||||
return conf->eht_oper_centr_freq_seg0_idx;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (conf->ieee80211ax)
|
||||
return conf->he_oper_centr_freq_seg0_idx;
|
||||
@ -1136,6 +1287,14 @@ static inline void
|
||||
hostapd_set_oper_centr_freq_seg0_idx(struct hostapd_config *conf,
|
||||
u8 oper_centr_freq_seg0_idx)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (conf->ieee80211be)
|
||||
conf->eht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
|
||||
if (is_6ghz_op_class(conf->op_class) &&
|
||||
center_idx_to_bw_6ghz(oper_centr_freq_seg0_idx) == 4)
|
||||
oper_centr_freq_seg0_idx +=
|
||||
conf->channel > oper_centr_freq_seg0_idx ? 16 : -16;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (conf->ieee80211ax)
|
||||
conf->he_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
|
||||
@ -1164,6 +1323,43 @@ hostapd_set_oper_centr_freq_seg1_idx(struct hostapd_config *conf,
|
||||
conf->vht_oper_centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
|
||||
}
|
||||
|
||||
static inline u8
|
||||
hostapd_get_bw320_offset(struct hostapd_config *conf)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (conf->ieee80211be && is_6ghz_op_class(conf->op_class) &&
|
||||
hostapd_get_oper_chwidth(conf) == CONF_OPER_CHWIDTH_320MHZ)
|
||||
return conf->eht_bw320_offset;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hostapd_set_and_check_bw320_offset(struct hostapd_config *conf,
|
||||
u8 bw320_offset)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (conf->ieee80211be && is_6ghz_op_class(conf->op_class) &&
|
||||
op_class_to_ch_width(conf->op_class) == CONF_OPER_CHWIDTH_320MHZ) {
|
||||
if (conf->channel) {
|
||||
/* If the channel is set, then calculate bw320_offset
|
||||
* by center frequency segment 0.
|
||||
*/
|
||||
u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(conf);
|
||||
|
||||
conf->eht_bw320_offset = (seg0 - 31) % 64 ? 2 : 1;
|
||||
} else {
|
||||
/* If the channel is not set, bw320_offset indicates
|
||||
* preferred offset of 320 MHz.
|
||||
*/
|
||||
conf->eht_bw320_offset = bw320_offset;
|
||||
}
|
||||
} else {
|
||||
conf->eht_bw320_offset = 0;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
}
|
||||
|
||||
|
||||
int hostapd_mac_comp(const void *a, const void *b);
|
||||
struct hostapd_config * hostapd_config_defaults(void);
|
||||
@ -1172,6 +1368,7 @@ void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr);
|
||||
void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
|
||||
void hostapd_config_free_eap_users(struct hostapd_eap_user *user);
|
||||
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
|
||||
void hostapd_config_clear_rxkhs(struct hostapd_bss_config *conf);
|
||||
void hostapd_config_free_bss(struct hostapd_bss_config *conf);
|
||||
void hostapd_config_free(struct hostapd_config *conf);
|
||||
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
|
||||
@ -1195,5 +1392,10 @@ int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf);
|
||||
bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf);
|
||||
bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf);
|
||||
int hostapd_setup_sae_pt(struct hostapd_bss_config *conf);
|
||||
int hostapd_acl_comp(const void *a, const void *b);
|
||||
int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
|
||||
int vlan_id, const u8 *addr);
|
||||
void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
|
||||
const u8 *addr);
|
||||
|
||||
#endif /* HOSTAPD_CONFIG_H */
|
||||
|
@ -75,6 +75,14 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
|
||||
*beacon_ret = *proberesp_ret = *assocresp_ret = NULL;
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
pos = buf;
|
||||
pos = hostapd_eid_rm_enabled_capab(hapd, pos, sizeof(buf));
|
||||
if (add_buf_data(&assocresp, buf, pos - buf) < 0 ||
|
||||
add_buf_data(&proberesp, buf, pos - buf) < 0)
|
||||
goto fail;
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
pos = buf;
|
||||
pos = hostapd_eid_time_adv(hapd, pos);
|
||||
if (add_buf_data(&beacon, buf, pos - buf) < 0)
|
||||
@ -84,7 +92,7 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
goto fail;
|
||||
|
||||
pos = buf;
|
||||
pos = hostapd_eid_ext_capab(hapd, pos);
|
||||
pos = hostapd_eid_ext_capab(hapd, pos, false);
|
||||
if (add_buf_data(&assocresp, buf, pos - buf) < 0)
|
||||
goto fail;
|
||||
pos = hostapd_eid_interworking(hapd, pos);
|
||||
@ -200,6 +208,9 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
|
||||
add_buf(&beacon, hapd->conf->vendor_elements);
|
||||
add_buf(&proberesp, hapd->conf->vendor_elements);
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
add_buf(&proberesp, hapd->conf->presp_elements);
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
add_buf(&assocresp, hapd->conf->assocresp_elements);
|
||||
|
||||
*beacon_ret = beacon;
|
||||
@ -257,9 +268,35 @@ int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
|
||||
bool hostapd_sta_is_link_sta(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (ap_sta_is_mld(hapd, sta) &&
|
||||
sta->mld_assoc_link_id != hapd->mld_link_id)
|
||||
return true;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_authorized(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int authorized)
|
||||
{
|
||||
/*
|
||||
* The WPA_STA_AUTHORIZED flag is relevant only for the MLD station and
|
||||
* not to the link stations (as the authorization is done between the
|
||||
* MLD peers). Thus, do not propagate the change to the driver for the
|
||||
* link stations.
|
||||
*/
|
||||
if (hostapd_sta_is_link_sta(hapd, sta)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: Do not update link station flags (" MACSTR ")",
|
||||
__func__, MAC2STR(sta->addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (authorized) {
|
||||
return hostapd_sta_set_flags(hapd, sta->addr,
|
||||
hostapd_sta_flags_to_drv(
|
||||
@ -277,11 +314,24 @@ int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
int set_flags, total_flags, flags_and, flags_or;
|
||||
total_flags = hostapd_sta_flags_to_drv(sta->flags);
|
||||
set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP;
|
||||
if (((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
|
||||
sta->auth_alg == WLAN_AUTH_FT) &&
|
||||
sta->flags & WLAN_STA_AUTHORIZED)
|
||||
set_flags |= WPA_STA_AUTHORIZED;
|
||||
set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP |
|
||||
WPA_STA_AUTHORIZED;
|
||||
|
||||
/*
|
||||
* All the station flags other than WPA_STA_SHORT_PREAMBLE are relevant
|
||||
* only for the MLD station and not to the link stations (as these flags
|
||||
* are related to the MLD state and not the link state). As for the
|
||||
* WPA_STA_SHORT_PREAMBLE, since the station is an EHT station, it must
|
||||
* support short preamble. Thus, do not propagate the change to the
|
||||
* driver for the link stations.
|
||||
*/
|
||||
if (hostapd_sta_is_link_sta(hapd, sta)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: Do not update link station flags (" MACSTR ")",
|
||||
__func__, MAC2STR(sta->addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
flags_or = total_flags & set_flags;
|
||||
flags_and = total_flags | ~set_flags;
|
||||
return hostapd_sta_set_flags(hapd, sta->addr, total_flags,
|
||||
@ -418,9 +468,11 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
const struct ieee80211_vht_capabilities *vht_capab,
|
||||
const struct ieee80211_he_capabilities *he_capab,
|
||||
size_t he_capab_len,
|
||||
const struct ieee80211_eht_capabilities *eht_capab,
|
||||
size_t eht_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)
|
||||
int set, const u8 *link_addr, bool mld_link_sta)
|
||||
{
|
||||
struct hostapd_sta_add_params params;
|
||||
|
||||
@ -440,6 +492,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
params.vht_capabilities = vht_capab;
|
||||
params.he_capab = he_capab;
|
||||
params.he_capab_len = he_capab_len;
|
||||
params.eht_capab = eht_capab;
|
||||
params.eht_capab_len = eht_capab_len;
|
||||
params.he_6ghz_capab = he_6ghz_capab;
|
||||
params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
|
||||
params.vht_opmode = vht_opmode;
|
||||
@ -447,6 +501,20 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
params.qosinfo = qosinfo;
|
||||
params.support_p2p_ps = supp_p2p_ps;
|
||||
params.set = set;
|
||||
params.mld_link_id = -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
/*
|
||||
* An AP MLD needs to always specify to what link the station needs
|
||||
* to be added.
|
||||
*/
|
||||
if (hapd->conf->mld_ap) {
|
||||
params.mld_link_id = hapd->mld_link_id;
|
||||
params.mld_link_addr = link_addr;
|
||||
params.mld_link_sta = mld_link_sta;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
return hapd->driver->sta_add(hapd->drv_priv, ¶ms);
|
||||
}
|
||||
|
||||
@ -507,12 +575,33 @@ int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
int hostapd_if_link_remove(struct hostapd_data *hapd,
|
||||
enum wpa_driver_if_type type,
|
||||
const char *ifname, u8 link_id)
|
||||
{
|
||||
if (!hapd->driver || !hapd->drv_priv || !hapd->driver->link_remove)
|
||||
return -1;
|
||||
|
||||
return hapd->driver->link_remove(hapd->drv_priv, type, ifname,
|
||||
hapd->mld_link_id);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
|
||||
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
|
||||
const char *ifname)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->drv_priv == NULL ||
|
||||
hapd->driver->if_remove == NULL)
|
||||
return -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hapd->conf->mld_ap)
|
||||
return hostapd_if_link_remove(hapd, type, ifname,
|
||||
hapd->mld_link_id);
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
|
||||
}
|
||||
|
||||
@ -527,27 +616,35 @@ int hostapd_set_ieee8021x(struct hostapd_data *hapd,
|
||||
|
||||
|
||||
int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
|
||||
const u8 *addr, int idx, u8 *seq)
|
||||
const u8 *addr, int idx, int link_id, u8 *seq)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL)
|
||||
return 0;
|
||||
return hapd->driver->get_seqnum(ifname, hapd->drv_priv, addr, idx,
|
||||
seq);
|
||||
link_id, seq);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_flush(struct hostapd_data *hapd)
|
||||
{
|
||||
int link_id = -1;
|
||||
|
||||
if (hapd->driver == NULL || hapd->driver->flush == NULL)
|
||||
return 0;
|
||||
return hapd->driver->flush(hapd->drv_priv);
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hapd->conf && hapd->conf->mld_ap)
|
||||
link_id = hapd->mld_link_id;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
return hapd->driver->flush(hapd->drv_priv, link_id);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
|
||||
int freq, int channel, int edmg, u8 edmg_channel,
|
||||
int ht_enabled, int vht_enabled,
|
||||
int he_enabled,
|
||||
int he_enabled, bool eht_enabled,
|
||||
int sec_channel_offset, int oper_chwidth,
|
||||
int center_segment0, int center_segment1)
|
||||
{
|
||||
@ -556,18 +653,32 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
|
||||
|
||||
if (hostapd_set_freq_params(&data, mode, freq, channel, edmg,
|
||||
edmg_channel, ht_enabled,
|
||||
vht_enabled, he_enabled, sec_channel_offset,
|
||||
oper_chwidth,
|
||||
vht_enabled, he_enabled, eht_enabled,
|
||||
sec_channel_offset, oper_chwidth,
|
||||
center_segment0, center_segment1,
|
||||
cmode ? cmode->vht_capab : 0,
|
||||
cmode ?
|
||||
&cmode->he_capab[IEEE80211_MODE_AP] : NULL))
|
||||
&cmode->he_capab[IEEE80211_MODE_AP] : NULL,
|
||||
cmode ?
|
||||
&cmode->eht_capab[IEEE80211_MODE_AP] :
|
||||
NULL, hostapd_get_punct_bitmap(hapd)))
|
||||
return -1;
|
||||
|
||||
if (hapd->driver == NULL)
|
||||
return 0;
|
||||
if (hapd->driver->set_freq == NULL)
|
||||
return 0;
|
||||
|
||||
data.link_id = -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hapd->conf->mld_ap) {
|
||||
data.link_id = hapd->mld_link_id;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"hostapd_set_freq: link_id=%d", data.link_id);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
return hapd->driver->set_freq(hapd->drv_priv, &data);
|
||||
}
|
||||
|
||||
@ -619,10 +730,19 @@ int hostapd_set_country(struct hostapd_data *hapd, const char *country)
|
||||
int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
|
||||
int cw_min, int cw_max, int burst_time)
|
||||
{
|
||||
int link_id = -1;
|
||||
|
||||
if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL)
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hapd->conf->mld_ap)
|
||||
link_id = hapd->mld_link_id;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
return hapd->driver->set_tx_queue_params(hapd->drv_priv, queue, aifs,
|
||||
cw_min, cw_max, burst_time);
|
||||
cw_min, cw_max, burst_time,
|
||||
link_id);
|
||||
}
|
||||
|
||||
|
||||
@ -630,8 +750,8 @@ struct hostapd_hw_modes *
|
||||
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
|
||||
u16 *flags, u8 *dfs_domain)
|
||||
{
|
||||
if (hapd->driver == NULL ||
|
||||
hapd->driver->get_hw_feature_data == NULL)
|
||||
if (!hapd->driver || !hapd->driver->get_hw_feature_data ||
|
||||
!hapd->drv_priv)
|
||||
return NULL;
|
||||
return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes,
|
||||
flags, dfs_domain);
|
||||
@ -670,6 +790,8 @@ int hostapd_driver_scan(struct hostapd_data *hapd,
|
||||
struct wpa_scan_results * hostapd_driver_get_scan_results(
|
||||
struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->driver && hapd->driver->get_scan_results)
|
||||
return hapd->driver->get_scan_results(hapd->drv_priv, NULL);
|
||||
if (hapd->driver && hapd->driver->get_scan_results2)
|
||||
return hapd->driver->get_scan_results2(hapd->drv_priv);
|
||||
return NULL;
|
||||
@ -709,6 +831,12 @@ int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
|
||||
params.key_len = key_len;
|
||||
params.vlan_id = vlan_id;
|
||||
params.key_flag = key_flag;
|
||||
params.link_id = -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hapd->conf->mld_ap && !(key_flag & KEY_FLAG_PAIRWISE))
|
||||
params.link_id = hapd->mld_link_id;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
return hapd->driver->set_key(hapd->drv_priv, ¶ms);
|
||||
}
|
||||
@ -719,29 +847,61 @@ int hostapd_drv_send_mlme(struct hostapd_data *hapd,
|
||||
const u16 *csa_offs, size_t csa_offs_len,
|
||||
int no_encrypt)
|
||||
{
|
||||
int link_id = -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hapd->conf->mld_ap)
|
||||
link_id = hapd->mld_link_id;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
|
||||
return 0;
|
||||
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
|
||||
csa_offs, csa_offs_len, no_encrypt, 0);
|
||||
csa_offs, csa_offs_len, no_encrypt, 0,
|
||||
link_id);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
|
||||
const u8 *addr, int reason)
|
||||
{
|
||||
int link_id = -1;
|
||||
const u8 *own_addr = hapd->own_addr;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hapd->conf->mld_ap) {
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
|
||||
link_id = hapd->mld_link_id;
|
||||
if (ap_sta_is_mld(hapd, sta))
|
||||
own_addr = hapd->mld->mld_addr;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
if (!hapd->driver || !hapd->driver->sta_deauth || !hapd->drv_priv)
|
||||
return 0;
|
||||
return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
|
||||
reason);
|
||||
return hapd->driver->sta_deauth(hapd->drv_priv, own_addr, addr,
|
||||
reason, link_id);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
|
||||
const u8 *addr, int reason)
|
||||
{
|
||||
const u8 *own_addr = hapd->own_addr;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hapd->conf->mld_ap) {
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
|
||||
if (ap_sta_is_mld(hapd, sta))
|
||||
own_addr = hapd->mld->mld_addr;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
if (!hapd->driver || !hapd->driver->sta_disassoc || !hapd->drv_priv)
|
||||
return 0;
|
||||
return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
|
||||
return hapd->driver->sta_disassoc(hapd->drv_priv, own_addr, addr,
|
||||
reason);
|
||||
}
|
||||
|
||||
@ -756,22 +916,22 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper,
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
|
||||
unsigned int wait, const u8 *dst, const u8 *data,
|
||||
size_t len)
|
||||
static int hapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
|
||||
unsigned int wait, const u8 *dst,
|
||||
const u8 *data, size_t len, bool addr3_ap)
|
||||
{
|
||||
const u8 *own_addr = hapd->own_addr;
|
||||
const u8 *bssid;
|
||||
const u8 wildcard_bssid[ETH_ALEN] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
struct sta_info *sta;
|
||||
|
||||
if (!hapd->driver || !hapd->driver->send_action || !hapd->drv_priv)
|
||||
return 0;
|
||||
bssid = hapd->own_addr;
|
||||
if (!is_multicast_ether_addr(dst) &&
|
||||
if (!addr3_ap && !is_multicast_ether_addr(dst) &&
|
||||
len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
|
||||
struct sta_info *sta;
|
||||
|
||||
/*
|
||||
* Public Action frames to a STA that is not a member of the BSS
|
||||
* shall use wildcard BSSID value.
|
||||
@ -779,7 +939,7 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
|
||||
sta = ap_get_sta(hapd, dst);
|
||||
if (!sta || !(sta->flags & WLAN_STA_ASSOC))
|
||||
bssid = wildcard_bssid;
|
||||
} else if (is_broadcast_ether_addr(dst) &&
|
||||
} else if (!addr3_ap && is_broadcast_ether_addr(dst) &&
|
||||
len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
|
||||
/*
|
||||
* The only current use case of Public Action frames with
|
||||
@ -788,9 +948,27 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
|
||||
* so have to use the wildcard BSSID value.
|
||||
*/
|
||||
bssid = wildcard_bssid;
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
} else if (hapd->conf->mld_ap) {
|
||||
sta = ap_get_sta(hapd, dst);
|
||||
|
||||
if (ap_sta_is_mld(hapd, sta)) {
|
||||
own_addr = hapd->mld->mld_addr;
|
||||
bssid = own_addr;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
}
|
||||
|
||||
return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
|
||||
hapd->own_addr, bssid, data, len, 0);
|
||||
own_addr, bssid, data, len, 0);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
|
||||
unsigned int wait, const u8 *dst, const u8 *data,
|
||||
size_t len)
|
||||
{
|
||||
return hapd_drv_send_action(hapd, freq, wait, dst, data, len, false);
|
||||
}
|
||||
|
||||
|
||||
@ -799,20 +977,17 @@ int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
|
||||
unsigned int wait, const u8 *dst,
|
||||
const u8 *data, size_t len)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->send_action == NULL)
|
||||
return 0;
|
||||
return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
|
||||
hapd->own_addr, hapd->own_addr, data,
|
||||
len, 0);
|
||||
return hapd_drv_send_action(hapd, freq, wait, dst, data, len, true);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
|
||||
enum hostapd_hw_mode mode, int freq,
|
||||
int channel, int ht_enabled, int vht_enabled,
|
||||
int he_enabled,
|
||||
int he_enabled, bool eht_enabled,
|
||||
int sec_channel_offset, int oper_chwidth,
|
||||
int center_segment0, int center_segment1)
|
||||
int center_segment0, int center_segment1,
|
||||
bool radar_background)
|
||||
{
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
struct hostapd_freq_params data;
|
||||
@ -830,18 +1005,25 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
|
||||
|
||||
if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0,
|
||||
ht_enabled,
|
||||
vht_enabled, he_enabled, sec_channel_offset,
|
||||
vht_enabled, he_enabled, eht_enabled,
|
||||
sec_channel_offset,
|
||||
oper_chwidth, center_segment0,
|
||||
center_segment1,
|
||||
cmode->vht_capab,
|
||||
&cmode->he_capab[IEEE80211_MODE_AP])) {
|
||||
&cmode->he_capab[IEEE80211_MODE_AP],
|
||||
&cmode->eht_capab[IEEE80211_MODE_AP],
|
||||
hostapd_get_punct_bitmap(hapd))) {
|
||||
wpa_printf(MSG_ERROR, "Can't set freq params");
|
||||
return -1;
|
||||
}
|
||||
data.radar_background = radar_background;
|
||||
|
||||
res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
|
||||
if (!res) {
|
||||
iface->cac_started = 1;
|
||||
if (radar_background)
|
||||
iface->radar_background.cac_started = 1;
|
||||
else
|
||||
iface->cac_started = 1;
|
||||
os_get_reltime(&iface->dfs_cac_start);
|
||||
}
|
||||
|
||||
@ -852,19 +1034,21 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
|
||||
int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
|
||||
const u8 *qos_map_set, u8 qos_map_set_len)
|
||||
{
|
||||
if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv)
|
||||
if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv ||
|
||||
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_QOS_MAPPING))
|
||||
return 0;
|
||||
return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
|
||||
qos_map_set_len);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
|
||||
struct hostapd_hw_modes *mode,
|
||||
int acs_ch_list_all,
|
||||
int **freq_list)
|
||||
void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
|
||||
struct hostapd_hw_modes *mode,
|
||||
int acs_ch_list_all, bool allow_disabled,
|
||||
int **freq_list)
|
||||
{
|
||||
int i;
|
||||
bool is_no_ir = false;
|
||||
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
struct hostapd_channel_data *chan = &mode->channels[i];
|
||||
@ -883,15 +1067,22 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
|
||||
chan->chan)))
|
||||
continue;
|
||||
if (is_6ghz_freq(chan->freq) &&
|
||||
hapd->iface->conf->acs_exclude_6ghz_non_psc &&
|
||||
!is_6ghz_psc_frequency(chan->freq))
|
||||
((hapd->iface->conf->acs_exclude_6ghz_non_psc &&
|
||||
!is_6ghz_psc_frequency(chan->freq)) ||
|
||||
(!hapd->iface->conf->ieee80211ax &&
|
||||
!hapd->iface->conf->ieee80211be)))
|
||||
continue;
|
||||
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
|
||||
if ((!(chan->flag & HOSTAPD_CHAN_DISABLED) || allow_disabled) &&
|
||||
!(hapd->iface->conf->acs_exclude_dfs &&
|
||||
(chan->flag & HOSTAPD_CHAN_RADAR)) &&
|
||||
!(chan->max_tx_power < hapd->iface->conf->min_tx_power))
|
||||
int_array_add_unique(freq_list, chan->freq);
|
||||
else if ((chan->flag & HOSTAPD_CHAN_NO_IR) &&
|
||||
is_6ghz_freq(chan->freq))
|
||||
is_no_ir = true;
|
||||
}
|
||||
|
||||
hapd->iface->is_no_ir = is_no_ir;
|
||||
}
|
||||
|
||||
|
||||
@ -909,6 +1100,24 @@ void hostapd_get_ext_capa(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
void hostapd_get_mld_capa(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
|
||||
if (!hapd->driver || !hapd->driver->get_mld_capab)
|
||||
return;
|
||||
|
||||
hapd->driver->get_mld_capab(hapd->drv_priv, WPA_IF_AP_BSS,
|
||||
&iface->mld_eml_capa,
|
||||
&iface->mld_mld_capa);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_drv_do_acs - Start automatic channel selection
|
||||
* @hapd: BSS data for the device initiating ACS
|
||||
* Returns: 0 on success, -1 on failure, 1 on failure due to NO_IR (AFC)
|
||||
*/
|
||||
int hostapd_drv_do_acs(struct hostapd_data *hapd)
|
||||
{
|
||||
struct drv_acs_params params;
|
||||
@ -922,6 +1131,12 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
|
||||
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
params.hw_mode = hapd->iface->conf->hw_mode;
|
||||
params.link_id = -1;
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hapd->conf->mld_ap && hapd->iconf->ieee80211be &&
|
||||
!hapd->conf->disable_11be)
|
||||
params.link_id = hapd->mld_link_id;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
/*
|
||||
* If no chanlist config parameter is provided, include all enabled
|
||||
@ -943,7 +1158,13 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
|
||||
selected_mode != mode->mode)
|
||||
continue;
|
||||
hostapd_get_hw_mode_any_channels(hapd, mode, acs_ch_list_all,
|
||||
&freq_list);
|
||||
false, &freq_list);
|
||||
}
|
||||
|
||||
if (!freq_list && hapd->iface->is_no_ir) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"NO_IR: Interface freq_list is empty. Failing do_acs.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
params.freq_list = freq_list;
|
||||
@ -953,22 +1174,27 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
|
||||
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
|
||||
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
|
||||
params.vht_enabled = !!(hapd->iface->conf->ieee80211ac);
|
||||
params.eht_enabled = !!(hapd->iface->conf->ieee80211be);
|
||||
params.ch_width = 20;
|
||||
if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
|
||||
params.ch_width = 40;
|
||||
|
||||
/* Note: VHT20 is defined by combination of ht_capab & oper_chwidth
|
||||
*/
|
||||
if ((hapd->iface->conf->ieee80211ax ||
|
||||
if ((hapd->iface->conf->ieee80211be ||
|
||||
hapd->iface->conf->ieee80211ax ||
|
||||
hapd->iface->conf->ieee80211ac) &&
|
||||
params.ht40_enabled) {
|
||||
u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
|
||||
enum oper_chan_width oper_chwidth;
|
||||
|
||||
if (oper_chwidth == CHANWIDTH_80MHZ)
|
||||
oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
|
||||
if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
|
||||
params.ch_width = 80;
|
||||
else if (oper_chwidth == CHANWIDTH_160MHZ ||
|
||||
oper_chwidth == CHANWIDTH_80P80MHZ)
|
||||
else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
|
||||
oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
|
||||
params.ch_width = 160;
|
||||
else if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ)
|
||||
params.ch_width = 320;
|
||||
}
|
||||
|
||||
if (hapd->iface->conf->op_class)
|
||||
@ -997,3 +1223,30 @@ int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable)
|
||||
return 0;
|
||||
return hapd->driver->dpp_listen(hapd->drv_priv, enable);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PASN
|
||||
int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd,
|
||||
const u8 *own_addr, const u8 *peer_addr,
|
||||
u32 cipher, u8 tk_len, const u8 *tk,
|
||||
u8 ltf_keyseed_len,
|
||||
const u8 *ltf_keyseed, u32 action)
|
||||
{
|
||||
struct secure_ranging_params params;
|
||||
|
||||
if (!hapd->driver || !hapd->driver->set_secure_ranging_ctx)
|
||||
return 0;
|
||||
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
params.own_addr = own_addr;
|
||||
params.peer_addr = peer_addr;
|
||||
params.cipher = cipher;
|
||||
params.tk_len = tk_len;
|
||||
params.tk = tk;
|
||||
params.ltf_keyseed_len = ltf_keyseed_len;
|
||||
params.ltf_keyseed = ltf_keyseed;
|
||||
params.action = action;
|
||||
|
||||
return hapd->driver->set_secure_ranging_ctx(hapd->drv_priv, ¶ms);
|
||||
}
|
||||
#endif /* CONFIG_PASN */
|
||||
|
@ -26,6 +26,8 @@ void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
|
||||
struct wpabuf *assocresp);
|
||||
int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd);
|
||||
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
|
||||
bool hostapd_sta_is_link_sta(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
int hostapd_set_authorized(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int authorized);
|
||||
int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
@ -43,9 +45,11 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
const struct ieee80211_vht_capabilities *vht_capab,
|
||||
const struct ieee80211_he_capabilities *he_capab,
|
||||
size_t he_capab_len,
|
||||
const struct ieee80211_eht_capabilities *eht_capab,
|
||||
size_t eht_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);
|
||||
int set, const u8 *link_addr, bool mld_link_sta);
|
||||
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
|
||||
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
|
||||
size_t elem_len);
|
||||
@ -57,15 +61,18 @@ int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
|
||||
const char *bridge, int use_existing);
|
||||
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
|
||||
const char *ifname);
|
||||
int hostapd_if_link_remove(struct hostapd_data *hapd,
|
||||
enum wpa_driver_if_type type,
|
||||
const char *ifname, u8 link_id);
|
||||
int hostapd_set_ieee8021x(struct hostapd_data *hapd,
|
||||
struct wpa_bss_params *params);
|
||||
int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
|
||||
const u8 *addr, int idx, u8 *seq);
|
||||
const u8 *addr, int idx, int link_id, u8 *seq);
|
||||
int hostapd_flush(struct hostapd_data *hapd);
|
||||
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
|
||||
int freq, int channel, int edmg, u8 edmg_channel,
|
||||
int ht_enabled, int vht_enabled,
|
||||
int he_enabled, int sec_channel_offset, int oper_chwidth,
|
||||
int ht_enabled, int vht_enabled, int he_enabled,
|
||||
bool eht_enabled, int sec_channel_offset, int oper_chwidth,
|
||||
int center_segment0, int center_segment1);
|
||||
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
|
||||
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
|
||||
@ -128,13 +135,19 @@ int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
|
||||
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
|
||||
enum hostapd_hw_mode mode, int freq,
|
||||
int channel, int ht_enabled, int vht_enabled,
|
||||
int he_enabled,
|
||||
int he_enabled, bool eht_enabled,
|
||||
int sec_channel_offset, int oper_chwidth,
|
||||
int center_segment0, int center_segment1);
|
||||
int center_segment0, int center_segment1,
|
||||
bool radar_background);
|
||||
int hostapd_drv_do_acs(struct hostapd_data *hapd);
|
||||
int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
|
||||
u16 reason_code, const u8 *ie, size_t ielen);
|
||||
int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable);
|
||||
int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd,
|
||||
const u8 *own_addr, const u8 *addr,
|
||||
u32 cipher, u8 key_len, const u8 *key,
|
||||
u8 ltf_keyseed_len,
|
||||
const u8 *ltf_keyseed, u32 action);
|
||||
|
||||
|
||||
#include "drivers/driver.h"
|
||||
@ -147,6 +160,12 @@ int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
|
||||
u8 qos_map_set_len);
|
||||
|
||||
void hostapd_get_ext_capa(struct hostapd_iface *iface);
|
||||
void hostapd_get_mld_capa(struct hostapd_iface *iface);
|
||||
|
||||
void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
|
||||
struct hostapd_hw_modes *mode,
|
||||
int acs_ch_list_all, bool allow_disabled,
|
||||
int **freq_list);
|
||||
|
||||
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
|
||||
int enabled)
|
||||
@ -159,12 +178,13 @@ static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
|
||||
|
||||
static inline int hostapd_drv_set_sta_vlan(const char *ifname,
|
||||
struct hostapd_data *hapd,
|
||||
const u8 *addr, int vlan_id)
|
||||
const u8 *addr, int vlan_id,
|
||||
int link_id)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname,
|
||||
vlan_id);
|
||||
vlan_id, link_id);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd,
|
||||
@ -186,13 +206,13 @@ static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd,
|
||||
static inline int hostapd_drv_hapd_send_eapol(struct hostapd_data *hapd,
|
||||
const u8 *addr, const u8 *data,
|
||||
size_t data_len, int encrypt,
|
||||
u32 flags)
|
||||
u32 flags, int link_id)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL)
|
||||
return 0;
|
||||
return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data,
|
||||
data_len, encrypt,
|
||||
hapd->own_addr, flags);
|
||||
hapd->own_addr, flags, link_id);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_read_sta_data(
|
||||
@ -299,6 +319,17 @@ static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
|
||||
return hapd->driver->switch_channel(hapd->drv_priv, settings);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
static inline int hostapd_drv_switch_color(struct hostapd_data *hapd,
|
||||
struct cca_settings *settings)
|
||||
{
|
||||
if (!hapd->driver || !hapd->driver->switch_color || !hapd->drv_priv)
|
||||
return -1;
|
||||
|
||||
return hapd->driver->switch_color(hapd->drv_priv, settings);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
@ -362,9 +393,15 @@ static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
|
||||
|
||||
static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
|
||||
{
|
||||
int link_id = -1;
|
||||
|
||||
if (!hapd->driver || !hapd->driver->stop_ap || !hapd->drv_priv)
|
||||
return 0;
|
||||
return hapd->driver->stop_ap(hapd->drv_priv);
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hapd->conf->mld_ap)
|
||||
link_id = hapd->mld_link_id;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
return hapd->driver->stop_ap(hapd->drv_priv, link_id);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_channel_info(struct hostapd_data *hapd,
|
||||
@ -416,4 +453,29 @@ hostapd_drv_register_frame(struct hostapd_data *hapd, u16 type,
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
|
||||
static inline int hostapd_drv_link_add(struct hostapd_data *hapd,
|
||||
u8 link_id, const u8 *addr)
|
||||
{
|
||||
if (!hapd->driver || !hapd->drv_priv || !hapd->driver->link_add)
|
||||
return -1;
|
||||
|
||||
return hapd->driver->link_add(hapd->drv_priv, link_id, addr, hapd);
|
||||
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_link_sta_remove(struct hostapd_data *hapd,
|
||||
const u8 *addr)
|
||||
{
|
||||
if (!hapd->conf->mld_ap || !hapd->driver || !hapd->drv_priv ||
|
||||
!hapd->driver->link_sta_remove)
|
||||
return -1;
|
||||
|
||||
return hapd->driver->link_sta_remove(hapd->drv_priv, hapd->mld_link_id,
|
||||
addr);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
#endif /* AP_DRV_OPS */
|
||||
|
@ -55,7 +55,7 @@ static struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
|
||||
struct ap_info *s;
|
||||
|
||||
s = iface->ap_hash[STA_HASH(ap)];
|
||||
while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
|
||||
while (s != NULL && !ether_addr_equal(s->addr, ap))
|
||||
s = s->hnext;
|
||||
return s;
|
||||
}
|
||||
@ -100,13 +100,13 @@ static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
|
||||
|
||||
s = iface->ap_hash[STA_HASH(ap->addr)];
|
||||
if (s == NULL) return;
|
||||
if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
|
||||
if (ether_addr_equal(s->addr, ap->addr)) {
|
||||
iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
|
||||
return;
|
||||
}
|
||||
|
||||
while (s->hnext != NULL &&
|
||||
os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
|
||||
!ether_addr_equal(s->hnext->addr, ap->addr))
|
||||
s = s->hnext;
|
||||
if (s->hnext != NULL)
|
||||
s->hnext = s->hnext->hnext;
|
||||
|
@ -29,9 +29,9 @@ static const char * mlme_auth_alg_str(int alg)
|
||||
return "SHARED_KEY";
|
||||
case WLAN_AUTH_FT:
|
||||
return "FT";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
#endif /* CONFIG_NO_HOSTAPD_LOGGER */
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "eap_server/eap.h"
|
||||
#include "eap_server/eap_sim_db.h"
|
||||
@ -105,6 +106,22 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
|
||||
{
|
||||
struct radius_server_conf srv;
|
||||
struct hostapd_bss_config *conf = hapd->conf;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (!hostapd_mld_is_first_bss(hapd)) {
|
||||
struct hostapd_data *first;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MLD: Using RADIUS server of the first BSS");
|
||||
|
||||
first = hostapd_mld_get_first_bss(hapd);
|
||||
if (!first)
|
||||
return -1;
|
||||
hapd->radius_srv = first->radius_srv;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
os_memset(&srv, 0, sizeof(srv));
|
||||
srv.client_file = conf->radius_server_clients;
|
||||
srv.auth_port = conf->radius_server_auth_port;
|
||||
@ -168,6 +185,9 @@ static void authsrv_tls_event(void *ctx, enum tls_event ev,
|
||||
wpa_printf(MSG_DEBUG, "authsrv: remote TLS alert: %s",
|
||||
data->alert.description);
|
||||
break;
|
||||
case TLS_UNSAFE_RENEGOTIATION_DISABLED:
|
||||
/* Not applicable to TLS server */
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* EAP_TLS_FUNCS */
|
||||
@ -207,8 +227,12 @@ static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd)
|
||||
cfg->eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner;
|
||||
cfg->eap_teap_separate_result = hapd->conf->eap_teap_separate_result;
|
||||
cfg->eap_teap_id = hapd->conf->eap_teap_id;
|
||||
cfg->eap_teap_method_sequence = hapd->conf->eap_teap_method_sequence;
|
||||
cfg->eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
|
||||
cfg->eap_sim_id = hapd->conf->eap_sim_id;
|
||||
cfg->imsi_privacy_key = hapd->imsi_privacy_key;
|
||||
cfg->eap_sim_aka_fast_reauth_limit =
|
||||
hapd->conf->eap_sim_aka_fast_reauth_limit;
|
||||
cfg->tnc = hapd->conf->tnc;
|
||||
cfg->wps = hapd->wps;
|
||||
cfg->fragment_size = hapd->conf->fragment_size;
|
||||
@ -222,6 +246,9 @@ static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd)
|
||||
cfg->server_id_len = 7;
|
||||
}
|
||||
cfg->erp = hapd->conf->eap_server_erp;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
cfg->skip_prot_success = hapd->conf->eap_skip_prot_success;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
return cfg;
|
||||
}
|
||||
@ -229,6 +256,35 @@ static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd)
|
||||
|
||||
int authsrv_init(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (!hostapd_mld_is_first_bss(hapd)) {
|
||||
struct hostapd_data *first;
|
||||
|
||||
first = hostapd_mld_get_first_bss(hapd);
|
||||
if (!first)
|
||||
return -1;
|
||||
|
||||
if (!first->eap_cfg) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MLD: First BSS auth_serv does not exist. Init on its behalf");
|
||||
|
||||
if (authsrv_init(first))
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "MLD: Using auth_serv of the first BSS");
|
||||
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
hapd->ssl_ctx = first->ssl_ctx;
|
||||
#endif /* EAP_TLS_FUNCS */
|
||||
hapd->eap_cfg = first->eap_cfg;
|
||||
#ifdef EAP_SIM_DB
|
||||
hapd->eap_sim_db_priv = first->eap_sim_db_priv;
|
||||
#endif /* EAP_SIM_DB */
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
if (hapd->conf->eap_server &&
|
||||
(hapd->conf->ca_cert || hapd->conf->server_cert ||
|
||||
@ -292,6 +348,22 @@ int authsrv_init(struct hostapd_data *hapd)
|
||||
}
|
||||
#endif /* EAP_TLS_FUNCS */
|
||||
|
||||
#ifdef CRYPTO_RSA_OAEP_SHA256
|
||||
crypto_rsa_key_free(hapd->imsi_privacy_key);
|
||||
hapd->imsi_privacy_key = NULL;
|
||||
if (hapd->conf->imsi_privacy_key) {
|
||||
hapd->imsi_privacy_key = crypto_rsa_key_read(
|
||||
hapd->conf->imsi_privacy_key, true);
|
||||
if (!hapd->imsi_privacy_key) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Failed to read/parse IMSI privacy key %s",
|
||||
hapd->conf->imsi_privacy_key);
|
||||
authsrv_deinit(hapd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif /* CRYPTO_RSA_OAEP_SHA256 */
|
||||
|
||||
#ifdef EAP_SIM_DB
|
||||
if (hapd->conf->eap_sim_db) {
|
||||
hapd->eap_sim_db_priv =
|
||||
@ -327,11 +399,33 @@ int authsrv_init(struct hostapd_data *hapd)
|
||||
|
||||
void authsrv_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (!hostapd_mld_is_first_bss(hapd)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MLD: Deinit auth_serv of a non-first BSS");
|
||||
|
||||
hapd->radius_srv = NULL;
|
||||
hapd->eap_cfg = NULL;
|
||||
#ifdef EAP_SIM_DB
|
||||
hapd->eap_sim_db_priv = NULL;
|
||||
#endif /* EAP_SIM_DB */
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
hapd->ssl_ctx = NULL;
|
||||
#endif /* EAP_TLS_FUNCS */
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
#ifdef RADIUS_SERVER
|
||||
radius_server_deinit(hapd->radius_srv);
|
||||
hapd->radius_srv = NULL;
|
||||
#endif /* RADIUS_SERVER */
|
||||
|
||||
#ifdef CRYPTO_RSA_OAEP_SHA256
|
||||
crypto_rsa_key_free(hapd->imsi_privacy_key);
|
||||
hapd->imsi_privacy_key = NULL;
|
||||
#endif /* CRYPTO_RSA_OAEP_SHA256 */
|
||||
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
if (hapd->ssl_ctx) {
|
||||
tls_deinit(hapd->ssl_ctx);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -15,6 +15,7 @@ struct ieee80211_mgmt;
|
||||
void handle_probe_req(struct hostapd_data *hapd,
|
||||
const struct ieee80211_mgmt *mgmt, size_t len,
|
||||
int ssi_signal);
|
||||
void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd);
|
||||
int ieee802_11_set_beacon(struct hostapd_data *hapd);
|
||||
int ieee802_11_set_beacons(struct hostapd_iface *iface);
|
||||
int ieee802_11_update_beacons(struct hostapd_iface *iface);
|
||||
@ -32,4 +33,7 @@ void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
|
||||
|
||||
const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid);
|
||||
|
||||
u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
|
||||
struct unsol_bcast_probe_resp *ubpr);
|
||||
|
||||
#endif /* BEACON_H */
|
||||
|
@ -55,7 +55,7 @@ static void update_channel_utilization(void *eloop_data, void *user_data)
|
||||
return;
|
||||
}
|
||||
|
||||
ieee802_11_set_beacon(hapd);
|
||||
ieee802_11_set_beacon_per_bss_only(hapd);
|
||||
|
||||
if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0)
|
||||
return;
|
||||
|
139
contrib/wpa/src/ap/comeback_token.c
Normal file
139
contrib/wpa/src/ap/comeback_token.c
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* hostapd / Comeback token mechanism for SAE
|
||||
* Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* 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 "hostapd.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/random.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "comeback_token.h"
|
||||
|
||||
|
||||
#if defined(CONFIG_SAE) || defined(CONFIG_PASN)
|
||||
|
||||
static int comeback_token_hash(const u8 *comeback_key, const u8 *addr, u8 *idx)
|
||||
{
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
|
||||
if (hmac_sha256(comeback_key, COMEBACK_KEY_SIZE,
|
||||
addr, ETH_ALEN, hash) < 0)
|
||||
return -1;
|
||||
*idx = hash[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int check_comeback_token(const u8 *comeback_key,
|
||||
u16 *comeback_pending_idx, const u8 *addr,
|
||||
const u8 *token, size_t token_len)
|
||||
{
|
||||
u8 mac[SHA256_MAC_LEN];
|
||||
const u8 *addrs[2];
|
||||
size_t len[2];
|
||||
u16 token_idx;
|
||||
u8 idx;
|
||||
|
||||
if (token_len != SHA256_MAC_LEN ||
|
||||
comeback_token_hash(comeback_key, addr, &idx) < 0)
|
||||
return -1;
|
||||
token_idx = comeback_pending_idx[idx];
|
||||
if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Comeback: Invalid anti-clogging token from "
|
||||
MACSTR " - token_idx 0x%04x, expected 0x%04x",
|
||||
MAC2STR(addr), WPA_GET_BE16(token), token_idx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
addrs[0] = addr;
|
||||
len[0] = ETH_ALEN;
|
||||
addrs[1] = token;
|
||||
len[1] = 2;
|
||||
if (hmac_sha256_vector(comeback_key, COMEBACK_KEY_SIZE,
|
||||
2, addrs, len, mac) < 0 ||
|
||||
os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
|
||||
return -1;
|
||||
|
||||
comeback_pending_idx[idx] = 0; /* invalidate used token */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf *
|
||||
auth_build_token_req(struct os_reltime *last_comeback_key_update,
|
||||
u8 *comeback_key, u16 comeback_idx,
|
||||
u16 *comeback_pending_idx, size_t idx_len,
|
||||
int group, const u8 *addr, int h2e)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
u8 *token;
|
||||
struct os_reltime now;
|
||||
u8 idx[2];
|
||||
const u8 *addrs[2];
|
||||
size_t len[2];
|
||||
u8 p_idx;
|
||||
u16 token_idx;
|
||||
|
||||
os_get_reltime(&now);
|
||||
if (!os_reltime_initialized(last_comeback_key_update) ||
|
||||
os_reltime_expired(&now, last_comeback_key_update, 60) ||
|
||||
comeback_idx == 0xffff) {
|
||||
if (random_get_bytes(comeback_key, COMEBACK_KEY_SIZE) < 0)
|
||||
return NULL;
|
||||
wpa_hexdump(MSG_DEBUG, "Comeback: Updated token key",
|
||||
comeback_key, COMEBACK_KEY_SIZE);
|
||||
*last_comeback_key_update = now;
|
||||
comeback_idx = 0;
|
||||
os_memset(comeback_pending_idx, 0, idx_len);
|
||||
}
|
||||
|
||||
buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
if (group)
|
||||
wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
|
||||
|
||||
if (h2e) {
|
||||
/* Encapsulate Anti-clogging Token field in a container IE */
|
||||
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
|
||||
wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN);
|
||||
wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
|
||||
}
|
||||
|
||||
if (comeback_token_hash(comeback_key, addr, &p_idx) < 0) {
|
||||
wpabuf_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
token_idx = comeback_pending_idx[p_idx];
|
||||
if (!token_idx) {
|
||||
comeback_idx++;
|
||||
token_idx = comeback_idx;
|
||||
comeback_pending_idx[p_idx] = token_idx;
|
||||
}
|
||||
WPA_PUT_BE16(idx, token_idx);
|
||||
token = wpabuf_put(buf, SHA256_MAC_LEN);
|
||||
addrs[0] = addr;
|
||||
len[0] = ETH_ALEN;
|
||||
addrs[1] = idx;
|
||||
len[1] = sizeof(idx);
|
||||
if (hmac_sha256_vector(comeback_key, COMEBACK_KEY_SIZE,
|
||||
2, addrs, len, token) < 0) {
|
||||
wpabuf_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
WPA_PUT_BE16(token, token_idx);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */
|
21
contrib/wpa/src/ap/comeback_token.h
Normal file
21
contrib/wpa/src/ap/comeback_token.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* hostapd / Comeback token mechanism for SAE
|
||||
* Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef COMEBACK_TOKEN_H
|
||||
#define COMEBACK_TOKEN_H
|
||||
|
||||
int check_comeback_token(const u8 *comeback_key,
|
||||
u16 *comeback_pending_idx, const u8 *addr,
|
||||
const u8 *token, size_t token_len);
|
||||
struct wpabuf *
|
||||
auth_build_token_req(struct os_reltime *last_comeback_key_update,
|
||||
u8 *comeback_key, u16 comeback_idx,
|
||||
u16 *comeback_pending_idx, size_t idx_len,
|
||||
int group, const u8 *addr, int h2e);
|
||||
|
||||
#endif /* COMEBACK_TOKEN_H */
|
@ -24,6 +24,7 @@
|
||||
#include "ap_drv_ops.h"
|
||||
#include "mbo_ap.h"
|
||||
#include "taxonomy.h"
|
||||
#include "wnm_ap.h"
|
||||
|
||||
|
||||
static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
|
||||
@ -98,7 +99,7 @@ static int hostapd_get_sta_info(struct hostapd_data *hapd,
|
||||
len += ret;
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu",
|
||||
data.current_rx_rate);
|
||||
data.current_rx_rate / 100);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
@ -130,7 +131,7 @@ static int hostapd_get_sta_info(struct hostapd_data *hapd,
|
||||
len += ret;
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu",
|
||||
data.current_tx_rate);
|
||||
data.current_tx_rate / 100);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
@ -205,9 +206,29 @@ static const char * timeout_next_str(int val)
|
||||
return "REMOVE";
|
||||
case STA_DISASSOC_FROM_CLI:
|
||||
return "DISASSOC_FROM_CLI";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
return "?";
|
||||
|
||||
static const char * hw_mode_str(enum hostapd_hw_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case HOSTAPD_MODE_IEEE80211B:
|
||||
return "b";
|
||||
case HOSTAPD_MODE_IEEE80211G:
|
||||
return "g";
|
||||
case HOSTAPD_MODE_IEEE80211A:
|
||||
return "a";
|
||||
case HOSTAPD_MODE_IEEE80211AD:
|
||||
return "ad";
|
||||
case HOSTAPD_MODE_IEEE80211ANY:
|
||||
return "any";
|
||||
case NUM_HOSTAPD_MODES:
|
||||
return "invalid";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
|
||||
@ -217,6 +238,7 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
{
|
||||
int len, res, ret, i;
|
||||
const char *keyid;
|
||||
const u8 *dpp_pkhash;
|
||||
|
||||
if (!sta)
|
||||
return 0;
|
||||
@ -255,6 +277,14 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
return len;
|
||||
len += ret;
|
||||
|
||||
if (sta->max_idle_period) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"max_idle_period=%d\n", sta->max_idle_period);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
|
||||
if (res >= 0)
|
||||
len += res;
|
||||
@ -326,11 +356,15 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
|
||||
if (sta->supp_op_classes &&
|
||||
buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
|
||||
len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
|
||||
res = os_snprintf(buf + len, buflen - len, "supp_op_classes=");
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
len += wpa_snprintf_hex(buf + len, buflen - len,
|
||||
sta->supp_op_classes + 1,
|
||||
sta->supp_op_classes[0]);
|
||||
len += os_snprintf(buf + len, buflen - len, "\n");
|
||||
res = os_snprintf(buf + len, buflen - len, "\n");
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
}
|
||||
|
||||
if (sta->power_capab) {
|
||||
@ -342,6 +376,34 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
len += ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if ((sta->flags & WLAN_STA_HE) && sta->he_capab) {
|
||||
res = os_snprintf(buf + len, buflen - len, "he_capab=");
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
len += wpa_snprintf_hex(buf + len, buflen - len,
|
||||
(const u8 *) sta->he_capab,
|
||||
sta->he_capab_len);
|
||||
res = os_snprintf(buf + len, buflen - len, "\n");
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if ((sta->flags & WLAN_STA_EHT) && sta->eht_capab) {
|
||||
res = os_snprintf(buf + len, buflen - len, "eht_capab=");
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
len += wpa_snprintf_hex(buf + len, buflen - len,
|
||||
(const u8 *) sta->eht_capab,
|
||||
sta->eht_capab_len);
|
||||
res = os_snprintf(buf + len, buflen - len, "\n");
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
|
||||
res = os_snprintf(buf + len, buflen - len,
|
||||
@ -350,6 +412,16 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
vht_capabilities_info));
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
|
||||
res = os_snprintf(buf + len, buflen - len, "vht_capab=");
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
len += wpa_snprintf_hex(buf + len, buflen - len,
|
||||
(const u8 *) sta->vht_capabilities,
|
||||
sizeof(*sta->vht_capabilities));
|
||||
res = os_snprintf(buf + len, buflen - len, "\n");
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
@ -364,11 +436,15 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
|
||||
if (sta->ext_capability &&
|
||||
buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
|
||||
len += os_snprintf(buf + len, buflen - len, "ext_capab=");
|
||||
res = os_snprintf(buf + len, buflen - len, "ext_capab=");
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
len += wpa_snprintf_hex(buf + len, buflen - len,
|
||||
sta->ext_capability + 1,
|
||||
sta->ext_capability[0]);
|
||||
len += os_snprintf(buf + len, buflen - len, "\n");
|
||||
res = os_snprintf(buf + len, buflen - len, "\n");
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
}
|
||||
|
||||
if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) {
|
||||
@ -385,6 +461,33 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
len += ret;
|
||||
}
|
||||
|
||||
dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta);
|
||||
if (dpp_pkhash) {
|
||||
ret = os_snprintf(buf + len, buflen - len, "dpp_pkhash=");
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
len += wpa_snprintf_hex(buf + len, buflen - len, dpp_pkhash,
|
||||
SHA256_MAC_LEN);
|
||||
ret = os_snprintf(buf + len, buflen - len, "\n");
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (sta->mld_info.mld_sta) {
|
||||
for (i = 0; i < MAX_NUM_MLD_LINKS; ++i) {
|
||||
if (!sta->mld_info.links[i].valid)
|
||||
continue;
|
||||
ret = os_snprintf(
|
||||
buf + len, buflen - len,
|
||||
"peer_addr[%d]=" MACSTR "\n",
|
||||
i, MAC2STR(sta->mld_info.links[i].peer_addr));
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -682,6 +785,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
{
|
||||
struct hostapd_iface *iface = hapd->iface;
|
||||
struct hostapd_hw_modes *mode = iface->current_mode;
|
||||
struct hostapd_config *iconf = hapd->iconf;
|
||||
int len = 0, ret, j;
|
||||
size_t i;
|
||||
|
||||
@ -716,6 +820,24 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
return len;
|
||||
len += ret;
|
||||
|
||||
if (mode) {
|
||||
ret = os_snprintf(buf + len, buflen - len, "hw_mode=%s\n",
|
||||
hw_mode_str(mode->mode));
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
if (iconf->country[0] && iconf->country[1]) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"country_code=%c%c\ncountry3=0x%X\n",
|
||||
iconf->country[0], iconf->country[1],
|
||||
iconf->country[2]);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
if (!iface->cac_started || !iface->dfs_cac_ms) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"cac_time_seconds=%d\n"
|
||||
@ -724,15 +846,15 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
} else {
|
||||
/* CAC started and CAC time set - calculate remaining time */
|
||||
struct os_reltime now;
|
||||
unsigned int left_time;
|
||||
long left_time;
|
||||
|
||||
os_reltime_age(&iface->dfs_cac_start, &now);
|
||||
left_time = iface->dfs_cac_ms / 1000 - now.sec;
|
||||
left_time = (long) iface->dfs_cac_ms / 1000 - now.sec;
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"cac_time_seconds=%u\n"
|
||||
"cac_time_left_seconds=%u\n",
|
||||
"cac_time_left_seconds=%lu\n",
|
||||
iface->dfs_cac_ms / 1000,
|
||||
left_time);
|
||||
left_time > 0 ? left_time : 0);
|
||||
}
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
@ -746,6 +868,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
"ieee80211n=%d\n"
|
||||
"ieee80211ac=%d\n"
|
||||
"ieee80211ax=%d\n"
|
||||
"ieee80211be=%d\n"
|
||||
"beacon_int=%u\n"
|
||||
"dtim_period=%d\n",
|
||||
iface->conf->channel,
|
||||
@ -758,12 +881,74 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
!hapd->conf->disable_11ac,
|
||||
iface->conf->ieee80211ax &&
|
||||
!hapd->conf->disable_11ax,
|
||||
iface->conf->ieee80211be &&
|
||||
!hapd->conf->disable_11be,
|
||||
iface->conf->beacon_int,
|
||||
hapd->conf->dtim_period);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (iface->conf->ieee80211be && !hapd->conf->disable_11be) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"eht_oper_chwidth=%d\n"
|
||||
"eht_oper_centr_freq_seg0_idx=%d\n",
|
||||
iface->conf->eht_oper_chwidth,
|
||||
iface->conf->eht_oper_centr_freq_seg0_idx);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
|
||||
if (is_6ghz_op_class(iface->conf->op_class) &&
|
||||
hostapd_get_oper_chwidth(iface->conf) ==
|
||||
CONF_OPER_CHWIDTH_320MHZ) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"eht_bw320_offset=%d\n",
|
||||
iface->conf->eht_bw320_offset);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
if (hapd->conf->mld_ap) {
|
||||
struct hostapd_data *link_bss;
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"num_links=%d\n",
|
||||
hapd->mld->num_links);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
|
||||
/* Self BSS */
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"link_id=%d\n"
|
||||
"link_addr=" MACSTR "\n",
|
||||
hapd->mld_link_id,
|
||||
MAC2STR(hapd->own_addr));
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
|
||||
/* Partner BSSs */
|
||||
for_each_mld_link(link_bss, hapd) {
|
||||
if (link_bss == hapd)
|
||||
continue;
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"partner_link[%d]=" MACSTR
|
||||
"\n",
|
||||
link_bss->mld_link_id,
|
||||
MAC2STR(link_bss->own_addr));
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
@ -776,6 +961,16 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
|
||||
if (!iconf->he_op.he_bss_color_disabled &&
|
||||
iconf->he_op.he_bss_color) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"he_bss_color=%d\n",
|
||||
iconf->he_op.he_bss_color);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
@ -869,6 +1064,21 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (bss->conf->mld_ap) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"mld_addr[%d]=" MACSTR "\n"
|
||||
"mld_id[%d]=%d\n"
|
||||
"mld_link_id[%d]=%d\n",
|
||||
(int) i, MAC2STR(bss->mld->mld_addr),
|
||||
(int) i, hostapd_get_mld_id(bss),
|
||||
(int) i, bss->mld_link_id);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
}
|
||||
|
||||
if (hapd->conf->chan_util_avg_period) {
|
||||
@ -911,15 +1121,27 @@ int hostapd_parse_csa_settings(const char *pos,
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SET_CSA_SETTING_EXT(str) \
|
||||
do { \
|
||||
const char *pos2 = os_strstr(pos, " " #str "="); \
|
||||
if (pos2) { \
|
||||
pos2 += sizeof(" " #str "=") - 1; \
|
||||
settings->str = atoi(pos2); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
SET_CSA_SETTING(center_freq1);
|
||||
SET_CSA_SETTING(center_freq2);
|
||||
SET_CSA_SETTING(bandwidth);
|
||||
SET_CSA_SETTING(sec_channel_offset);
|
||||
SET_CSA_SETTING_EXT(punct_bitmap);
|
||||
settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
|
||||
settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
|
||||
settings->freq_params.he_enabled = !!os_strstr(pos, " he");
|
||||
settings->freq_params.eht_enabled = !!os_strstr(pos, " eht");
|
||||
settings->block_tx = !!os_strstr(pos, " blocktx");
|
||||
#undef SET_CSA_SETTING
|
||||
#undef SET_CSA_SETTING_EXT
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -988,7 +1210,7 @@ int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd)
|
||||
return -1;
|
||||
|
||||
return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
|
||||
pmkid, expiration, akmp);
|
||||
pmkid, expiration, akmp, NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -1042,8 +1264,359 @@ void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
|
||||
if (sscanf(pos, "%d", &expiration) != 1)
|
||||
return NULL;
|
||||
|
||||
return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration);
|
||||
return wpa_auth_pmksa_create_entry(aa, spa, pmk, PMK_LEN,
|
||||
WPA_KEY_MGMT_SAE, pmkid, expiration);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MESH */
|
||||
#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
|
||||
|
||||
|
||||
#ifdef CONFIG_WNM_AP
|
||||
|
||||
int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
|
||||
const char *cmd)
|
||||
{
|
||||
u8 addr[ETH_ALEN];
|
||||
int disassoc_timer;
|
||||
struct sta_info *sta;
|
||||
|
||||
if (hwaddr_aton(cmd, addr))
|
||||
return -1;
|
||||
if (cmd[17] != ' ')
|
||||
return -1;
|
||||
disassoc_timer = atoi(cmd + 17);
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Station " MACSTR
|
||||
" not found for disassociation imminent message",
|
||||
MAC2STR(addr));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
|
||||
const char *cmd)
|
||||
{
|
||||
u8 addr[ETH_ALEN];
|
||||
const char *url, *timerstr;
|
||||
int disassoc_timer;
|
||||
struct sta_info *sta;
|
||||
|
||||
if (hwaddr_aton(cmd, addr))
|
||||
return -1;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Station " MACSTR
|
||||
" not found for ESS disassociation imminent message",
|
||||
MAC2STR(addr));
|
||||
return -1;
|
||||
}
|
||||
|
||||
timerstr = cmd + 17;
|
||||
if (*timerstr != ' ')
|
||||
return -1;
|
||||
timerstr++;
|
||||
disassoc_timer = atoi(timerstr);
|
||||
if (disassoc_timer < 0 || disassoc_timer > 65535)
|
||||
return -1;
|
||||
|
||||
url = os_strchr(timerstr, ' ');
|
||||
if (url == NULL)
|
||||
return -1;
|
||||
url++;
|
||||
|
||||
return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
|
||||
const char *cmd)
|
||||
{
|
||||
u8 addr[ETH_ALEN];
|
||||
const char *pos, *end;
|
||||
int disassoc_timer = 0;
|
||||
struct sta_info *sta;
|
||||
u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01;
|
||||
u8 bss_term_dur[12];
|
||||
char *url = NULL;
|
||||
int ret;
|
||||
u8 nei_rep[1000];
|
||||
int nei_len;
|
||||
u8 mbo[10];
|
||||
size_t mbo_len = 0;
|
||||
|
||||
if (hwaddr_aton(cmd, addr)) {
|
||||
wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Station " MACSTR
|
||||
" not found for BSS TM Request message",
|
||||
MAC2STR(addr));
|
||||
return -1;
|
||||
}
|
||||
|
||||
pos = os_strstr(cmd, " disassoc_timer=");
|
||||
if (pos) {
|
||||
pos += 16;
|
||||
disassoc_timer = atoi(pos);
|
||||
if (disassoc_timer < 0 || disassoc_timer > 65535) {
|
||||
wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pos = os_strstr(cmd, " valid_int=");
|
||||
if (pos) {
|
||||
pos += 11;
|
||||
valid_int = atoi(pos);
|
||||
}
|
||||
|
||||
pos = os_strstr(cmd, " dialog_token=");
|
||||
if (pos) {
|
||||
pos += 14;
|
||||
dialog_token = atoi(pos);
|
||||
}
|
||||
|
||||
pos = os_strstr(cmd, " bss_term=");
|
||||
if (pos) {
|
||||
pos += 10;
|
||||
req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
|
||||
/* TODO: TSF configurable/learnable */
|
||||
bss_term_dur[0] = 4; /* Subelement ID */
|
||||
bss_term_dur[1] = 10; /* Length */
|
||||
os_memset(&bss_term_dur[2], 0, 8);
|
||||
end = os_strchr(pos, ',');
|
||||
if (end == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Invalid bss_term data");
|
||||
return -1;
|
||||
}
|
||||
end++;
|
||||
WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
|
||||
}
|
||||
|
||||
nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep,
|
||||
sizeof(nei_rep));
|
||||
if (nei_len < 0)
|
||||
return -1;
|
||||
|
||||
pos = os_strstr(cmd, " url=");
|
||||
if (pos) {
|
||||
size_t len;
|
||||
pos += 5;
|
||||
end = os_strchr(pos, ' ');
|
||||
if (end)
|
||||
len = end - pos;
|
||||
else
|
||||
len = os_strlen(pos);
|
||||
url = os_malloc(len + 1);
|
||||
if (url == NULL)
|
||||
return -1;
|
||||
os_memcpy(url, pos, len);
|
||||
url[len] = '\0';
|
||||
req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
|
||||
}
|
||||
|
||||
if (os_strstr(cmd, " pref=1"))
|
||||
req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
|
||||
if (os_strstr(cmd, " abridged=1"))
|
||||
req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
|
||||
if (os_strstr(cmd, " disassoc_imminent=1"))
|
||||
req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
|
||||
if (os_strstr(cmd, " link_removal_imminent=1"))
|
||||
req_mode |= WNM_BSS_TM_REQ_LINK_REMOVAL_IMMINENT;
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
pos = os_strstr(cmd, "mbo=");
|
||||
if (pos) {
|
||||
unsigned int mbo_reason, cell_pref, reassoc_delay;
|
||||
u8 *mbo_pos = mbo;
|
||||
|
||||
ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
|
||||
&reassoc_delay, &cell_pref);
|
||||
if (ret != 3) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Invalid MBO transition reason code %u",
|
||||
mbo_reason);
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Valid values for Cellular preference are: 0, 1, 255 */
|
||||
if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Invalid MBO cellular capability %u",
|
||||
cell_pref);
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (reassoc_delay > 65535 ||
|
||||
(reassoc_delay &&
|
||||
!(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MBO: Assoc retry delay is only valid in disassoc imminent mode");
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
|
||||
*mbo_pos++ = 1;
|
||||
*mbo_pos++ = mbo_reason;
|
||||
*mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
|
||||
*mbo_pos++ = 1;
|
||||
*mbo_pos++ = cell_pref;
|
||||
|
||||
if (reassoc_delay) {
|
||||
*mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
|
||||
*mbo_pos++ = 2;
|
||||
WPA_PUT_LE16(mbo_pos, reassoc_delay);
|
||||
mbo_pos += 2;
|
||||
}
|
||||
|
||||
mbo_len = mbo_pos - mbo;
|
||||
}
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
|
||||
valid_int, bss_term_dur, dialog_token, url,
|
||||
nei_len ? nei_rep : NULL, nei_len,
|
||||
mbo_len ? mbo : NULL, mbo_len);
|
||||
#ifdef CONFIG_MBO
|
||||
fail:
|
||||
#endif /* CONFIG_MBO */
|
||||
os_free(url);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
|
||||
|
||||
int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
|
||||
const char *txtaddr)
|
||||
{
|
||||
u8 addr[ETH_ALEN];
|
||||
struct vlan_description vlan_id;
|
||||
|
||||
if (!(*num))
|
||||
return 0;
|
||||
|
||||
if (hwaddr_aton(txtaddr, addr))
|
||||
return -1;
|
||||
|
||||
if (hostapd_maclist_found(*acl, *num, addr, &vlan_id))
|
||||
hostapd_remove_acl_mac(acl, num, addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
|
||||
int *num)
|
||||
{
|
||||
while (*num)
|
||||
hostapd_remove_acl_mac(acl, num, (*acl)[0].addr);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
int i = 0, len = 0, ret = 0;
|
||||
|
||||
if (!acl)
|
||||
return 0;
|
||||
|
||||
while (i < num) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
MACSTR " VLAN_ID=%d\n",
|
||||
MAC2STR(acl[i].addr),
|
||||
acl[i].vlan_id.untagged);
|
||||
if (ret < 0 || (size_t) ret >= buflen - len)
|
||||
return len;
|
||||
i++;
|
||||
len += ret;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
|
||||
const char *cmd)
|
||||
{
|
||||
u8 addr[ETH_ALEN];
|
||||
struct vlan_description vlan_id;
|
||||
int ret = 0, vlanid = 0;
|
||||
const char *pos;
|
||||
|
||||
if (hwaddr_aton(cmd, addr))
|
||||
return -1;
|
||||
|
||||
pos = os_strstr(cmd, "VLAN_ID=");
|
||||
if (pos)
|
||||
vlanid = atoi(pos + 8);
|
||||
|
||||
if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) {
|
||||
ret = hostapd_add_acl_maclist(acl, num, vlanid, addr);
|
||||
if (ret != -1 && *acl)
|
||||
qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
|
||||
}
|
||||
|
||||
return ret < 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_disassoc_accept_mac(struct hostapd_data *hapd)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
struct vlan_description vlan_id;
|
||||
|
||||
if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED)
|
||||
return 0;
|
||||
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
if (!hostapd_maclist_found(hapd->conf->accept_mac,
|
||||
hapd->conf->num_accept_mac,
|
||||
sta->addr, &vlan_id) ||
|
||||
(vlan_id.notempty &&
|
||||
vlan_compare(&vlan_id, sta->vlan_desc)))
|
||||
ap_sta_disconnect(hapd, sta, sta->addr,
|
||||
WLAN_REASON_UNSPECIFIED);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
struct vlan_description vlan_id;
|
||||
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
if (hostapd_maclist_found(hapd->conf->deny_mac,
|
||||
hapd->conf->num_deny_mac, sta->addr,
|
||||
&vlan_id) &&
|
||||
(!vlan_id.notempty ||
|
||||
!vlan_compare(&vlan_id, sta->vlan_desc)))
|
||||
ap_sta_disconnect(hapd, sta, sta->addr,
|
||||
WLAN_REASON_UNSPECIFIED);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -37,4 +37,21 @@ int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
|
||||
const u8 *addr, char *buf, size_t len);
|
||||
void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd);
|
||||
|
||||
int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
|
||||
const char *cmd);
|
||||
int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
|
||||
const char *cmd);
|
||||
int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
|
||||
const char *cmd);
|
||||
int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
|
||||
const char *cmd);
|
||||
int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
|
||||
const char *txtaddr);
|
||||
void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
|
||||
int *num);
|
||||
int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
|
||||
char *buf, size_t buflen);
|
||||
int hostapd_disassoc_accept_mac(struct hostapd_data *hapd);
|
||||
int hostapd_disassoc_deny_mac(struct hostapd_data *hapd);
|
||||
|
||||
#endif /* CTRL_IFACE_AP_H */
|
||||
|
@ -14,11 +14,32 @@
|
||||
#include "common/hw_features_common.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "hostapd.h"
|
||||
#include "beacon.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "dfs.h"
|
||||
|
||||
|
||||
enum dfs_channel_type {
|
||||
DFS_ANY_CHANNEL,
|
||||
DFS_AVAILABLE, /* non-radar or radar-available */
|
||||
DFS_NO_CAC_YET, /* radar-not-yet-available */
|
||||
};
|
||||
|
||||
static struct hostapd_channel_data *
|
||||
dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
|
||||
u8 *oper_centr_freq_seg0_idx,
|
||||
u8 *oper_centr_freq_seg1_idx,
|
||||
enum dfs_channel_type *channel_type);
|
||||
|
||||
|
||||
static bool dfs_use_radar_background(struct hostapd_iface *iface)
|
||||
{
|
||||
return (iface->drv_flags2 & WPA_DRIVER_FLAGS2_RADAR_BACKGROUND) &&
|
||||
iface->conf->enable_background_radar;
|
||||
}
|
||||
|
||||
|
||||
static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
|
||||
{
|
||||
int n_chans = 1;
|
||||
@ -30,15 +51,15 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
|
||||
|
||||
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
|
||||
switch (hostapd_get_oper_chwidth(iface->conf)) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
case CONF_OPER_CHWIDTH_USE_HT:
|
||||
break;
|
||||
case CHANWIDTH_80MHZ:
|
||||
case CONF_OPER_CHWIDTH_80MHZ:
|
||||
n_chans = 4;
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
case CONF_OPER_CHWIDTH_160MHZ:
|
||||
n_chans = 8;
|
||||
break;
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
case CONF_OPER_CHWIDTH_80P80MHZ:
|
||||
n_chans = 4;
|
||||
*seg1 = 4;
|
||||
break;
|
||||
@ -51,15 +72,27 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
|
||||
}
|
||||
|
||||
|
||||
/* dfs_channel_available: select new channel according to type parameter */
|
||||
static int dfs_channel_available(struct hostapd_channel_data *chan,
|
||||
int skip_radar)
|
||||
enum dfs_channel_type type)
|
||||
{
|
||||
if (type == DFS_NO_CAC_YET) {
|
||||
/* Select only radar channel where CAC has not been
|
||||
* performed yet
|
||||
*/
|
||||
if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
|
||||
(chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
|
||||
HOSTAPD_CHAN_DFS_USABLE)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* When radar detection happens, CSA is performed. However, there's no
|
||||
* time for CAC, so radar channels must be skipped when finding a new
|
||||
* channel for CSA, unless they are available for immediate use.
|
||||
*/
|
||||
if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
|
||||
if (type == DFS_AVAILABLE && (chan->flag & HOSTAPD_CHAN_RADAR) &&
|
||||
((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
|
||||
HOSTAPD_CHAN_DFS_AVAILABLE))
|
||||
return 0;
|
||||
@ -138,7 +171,7 @@ dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
|
||||
|
||||
static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
|
||||
int first_chan_idx, int num_chans,
|
||||
int skip_radar)
|
||||
enum dfs_channel_type type)
|
||||
{
|
||||
struct hostapd_channel_data *first_chan, *chan;
|
||||
int i;
|
||||
@ -156,7 +189,7 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
|
||||
* If it's not allowed to use the first channel as primary, decline the
|
||||
* whole channel range. */
|
||||
if (!chan_pri_allowed(first_chan)) {
|
||||
wpa_printf(MSG_DEBUG, "DFS: primary chanenl not allowed");
|
||||
wpa_printf(MSG_DEBUG, "DFS: primary channel not allowed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -177,7 +210,7 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dfs_channel_available(chan, skip_radar)) {
|
||||
if (!dfs_channel_available(chan, type)) {
|
||||
wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
|
||||
first_chan->freq + i * 20);
|
||||
return 0;
|
||||
@ -207,7 +240,7 @@ static int is_in_chanlist(struct hostapd_iface *iface,
|
||||
*/
|
||||
static int dfs_find_channel(struct hostapd_iface *iface,
|
||||
struct hostapd_channel_data **ret_chan,
|
||||
int idx, int skip_radar)
|
||||
int idx, enum dfs_channel_type type)
|
||||
{
|
||||
struct hostapd_hw_modes *mode;
|
||||
struct hostapd_channel_data *chan;
|
||||
@ -232,7 +265,7 @@ static int dfs_find_channel(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
/* Skip incompatible chandefs */
|
||||
if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) {
|
||||
if (!dfs_chan_range_available(mode, i, n_chans, type)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DFS: range not available for %d (%d)",
|
||||
chan->freq, chan->chan);
|
||||
@ -249,6 +282,10 @@ static int dfs_find_channel(struct hostapd_iface *iface,
|
||||
if (chan->max_tx_power < iface->conf->min_tx_power)
|
||||
continue;
|
||||
|
||||
if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
|
||||
iface->conf->country[2] == 0x4f)
|
||||
continue;
|
||||
|
||||
if (ret_chan && idx == channel_idx) {
|
||||
wpa_printf(MSG_DEBUG, "Selected channel %d (%d)",
|
||||
chan->freq, chan->chan);
|
||||
@ -279,7 +316,7 @@ static void dfs_adjust_center_freq(struct hostapd_iface *iface,
|
||||
*oper_centr_freq_seg1_idx = 0;
|
||||
|
||||
switch (hostapd_get_oper_chwidth(iface->conf)) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
case CONF_OPER_CHWIDTH_USE_HT:
|
||||
if (secondary_channel == 1)
|
||||
*oper_centr_freq_seg0_idx = chan->chan + 2;
|
||||
else if (secondary_channel == -1)
|
||||
@ -287,13 +324,13 @@ static void dfs_adjust_center_freq(struct hostapd_iface *iface,
|
||||
else
|
||||
*oper_centr_freq_seg0_idx = chan->chan;
|
||||
break;
|
||||
case CHANWIDTH_80MHZ:
|
||||
case CONF_OPER_CHWIDTH_80MHZ:
|
||||
*oper_centr_freq_seg0_idx = chan->chan + 6;
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
case CONF_OPER_CHWIDTH_160MHZ:
|
||||
*oper_centr_freq_seg0_idx = chan->chan + 14;
|
||||
break;
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
case CONF_OPER_CHWIDTH_80P80MHZ:
|
||||
*oper_centr_freq_seg0_idx = chan->chan + 6;
|
||||
*oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
|
||||
break;
|
||||
@ -326,28 +363,33 @@ static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
|
||||
if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
|
||||
channel_no -= 4;
|
||||
|
||||
/* VHT/HE */
|
||||
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
|
||||
/* VHT/HE/EHT */
|
||||
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
|
||||
iface->conf->ieee80211be) {
|
||||
switch (hostapd_get_oper_chwidth(iface->conf)) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
case CONF_OPER_CHWIDTH_USE_HT:
|
||||
break;
|
||||
case CHANWIDTH_80MHZ:
|
||||
case CONF_OPER_CHWIDTH_80MHZ:
|
||||
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
|
||||
iface->conf) - 6;
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
case CONF_OPER_CHWIDTH_160MHZ:
|
||||
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
|
||||
iface->conf) - 14;
|
||||
break;
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
case CONF_OPER_CHWIDTH_80P80MHZ:
|
||||
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
|
||||
iface->conf) - 6;
|
||||
chan_seg1 = hostapd_get_oper_centr_freq_seg1_idx(
|
||||
iface->conf) - 6;
|
||||
break;
|
||||
case CONF_OPER_CHWIDTH_320MHZ:
|
||||
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
|
||||
iface->conf) - 30;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_INFO,
|
||||
"DFS only VHT20/40/80/160/80+80 is supported now");
|
||||
"DFS only EHT20/40/80/160/80+80/320 is supported now");
|
||||
channel_no = -1;
|
||||
break;
|
||||
}
|
||||
@ -409,6 +451,8 @@ static int dfs_check_chans_radar(struct hostapd_iface *iface,
|
||||
mode = iface->current_mode;
|
||||
|
||||
for (i = 0; i < n_chans; i++) {
|
||||
if (start_chan_idx + i >= mode->num_channels)
|
||||
break;
|
||||
channel = &mode->channels[start_chan_idx + i];
|
||||
if (channel->flag & HOSTAPD_CHAN_RADAR)
|
||||
res++;
|
||||
@ -475,7 +519,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
|
||||
int *secondary_channel,
|
||||
u8 *oper_centr_freq_seg0_idx,
|
||||
u8 *oper_centr_freq_seg1_idx,
|
||||
int skip_radar)
|
||||
enum dfs_channel_type type)
|
||||
{
|
||||
struct hostapd_hw_modes *mode;
|
||||
struct hostapd_channel_data *chan = NULL;
|
||||
@ -499,7 +543,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
|
||||
return NULL;
|
||||
|
||||
/* Get the count first */
|
||||
num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
|
||||
num_available_chandefs = dfs_find_channel(iface, NULL, 0, type);
|
||||
wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
|
||||
num_available_chandefs);
|
||||
if (num_available_chandefs == 0)
|
||||
@ -508,7 +552,9 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
|
||||
if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
|
||||
return NULL;
|
||||
chan_idx = _rand % num_available_chandefs;
|
||||
dfs_find_channel(iface, &chan, chan_idx, skip_radar);
|
||||
wpa_printf(MSG_DEBUG, "DFS: Picked random entry from the list: %d/%d",
|
||||
chan_idx, num_available_chandefs);
|
||||
dfs_find_channel(iface, &chan, chan_idx, type);
|
||||
if (!chan) {
|
||||
wpa_printf(MSG_DEBUG, "DFS: no random channel found");
|
||||
return NULL;
|
||||
@ -523,7 +569,8 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
|
||||
*secondary_channel = 0;
|
||||
|
||||
/* Get secondary channel for HT80P80 */
|
||||
if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80P80MHZ) {
|
||||
if (hostapd_get_oper_chwidth(iface->conf) ==
|
||||
CONF_OPER_CHWIDTH_80P80MHZ) {
|
||||
if (num_available_chandefs <= 1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"only 1 valid chan, can't support 80+80");
|
||||
@ -537,7 +584,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
|
||||
for (i = 0; i < num_available_chandefs - 1; i++) {
|
||||
/* start from chan_idx + 1, end when chan_idx - 1 */
|
||||
chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
|
||||
dfs_find_channel(iface, &chan2, chan_idx2, skip_radar);
|
||||
dfs_find_channel(iface, &chan2, chan_idx2, type);
|
||||
if (chan2 && abs(chan2->chan - chan->chan) > 12) {
|
||||
/* two channels are not adjacent */
|
||||
sec_chan_idx_80p80 = chan2->chan;
|
||||
@ -568,6 +615,30 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
|
||||
static int dfs_set_valid_channel(struct hostapd_iface *iface, int skip_radar)
|
||||
{
|
||||
struct hostapd_channel_data *channel;
|
||||
u8 cf1 = 0, cf2 = 0;
|
||||
int sec = 0;
|
||||
|
||||
channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
|
||||
skip_radar ? DFS_AVAILABLE :
|
||||
DFS_ANY_CHANNEL);
|
||||
if (!channel) {
|
||||
wpa_printf(MSG_ERROR, "could not get valid channel");
|
||||
return -1;
|
||||
}
|
||||
|
||||
iface->freq = channel->freq;
|
||||
iface->conf->channel = channel->chan;
|
||||
iface->conf->secondary_channel = sec;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
|
||||
{
|
||||
struct hostapd_hw_modes *mode;
|
||||
@ -736,6 +807,8 @@ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
|
||||
mode = iface->current_mode;
|
||||
|
||||
for (i = 0; i < n_chans; i++) {
|
||||
if (start_chan_idx + i >= mode->num_channels)
|
||||
break;
|
||||
channel = &mode->channels[start_chan_idx + i];
|
||||
if (!(channel->flag & HOSTAPD_CHAN_RADAR))
|
||||
continue;
|
||||
@ -755,7 +828,6 @@ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
|
||||
*/
|
||||
int hostapd_handle_dfs(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_channel_data *channel;
|
||||
int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
|
||||
int skip_radar = 0;
|
||||
|
||||
@ -810,28 +882,17 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
|
||||
wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
|
||||
res, res ? "yes": "no");
|
||||
if (res) {
|
||||
int sec = 0;
|
||||
u8 cf1 = 0, cf2 = 0;
|
||||
|
||||
channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
|
||||
skip_radar);
|
||||
if (!channel) {
|
||||
wpa_printf(MSG_ERROR, "could not get valid channel");
|
||||
if (dfs_set_valid_channel(iface, skip_radar) < 0) {
|
||||
hostapd_set_state(iface, HAPD_IFACE_DFS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
iface->freq = channel->freq;
|
||||
iface->conf->channel = channel->chan;
|
||||
iface->conf->secondary_channel = sec;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
|
||||
}
|
||||
} while (res);
|
||||
|
||||
/* Finally start CAC */
|
||||
hostapd_set_state(iface, HAPD_IFACE_DFS);
|
||||
wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
|
||||
wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz%s", iface->freq,
|
||||
dfs_use_radar_background(iface) ? " (background)" : "");
|
||||
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
|
||||
"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
|
||||
iface->freq,
|
||||
@ -844,17 +905,41 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
|
||||
res = hostapd_start_dfs_cac(
|
||||
iface, iface->conf->hw_mode, iface->freq, iface->conf->channel,
|
||||
iface->conf->ieee80211n, iface->conf->ieee80211ac,
|
||||
iface->conf->ieee80211ax,
|
||||
iface->conf->ieee80211ax, iface->conf->ieee80211be,
|
||||
iface->conf->secondary_channel,
|
||||
hostapd_get_oper_chwidth(iface->conf),
|
||||
hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
|
||||
hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
|
||||
hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
|
||||
dfs_use_radar_background(iface));
|
||||
|
||||
if (res) {
|
||||
wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dfs_use_radar_background(iface)) {
|
||||
/* Cache background radar parameters. */
|
||||
iface->radar_background.channel = iface->conf->channel;
|
||||
iface->radar_background.secondary_channel =
|
||||
iface->conf->secondary_channel;
|
||||
iface->radar_background.freq = iface->freq;
|
||||
iface->radar_background.centr_freq_seg0_idx =
|
||||
hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
|
||||
iface->radar_background.centr_freq_seg1_idx =
|
||||
hostapd_get_oper_centr_freq_seg1_idx(iface->conf);
|
||||
|
||||
/*
|
||||
* Let's select a random channel according to the
|
||||
* regulations and perform CAC on dedicated radar chain.
|
||||
*/
|
||||
res = dfs_set_valid_channel(iface, 1);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
iface->radar_background.temp_ch = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -876,19 +961,206 @@ int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
|
||||
int channel, int freq,
|
||||
int secondary_channel,
|
||||
u8 current_vht_oper_chwidth,
|
||||
u8 oper_centr_freq_seg0_idx,
|
||||
u8 oper_centr_freq_seg1_idx)
|
||||
{
|
||||
struct hostapd_hw_modes *cmode = iface->current_mode;
|
||||
int ieee80211_mode = IEEE80211_MODE_AP, err;
|
||||
struct csa_settings csa_settings;
|
||||
u8 new_vht_oper_chwidth;
|
||||
unsigned int i;
|
||||
unsigned int num_err = 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", channel);
|
||||
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
|
||||
"freq=%d chan=%d sec_chan=%d", freq, channel,
|
||||
secondary_channel);
|
||||
|
||||
new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
|
||||
hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
|
||||
|
||||
/* Setup CSA request */
|
||||
os_memset(&csa_settings, 0, sizeof(csa_settings));
|
||||
csa_settings.cs_count = 5;
|
||||
csa_settings.block_tx = 1;
|
||||
csa_settings.link_id = -1;
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (iface->bss[0]->conf->mld_ap)
|
||||
csa_settings.link_id = iface->bss[0]->mld_link_id;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
#ifdef CONFIG_MESH
|
||||
if (iface->mconf)
|
||||
ieee80211_mode = IEEE80211_MODE_MESH;
|
||||
#endif /* CONFIG_MESH */
|
||||
err = hostapd_set_freq_params(&csa_settings.freq_params,
|
||||
iface->conf->hw_mode,
|
||||
freq, channel,
|
||||
iface->conf->enable_edmg,
|
||||
iface->conf->edmg_channel,
|
||||
iface->conf->ieee80211n,
|
||||
iface->conf->ieee80211ac,
|
||||
iface->conf->ieee80211ax,
|
||||
iface->conf->ieee80211be,
|
||||
secondary_channel,
|
||||
new_vht_oper_chwidth,
|
||||
oper_centr_freq_seg0_idx,
|
||||
oper_centr_freq_seg1_idx,
|
||||
cmode->vht_capab,
|
||||
&cmode->he_capab[ieee80211_mode],
|
||||
&cmode->eht_capab[ieee80211_mode],
|
||||
hostapd_get_punct_bitmap(iface->bss[0]));
|
||||
|
||||
if (err) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"DFS failed to calculate CSA freq params");
|
||||
hostapd_disable_iface(iface);
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
err = hostapd_switch_channel(iface->bss[i], &csa_settings);
|
||||
if (err)
|
||||
num_err++;
|
||||
}
|
||||
|
||||
if (num_err == iface->num_bss) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"DFS failed to schedule CSA (%d) - trying fallback",
|
||||
err);
|
||||
iface->freq = freq;
|
||||
iface->conf->channel = channel;
|
||||
iface->conf->secondary_channel = secondary_channel;
|
||||
hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
|
||||
oper_centr_freq_seg0_idx);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
|
||||
oper_centr_freq_seg1_idx);
|
||||
|
||||
hostapd_disable_iface(iface);
|
||||
hostapd_enable_iface(iface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Channel configuration will be updated once CSA completes and
|
||||
* ch_switch_notify event is received */
|
||||
wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_dfs_update_background_chain(struct hostapd_iface *iface)
|
||||
{
|
||||
int sec = 0;
|
||||
enum dfs_channel_type channel_type = DFS_NO_CAC_YET;
|
||||
struct hostapd_channel_data *channel;
|
||||
u8 oper_centr_freq_seg0_idx = 0;
|
||||
u8 oper_centr_freq_seg1_idx = 0;
|
||||
|
||||
/*
|
||||
* Allow selection of DFS channel in ETSI to comply with
|
||||
* uniform spreading.
|
||||
*/
|
||||
if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
|
||||
channel_type = DFS_ANY_CHANNEL;
|
||||
|
||||
channel = dfs_get_valid_channel(iface, &sec, &oper_centr_freq_seg0_idx,
|
||||
&oper_centr_freq_seg1_idx,
|
||||
channel_type);
|
||||
if (!channel ||
|
||||
channel->chan == iface->conf->channel ||
|
||||
channel->chan == iface->radar_background.channel)
|
||||
channel = dfs_downgrade_bandwidth(iface, &sec,
|
||||
&oper_centr_freq_seg0_idx,
|
||||
&oper_centr_freq_seg1_idx,
|
||||
&channel_type);
|
||||
if (!channel ||
|
||||
hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
|
||||
channel->freq, channel->chan,
|
||||
iface->conf->ieee80211n,
|
||||
iface->conf->ieee80211ac,
|
||||
iface->conf->ieee80211ax,
|
||||
iface->conf->ieee80211be,
|
||||
sec, hostapd_get_oper_chwidth(iface->conf),
|
||||
oper_centr_freq_seg0_idx,
|
||||
oper_centr_freq_seg1_idx, true)) {
|
||||
wpa_printf(MSG_ERROR, "DFS failed to start CAC offchannel");
|
||||
iface->radar_background.channel = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
iface->radar_background.channel = channel->chan;
|
||||
iface->radar_background.freq = channel->freq;
|
||||
iface->radar_background.secondary_channel = sec;
|
||||
iface->radar_background.centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
|
||||
iface->radar_background.centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: setting background chain to chan %d (%d MHz)",
|
||||
__func__, channel->chan, channel->freq);
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
hostapd_dfs_is_background_event(struct hostapd_iface *iface, int freq)
|
||||
{
|
||||
return dfs_use_radar_background(iface) &&
|
||||
iface->radar_background.channel != -1 &&
|
||||
iface->radar_background.freq == freq;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface)
|
||||
{
|
||||
u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
|
||||
|
||||
iface->conf->channel = iface->radar_background.channel;
|
||||
iface->freq = iface->radar_background.freq;
|
||||
iface->conf->secondary_channel =
|
||||
iface->radar_background.secondary_channel;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(
|
||||
iface->conf, iface->radar_background.centr_freq_seg0_idx);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(
|
||||
iface->conf, iface->radar_background.centr_freq_seg1_idx);
|
||||
|
||||
hostapd_dfs_update_background_chain(iface);
|
||||
|
||||
return hostapd_dfs_request_channel_switch(
|
||||
iface, iface->conf->channel, iface->freq,
|
||||
iface->conf->secondary_channel, current_vht_oper_chwidth,
|
||||
hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
|
||||
hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
|
||||
}
|
||||
|
||||
|
||||
int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
|
||||
int ht_enabled, int chan_offset, int chan_width,
|
||||
int cf1, int cf2)
|
||||
{
|
||||
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
|
||||
"success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
|
||||
success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
|
||||
"success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d radar_detected=%d",
|
||||
success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2,
|
||||
iface->radar_detected);
|
||||
|
||||
if (success) {
|
||||
/* Complete iface/ap configuration */
|
||||
if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
|
||||
/* Complete AP configuration for the first bring up. */
|
||||
if (iface->state != HAPD_IFACE_ENABLED)
|
||||
/* Complete AP configuration for the first bring up. If
|
||||
* a radar was detected in this channel, interface setup
|
||||
* will be handled in
|
||||
* 1. hostapd_event_ch_switch() if switching to a
|
||||
* non-DFS channel
|
||||
* 2. on next CAC complete event if switching to another
|
||||
* DFS channel.
|
||||
*/
|
||||
if (iface->state != HAPD_IFACE_ENABLED &&
|
||||
!iface->radar_detected)
|
||||
hostapd_setup_interface_complete(iface, 0);
|
||||
else
|
||||
iface->cac_started = 0;
|
||||
@ -896,6 +1168,22 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
|
||||
set_dfs_state(iface, freq, ht_enabled, chan_offset,
|
||||
chan_width, cf1, cf2,
|
||||
HOSTAPD_CHAN_DFS_AVAILABLE);
|
||||
|
||||
/*
|
||||
* Radar event from background chain for the selected
|
||||
* channel. Perform CSA, move the main chain to the
|
||||
* selected channel and configure the background chain
|
||||
* to a new DFS channel.
|
||||
*/
|
||||
if (hostapd_dfs_is_background_event(iface, freq)) {
|
||||
iface->radar_background.cac_started = 0;
|
||||
if (!iface->radar_background.temp_ch)
|
||||
return 0;
|
||||
|
||||
iface->radar_background.temp_ch = 0;
|
||||
return hostapd_dfs_start_channel_switch_background(iface);
|
||||
}
|
||||
|
||||
/*
|
||||
* Just mark the channel available when CAC completion
|
||||
* event is received in enabled state. CAC result could
|
||||
@ -912,8 +1200,12 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
|
||||
iface->cac_started = 0;
|
||||
}
|
||||
}
|
||||
} else if (hostapd_dfs_is_background_event(iface, freq)) {
|
||||
iface->radar_background.cac_started = 0;
|
||||
hostapd_dfs_update_background_chain(iface);
|
||||
}
|
||||
|
||||
iface->radar_detected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -940,7 +1232,8 @@ int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
|
||||
static struct hostapd_channel_data *
|
||||
dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
|
||||
u8 *oper_centr_freq_seg0_idx,
|
||||
u8 *oper_centr_freq_seg1_idx, int *skip_radar)
|
||||
u8 *oper_centr_freq_seg1_idx,
|
||||
enum dfs_channel_type *channel_type)
|
||||
{
|
||||
struct hostapd_channel_data *channel;
|
||||
|
||||
@ -948,22 +1241,22 @@ dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
|
||||
channel = dfs_get_valid_channel(iface, secondary_channel,
|
||||
oper_centr_freq_seg0_idx,
|
||||
oper_centr_freq_seg1_idx,
|
||||
*skip_radar);
|
||||
*channel_type);
|
||||
if (channel) {
|
||||
wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d",
|
||||
channel->chan);
|
||||
return channel;
|
||||
}
|
||||
|
||||
if (*skip_radar) {
|
||||
*skip_radar = 0;
|
||||
if (*channel_type != DFS_ANY_CHANNEL) {
|
||||
*channel_type = DFS_ANY_CHANNEL;
|
||||
} else {
|
||||
int oper_chwidth;
|
||||
|
||||
oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
|
||||
if (oper_chwidth == CHANWIDTH_USE_HT)
|
||||
if (oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
|
||||
break;
|
||||
*skip_radar = 1;
|
||||
*channel_type = DFS_AVAILABLE;
|
||||
hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
|
||||
}
|
||||
}
|
||||
@ -981,7 +1274,7 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
|
||||
int secondary_channel;
|
||||
u8 oper_centr_freq_seg0_idx = 0;
|
||||
u8 oper_centr_freq_seg1_idx = 0;
|
||||
int skip_radar = 0;
|
||||
enum dfs_channel_type channel_type = DFS_ANY_CHANNEL;
|
||||
int err = 1;
|
||||
|
||||
/* Radar detected during active CAC */
|
||||
@ -989,13 +1282,13 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
|
||||
channel = dfs_get_valid_channel(iface, &secondary_channel,
|
||||
&oper_centr_freq_seg0_idx,
|
||||
&oper_centr_freq_seg1_idx,
|
||||
skip_radar);
|
||||
channel_type);
|
||||
|
||||
if (!channel) {
|
||||
channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
|
||||
&oper_centr_freq_seg0_idx,
|
||||
&oper_centr_freq_seg1_idx,
|
||||
&skip_radar);
|
||||
&channel_type);
|
||||
if (!channel) {
|
||||
wpa_printf(MSG_ERROR, "No valid channel available");
|
||||
return err;
|
||||
@ -1022,20 +1315,61 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
hostapd_dfs_background_start_channel_switch(struct hostapd_iface *iface,
|
||||
int freq)
|
||||
{
|
||||
if (!dfs_use_radar_background(iface))
|
||||
return -1; /* Background radar chain not supported. */
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s called (background CAC active: %s, CSA active: %s)",
|
||||
__func__, iface->radar_background.cac_started ? "yes" : "no",
|
||||
hostapd_csa_in_progress(iface) ? "yes" : "no");
|
||||
|
||||
/* Check if CSA in progress */
|
||||
if (hostapd_csa_in_progress(iface))
|
||||
return 0;
|
||||
|
||||
if (hostapd_dfs_is_background_event(iface, freq)) {
|
||||
/*
|
||||
* Radar pattern is reported on the background chain.
|
||||
* Just select a new random channel according to the
|
||||
* regulations for monitoring.
|
||||
*/
|
||||
hostapd_dfs_update_background_chain(iface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If background radar detection is supported and the radar channel
|
||||
* monitored by the background chain is available switch to it without
|
||||
* waiting for the CAC.
|
||||
*/
|
||||
if (iface->radar_background.channel == -1)
|
||||
return -1; /* Background radar chain not available. */
|
||||
|
||||
if (iface->radar_background.cac_started) {
|
||||
/*
|
||||
* Background channel not available yet. Perform CAC on the
|
||||
* main chain.
|
||||
*/
|
||||
iface->radar_background.temp_ch = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return hostapd_dfs_start_channel_switch_background(iface);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_channel_data *channel;
|
||||
int secondary_channel;
|
||||
u8 oper_centr_freq_seg0_idx;
|
||||
u8 oper_centr_freq_seg1_idx;
|
||||
u8 new_vht_oper_chwidth;
|
||||
int skip_radar = 1;
|
||||
struct csa_settings csa_settings;
|
||||
unsigned int i;
|
||||
int err = 1;
|
||||
struct hostapd_hw_modes *cmode = iface->current_mode;
|
||||
enum dfs_channel_type channel_type = DFS_AVAILABLE;
|
||||
u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
|
||||
int ieee80211_mode = IEEE80211_MODE_AP;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
|
||||
__func__, iface->cac_started ? "yes" : "no",
|
||||
@ -1054,13 +1388,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
* uniform spreading.
|
||||
*/
|
||||
if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
|
||||
skip_radar = 0;
|
||||
channel_type = DFS_ANY_CHANNEL;
|
||||
|
||||
/* Perform channel switch/CSA */
|
||||
channel = dfs_get_valid_channel(iface, &secondary_channel,
|
||||
&oper_centr_freq_seg0_idx,
|
||||
&oper_centr_freq_seg1_idx,
|
||||
skip_radar);
|
||||
channel_type);
|
||||
|
||||
if (!channel) {
|
||||
/*
|
||||
@ -1068,11 +1402,11 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
* there is another channel where we can switch even if it
|
||||
* requires to perform a CAC first.
|
||||
*/
|
||||
skip_radar = 0;
|
||||
channel_type = DFS_ANY_CHANNEL;
|
||||
channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
|
||||
&oper_centr_freq_seg0_idx,
|
||||
&oper_centr_freq_seg1_idx,
|
||||
&skip_radar);
|
||||
&channel_type);
|
||||
if (!channel) {
|
||||
/*
|
||||
* Toggle interface state to enter DFS state
|
||||
@ -1083,7 +1417,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!skip_radar) {
|
||||
if (channel_type == DFS_ANY_CHANNEL) {
|
||||
iface->freq = channel->freq;
|
||||
iface->conf->channel = channel->chan;
|
||||
iface->conf->secondary_channel = secondary_channel;
|
||||
@ -1098,73 +1432,12 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
}
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
|
||||
channel->chan);
|
||||
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
|
||||
"freq=%d chan=%d sec_chan=%d", channel->freq,
|
||||
channel->chan, secondary_channel);
|
||||
|
||||
new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
|
||||
hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
|
||||
|
||||
/* Setup CSA request */
|
||||
os_memset(&csa_settings, 0, sizeof(csa_settings));
|
||||
csa_settings.cs_count = 5;
|
||||
csa_settings.block_tx = 1;
|
||||
#ifdef CONFIG_MESH
|
||||
if (iface->mconf)
|
||||
ieee80211_mode = IEEE80211_MODE_MESH;
|
||||
#endif /* CONFIG_MESH */
|
||||
err = hostapd_set_freq_params(&csa_settings.freq_params,
|
||||
iface->conf->hw_mode,
|
||||
channel->freq,
|
||||
channel->chan,
|
||||
iface->conf->enable_edmg,
|
||||
iface->conf->edmg_channel,
|
||||
iface->conf->ieee80211n,
|
||||
iface->conf->ieee80211ac,
|
||||
iface->conf->ieee80211ax,
|
||||
secondary_channel,
|
||||
new_vht_oper_chwidth,
|
||||
oper_centr_freq_seg0_idx,
|
||||
oper_centr_freq_seg1_idx,
|
||||
cmode->vht_capab,
|
||||
&cmode->he_capab[ieee80211_mode]);
|
||||
|
||||
if (err) {
|
||||
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
|
||||
hostapd_disable_iface(iface);
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
err = hostapd_switch_channel(iface->bss[i], &csa_settings);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
|
||||
err);
|
||||
iface->freq = channel->freq;
|
||||
iface->conf->channel = channel->chan;
|
||||
iface->conf->secondary_channel = secondary_channel;
|
||||
hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
|
||||
oper_centr_freq_seg0_idx);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
|
||||
oper_centr_freq_seg1_idx);
|
||||
|
||||
hostapd_disable_iface(iface);
|
||||
hostapd_enable_iface(iface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Channel configuration will be updated once CSA completes and
|
||||
* ch_switch_notify event is received */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
|
||||
return 0;
|
||||
return hostapd_dfs_request_channel_switch(iface, channel->chan,
|
||||
channel->freq,
|
||||
secondary_channel,
|
||||
current_vht_oper_chwidth,
|
||||
oper_centr_freq_seg0_idx,
|
||||
oper_centr_freq_seg1_idx);
|
||||
}
|
||||
|
||||
|
||||
@ -1172,12 +1445,12 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
|
||||
int ht_enabled, int chan_offset, int chan_width,
|
||||
int cf1, int cf2)
|
||||
{
|
||||
int res;
|
||||
|
||||
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
|
||||
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
|
||||
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
|
||||
|
||||
iface->radar_detected = true;
|
||||
|
||||
/* Proceed only if DFS is not offloaded to the driver */
|
||||
if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
|
||||
return 0;
|
||||
@ -1186,20 +1459,23 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
|
||||
return 0;
|
||||
|
||||
/* mark radar frequency as invalid */
|
||||
res = set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
|
||||
cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
|
||||
if (!res)
|
||||
if (!set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
|
||||
cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE))
|
||||
return 0;
|
||||
|
||||
/* Skip if reported radar event not overlapped our channels */
|
||||
res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
|
||||
if (!res)
|
||||
return 0;
|
||||
if (!hostapd_dfs_is_background_event(iface, freq)) {
|
||||
/* Skip if reported radar event not overlapped our channels */
|
||||
if (!dfs_are_channels_overlapped(iface, freq, chan_width,
|
||||
cf1, cf2))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* radar detected while operating, switch the channel. */
|
||||
res = hostapd_dfs_start_channel_switch(iface);
|
||||
if (hostapd_dfs_background_start_channel_switch(iface, freq)) {
|
||||
/* Radar detected while operating, switch the channel. */
|
||||
return hostapd_dfs_start_channel_switch(iface);
|
||||
}
|
||||
|
||||
return res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1219,9 +1495,14 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
|
||||
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
|
||||
cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
|
||||
|
||||
/* Handle cases where all channels were initially unavailable */
|
||||
if (iface->state == HAPD_IFACE_DFS && !iface->cac_started)
|
||||
if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) {
|
||||
/* Handle cases where all channels were initially unavailable */
|
||||
hostapd_handle_dfs(iface);
|
||||
} else if (dfs_use_radar_background(iface) &&
|
||||
iface->radar_background.channel == -1) {
|
||||
/* Reset radar background chain if disabled */
|
||||
hostapd_dfs_update_background_chain(iface);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1259,17 +1540,32 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
|
||||
int ht_enabled, int chan_offset, int chan_width,
|
||||
int cf1, int cf2)
|
||||
{
|
||||
/* This is called when the driver indicates that an offloaded DFS has
|
||||
* started CAC. */
|
||||
hostapd_set_state(iface, HAPD_IFACE_DFS);
|
||||
if (hostapd_dfs_is_background_event(iface, freq)) {
|
||||
iface->radar_background.cac_started = 1;
|
||||
} else {
|
||||
/* This is called when the driver indicates that an offloaded
|
||||
* DFS has started CAC. radar_detected might be set for previous
|
||||
* DFS channel. Clear it for this new CAC process. */
|
||||
hostapd_set_state(iface, HAPD_IFACE_DFS);
|
||||
iface->cac_started = 1;
|
||||
|
||||
/* Clear radar_detected in case it is for the previous
|
||||
* frequency. Also remove disabled link's information in RNR
|
||||
* element from other links. */
|
||||
iface->radar_detected = false;
|
||||
if (iface->interfaces && iface->interfaces->count > 1)
|
||||
ieee802_11_set_beacons(iface);
|
||||
}
|
||||
/* TODO: How to check CAC time for ETSI weather channels? */
|
||||
iface->dfs_cac_ms = 60000;
|
||||
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
|
||||
"freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
|
||||
"seg1=%d cac_time=%ds",
|
||||
"seg1=%d cac_time=%ds%s",
|
||||
freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
|
||||
iface->dfs_cac_ms / 1000);
|
||||
iface->cac_started = 1;
|
||||
iface->dfs_cac_ms / 1000,
|
||||
hostapd_dfs_is_background_event(iface, freq) ?
|
||||
" (background)" : "");
|
||||
|
||||
os_get_reltime(&iface->dfs_cac_start);
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -45,5 +45,10 @@ int hostapd_dpp_controller_start(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_chirp(struct hostapd_data *hapd, const char *cmd);
|
||||
void hostapd_dpp_chirp_stop(struct hostapd_data *hapd);
|
||||
void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi);
|
||||
int hostapd_dpp_push_button(struct hostapd_data *hapd, const char *cmd);
|
||||
void hostapd_dpp_push_button_stop(struct hostapd_data *hapd);
|
||||
bool hostapd_dpp_configurator_connectivity(struct hostapd_data *hapd);
|
||||
int hostapd_dpp_add_controller(struct hostapd_data *hapd, const char *cmd);
|
||||
void hostapd_dpp_remove_controller(struct hostapd_data *hapd, const char *cmd);
|
||||
|
||||
#endif /* DPP_HOSTAPD_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -530,9 +530,9 @@ static int fils_process_hlp_ip(struct hostapd_data *hapd,
|
||||
switch (iph->ip_p) {
|
||||
case 17:
|
||||
return fils_process_hlp_udp(hapd, sta, dst, pos, len);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -546,7 +546,7 @@ static int fils_process_hlp_req(struct hostapd_data *hapd,
|
||||
" src=" MACSTR " len=%u)",
|
||||
MAC2STR(sta->addr), MAC2STR(pos), MAC2STR(pos + ETH_ALEN),
|
||||
(unsigned int) len);
|
||||
if (os_memcmp(sta->addr, pos + ETH_ALEN, ETH_ALEN) != 0) {
|
||||
if (!ether_addr_equal(sta->addr, pos + ETH_ALEN)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Ignore HLP request with unexpected source address"
|
||||
MACSTR, MAC2STR(pos + ETH_ALEN));
|
||||
@ -567,9 +567,9 @@ static int fils_process_hlp_req(struct hostapd_data *hapd,
|
||||
case ETH_P_IP:
|
||||
return fils_process_hlp_ip(hapd, sta, pos, pkt + 2,
|
||||
end - pkt - 2);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -29,6 +29,8 @@
|
||||
#define GAS_QUERY_WAIT_TIME_INITIAL 1000
|
||||
#define GAS_QUERY_WAIT_TIME_COMEBACK 150
|
||||
|
||||
#define GAS_QUERY_MAX_COMEBACK_DELAY 60000
|
||||
|
||||
/**
|
||||
* struct gas_query_pending - Pending GAS query
|
||||
*/
|
||||
@ -183,7 +185,7 @@ gas_query_get_pending(struct gas_query_ap *gas, const u8 *addr, u8 dialog_token)
|
||||
{
|
||||
struct gas_query_pending *q;
|
||||
dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
|
||||
if (os_memcmp(q->addr, addr, ETH_ALEN) == 0 &&
|
||||
if (ether_addr_equal(q->addr, addr) &&
|
||||
q->dialog_token == dialog_token)
|
||||
return q;
|
||||
}
|
||||
@ -221,7 +223,7 @@ void gas_query_ap_tx_status(struct gas_query_ap *gas, const u8 *dst,
|
||||
wpa_printf(MSG_DEBUG, "GAS: TX status: dst=" MACSTR
|
||||
" ok=%d query=%p dialog_token=%u dur=%d ms",
|
||||
MAC2STR(dst), ok, query, query->dialog_token, dur);
|
||||
if (os_memcmp(dst, query->addr, ETH_ALEN) != 0) {
|
||||
if (!ether_addr_equal(dst, query->addr)) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination");
|
||||
return;
|
||||
}
|
||||
@ -545,6 +547,8 @@ int gas_query_ap_rx(struct gas_query_ap *gas, const u8 *sa, u8 categ,
|
||||
if (pos + 2 > data + len)
|
||||
return 0;
|
||||
comeback_delay = WPA_GET_LE16(pos);
|
||||
if (comeback_delay > GAS_QUERY_MAX_COMEBACK_DELAY)
|
||||
comeback_delay = GAS_QUERY_MAX_COMEBACK_DELAY;
|
||||
pos += 2;
|
||||
|
||||
/* Advertisement Protocol element */
|
||||
@ -614,7 +618,7 @@ static int gas_query_dialog_token_available(struct gas_query_ap *gas,
|
||||
{
|
||||
struct gas_query_pending *q;
|
||||
dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
|
||||
if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 &&
|
||||
if (ether_addr_equal(dst, q->addr) &&
|
||||
dialog_token == q->dialog_token)
|
||||
return 0;
|
||||
}
|
||||
|
@ -1524,7 +1524,7 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
|
||||
#ifdef CONFIG_DPP
|
||||
void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
|
||||
const u8 *sa, u8 dialog_token,
|
||||
int prot, struct wpabuf *buf)
|
||||
int prot, struct wpabuf *buf, int freq)
|
||||
{
|
||||
struct wpabuf *tx_buf;
|
||||
|
||||
@ -1582,7 +1582,7 @@ void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
|
||||
return;
|
||||
if (prot)
|
||||
convert_to_protected_dual(tx_buf);
|
||||
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
|
||||
hostapd_drv_send_action(hapd, freq ? freq : hapd->iface->freq, 0, sa,
|
||||
wpabuf_head(tx_buf),
|
||||
wpabuf_len(tx_buf));
|
||||
wpabuf_free(tx_buf);
|
||||
@ -1593,7 +1593,7 @@ void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
|
||||
static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
const u8 *sa,
|
||||
const u8 *data, size_t len, int prot,
|
||||
int std_addr3)
|
||||
int std_addr3, int freq)
|
||||
{
|
||||
const u8 *pos = data;
|
||||
const u8 *end = data + len;
|
||||
@ -1688,7 +1688,8 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
data, len);
|
||||
if (!msg)
|
||||
return;
|
||||
gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);
|
||||
gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg,
|
||||
freq);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_DPP */
|
||||
@ -1871,7 +1872,7 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
|
||||
switch (data[0]) {
|
||||
case WLAN_PA_GAS_INITIAL_REQ:
|
||||
gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot,
|
||||
std_addr3);
|
||||
std_addr3, freq);
|
||||
break;
|
||||
case WLAN_PA_GAS_COMEBACK_REQ:
|
||||
gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot,
|
||||
|
@ -90,6 +90,6 @@ void gas_serv_deinit(struct hostapd_data *hapd);
|
||||
|
||||
void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
|
||||
const u8 *sa, u8 dialog_token,
|
||||
int prot, struct wpabuf *buf);
|
||||
int prot, struct wpabuf *buf, int freq);
|
||||
|
||||
#endif /* GAS_SERV_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -14,6 +14,7 @@
|
||||
#endif /* CONFIG_SQLITE */
|
||||
|
||||
#include "common/defs.h"
|
||||
#include "common/dpp.h"
|
||||
#include "utils/list.h"
|
||||
#include "ap_config.h"
|
||||
#include "drivers/driver.h"
|
||||
@ -43,6 +44,7 @@ struct mesh_conf;
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
struct hostapd_iface;
|
||||
struct hostapd_mld;
|
||||
|
||||
struct hapd_interfaces {
|
||||
int (*reload_config)(struct hostapd_iface *iface);
|
||||
@ -75,18 +77,34 @@ struct hapd_interfaces {
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
struct dpp_global *dpp;
|
||||
#ifdef CONFIG_DPP3
|
||||
struct os_reltime dpp_pb_time;
|
||||
struct os_reltime dpp_pb_announce_time;
|
||||
struct dpp_pb_info dpp_pb[DPP_PB_INFO_COUNT];
|
||||
struct dpp_bootstrap_info *dpp_pb_bi;
|
||||
u8 dpp_pb_c_nonce[DPP_MAX_NONCE_LEN];
|
||||
u8 dpp_pb_resp_hash[SHA256_MAC_LEN];
|
||||
struct os_reltime dpp_pb_last_resp;
|
||||
bool dpp_pb_result_indicated;
|
||||
char *dpp_pb_cmd;
|
||||
#endif /* CONFIG_DPP3 */
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
struct hostapd_mld **mld;
|
||||
size_t mld_count;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
};
|
||||
|
||||
enum hostapd_chan_status {
|
||||
HOSTAPD_CHAN_VALID = 0, /* channel is ready */
|
||||
HOSTAPD_CHAN_INVALID = 1, /* no usable channel found */
|
||||
HOSTAPD_CHAN_ACS = 2, /* ACS work being performed */
|
||||
HOSTAPD_CHAN_INVALID_NO_IR = 3, /* channel invalid due to AFC NO IR */
|
||||
};
|
||||
|
||||
struct hostapd_probereq_cb {
|
||||
@ -207,6 +225,7 @@ struct hostapd_data {
|
||||
|
||||
void *ssl_ctx;
|
||||
void *eap_sim_db_priv;
|
||||
struct crypto_rsa_key *imsi_privacy_key;
|
||||
struct radius_server_data *radius_srv;
|
||||
struct dl_list erp_keys; /* struct eap_server_erp_key */
|
||||
|
||||
@ -273,7 +292,8 @@ struct hostapd_data {
|
||||
void *wps_event_cb_ctx;
|
||||
|
||||
void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr,
|
||||
int authorized, const u8 *p2p_dev_addr);
|
||||
int authorized, const u8 *p2p_dev_addr,
|
||||
const u8 *ip);
|
||||
void *sta_authorized_cb_ctx;
|
||||
|
||||
void (*setup_complete_cb)(void *ctx);
|
||||
@ -294,6 +314,17 @@ struct hostapd_data {
|
||||
unsigned int cs_c_off_ecsa_beacon;
|
||||
unsigned int cs_c_off_ecsa_proberesp;
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
bool cca_in_progress;
|
||||
u8 cca_count;
|
||||
u8 cca_color;
|
||||
unsigned int cca_c_off_beacon;
|
||||
unsigned int cca_c_off_proberesp;
|
||||
struct os_reltime first_color_collision;
|
||||
struct os_reltime last_color_collision;
|
||||
u64 color_collision_bitmap;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
struct p2p_data *p2p;
|
||||
struct p2p_group *p2p_group;
|
||||
@ -311,6 +342,7 @@ struct hostapd_data {
|
||||
#ifdef CONFIG_PROXYARP
|
||||
struct l2_packet_data *sock_dhcp;
|
||||
struct l2_packet_data *sock_ndisc;
|
||||
bool x_snoop_initialized;
|
||||
#endif /* CONFIG_PROXYARP */
|
||||
#ifdef CONFIG_MESH
|
||||
int num_plinks;
|
||||
@ -327,11 +359,15 @@ struct hostapd_data {
|
||||
#endif /* CONFIG_SQLITE */
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
|
||||
#define COMEBACK_KEY_SIZE 8
|
||||
#define COMEBACK_PENDING_IDX_SIZE 256
|
||||
|
||||
/** Key used for generating SAE anti-clogging tokens */
|
||||
u8 comeback_key[8];
|
||||
u8 comeback_key[COMEBACK_KEY_SIZE];
|
||||
struct os_reltime last_comeback_key_update;
|
||||
u16 comeback_idx;
|
||||
u16 comeback_pending_idx[256];
|
||||
u16 comeback_pending_idx[COMEBACK_PENDING_IDX_SIZE];
|
||||
int dot11RSNASAERetransPeriod; /* msec */
|
||||
struct dl_list sae_commit_queue; /* struct hostapd_sae_commit_queue */
|
||||
#endif /* CONFIG_SAE */
|
||||
@ -369,8 +405,10 @@ struct hostapd_data {
|
||||
u8 beacon_req_token;
|
||||
u8 lci_req_token;
|
||||
u8 range_req_token;
|
||||
u8 link_measurement_req_token;
|
||||
unsigned int lci_req_active:1;
|
||||
unsigned int range_req_active:1;
|
||||
unsigned int link_mesr_req_active:1;
|
||||
|
||||
int dhcp_sock; /* UDP socket used with the DHCP server */
|
||||
|
||||
@ -387,7 +425,9 @@ struct hostapd_data {
|
||||
struct dpp_pkex *dpp_pkex;
|
||||
struct dpp_bootstrap_info *dpp_pkex_bi;
|
||||
char *dpp_pkex_code;
|
||||
size_t dpp_pkex_code_len;
|
||||
char *dpp_pkex_identifier;
|
||||
enum dpp_pkex_ver dpp_pkex_ver;
|
||||
char *dpp_pkex_auth_cmd;
|
||||
char *dpp_configurator_params;
|
||||
struct os_reltime dpp_last_init;
|
||||
@ -406,6 +446,7 @@ struct hostapd_data {
|
||||
int dpp_chirp_round;
|
||||
int dpp_chirp_scan_done;
|
||||
int dpp_chirp_listen;
|
||||
struct os_reltime dpp_relay_last_needs_ctrl;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
char *dpp_config_obj_override;
|
||||
@ -429,6 +470,23 @@ struct hostapd_data {
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
u8 eht_mld_bss_param_change;
|
||||
struct hostapd_mld *mld;
|
||||
struct dl_list link;
|
||||
u8 mld_link_id;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
u8 eht_mld_link_removal_count;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
#ifdef CONFIG_NAN_USD
|
||||
struct nan_de *nan_de;
|
||||
#endif /* CONFIG_NAN_USD */
|
||||
|
||||
u64 scan_cookie; /* Scan instance identifier for the ongoing HT40 scan
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
@ -442,6 +500,29 @@ struct hostapd_sta_info {
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
/**
|
||||
* struct hostapd_mld - hostapd per-mld data structure
|
||||
*/
|
||||
struct hostapd_mld {
|
||||
char name[IFNAMSIZ + 1];
|
||||
u8 mld_addr[ETH_ALEN];
|
||||
u8 next_link_id;
|
||||
u8 num_links;
|
||||
/* Number of hostapd_data (hapd) referencing this. num_links cannot be
|
||||
* used since num_links can go to 0 even when a BSS is disabled and
|
||||
* when it is re-enabled, the MLD should exist and hence it cannot be
|
||||
* freed when num_links is 0.
|
||||
*/
|
||||
u8 refcount;
|
||||
|
||||
struct hostapd_data *fbss;
|
||||
struct dl_list links; /* List head of all affiliated links */
|
||||
};
|
||||
|
||||
#define HOSTAPD_MLD_MAX_REF_COUNT 0xFF
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
/**
|
||||
* struct hostapd_iface - hostapd per-interface data structure
|
||||
*/
|
||||
@ -459,6 +540,7 @@ struct hostapd_iface {
|
||||
HAPD_IFACE_ACS,
|
||||
HAPD_IFACE_HT_SCAN,
|
||||
HAPD_IFACE_DFS,
|
||||
HAPD_IFACE_NO_IR,
|
||||
HAPD_IFACE_ENABLED
|
||||
} state;
|
||||
|
||||
@ -497,6 +579,7 @@ struct hostapd_iface {
|
||||
|
||||
u64 drv_flags;
|
||||
u64 drv_flags2;
|
||||
unsigned int drv_rrm_flags;
|
||||
|
||||
/*
|
||||
* A bitmap of supported protocols for probe response offload. See
|
||||
@ -508,6 +591,8 @@ struct hostapd_iface {
|
||||
const u8 *extended_capa, *extended_capa_mask;
|
||||
unsigned int extended_capa_len;
|
||||
|
||||
u16 mld_eml_capa, mld_mld_capa;
|
||||
|
||||
unsigned int drv_max_acl_mac_addrs;
|
||||
|
||||
struct hostapd_hw_modes *hw_features;
|
||||
@ -520,6 +605,23 @@ struct hostapd_iface {
|
||||
int *basic_rates;
|
||||
int freq;
|
||||
|
||||
bool radar_detected;
|
||||
|
||||
/* Background radar configuration */
|
||||
struct {
|
||||
int channel;
|
||||
int secondary_channel;
|
||||
int freq;
|
||||
int centr_freq_seg0_idx;
|
||||
int centr_freq_seg1_idx;
|
||||
/* Main chain is on temporary channel during
|
||||
* CAC detection on radar offchain.
|
||||
*/
|
||||
unsigned int temp_ch:1;
|
||||
/* CAC started on radar offchain */
|
||||
unsigned int cac_started:1;
|
||||
} radar_background;
|
||||
|
||||
u16 hw_flags;
|
||||
|
||||
/* Number of associated Non-ERP stations (i.e., stations using 802.11b
|
||||
@ -580,6 +682,7 @@ struct hostapd_iface {
|
||||
|
||||
#ifdef CONFIG_ACS
|
||||
unsigned int acs_num_completed_scans;
|
||||
unsigned int acs_num_retries;
|
||||
#endif /* CONFIG_ACS */
|
||||
|
||||
void (*scan_cb)(struct hostapd_iface *iface);
|
||||
@ -596,8 +699,18 @@ struct hostapd_iface {
|
||||
/* Previous WMM element information */
|
||||
struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
|
||||
|
||||
/* Maximum number of interfaces supported for MBSSID advertisement */
|
||||
unsigned int mbssid_max_interfaces;
|
||||
/* Maximum profile periodicity for enhanced MBSSID advertisement */
|
||||
unsigned int ema_max_periodicity;
|
||||
|
||||
int (*enable_iface_cb)(struct hostapd_iface *iface);
|
||||
int (*disable_iface_cb)(struct hostapd_iface *iface);
|
||||
|
||||
/* Configured freq of interface is NO_IR */
|
||||
bool is_no_ir;
|
||||
|
||||
bool is_ch_switch_dfs; /* Channel switch from ACS to DFS */
|
||||
};
|
||||
|
||||
/* hostapd.c */
|
||||
@ -625,6 +738,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
void hostapd_interface_deinit_free(struct hostapd_iface *iface);
|
||||
int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
|
||||
int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
|
||||
int hostapd_reload_bss_only(struct hostapd_data *bss);
|
||||
int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
|
||||
void hostapd_bss_deinit_no_free(struct hostapd_data *hapd);
|
||||
void hostapd_free_hapd_data(struct hostapd_data *hapd);
|
||||
@ -647,6 +761,9 @@ void hostapd_periodic_iface(struct hostapd_iface *iface);
|
||||
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
|
||||
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
|
||||
|
||||
void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap);
|
||||
void hostapd_cleanup_cca_params(struct hostapd_data *hapd);
|
||||
|
||||
/* utils.c */
|
||||
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
|
||||
int (*cb)(void *ctx, const u8 *sa,
|
||||
@ -654,13 +771,15 @@ int hostapd_register_probereq_cb(struct hostapd_data *hapd,
|
||||
const u8 *ie, size_t ie_len,
|
||||
int ssi_signal),
|
||||
void *ctx);
|
||||
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
|
||||
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr,
|
||||
int mld_assoc_link_id);
|
||||
|
||||
/* drv_callbacks.c (TODO: move to somewhere else?) */
|
||||
void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *ie, size_t ielen, int reassoc);
|
||||
const u8 *req_ie, size_t req_ielen, const u8 *resp_ie,
|
||||
size_t resp_ielen, const u8 *link_addr, int reassoc);
|
||||
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
|
||||
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
|
||||
void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
|
||||
@ -670,7 +789,7 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
|
||||
int ssi_signal);
|
||||
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
int offset, int width, int cf1, int cf2,
|
||||
int finished);
|
||||
u16 punct_bitmap, int finished);
|
||||
struct survey_results;
|
||||
void hostapd_event_get_survey(struct hostapd_iface *iface,
|
||||
struct survey_results *survey_results);
|
||||
@ -692,4 +811,42 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
|
||||
struct fst_wpa_obj *iface_obj);
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
int hostapd_set_acl(struct hostapd_data *hapd);
|
||||
struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd);
|
||||
int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd);
|
||||
struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd,
|
||||
u8 link_id);
|
||||
int hostapd_link_remove(struct hostapd_data *hapd, u32 count);
|
||||
bool hostapd_is_ml_partner(struct hostapd_data *hapd1,
|
||||
struct hostapd_data *hapd2);
|
||||
u8 hostapd_get_mld_id(struct hostapd_data *hapd);
|
||||
int hostapd_mld_add_link(struct hostapd_data *hapd);
|
||||
int hostapd_mld_remove_link(struct hostapd_data *hapd);
|
||||
struct hostapd_data * hostapd_mld_get_first_bss(struct hostapd_data *hapd);
|
||||
|
||||
void free_beacon_data(struct beacon_data *beacon);
|
||||
int hostapd_fill_cca_settings(struct hostapd_data *hapd,
|
||||
struct cca_settings *settings);
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
|
||||
bool hostapd_mld_is_first_bss(struct hostapd_data *hapd);
|
||||
|
||||
#define for_each_mld_link(partner, self) \
|
||||
dl_list_for_each(partner, &self->mld->links, struct hostapd_data, link)
|
||||
|
||||
#else /* CONFIG_IEEE80211BE */
|
||||
|
||||
static inline bool hostapd_mld_is_first_bss(struct hostapd_data *hapd)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#define for_each_mld_link(partner, self) \
|
||||
if (false)
|
||||
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
u16 hostapd_get_punct_bitmap(struct hostapd_data *hapd);
|
||||
|
||||
#endif /* HOSTAPD_H */
|
||||
|
@ -79,6 +79,9 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
|
||||
u16 num_modes, flags;
|
||||
struct hostapd_hw_modes *modes;
|
||||
u8 dfs_domain;
|
||||
enum hostapd_hw_mode mode = HOSTAPD_MODE_IEEE80211ANY;
|
||||
bool is_6ghz = false;
|
||||
bool orig_mode_valid = false;
|
||||
|
||||
if (hostapd_drv_none(hapd))
|
||||
return -1;
|
||||
@ -95,6 +98,18 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
|
||||
iface->hw_flags = flags;
|
||||
iface->dfs_domain = dfs_domain;
|
||||
|
||||
if (iface->current_mode) {
|
||||
/*
|
||||
* Received driver event CHANNEL_LIST_CHANGED when the current
|
||||
* hw mode is valid. Clear iface->current_mode temporarily as
|
||||
* the mode instance will be replaced with a new instance and
|
||||
* the current pointer would be pointing to freed memory.
|
||||
*/
|
||||
orig_mode_valid = true;
|
||||
mode = iface->current_mode->mode;
|
||||
is_6ghz = iface->current_mode->is_6ghz;
|
||||
iface->current_mode = NULL;
|
||||
}
|
||||
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
|
||||
iface->hw_features = modes;
|
||||
iface->num_hw_features = num_modes;
|
||||
@ -104,6 +119,12 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
|
||||
int dfs_enabled = hapd->iconf->ieee80211h &&
|
||||
(iface->drv_flags & WPA_DRIVER_FLAGS_RADAR);
|
||||
|
||||
/* Restore orignal mode if possible */
|
||||
if (orig_mode_valid && feature->mode == mode &&
|
||||
feature->num_channels > 0 &&
|
||||
is_6ghz == is_6ghz_freq(feature->channels[0].freq))
|
||||
iface->current_mode = feature;
|
||||
|
||||
/* set flag for channels we can use in current regulatory
|
||||
* domain */
|
||||
for (j = 0; j < feature->num_channels; j++) {
|
||||
@ -141,6 +162,12 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
|
||||
}
|
||||
}
|
||||
|
||||
if (orig_mode_valid && !iface->current_mode) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"%s: Could not update iface->current_mode",
|
||||
__func__);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -371,7 +398,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
|
||||
iface->conf->secondary_channel = 0;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 0);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, 0);
|
||||
hostapd_set_oper_chwidth(iface->conf, CHANWIDTH_USE_HT);
|
||||
hostapd_set_oper_chwidth(iface->conf, CONF_OPER_CHWIDTH_USE_HT);
|
||||
res = 1;
|
||||
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
|
||||
}
|
||||
@ -479,6 +506,12 @@ static void ap_ht40_scan_retry(void *eloop_data, void *user_data)
|
||||
else
|
||||
ieee80211n_scan_channels_5g(iface, ¶ms);
|
||||
|
||||
params.link_id = -1;
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (iface->bss[0]->conf->mld_ap)
|
||||
params.link_id = iface->bss[0]->mld_link_id;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
ret = hostapd_driver_scan(iface->bss[0], ¶ms);
|
||||
iface->num_ht40_scan_tries++;
|
||||
os_free(params.freqs);
|
||||
@ -494,6 +527,7 @@ static void ap_ht40_scan_retry(void *eloop_data, void *user_data)
|
||||
|
||||
if (ret == 0) {
|
||||
iface->scan_cb = ieee80211n_check_scan;
|
||||
iface->bss[0]->scan_cookie = params.scan_cookie;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -529,6 +563,11 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
|
||||
else
|
||||
ieee80211n_scan_channels_5g(iface, ¶ms);
|
||||
|
||||
params.link_id = -1;
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (iface->bss[0]->conf->mld_ap)
|
||||
params.link_id = iface->bss[0]->mld_link_id;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
ret = hostapd_driver_scan(iface->bss[0], ¶ms);
|
||||
os_free(params.freqs);
|
||||
|
||||
@ -550,6 +589,7 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
iface->scan_cb = ieee80211n_check_scan;
|
||||
iface->bss[0]->scan_cookie = params.scan_cookie;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -794,6 +834,11 @@ int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
/* Returns:
|
||||
* 1 = usable
|
||||
* 0 = not usable
|
||||
* -1 = not currently usable due to 6 GHz NO-IR
|
||||
*/
|
||||
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
|
||||
int frequency, int primary)
|
||||
{
|
||||
@ -817,6 +862,10 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
|
||||
chan->flag,
|
||||
chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
|
||||
chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
|
||||
|
||||
if (is_6ghz_freq(chan->freq) && (chan->flag & HOSTAPD_CHAN_NO_IR))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -826,6 +875,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
|
||||
int i, contiguous = 0;
|
||||
int num_of_enabled = 0;
|
||||
int max_contiguous = 0;
|
||||
int err;
|
||||
struct ieee80211_edmg_config edmg;
|
||||
struct hostapd_channel_data *pri_chan;
|
||||
|
||||
@ -865,8 +915,9 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
|
||||
if (num_of_enabled > 4)
|
||||
return 0;
|
||||
|
||||
if (!hostapd_is_usable_chan(iface, freq, 1))
|
||||
return 0;
|
||||
err = hostapd_is_usable_chan(iface, freq, 1);
|
||||
if (err <= 0)
|
||||
return err;
|
||||
|
||||
if (contiguous > max_contiguous)
|
||||
max_contiguous = contiguous;
|
||||
@ -893,10 +944,75 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
static bool hostapd_is_usable_punct_bitmap(struct hostapd_iface *iface)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
struct hostapd_config *conf = iface->conf;
|
||||
u16 bw;
|
||||
u8 start_chan;
|
||||
|
||||
if (!conf->punct_bitmap)
|
||||
return true;
|
||||
|
||||
if (!conf->ieee80211be) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Currently RU puncturing is supported only if ieee80211be is enabled");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iface->freq >= 2412 && iface->freq <= 2484) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"RU puncturing not supported in 2.4 GHz");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the 6 GHz band, eht_oper_chwidth is ignored. Use operating class
|
||||
* to determine channel width.
|
||||
*/
|
||||
if (conf->op_class == 137) {
|
||||
bw = 320;
|
||||
start_chan = conf->eht_oper_centr_freq_seg0_idx - 30;
|
||||
} else {
|
||||
switch (conf->eht_oper_chwidth) {
|
||||
case 0:
|
||||
wpa_printf(MSG_ERROR,
|
||||
"RU puncturing is supported only in 80 MHz and 160 MHz");
|
||||
return false;
|
||||
case 1:
|
||||
bw = 80;
|
||||
start_chan = conf->eht_oper_centr_freq_seg0_idx - 6;
|
||||
break;
|
||||
case 2:
|
||||
bw = 160;
|
||||
start_chan = conf->eht_oper_centr_freq_seg0_idx - 14;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_punct_bitmap_valid(bw, (conf->channel - start_chan) / 4,
|
||||
conf->punct_bitmap)) {
|
||||
wpa_printf(MSG_ERROR, "Invalid puncturing bitmap");
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Returns:
|
||||
* 1 = usable
|
||||
* 0 = not usable
|
||||
* -1 = not currently usable due to 6 GHz NO-IR
|
||||
*/
|
||||
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
|
||||
{
|
||||
int secondary_freq;
|
||||
struct hostapd_channel_data *pri_chan;
|
||||
int err, err2;
|
||||
|
||||
if (!iface->current_mode)
|
||||
return 0;
|
||||
@ -908,18 +1024,25 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
|
||||
wpa_printf(MSG_ERROR, "Primary frequency not present");
|
||||
return 0;
|
||||
}
|
||||
if (!hostapd_is_usable_chan(iface, pri_chan->freq, 1)) {
|
||||
|
||||
err = hostapd_is_usable_chan(iface, pri_chan->freq, 1);
|
||||
if (err <= 0) {
|
||||
wpa_printf(MSG_ERROR, "Primary frequency not allowed");
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
if (!hostapd_is_usable_edmg(iface))
|
||||
err = hostapd_is_usable_edmg(iface);
|
||||
if (err <= 0)
|
||||
return err;
|
||||
|
||||
if (!hostapd_is_usable_punct_bitmap(iface))
|
||||
return 0;
|
||||
|
||||
if (!iface->conf->secondary_channel)
|
||||
return 1;
|
||||
|
||||
if (hostapd_is_usable_chan(iface, iface->freq +
|
||||
iface->conf->secondary_channel * 20, 0)) {
|
||||
err = hostapd_is_usable_chan(iface, iface->freq +
|
||||
iface->conf->secondary_channel * 20, 0);
|
||||
if (err > 0) {
|
||||
if (iface->conf->secondary_channel == 1 &&
|
||||
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))
|
||||
return 1;
|
||||
@ -928,35 +1051,51 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
|
||||
return 1;
|
||||
}
|
||||
if (!iface->conf->ht40_plus_minus_allowed)
|
||||
return 0;
|
||||
return err;
|
||||
|
||||
/* Both HT40+ and HT40- are set, pick a valid secondary channel */
|
||||
secondary_freq = iface->freq + 20;
|
||||
if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
|
||||
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
|
||||
err2 = hostapd_is_usable_chan(iface, secondary_freq, 0);
|
||||
if (err2 > 0 && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
|
||||
iface->conf->secondary_channel = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
secondary_freq = iface->freq - 20;
|
||||
if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
|
||||
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
|
||||
err2 = hostapd_is_usable_chan(iface, secondary_freq, 0);
|
||||
if (err2 > 0 && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
|
||||
iface->conf->secondary_channel = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_determine_mode(struct hostapd_iface *iface)
|
||||
static bool skip_mode(struct hostapd_iface *iface,
|
||||
struct hostapd_hw_modes *mode)
|
||||
{
|
||||
int chan;
|
||||
|
||||
if (iface->freq > 0 && !hw_mode_get_channel(mode, iface->freq, &chan))
|
||||
return true;
|
||||
|
||||
if (is_6ghz_op_class(iface->conf->op_class) && iface->freq == 0 &&
|
||||
!mode->is_6ghz)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_determine_mode(struct hostapd_iface *iface)
|
||||
{
|
||||
int i;
|
||||
enum hostapd_hw_mode target_mode;
|
||||
|
||||
if (iface->current_mode ||
|
||||
iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (iface->freq < 4000)
|
||||
target_mode = HOSTAPD_MODE_IEEE80211G;
|
||||
@ -970,14 +1109,20 @@ static void hostapd_determine_mode(struct hostapd_iface *iface)
|
||||
|
||||
mode = &iface->hw_features[i];
|
||||
if (mode->mode == target_mode) {
|
||||
if (skip_mode(iface, mode))
|
||||
continue;
|
||||
|
||||
iface->current_mode = mode;
|
||||
iface->conf->hw_mode = mode->mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iface->current_mode)
|
||||
wpa_printf(MSG_ERROR, "ACS: Cannot decide mode");
|
||||
if (!iface->current_mode) {
|
||||
wpa_printf(MSG_ERROR, "ACS/CSA: Cannot decide mode");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -985,11 +1130,17 @@ static enum hostapd_chan_status
|
||||
hostapd_check_chans(struct hostapd_iface *iface)
|
||||
{
|
||||
if (iface->freq) {
|
||||
int err;
|
||||
|
||||
hostapd_determine_mode(iface);
|
||||
if (hostapd_is_usable_chans(iface))
|
||||
return HOSTAPD_CHAN_VALID;
|
||||
else
|
||||
return HOSTAPD_CHAN_INVALID;
|
||||
|
||||
err = hostapd_is_usable_chans(iface);
|
||||
if (err <= 0) {
|
||||
if (!err)
|
||||
return HOSTAPD_CHAN_INVALID;
|
||||
return HOSTAPD_CHAN_INVALID_NO_IR;
|
||||
}
|
||||
return HOSTAPD_CHAN_VALID;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1000,6 +1151,8 @@ hostapd_check_chans(struct hostapd_iface *iface)
|
||||
switch (acs_init(iface)) {
|
||||
case HOSTAPD_CHAN_ACS:
|
||||
return HOSTAPD_CHAN_ACS;
|
||||
case HOSTAPD_CHAN_INVALID_NO_IR:
|
||||
return HOSTAPD_CHAN_INVALID_NO_IR;
|
||||
case HOSTAPD_CHAN_VALID:
|
||||
case HOSTAPD_CHAN_INVALID:
|
||||
default:
|
||||
@ -1039,6 +1192,7 @@ int hostapd_acs_completed(struct hostapd_iface *iface, int err)
|
||||
|
||||
switch (hostapd_check_chans(iface)) {
|
||||
case HOSTAPD_CHAN_VALID:
|
||||
iface->is_no_ir = false;
|
||||
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
|
||||
ACS_EVENT_COMPLETED "freq=%d channel=%d",
|
||||
iface->freq, iface->conf->channel);
|
||||
@ -1048,6 +1202,9 @@ int hostapd_acs_completed(struct hostapd_iface *iface, int err)
|
||||
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
|
||||
hostapd_notify_bad_chans(iface);
|
||||
goto out;
|
||||
case HOSTAPD_CHAN_INVALID_NO_IR:
|
||||
iface->is_no_ir = true;
|
||||
/* fall through */
|
||||
case HOSTAPD_CHAN_INVALID:
|
||||
default:
|
||||
wpa_printf(MSG_ERROR, "ACS picked unusable channels");
|
||||
@ -1070,6 +1227,25 @@ int hostapd_acs_completed(struct hostapd_iface *iface, int err)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_csa_update_hwmode - Update hardware mode
|
||||
* @iface: Pointer to interface data.
|
||||
* Returns: 0 on success, < 0 on failure
|
||||
*
|
||||
* Update hardware mode when the operating channel changed because of CSA.
|
||||
*/
|
||||
int hostapd_csa_update_hwmode(struct hostapd_iface *iface)
|
||||
{
|
||||
if (!iface || !iface->conf)
|
||||
return -1;
|
||||
|
||||
iface->current_mode = NULL;
|
||||
iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211ANY;
|
||||
|
||||
return hostapd_determine_mode(iface);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_select_hw_mode - Select the hardware mode
|
||||
* @iface: Pointer to interface data.
|
||||
@ -1087,23 +1263,22 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
|
||||
|
||||
if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
|
||||
iface->conf->ieee80211n || iface->conf->ieee80211ac ||
|
||||
iface->conf->ieee80211ax) &&
|
||||
iface->conf->ieee80211ax || iface->conf->ieee80211be) &&
|
||||
iface->conf->channel == 14) {
|
||||
wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE on channel 14");
|
||||
wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE/EHT on channel 14");
|
||||
iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
|
||||
iface->conf->ieee80211n = 0;
|
||||
iface->conf->ieee80211ac = 0;
|
||||
iface->conf->ieee80211ax = 0;
|
||||
iface->conf->ieee80211be = 0;
|
||||
}
|
||||
|
||||
iface->current_mode = NULL;
|
||||
for (i = 0; i < iface->num_hw_features; i++) {
|
||||
struct hostapd_hw_modes *mode = &iface->hw_features[i];
|
||||
int chan;
|
||||
|
||||
if (mode->mode == iface->conf->hw_mode) {
|
||||
if (iface->freq > 0 &&
|
||||
!hw_mode_get_channel(mode, iface->freq, &chan))
|
||||
if (skip_mode(iface, mode))
|
||||
continue;
|
||||
|
||||
iface->current_mode = mode;
|
||||
@ -1134,9 +1309,13 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
|
||||
|
||||
switch (hostapd_check_chans(iface)) {
|
||||
case HOSTAPD_CHAN_VALID:
|
||||
iface->is_no_ir = false;
|
||||
return 0;
|
||||
case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */
|
||||
return 1;
|
||||
case HOSTAPD_CHAN_INVALID_NO_IR:
|
||||
iface->is_no_ir = true;
|
||||
/* fall through */
|
||||
case HOSTAPD_CHAN_INVALID:
|
||||
default:
|
||||
hostapd_notify_bad_chans(iface);
|
||||
|
@ -15,6 +15,7 @@
|
||||
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
|
||||
size_t num_hw_features);
|
||||
int hostapd_get_hw_features(struct hostapd_iface *iface);
|
||||
int hostapd_csa_update_hwmode(struct hostapd_iface *iface);
|
||||
int hostapd_acs_completed(struct hostapd_iface *iface, int err);
|
||||
int hostapd_select_hw_mode(struct hostapd_iface *iface);
|
||||
const char * hostapd_hw_mode_txt(int mode);
|
||||
@ -28,6 +29,7 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
|
||||
void hostapd_stop_setup_timers(struct hostapd_iface *iface);
|
||||
int hostapd_hw_skip_mode(struct hostapd_iface *iface,
|
||||
struct hostapd_hw_modes *mode);
|
||||
int hostapd_determine_mode(struct hostapd_iface *iface);
|
||||
#else /* NEED_AP_MLME */
|
||||
static inline void
|
||||
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
|
||||
@ -40,6 +42,11 @@ static inline int hostapd_get_hw_features(struct hostapd_iface *iface)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int hostapd_csa_update_hwmode(struct hostapd_iface *iface)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int hostapd_acs_completed(struct hostapd_iface *iface, int err)
|
||||
{
|
||||
return -1;
|
||||
@ -91,6 +98,11 @@ static inline int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int hostapd_determine_mode(struct hostapd_iface *iface)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
#endif /* HW_FEATURES_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,12 @@ struct ieee80211_vht_capabilities;
|
||||
struct ieee80211_mgmt;
|
||||
struct radius_sta;
|
||||
enum ieee80211_op_mode;
|
||||
enum oper_chan_width;
|
||||
struct ieee802_11_elems;
|
||||
struct sae_pk;
|
||||
struct sae_pt;
|
||||
struct sae_password_entry;
|
||||
struct mld_info;
|
||||
|
||||
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
|
||||
struct hostapd_frame_info *fi);
|
||||
@ -45,7 +51,8 @@ static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
|
||||
#endif /* NEED_AP_MLME */
|
||||
u16 hostapd_own_capab_info(struct hostapd_data *hapd);
|
||||
void ap_ht2040_timeout(void *eloop_data, void *user_data);
|
||||
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid,
|
||||
bool mbssid_complete);
|
||||
u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
|
||||
@ -78,13 +85,35 @@ void hostapd_get_he_capab(struct hostapd_data *hapd,
|
||||
const struct ieee80211_he_capabilities *he_cap,
|
||||
struct ieee80211_he_capabilities *neg_he_cap,
|
||||
size_t he_capab_len);
|
||||
void hostapd_get_eht_capab(struct hostapd_data *hapd,
|
||||
const struct ieee80211_eht_capabilities *src,
|
||||
struct ieee80211_eht_capabilities *dest,
|
||||
size_t len);
|
||||
u8 * hostapd_eid_eht_ml_beacon(struct hostapd_data *hapd,
|
||||
struct mld_info *mld_info,
|
||||
u8 *eid, bool include_mld_id);
|
||||
u8 * hostapd_eid_eht_ml_assoc(struct hostapd_data *hapd, struct sta_info *info,
|
||||
u8 *eid);
|
||||
size_t hostapd_eid_eht_ml_beacon_len(struct hostapd_data *hapd,
|
||||
struct mld_info *info,
|
||||
bool include_mld_id);
|
||||
struct wpabuf * hostapd_ml_auth_resp(struct hostapd_data *hapd);
|
||||
const u8 * hostapd_process_ml_auth(struct hostapd_data *hapd,
|
||||
const struct ieee80211_mgmt *mgmt,
|
||||
size_t len);
|
||||
u16 hostapd_process_ml_assoc_req(struct hostapd_data *hapd,
|
||||
struct ieee802_11_elems *elems,
|
||||
struct sta_info *sta);
|
||||
int hostapd_process_ml_assoc_req_addr(struct hostapd_data *hapd,
|
||||
const u8 *basic_mle, size_t basic_mle_len,
|
||||
u8 *mld_addr);
|
||||
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ht_capab);
|
||||
u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ie, size_t len);
|
||||
|
||||
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
int update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta);
|
||||
void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta);
|
||||
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
@ -100,10 +129,10 @@ u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *he_6ghz_capab);
|
||||
int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
|
||||
enum ieee80211_op_mode mode);
|
||||
bool hostapd_get_ht_vht_twt_responder(struct hostapd_data *hapd);
|
||||
u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid);
|
||||
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *buf, size_t len, int ack);
|
||||
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
|
||||
const u8 *data, size_t len, int ack);
|
||||
void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
|
||||
int wds);
|
||||
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
|
||||
@ -118,7 +147,8 @@ u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
|
||||
int hostapd_update_time_adv(struct hostapd_data *hapd);
|
||||
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
|
||||
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid,
|
||||
u16 value);
|
||||
|
||||
int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
#ifdef CONFIG_SAE
|
||||
@ -170,7 +200,8 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 *owe_buf, size_t owe_buf_len, u16 *status);
|
||||
u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len);
|
||||
const u8 *owe_dh, size_t owe_dh_len,
|
||||
const u8 *link_addr);
|
||||
u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
|
||||
const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len);
|
||||
@ -194,7 +225,43 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
|
||||
|
||||
void auth_sae_process_commit(void *eloop_ctx, void *user_ctx);
|
||||
u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len);
|
||||
size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type);
|
||||
u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type);
|
||||
u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ext_capab_ie, size_t ext_capab_ie_len);
|
||||
size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type,
|
||||
bool include_mld_params);
|
||||
u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type,
|
||||
bool include_mld_params);
|
||||
int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int res, struct radius_sta *info);
|
||||
size_t hostapd_eid_eht_capab_len(struct hostapd_data *hapd,
|
||||
enum ieee80211_op_mode opmode);
|
||||
u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid,
|
||||
enum ieee80211_op_mode opmode);
|
||||
u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid);
|
||||
u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
enum ieee80211_op_mode opmode,
|
||||
const u8 *he_capab, size_t he_capab_len,
|
||||
const u8 *eht_capab, size_t eht_capab_len);
|
||||
size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
|
||||
u8 *elem_count, const u8 *known_bss,
|
||||
size_t known_bss_len, size_t *rnr_len);
|
||||
u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
|
||||
unsigned int frame_stype, u8 elem_count,
|
||||
u8 **elem_offset,
|
||||
const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid,
|
||||
u8 *rnr_count, u8 **rnr_offset, size_t rnr_len);
|
||||
bool hostapd_is_mld_ap(struct hostapd_data *hapd);
|
||||
const char * sae_get_password(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, const char *rx_id,
|
||||
struct sae_password_entry **pw_entry,
|
||||
struct sae_pt **s_pt, const struct sae_pk **s_pk);
|
||||
struct sta_info * hostapd_ml_get_assoc_sta(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
struct hostapd_data **assoc_hapd);
|
||||
int hostapd_process_assoc_ml_info(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *ies, size_t ies_len,
|
||||
bool reassoc, int tx_link_status,
|
||||
bool offload);
|
||||
|
||||
#endif /* IEEE802_11_H */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11 authentication (ACL)
|
||||
* Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -20,6 +20,8 @@
|
||||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "sta_info.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "ieee802_11_auth.h"
|
||||
@ -43,6 +45,11 @@ struct hostapd_acl_query_data {
|
||||
u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
|
||||
size_t auth_msg_len;
|
||||
struct hostapd_acl_query_data *next;
|
||||
bool radius_psk;
|
||||
int akm;
|
||||
u8 *anonce;
|
||||
u8 *eapol;
|
||||
size_t eapol_len;
|
||||
};
|
||||
|
||||
|
||||
@ -77,7 +84,7 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
|
||||
os_get_reltime(&now);
|
||||
|
||||
for (entry = hapd->acl_cache; entry; entry = entry->next) {
|
||||
if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0)
|
||||
if (!ether_addr_equal(entry->addr, addr))
|
||||
continue;
|
||||
|
||||
if (os_reltime_expired(&now, &entry->timestamp,
|
||||
@ -95,9 +102,11 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
|
||||
|
||||
static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
|
||||
{
|
||||
if (query == NULL)
|
||||
if (!query)
|
||||
return;
|
||||
os_free(query->auth_msg);
|
||||
os_free(query->anonce);
|
||||
os_free(query->eapol);
|
||||
os_free(query);
|
||||
}
|
||||
|
||||
@ -111,7 +120,7 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
|
||||
|
||||
query->radius_id = radius_client_get_id(hapd->radius);
|
||||
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
|
||||
if (msg == NULL)
|
||||
if (!msg)
|
||||
return -1;
|
||||
|
||||
if (radius_msg_make_authenticator(msg) < 0) {
|
||||
@ -119,6 +128,9 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!radius_msg_add_msg_auth(msg))
|
||||
goto fail;
|
||||
|
||||
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
|
||||
os_strlen(buf))) {
|
||||
@ -153,6 +165,31 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (query->akm &&
|
||||
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE,
|
||||
wpa_akm_to_suite(query->akm))) {
|
||||
wpa_printf(MSG_DEBUG, "Could not add WLAN-AKM-Suite");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (query->anonce &&
|
||||
!radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5,
|
||||
RADIUS_VENDOR_ID_FREERADIUS,
|
||||
RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_ANONCE,
|
||||
query->anonce, WPA_NONCE_LEN)) {
|
||||
wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-Anonce");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (query->eapol &&
|
||||
!radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5,
|
||||
RADIUS_VENDOR_ID_FREERADIUS,
|
||||
RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_EAPOL_KEY_MSG,
|
||||
query->eapol, query->eapol_len)) {
|
||||
wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-EAPoL-Key-Msg");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
|
||||
goto fail;
|
||||
return 0;
|
||||
@ -247,7 +284,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
|
||||
query = hapd->acl_queries;
|
||||
while (query) {
|
||||
if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
|
||||
if (ether_addr_equal(query->addr, addr)) {
|
||||
/* pending query in RADIUS retransmit queue;
|
||||
* do not generate a new one */
|
||||
return HOSTAPD_ACL_PENDING;
|
||||
@ -260,23 +297,23 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
|
||||
/* No entry in the cache - query external RADIUS server */
|
||||
query = os_zalloc(sizeof(*query));
|
||||
if (query == NULL) {
|
||||
if (!query) {
|
||||
wpa_printf(MSG_ERROR, "malloc for query data failed");
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
}
|
||||
os_get_reltime(&query->timestamp);
|
||||
os_memcpy(query->addr, addr, ETH_ALEN);
|
||||
if (hostapd_radius_acl_query(hapd, addr, query)) {
|
||||
wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
|
||||
"for ACL query.");
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Failed to send Access-Request for ACL query.");
|
||||
hostapd_acl_query_free(query);
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
}
|
||||
|
||||
query->auth_msg = os_memdup(msg, len);
|
||||
if (query->auth_msg == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
|
||||
"auth frame.");
|
||||
if (!query->auth_msg) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Failed to allocate memory for auth frame.");
|
||||
hostapd_acl_query_free(query);
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
}
|
||||
@ -392,7 +429,7 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
|
||||
* Passphrase is NULL iff there is no i-th Tunnel-Password
|
||||
* attribute in msg.
|
||||
*/
|
||||
if (passphrase == NULL)
|
||||
if (!passphrase)
|
||||
break;
|
||||
|
||||
/*
|
||||
@ -464,28 +501,32 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||
prev = query;
|
||||
query = query->next;
|
||||
}
|
||||
if (query == NULL)
|
||||
if (!query)
|
||||
return RADIUS_RX_UNKNOWN;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
|
||||
"message (id=%d)", query->radius_id);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Found matching Access-Request for RADIUS message (id=%d)",
|
||||
query->radius_id);
|
||||
|
||||
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
|
||||
wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
|
||||
"correct authenticator - dropped\n");
|
||||
if (radius_msg_verify(
|
||||
msg, shared_secret, shared_secret_len, req,
|
||||
hapd->conf->radius_require_message_authenticator)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Incoming RADIUS packet did not have correct authenticator - dropped");
|
||||
return RADIUS_RX_INVALID_AUTHENTICATOR;
|
||||
}
|
||||
|
||||
if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
|
||||
hdr->code != RADIUS_CODE_ACCESS_REJECT) {
|
||||
wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
|
||||
"query", hdr->code);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Unknown RADIUS message code %d to ACL query",
|
||||
hdr->code);
|
||||
return RADIUS_RX_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Insert Accept/Reject info into ACL cache */
|
||||
cache = os_zalloc(sizeof(*cache));
|
||||
if (cache == NULL) {
|
||||
if (!cache) {
|
||||
wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
|
||||
goto done;
|
||||
}
|
||||
@ -506,8 +547,9 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||
msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
|
||||
&info->acct_interim_interval) == 0 &&
|
||||
info->acct_interim_interval < 60) {
|
||||
wpa_printf(MSG_DEBUG, "Ignored too small "
|
||||
"Acct-Interim-Interval %d for STA " MACSTR,
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Ignored too small Acct-Interim-Interval %d for STA "
|
||||
MACSTR,
|
||||
info->acct_interim_interval,
|
||||
MAC2STR(query->addr));
|
||||
info->acct_interim_interval = 0;
|
||||
@ -557,20 +599,44 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||
cache->next = hapd->acl_cache;
|
||||
hapd->acl_cache = cache;
|
||||
|
||||
if (query->radius_psk) {
|
||||
struct sta_info *sta;
|
||||
bool success = cache->accepted == HOSTAPD_ACL_ACCEPT ||
|
||||
cache->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT;
|
||||
|
||||
sta = ap_get_sta(hapd, query->addr);
|
||||
if (!sta || !sta->wpa_sm) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"No STA/SM entry found for the RADIUS PSK response");
|
||||
goto done;
|
||||
}
|
||||
#ifdef NEED_AP_MLME
|
||||
if (success &&
|
||||
(ieee802_11_set_radius_info(hapd, sta, cache->accepted,
|
||||
info) < 0 ||
|
||||
ap_sta_bind_vlan(hapd, sta) < 0))
|
||||
success = false;
|
||||
#endif /* NEED_AP_MLME */
|
||||
wpa_auth_sta_radius_psk_resp(sta->wpa_sm, success);
|
||||
} else {
|
||||
#ifdef CONFIG_DRIVER_RADIUS_ACL
|
||||
hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
|
||||
info->session_timeout);
|
||||
hostapd_drv_set_radius_acl_auth(hapd, query->addr,
|
||||
cache->accepted,
|
||||
info->session_timeout);
|
||||
#else /* CONFIG_DRIVER_RADIUS_ACL */
|
||||
#ifdef NEED_AP_MLME
|
||||
/* Re-send original authentication frame for 802.11 processing */
|
||||
wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
|
||||
"successful RADIUS ACL query");
|
||||
ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL);
|
||||
/* Re-send original authentication frame for 802.11 processing
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Re-sending authentication frame after successful RADIUS ACL query");
|
||||
ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len,
|
||||
NULL);
|
||||
#endif /* NEED_AP_MLME */
|
||||
#endif /* CONFIG_DRIVER_RADIUS_ACL */
|
||||
}
|
||||
|
||||
done:
|
||||
if (prev == NULL)
|
||||
if (!prev)
|
||||
hapd->acl_queries = query->next;
|
||||
else
|
||||
prev->next = query->next;
|
||||
@ -646,6 +712,40 @@ void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
|
||||
while (psk) {
|
||||
struct hostapd_sta_wpa_psk_short *prev = psk;
|
||||
psk = psk->next;
|
||||
os_free(prev);
|
||||
bin_clear_free(prev, sizeof(*prev));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr,
|
||||
int key_mgmt, const u8 *anonce,
|
||||
const u8 *eapol, size_t eapol_len)
|
||||
{
|
||||
struct hostapd_acl_query_data *query;
|
||||
|
||||
query = os_zalloc(sizeof(*query));
|
||||
if (!query)
|
||||
return;
|
||||
|
||||
query->radius_psk = true;
|
||||
query->akm = key_mgmt;
|
||||
os_get_reltime(&query->timestamp);
|
||||
os_memcpy(query->addr, addr, ETH_ALEN);
|
||||
if (anonce)
|
||||
query->anonce = os_memdup(anonce, WPA_NONCE_LEN);
|
||||
if (eapol) {
|
||||
query->eapol = os_memdup(eapol, eapol_len);
|
||||
query->eapol_len = eapol_len;
|
||||
}
|
||||
if (hostapd_radius_acl_query(hapd, addr, query)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Failed to send Access-Request for RADIUS PSK/ACL query");
|
||||
hostapd_acl_query_free(query);
|
||||
return;
|
||||
}
|
||||
|
||||
query->next = hapd->acl_queries;
|
||||
hapd->acl_queries = query;
|
||||
}
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11 authentication (ACL)
|
||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -36,5 +36,8 @@ void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
|
||||
void hostapd_acl_expire(struct hostapd_data *hapd);
|
||||
void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
|
||||
struct hostapd_sta_wpa_psk_short *src);
|
||||
void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr,
|
||||
int key_mgmt, const u8 *anonce,
|
||||
const u8 *eapol, size_t eapol_len);
|
||||
|
||||
#endif /* IEEE802_11_AUTH_H */
|
||||
|
1405
contrib/wpa/src/ap/ieee802_11_eht.c
Normal file
1405
contrib/wpa/src/ap/ieee802_11_eht.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,7 @@
|
||||
#include "utils/common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "common/hw_features_common.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "beacon.h"
|
||||
@ -29,17 +30,19 @@ static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
|
||||
|
||||
ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) &
|
||||
HE_PPE_THRES_RU_INDEX_BITMASK_MASK;
|
||||
/* Count the number of 1 bits in RU Index Bitmask */
|
||||
while (ru) {
|
||||
if (ru & 0x1)
|
||||
sz++;
|
||||
ru >>= 1;
|
||||
}
|
||||
|
||||
/* fixed header of 3 (NSTS) + 4 (RU Index Bitmask) = 7 bits */
|
||||
/* 6 * (NSTS + 1) bits for bit 1 in RU Index Bitmask */
|
||||
sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK);
|
||||
sz = (sz * 6) + 7;
|
||||
if (sz % 8)
|
||||
sz += 8;
|
||||
sz /= 8;
|
||||
/* PPE Pad to count the number of needed full octets */
|
||||
sz = (sz + 7) / 8;
|
||||
|
||||
return sz;
|
||||
}
|
||||
@ -64,6 +67,7 @@ static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len)
|
||||
{
|
||||
struct ieee80211_he_capabilities *cap;
|
||||
size_t cap_len;
|
||||
u8 ppe_thres_hdr;
|
||||
|
||||
cap = (struct ieee80211_he_capabilities *) buf;
|
||||
cap_len = sizeof(*cap) - sizeof(cap->optional);
|
||||
@ -74,9 +78,11 @@ static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len)
|
||||
if (len < cap_len)
|
||||
return 1;
|
||||
|
||||
cap_len += ieee80211_he_ppet_size(buf[cap_len], cap->he_phy_capab_info);
|
||||
ppe_thres_hdr = len > cap_len ? buf[cap_len] : 0xff;
|
||||
cap_len += ieee80211_he_ppet_size(ppe_thres_hdr,
|
||||
cap->he_phy_capab_info);
|
||||
|
||||
return len != cap_len;
|
||||
return len < cap_len;
|
||||
}
|
||||
|
||||
|
||||
@ -97,20 +103,22 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
|
||||
mode->he_capab[opmode].phy_cap);
|
||||
|
||||
switch (hapd->iface->conf->he_oper_chwidth) {
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
case CONF_OPER_CHWIDTH_80P80MHZ:
|
||||
he_oper_chwidth |=
|
||||
HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G;
|
||||
mcs_nss_size += 4;
|
||||
/* fall through */
|
||||
case CHANWIDTH_160MHZ:
|
||||
case CONF_OPER_CHWIDTH_160MHZ:
|
||||
he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
|
||||
mcs_nss_size += 4;
|
||||
/* fall through */
|
||||
case CHANWIDTH_80MHZ:
|
||||
case CHANWIDTH_USE_HT:
|
||||
case CONF_OPER_CHWIDTH_80MHZ:
|
||||
case CONF_OPER_CHWIDTH_USE_HT:
|
||||
he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
|
||||
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ie_size += mcs_nss_size + ppet_size;
|
||||
@ -195,7 +203,8 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
if (hapd->iface->conf->he_op.he_er_su_disable)
|
||||
params |= HE_OPERATION_ER_SU_DISABLE;
|
||||
|
||||
if (hapd->iface->conf->he_op.he_bss_color_disabled)
|
||||
if (hapd->iface->conf->he_op.he_bss_color_disabled ||
|
||||
hapd->cca_in_progress)
|
||||
params |= HE_OPERATION_BSS_COLOR_DISABLED;
|
||||
if (hapd->iface->conf->he_op.he_bss_color_partial)
|
||||
params |= HE_OPERATION_BSS_COLOR_PARTIAL;
|
||||
@ -211,8 +220,20 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
pos += 6; /* skip the fixed part */
|
||||
|
||||
if (is_6ghz_op_class(hapd->iconf->op_class)) {
|
||||
u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
|
||||
enum oper_chan_width oper_chwidth =
|
||||
hostapd_get_oper_chwidth(hapd->iconf);
|
||||
u8 seg0 = hapd->iconf->he_oper_centr_freq_seg0_idx;
|
||||
u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
|
||||
u8 control;
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
u16 punct_bitmap = hostapd_get_punct_bitmap(hapd);
|
||||
|
||||
if (punct_bitmap) {
|
||||
punct_update_legacy_bw(punct_bitmap,
|
||||
hapd->iconf->channel,
|
||||
&oper_chwidth, &seg0, &seg1);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
if (!seg0)
|
||||
seg0 = hapd->iconf->channel;
|
||||
@ -220,19 +241,30 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
params |= HE_OPERATION_6GHZ_OPER_INFO;
|
||||
|
||||
/* 6 GHz Operation Information field
|
||||
* IEEE P802.11ax/D8.0, 9.4.2.249 HE Operation element,
|
||||
* IEEE Std 802.11ax-2021, 9.4.2.249 HE Operation element,
|
||||
* Figure 9-788k
|
||||
*/
|
||||
*pos++ = hapd->iconf->channel; /* Primary Channel */
|
||||
|
||||
/* Control: Channel Width */
|
||||
/* Control:
|
||||
* bits 0-1: Channel Width
|
||||
* bit 2: Duplicate Beacon
|
||||
* bits 3-5: Regulatory Info
|
||||
*/
|
||||
/* Channel Width */
|
||||
if (seg1)
|
||||
*pos++ = 3;
|
||||
control = 3;
|
||||
else
|
||||
*pos++ = center_idx_to_bw_6ghz(seg0);
|
||||
control = center_idx_to_bw_6ghz(seg0);
|
||||
|
||||
control |= hapd->iconf->he_6ghz_reg_pwr_type <<
|
||||
HE_6GHZ_OPER_INFO_CTRL_REG_INFO_SHIFT;
|
||||
|
||||
*pos++ = control;
|
||||
|
||||
/* Channel Center Freq Seg0/Seg1 */
|
||||
if (hapd->iconf->he_oper_chwidth == 2) {
|
||||
if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
|
||||
oper_chwidth == CONF_OPER_CHWIDTH_320MHZ) {
|
||||
/*
|
||||
* Seg 0 indicates the channel center frequency index of
|
||||
* the 160 MHz channel.
|
||||
@ -411,10 +443,10 @@ static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab,
|
||||
* band/stream cases.
|
||||
*/
|
||||
switch (hapd->iface->conf->he_oper_chwidth) {
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
case CONF_OPER_CHWIDTH_80P80MHZ:
|
||||
mcs_count = 3;
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
case CONF_OPER_CHWIDTH_160MHZ:
|
||||
mcs_count = 2;
|
||||
break;
|
||||
default:
|
||||
@ -512,7 +544,8 @@ int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
|
||||
u8 *mac_cap;
|
||||
|
||||
if (!hapd->iface->current_mode ||
|
||||
!hapd->iface->current_mode->he_capab[mode].he_supported)
|
||||
!hapd->iface->current_mode->he_capab[mode].he_supported ||
|
||||
!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax)
|
||||
return 0;
|
||||
|
||||
mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap;
|
||||
@ -520,3 +553,19 @@ int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
|
||||
return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER) &&
|
||||
hapd->iface->conf->he_op.he_twt_responder;
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
if (!hapd->cca_in_progress)
|
||||
return eid;
|
||||
|
||||
/* BSS Color Change Announcement element */
|
||||
*eid++ = WLAN_EID_EXTENSION;
|
||||
*eid++ = 3;
|
||||
*eid++ = WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT;
|
||||
*eid++ = hapd->cca_count; /* Color Switch Countdown */
|
||||
*eid++ = hapd->cca_color; /* New BSS Color Information */
|
||||
|
||||
return eid;
|
||||
}
|
||||
|
@ -479,15 +479,14 @@ static void update_sta_no_ht(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
}
|
||||
|
||||
|
||||
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
int update_ht_state(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities)
|
||||
update_sta_ht(hapd, sta);
|
||||
else
|
||||
update_sta_no_ht(hapd, sta);
|
||||
|
||||
if (hostapd_ht_operation_update(hapd->iface) > 0)
|
||||
ieee802_11_set_beacons(hapd->iface);
|
||||
return hostapd_ht_operation_update(hapd->iface);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11 Management
|
||||
* Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2024, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -17,19 +17,29 @@
|
||||
#include "ap_config.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "dpp_hostapd.h"
|
||||
#include "ieee802_11.h"
|
||||
|
||||
|
||||
static u8 * hostapd_eid_timeout_interval(u8 *pos, u8 type, u32 value)
|
||||
{
|
||||
*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
|
||||
*pos++ = 5;
|
||||
*pos++ = type;
|
||||
WPA_PUT_LE32(pos, value);
|
||||
pos += 4;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u8 *eid)
|
||||
{
|
||||
u8 *pos = eid;
|
||||
u32 timeout, tu;
|
||||
struct os_reltime now, passed;
|
||||
u8 type = WLAN_TIMEOUT_ASSOC_COMEBACK;
|
||||
|
||||
*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
|
||||
*pos++ = 5;
|
||||
*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
|
||||
os_get_reltime(&now);
|
||||
os_reltime_sub(&now, &sta->sa_query_start, &passed);
|
||||
tu = (passed.sec * 1000000 + passed.usec) / 1024;
|
||||
@ -39,10 +49,12 @@ u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
|
||||
timeout = 0;
|
||||
if (timeout < hapd->conf->assoc_sa_query_max_timeout)
|
||||
timeout++; /* add some extra time for local timers */
|
||||
WPA_PUT_LE32(pos, timeout);
|
||||
pos += 4;
|
||||
|
||||
return pos;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (hapd->conf->test_assoc_comeback_type != -1)
|
||||
type = hapd->conf->test_assoc_comeback_type;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
return hostapd_eid_timeout_interval(eid, type, timeout);
|
||||
}
|
||||
|
||||
|
||||
@ -50,13 +62,14 @@ u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
|
||||
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
|
||||
const u8 *addr, const u8 *trans_id)
|
||||
{
|
||||
#ifdef CONFIG_OCV
|
||||
struct sta_info *sta;
|
||||
#endif /* CONFIG_OCV */
|
||||
#if defined(CONFIG_OCV) || defined(CONFIG_IEEE80211BE)
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
#endif /* CONFIG_OCV || CONFIG_IEEE80211BE */
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u8 *oci_ie = NULL;
|
||||
u8 oci_ie_len = 0;
|
||||
u8 *end;
|
||||
const u8 *own_addr = hapd->own_addr;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
|
||||
MACSTR, MAC2STR(addr));
|
||||
@ -64,7 +77,6 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
|
||||
trans_id, WLAN_SA_QUERY_TR_ID_LEN);
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
|
||||
struct wpa_channel_info ci;
|
||||
|
||||
@ -107,11 +119,16 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (ap_sta_is_mld(hapd, sta))
|
||||
own_addr = hapd->mld->mld_addr;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
os_memcpy(mgmt->da, addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, own_addr, ETH_ALEN);
|
||||
mgmt->u.action.category = WLAN_ACTION_SA_QUERY;
|
||||
mgmt->u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
|
||||
os_memcpy(mgmt->u.action.u.sa_query_req.trans_id, trans_id,
|
||||
@ -140,6 +157,7 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
|
||||
u8 *oci_ie = NULL;
|
||||
u8 oci_ie_len = 0;
|
||||
u8 *end;
|
||||
const u8 *own_addr = hapd->own_addr;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
|
||||
MACSTR, MAC2STR(sa));
|
||||
@ -199,11 +217,16 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
|
||||
MACSTR, MAC2STR(sa));
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (ap_sta_is_mld(hapd, sta))
|
||||
own_addr = hapd->mld->mld_addr;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
os_memcpy(resp->da, sa, ETH_ALEN);
|
||||
os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(resp->sa, own_addr, ETH_ALEN);
|
||||
os_memcpy(resp->bssid, own_addr, ETH_ALEN);
|
||||
resp->u.action.category = WLAN_ACTION_SA_QUERY;
|
||||
resp->u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
|
||||
os_memcpy(resp->u.action.u.sa_query_req.trans_id, trans_id,
|
||||
@ -339,7 +362,8 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx,
|
||||
bool mbssid_complete)
|
||||
{
|
||||
*pos = 0x00;
|
||||
|
||||
@ -363,6 +387,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
|
||||
if (hapd->conf->bss_transition)
|
||||
*pos |= 0x08; /* Bit 19 - BSS Transition */
|
||||
if (hapd->iconf->mbssid)
|
||||
*pos |= 0x40; /* Bit 22 - Multiple BSSID */
|
||||
break;
|
||||
case 3: /* Bits 24-31 */
|
||||
#ifdef CONFIG_WNM_AP
|
||||
@ -412,10 +438,11 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
*pos |= 0x01;
|
||||
#endif /* CONFIG_FILS */
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax &&
|
||||
hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
|
||||
if (hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
|
||||
*pos |= 0x40; /* Bit 78 - TWT responder */
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
if (hostapd_get_ht_vht_twt_responder(hapd))
|
||||
*pos |= 0x40; /* Bit 78 - TWT responder */
|
||||
break;
|
||||
case 10: /* Bits 80-87 */
|
||||
#ifdef CONFIG_SAE
|
||||
@ -435,6 +462,11 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
(hapd->iface->drv_flags &
|
||||
WPA_DRIVER_FLAGS_BEACON_PROTECTION))
|
||||
*pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
|
||||
if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED)
|
||||
*pos |= 0x08; /* Bit 83 - Enhanced multiple BSSID */
|
||||
if (mbssid_complete)
|
||||
*pos |= 0x01; /* Bit 80 - Complete List of NonTxBSSID
|
||||
* Profiles */
|
||||
break;
|
||||
case 11: /* Bits 88-95 */
|
||||
#ifdef CONFIG_SAE_PK
|
||||
@ -448,7 +480,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid,
|
||||
bool mbssid_complete)
|
||||
{
|
||||
u8 *pos = eid;
|
||||
u8 len = EXT_CAPA_MAX_LEN, i;
|
||||
@ -459,7 +492,7 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||
*pos++ = WLAN_EID_EXT_CAPAB;
|
||||
*pos++ = len;
|
||||
for (i = 0; i < len; i++, pos++) {
|
||||
hostapd_ext_capab_byte(hapd, pos, i);
|
||||
hostapd_ext_capab_byte(hapd, pos, i, mbssid_complete);
|
||||
|
||||
if (i < hapd->iface->extended_capa_len) {
|
||||
*pos &= ~hapd->iface->extended_capa_mask[i];
|
||||
@ -470,6 +503,13 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||
*pos &= ~hapd->conf->ext_capa_mask[i];
|
||||
*pos |= hapd->conf->ext_capa[i];
|
||||
}
|
||||
|
||||
/* Clear bits 83 and 22 if EMA and MBSSID are not enabled
|
||||
* otherwise association fails with some clients */
|
||||
if (i == 10 && hapd->iconf->mbssid < ENHANCED_MBSSID_ENABLED)
|
||||
*pos &= ~0x08;
|
||||
if (i == 2 && !hapd->iconf->mbssid)
|
||||
*pos &= ~0x40;
|
||||
}
|
||||
|
||||
while (len > 0 && eid[1 + len] == 0) {
|
||||
@ -697,12 +737,14 @@ int hostapd_update_time_adv(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
|
||||
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid,
|
||||
u16 value)
|
||||
{
|
||||
u8 *pos = eid;
|
||||
|
||||
#ifdef CONFIG_WNM_AP
|
||||
if (hapd->conf->ap_max_inactivity > 0) {
|
||||
if (hapd->conf->ap_max_inactivity > 0 &&
|
||||
hapd->conf->bss_max_idle) {
|
||||
unsigned int val;
|
||||
*pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
|
||||
*pos++ = 3;
|
||||
@ -715,9 +757,13 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
|
||||
val = 1;
|
||||
if (val > 65535)
|
||||
val = 65535;
|
||||
if (value)
|
||||
val = value;
|
||||
WPA_PUT_LE16(pos, val);
|
||||
pos += 2;
|
||||
*pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
|
||||
/* Set the Protected Keep-Alive Required bit based on
|
||||
* configuration */
|
||||
*pos++ = hapd->conf->bss_max_idle == 2 ? BIT(0) : 0x00;
|
||||
}
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
|
||||
@ -873,7 +919,7 @@ u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid,
|
||||
size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifdef CONFIG_DPP2
|
||||
if (hapd->conf->dpp_configurator_connectivity)
|
||||
if (hostapd_dpp_configurator_connectivity(hapd))
|
||||
return 6;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
return 0;
|
||||
@ -885,7 +931,7 @@ u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
u8 *pos = eid;
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
if (!hapd->conf->dpp_configurator_connectivity || len < 6)
|
||||
if (!hostapd_dpp_configurator_connectivity(hapd) || len < 6)
|
||||
return pos;
|
||||
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
@ -998,7 +1044,7 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
|
||||
* If a VHT Operation element was present, use it to determine
|
||||
* the supported channel bandwidth.
|
||||
*/
|
||||
if (oper->vht_op_info_chwidth == 0) {
|
||||
if (oper->vht_op_info_chwidth == CHANWIDTH_USE_HT) {
|
||||
requested_bw = ht_40mhz ? 40 : 20;
|
||||
} else if (oper->vht_op_info_chan_center_freq_seg1_idx == 0) {
|
||||
requested_bw = 80;
|
||||
@ -1051,7 +1097,7 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
{
|
||||
u8 *pos = eid;
|
||||
bool sae_pk = false;
|
||||
u16 capab = 0;
|
||||
u32 capab = 0, tmp;
|
||||
size_t flen;
|
||||
|
||||
if (!(hapd->conf->wpa & WPA_PROTO_RSN))
|
||||
@ -1062,9 +1108,11 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
|
||||
if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
|
||||
(hapd->conf->sae_pwe == 1 || hapd->conf->sae_pwe == 2 ||
|
||||
hostapd_sae_pw_id_in_use(hapd->conf) || sae_pk) &&
|
||||
hapd->conf->sae_pwe != 3) {
|
||||
(hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
|
||||
hapd->conf->sae_pwe == SAE_PWE_BOTH ||
|
||||
hostapd_sae_pw_id_in_use(hapd->conf) || sae_pk ||
|
||||
wpa_key_mgmt_sae_ext_key(hapd->conf->wpa_key_mgmt)) &&
|
||||
hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK) {
|
||||
capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
|
||||
#ifdef CONFIG_SAE_PK
|
||||
if (sae_pk)
|
||||
@ -1072,24 +1120,109 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
}
|
||||
|
||||
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF)
|
||||
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP)
|
||||
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
|
||||
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT)
|
||||
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_AP)
|
||||
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
|
||||
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG)
|
||||
capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
|
||||
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP)
|
||||
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
|
||||
if (hapd->conf->ssid_protection)
|
||||
capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION);
|
||||
|
||||
flen = (capab & 0xff00) ? 2 : 1;
|
||||
if (len < 2 + flen || !capab)
|
||||
if (!capab)
|
||||
return eid; /* no supported extended RSN capabilities */
|
||||
tmp = capab;
|
||||
flen = 0;
|
||||
while (tmp) {
|
||||
flen++;
|
||||
tmp >>= 8;
|
||||
}
|
||||
|
||||
if (len < 2 + flen)
|
||||
return eid; /* no supported extended RSN capabilities */
|
||||
capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
|
||||
|
||||
*pos++ = WLAN_EID_RSNX;
|
||||
*pos++ = flen;
|
||||
*pos++ = capab & 0x00ff;
|
||||
capab >>= 8;
|
||||
if (capab)
|
||||
*pos++ = capab;
|
||||
while (capab) {
|
||||
*pos++ = capab & 0xff;
|
||||
capab >>= 8;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ext_capab_ie, size_t ext_capab_ie_len)
|
||||
{
|
||||
/* check for QoS Map support */
|
||||
if (ext_capab_ie_len >= 5) {
|
||||
if (ext_capab_ie[4] & 0x01)
|
||||
sta->qos_map_enabled = 1;
|
||||
}
|
||||
|
||||
if (ext_capab_ie_len > 0) {
|
||||
sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
|
||||
os_free(sta->ext_capability);
|
||||
sta->ext_capability = os_malloc(1 + ext_capab_ie_len);
|
||||
if (sta->ext_capability) {
|
||||
sta->ext_capability[0] = ext_capab_ie_len;
|
||||
os_memcpy(sta->ext_capability + 1, ext_capab_ie,
|
||||
ext_capab_ie_len);
|
||||
}
|
||||
}
|
||||
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
struct sta_info * hostapd_ml_get_assoc_sta(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
struct hostapd_data **assoc_hapd)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
struct hostapd_data *other_hapd = NULL;
|
||||
struct sta_info *tmp_sta;
|
||||
|
||||
if (!ap_sta_is_mld(hapd, sta))
|
||||
return NULL;
|
||||
|
||||
*assoc_hapd = hapd;
|
||||
|
||||
/* The station is the one on which the association was performed */
|
||||
if (sta->mld_assoc_link_id == hapd->mld_link_id)
|
||||
return sta;
|
||||
|
||||
other_hapd = hostapd_mld_get_link_bss(hapd, sta->mld_assoc_link_id);
|
||||
if (!other_hapd) {
|
||||
wpa_printf(MSG_DEBUG, "MLD: No link match for link_id=%u",
|
||||
sta->mld_assoc_link_id);
|
||||
return sta;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over the stations and find the one with the matching link ID
|
||||
* and association ID.
|
||||
*/
|
||||
for (tmp_sta = other_hapd->sta_list; tmp_sta; tmp_sta = tmp_sta->next) {
|
||||
if (tmp_sta->mld_assoc_link_id == sta->mld_assoc_link_id &&
|
||||
tmp_sta->aid == sta->aid) {
|
||||
*assoc_hapd = other_hapd;
|
||||
return tmp_sta;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
return sta;
|
||||
}
|
||||
|
||||
|
||||
bool hostapd_get_ht_vht_twt_responder(struct hostapd_data *hapd)
|
||||
{
|
||||
return hapd->iconf->ht_vht_twt_responder &&
|
||||
((hapd->iconf->ieee80211n && !hapd->conf->disable_11n) ||
|
||||
(hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac)) &&
|
||||
(hapd->iface->drv_flags2 &
|
||||
WPA_DRIVER_FLAGS2_HT_VHT_TWT_RESPONDER);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/hw_features_common.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "sta_info.h"
|
||||
@ -75,6 +76,13 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
struct ieee80211_vht_operation *oper;
|
||||
u8 *pos = eid;
|
||||
enum oper_chan_width oper_chwidth =
|
||||
hostapd_get_oper_chwidth(hapd->iconf);
|
||||
u8 seg0 = hapd->iconf->vht_oper_centr_freq_seg0_idx;
|
||||
u8 seg1 = hapd->iconf->vht_oper_centr_freq_seg1_idx;
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
u16 punct_bitmap = hostapd_get_punct_bitmap(hapd);
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
if (is_6ghz_op_class(hapd->iconf->op_class))
|
||||
return eid;
|
||||
@ -85,23 +93,29 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
oper = (struct ieee80211_vht_operation *) pos;
|
||||
os_memset(oper, 0, sizeof(*oper));
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (punct_bitmap) {
|
||||
punct_update_legacy_bw(punct_bitmap,
|
||||
hapd->iconf->channel,
|
||||
&oper_chwidth, &seg0, &seg1);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
/*
|
||||
* center freq = 5 GHz + (5 * index)
|
||||
* So index 42 gives center freq 5.210 GHz
|
||||
* which is channel 42 in 5G band
|
||||
*/
|
||||
oper->vht_op_info_chan_center_freq_seg0_idx =
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx;
|
||||
oper->vht_op_info_chan_center_freq_seg1_idx =
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx;
|
||||
oper->vht_op_info_chan_center_freq_seg0_idx = seg0;
|
||||
oper->vht_op_info_chan_center_freq_seg1_idx = seg1;
|
||||
|
||||
oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
|
||||
if (hapd->iconf->vht_oper_chwidth == 2) {
|
||||
oper->vht_op_info_chwidth = oper_chwidth;
|
||||
if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) {
|
||||
/*
|
||||
* Convert 160 MHz channel width to new style as interop
|
||||
* workaround.
|
||||
*/
|
||||
oper->vht_op_info_chwidth = 1;
|
||||
oper->vht_op_info_chwidth = CHANWIDTH_80MHZ;
|
||||
oper->vht_op_info_chan_center_freq_seg1_idx =
|
||||
oper->vht_op_info_chan_center_freq_seg0_idx;
|
||||
if (hapd->iconf->channel <
|
||||
@ -109,12 +123,12 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
oper->vht_op_info_chan_center_freq_seg0_idx -= 8;
|
||||
else
|
||||
oper->vht_op_info_chan_center_freq_seg0_idx += 8;
|
||||
} else if (hapd->iconf->vht_oper_chwidth == 3) {
|
||||
} else if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) {
|
||||
/*
|
||||
* Convert 80+80 MHz channel width to new style as interop
|
||||
* workaround.
|
||||
*/
|
||||
oper->vht_op_info_chwidth = 1;
|
||||
oper->vht_op_info_chwidth = CHANWIDTH_80MHZ;
|
||||
}
|
||||
|
||||
/* VHT Basic MCS set comes from hw */
|
||||
|
@ -43,9 +43,9 @@
|
||||
#ifdef CONFIG_HS20
|
||||
static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx);
|
||||
#endif /* CONFIG_HS20 */
|
||||
static void ieee802_1x_finished(struct hostapd_data *hapd,
|
||||
static bool ieee802_1x_finished(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int success,
|
||||
int remediation);
|
||||
int remediation, bool logoff);
|
||||
|
||||
|
||||
static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
@ -95,39 +95,46 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
if (sta->flags & WLAN_STA_PREAUTH) {
|
||||
rsn_preauth_send(hapd, sta, buf, len);
|
||||
} else {
|
||||
int link_id = -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
link_id = hapd->conf->mld_ap ? hapd->mld_link_id : -1;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
hostapd_drv_hapd_send_eapol(
|
||||
hapd, sta->addr, buf, len,
|
||||
encrypt, hostapd_sta_flags_to_drv(sta->flags));
|
||||
encrypt, hostapd_sta_flags_to_drv(sta->flags), link_id);
|
||||
}
|
||||
|
||||
os_free(buf);
|
||||
}
|
||||
|
||||
|
||||
void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int authorized)
|
||||
static void ieee802_1x_set_authorized(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
bool authorized, bool mld)
|
||||
{
|
||||
int res;
|
||||
bool update;
|
||||
|
||||
if (sta->flags & WLAN_STA_PREAUTH)
|
||||
return;
|
||||
|
||||
if (authorized) {
|
||||
ap_sta_set_authorized(hapd, sta, 1);
|
||||
res = hostapd_set_authorized(hapd, sta, 1);
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_DEBUG, "authorizing port");
|
||||
} else {
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
res = hostapd_set_authorized(hapd, sta, 0);
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_DEBUG, "unauthorizing port");
|
||||
}
|
||||
update = ap_sta_set_authorized_flag(hapd, sta, authorized);
|
||||
res = hostapd_set_authorized(hapd, sta, authorized);
|
||||
if (update)
|
||||
ap_sta_set_authorized_event(hapd, sta, authorized);
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_DEBUG, "%sauthorizing port",
|
||||
authorized ? "" : "un");
|
||||
|
||||
if (res && errno != ENOENT) {
|
||||
if (!mld && res && errno != ENOENT) {
|
||||
wpa_printf(MSG_DEBUG, "Could not set station " MACSTR
|
||||
" flags for kernel driver (errno=%d).",
|
||||
MAC2STR(sta->addr), errno);
|
||||
} else if (mld && res) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MLD: Could not set station " MACSTR " flags",
|
||||
MAC2STR(sta->addr));
|
||||
}
|
||||
|
||||
if (authorized) {
|
||||
@ -137,6 +144,64 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void ieee802_1x_ml_set_sta_authorized(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
bool authorized)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
unsigned int i, link_id;
|
||||
|
||||
if (!hostapd_is_mld_ap(hapd))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Authorizing the station should be done only in the station
|
||||
* performing the association
|
||||
*/
|
||||
if (authorized && hapd->mld_link_id != sta->mld_assoc_link_id)
|
||||
return;
|
||||
|
||||
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
|
||||
struct mld_link_info *link = &sta->mld_info.links[link_id];
|
||||
|
||||
if (!link->valid)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < hapd->iface->interfaces->count; i++) {
|
||||
struct sta_info *tmp_sta;
|
||||
struct hostapd_data *tmp_hapd =
|
||||
hapd->iface->interfaces->iface[i]->bss[0];
|
||||
|
||||
if (!hostapd_is_ml_partner(hapd, tmp_hapd))
|
||||
continue;
|
||||
|
||||
for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
|
||||
tmp_sta = tmp_sta->next) {
|
||||
if (tmp_sta == sta ||
|
||||
tmp_sta->mld_assoc_link_id !=
|
||||
sta->mld_assoc_link_id ||
|
||||
tmp_sta->aid != sta->aid)
|
||||
continue;
|
||||
|
||||
ieee802_1x_set_authorized(tmp_hapd, tmp_sta,
|
||||
authorized, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int authorized)
|
||||
{
|
||||
ieee802_1x_set_authorized(hapd, sta, authorized, false);
|
||||
ieee802_1x_ml_set_sta_authorized(hapd, sta, !!authorized);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
#ifndef CONFIG_FIPS
|
||||
#ifndef CONFIG_NO_RC4
|
||||
@ -702,6 +767,9 @@ void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!radius_msg_add_msg_auth(msg))
|
||||
goto fail;
|
||||
|
||||
if (sm->identity &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
|
||||
sm->identity, sm->identity_len)) {
|
||||
@ -998,7 +1066,7 @@ ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
|
||||
|
||||
static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
|
||||
size_t len)
|
||||
size_t len, enum frame_encryption encrypted)
|
||||
{
|
||||
if (sta->pending_eapol_rx) {
|
||||
wpabuf_free(sta->pending_eapol_rx->buf);
|
||||
@ -1016,21 +1084,39 @@ static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
|
||||
return;
|
||||
}
|
||||
|
||||
sta->pending_eapol_rx->encrypted = encrypted;
|
||||
os_get_reltime(&sta->pending_eapol_rx->rx_time);
|
||||
}
|
||||
|
||||
|
||||
static bool ieee802_1x_check_encryption(struct sta_info *sta,
|
||||
enum frame_encryption encrypted,
|
||||
u8 type)
|
||||
{
|
||||
if (encrypted != FRAME_NOT_ENCRYPTED)
|
||||
return true;
|
||||
if (type != IEEE802_1X_TYPE_EAP_PACKET &&
|
||||
type != IEEE802_1X_TYPE_EAPOL_START &&
|
||||
type != IEEE802_1X_TYPE_EAPOL_LOGOFF)
|
||||
return true;
|
||||
if (!(sta->flags & WLAN_STA_MFP))
|
||||
return true;
|
||||
return !wpa_auth_pairwise_set(sta->wpa_sm);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ieee802_1x_receive - Process the EAPOL frames from the Supplicant
|
||||
* @hapd: hostapd BSS data
|
||||
* @sa: Source address (sender of the EAPOL frame)
|
||||
* @buf: EAPOL frame
|
||||
* @len: Length of buf in octets
|
||||
* @encrypted: Whether the frame was encrypted
|
||||
*
|
||||
* This function is called for each incoming EAPOL frame from the interface
|
||||
*/
|
||||
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
size_t len)
|
||||
size_t len, enum frame_encryption encrypted)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
struct ieee802_1x_hdr *hdr;
|
||||
@ -1043,8 +1129,9 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
!hapd->conf->wps_state)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
|
||||
(unsigned long) len, MAC2STR(sa));
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR
|
||||
" (encrypted=%d)",
|
||||
(unsigned long) len, MAC2STR(sa), encrypted);
|
||||
sta = ap_get_sta(hapd, sa);
|
||||
if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
|
||||
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
|
||||
@ -1054,7 +1141,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
if (sta && (sta->flags & WLAN_STA_AUTH)) {
|
||||
wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
|
||||
" for later use", MAC2STR(sta->addr));
|
||||
ieee802_1x_save_eapol(sta, buf, len);
|
||||
ieee802_1x_save_eapol(sta, buf, len, encrypted);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -1114,6 +1201,12 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ieee802_1x_check_encryption(sta, encrypted, hdr->type)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"IEEE 802.1X: Discard unencrypted EAPOL message - encryption was expected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sta->eapol_sm) {
|
||||
sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
|
||||
if (!sta->eapol_sm)
|
||||
@ -1684,23 +1777,35 @@ static void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len)
|
||||
|
||||
|
||||
static void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u8 *pos,
|
||||
struct sta_info *sta, const u8 *pos,
|
||||
size_t len)
|
||||
{
|
||||
size_t url_len;
|
||||
unsigned int timeout;
|
||||
|
||||
if (len < 3)
|
||||
return; /* Malformed information */
|
||||
url_len = len - 3;
|
||||
sta->hs20_deauth_requested = 1;
|
||||
sta->hs20_deauth_on_ack = url_len == 0;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"HS 2.0: Deauthentication request - Code %u Re-auth Delay %u",
|
||||
*pos, WPA_GET_LE16(pos + 1));
|
||||
"HS 2.0: Deauthentication request - Code %u Re-auth Delay %u URL length %zu",
|
||||
*pos, WPA_GET_LE16(pos + 1), url_len);
|
||||
wpabuf_free(sta->hs20_deauth_req);
|
||||
sta->hs20_deauth_req = wpabuf_alloc(len + 1);
|
||||
if (sta->hs20_deauth_req) {
|
||||
wpabuf_put_data(sta->hs20_deauth_req, pos, 3);
|
||||
wpabuf_put_u8(sta->hs20_deauth_req, len - 3);
|
||||
wpabuf_put_data(sta->hs20_deauth_req, pos + 3, len - 3);
|
||||
wpabuf_put_u8(sta->hs20_deauth_req, url_len);
|
||||
wpabuf_put_data(sta->hs20_deauth_req, pos + 3, url_len);
|
||||
}
|
||||
ap_sta_session_timeout(hapd, sta, hapd->conf->hs20_deauth_req_timeout);
|
||||
timeout = hapd->conf->hs20_deauth_req_timeout;
|
||||
/* If there is no URL, no need to provide time to fetch it. Use a short
|
||||
* timeout here to allow maximum time for completing 4-way handshake and
|
||||
* WNM-Notification delivery. Acknowledgement of the frame will result
|
||||
* in cutting this wait further. */
|
||||
if (!url_len && timeout > 2)
|
||||
timeout = 2;
|
||||
ap_sta_session_timeout(hapd, sta, timeout);
|
||||
}
|
||||
|
||||
|
||||
@ -1788,6 +1893,7 @@ static void ieee802_1x_check_hs20(struct hostapd_data *hapd,
|
||||
buf = NULL;
|
||||
sta->remediation = 0;
|
||||
sta->hs20_deauth_requested = 0;
|
||||
sta->hs20_deauth_on_ack = 0;
|
||||
|
||||
for (;;) {
|
||||
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
|
||||
@ -1936,16 +2042,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
}
|
||||
sta = sm->sta;
|
||||
|
||||
/* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
|
||||
* present when packet contains an EAP-Message attribute */
|
||||
if (hdr->code == RADIUS_CODE_ACCESS_REJECT &&
|
||||
radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
|
||||
0) < 0 &&
|
||||
radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Allowing RADIUS Access-Reject without Message-Authenticator since it does not include EAP-Message");
|
||||
} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
|
||||
req, 1)) {
|
||||
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 1)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
|
||||
return RADIUS_RX_INVALID_AUTHENTICATOR;
|
||||
@ -2249,16 +2346,18 @@ static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx,
|
||||
}
|
||||
|
||||
|
||||
static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
|
||||
int preauth, int remediation)
|
||||
static bool _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
|
||||
int preauth, int remediation, bool logoff)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta = sta_ctx;
|
||||
|
||||
if (preauth)
|
||||
if (preauth) {
|
||||
rsn_preauth_finished(hapd, sta, success);
|
||||
else
|
||||
ieee802_1x_finished(hapd, sta, success, remediation);
|
||||
return false;
|
||||
}
|
||||
|
||||
return ieee802_1x_finished(hapd, sta, success, remediation, logoff);
|
||||
}
|
||||
|
||||
|
||||
@ -2434,6 +2533,30 @@ int ieee802_1x_init(struct hostapd_data *hapd)
|
||||
struct eapol_auth_config conf;
|
||||
struct eapol_auth_cb cb;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (!hostapd_mld_is_first_bss(hapd)) {
|
||||
struct hostapd_data *first;
|
||||
|
||||
first = hostapd_mld_get_first_bss(hapd);
|
||||
if (!first)
|
||||
return -1;
|
||||
|
||||
if (!first->eapol_auth) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MLD: First BSS IEEE 802.1X state machine does not exist. Init on its behalf");
|
||||
|
||||
if (ieee802_1x_init(first))
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MLD: Using IEEE 802.1X state machine of the first BSS");
|
||||
|
||||
hapd->eapol_auth = first->eapol_auth;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
dl_list_init(&hapd->erp_keys);
|
||||
|
||||
os_memset(&conf, 0, sizeof(conf));
|
||||
@ -2448,6 +2571,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
|
||||
conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
|
||||
conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
|
||||
conf.erp_domain = hapd->conf->erp_domain;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
conf.eap_skip_prot_success = hapd->conf->eap_skip_prot_success;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
os_memset(&cb, 0, sizeof(cb));
|
||||
cb.eapol_send = ieee802_1x_eapol_send;
|
||||
@ -2515,6 +2641,16 @@ void ieee802_1x_erp_flush(struct hostapd_data *hapd)
|
||||
|
||||
void ieee802_1x_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (!hostapd_mld_is_first_bss(hapd)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MLD: Deinit IEEE 802.1X state machine of a non-first BSS");
|
||||
|
||||
hapd->eapol_auth = NULL;
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
|
||||
#endif /* CONFIG_WEP */
|
||||
@ -2936,9 +3072,9 @@ static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx)
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
|
||||
static void ieee802_1x_finished(struct hostapd_data *hapd,
|
||||
static bool ieee802_1x_finished(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int success,
|
||||
int remediation)
|
||||
int remediation, bool logoff)
|
||||
{
|
||||
const u8 *key;
|
||||
size_t len;
|
||||
@ -2998,6 +3134,11 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
|
||||
* EAP-FAST with anonymous provisioning, may require another
|
||||
* EAPOL authentication to be started to complete connection.
|
||||
*/
|
||||
ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta);
|
||||
ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta,
|
||||
logoff ? 0 : 10);
|
||||
if (logoff && sta->wpa_sm)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ struct radius_msg;
|
||||
|
||||
|
||||
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
size_t len);
|
||||
size_t len, enum frame_encryption encrypted);
|
||||
void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
|
||||
|
267
contrib/wpa/src/ap/nan_usd_ap.c
Normal file
267
contrib/wpa/src/ap/nan_usd_ap.c
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* NAN unsynchronized service discovery (USD)
|
||||
* Copyright (c) 2024, Qualcomm Innovation Center, Inc.
|
||||
*
|
||||
* 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/wpa_ctrl.h"
|
||||
#include "common/nan_de.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "nan_usd_ap.h"
|
||||
|
||||
|
||||
static int hostapd_nan_de_tx(void *ctx, unsigned int freq,
|
||||
unsigned int wait_time,
|
||||
const u8 *dst, const u8 *src, const u8 *bssid,
|
||||
const struct wpabuf *buf)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "NAN: TX NAN SDF A1=" MACSTR " A2=" MACSTR
|
||||
" A3=" MACSTR " len=%zu",
|
||||
MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
|
||||
wpabuf_len(buf));
|
||||
|
||||
/* TODO: Force use of OFDM */
|
||||
return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
|
||||
wpabuf_head(buf), wpabuf_len(buf));
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_nan_de_listen(void *ctx, unsigned int freq,
|
||||
unsigned int duration)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hostapd_nan_de_discovery_result(void *ctx, int subscribe_id,
|
||||
enum nan_service_protocol_type srv_proto_type,
|
||||
const u8 *ssi, size_t ssi_len,
|
||||
int peer_publish_id, const u8 *peer_addr,
|
||||
bool fsd, bool fsd_gas)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
char *ssi_hex;
|
||||
|
||||
ssi_hex = os_zalloc(2 * ssi_len + 1);
|
||||
if (!ssi_hex)
|
||||
return;
|
||||
if (ssi)
|
||||
wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_DISCOVERY_RESULT
|
||||
"subscribe_id=%d publish_id=%d address=" MACSTR
|
||||
" fsd=%d fsd_gas=%d srv_proto_type=%u ssi=%s",
|
||||
subscribe_id, peer_publish_id, MAC2STR(peer_addr),
|
||||
fsd, fsd_gas, srv_proto_type, ssi_hex);
|
||||
os_free(ssi_hex);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hostapd_nan_de_replied(void *ctx, int publish_id, const u8 *peer_addr,
|
||||
int peer_subscribe_id,
|
||||
enum nan_service_protocol_type srv_proto_type,
|
||||
const u8 *ssi, size_t ssi_len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
char *ssi_hex;
|
||||
|
||||
ssi_hex = os_zalloc(2 * ssi_len + 1);
|
||||
if (!ssi_hex)
|
||||
return;
|
||||
if (ssi)
|
||||
wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_REPLIED
|
||||
"publish_id=%d address=" MACSTR
|
||||
" subscribe_id=%d srv_proto_type=%u ssi=%s",
|
||||
publish_id, MAC2STR(peer_addr), peer_subscribe_id,
|
||||
srv_proto_type, ssi_hex);
|
||||
os_free(ssi_hex);
|
||||
}
|
||||
|
||||
|
||||
static const char * nan_reason_txt(enum nan_de_reason reason)
|
||||
{
|
||||
switch (reason) {
|
||||
case NAN_DE_REASON_TIMEOUT:
|
||||
return "timeout";
|
||||
case NAN_DE_REASON_USER_REQUEST:
|
||||
return "user-request";
|
||||
case NAN_DE_REASON_FAILURE:
|
||||
return "failure";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_nan_de_publish_terminated(void *ctx, int publish_id,
|
||||
enum nan_de_reason reason)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_PUBLISH_TERMINATED
|
||||
"publish_id=%d reason=%s",
|
||||
publish_id, nan_reason_txt(reason));
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_nan_de_subscribe_terminated(void *ctx, int subscribe_id,
|
||||
enum nan_de_reason reason)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_SUBSCRIBE_TERMINATED
|
||||
"subscribe_id=%d reason=%s",
|
||||
subscribe_id, nan_reason_txt(reason));
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_nan_de_receive(void *ctx, int id, int peer_instance_id,
|
||||
const u8 *ssi, size_t ssi_len,
|
||||
const u8 *peer_addr)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
char *ssi_hex;
|
||||
|
||||
ssi_hex = os_zalloc(2 * ssi_len + 1);
|
||||
if (!ssi_hex)
|
||||
return;
|
||||
if (ssi)
|
||||
wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_RECEIVE
|
||||
"id=%d peer_instance_id=%d address=" MACSTR " ssi=%s",
|
||||
id, peer_instance_id, MAC2STR(peer_addr), ssi_hex);
|
||||
os_free(ssi_hex);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_nan_usd_init(struct hostapd_data *hapd)
|
||||
{
|
||||
struct nan_callbacks cb;
|
||||
|
||||
os_memset(&cb, 0, sizeof(cb));
|
||||
cb.ctx = hapd;
|
||||
cb.tx = hostapd_nan_de_tx;
|
||||
cb.listen = hostapd_nan_de_listen;
|
||||
cb.discovery_result = hostapd_nan_de_discovery_result;
|
||||
cb.replied = hostapd_nan_de_replied;
|
||||
cb.publish_terminated = hostapd_nan_de_publish_terminated;
|
||||
cb.subscribe_terminated = hostapd_nan_de_subscribe_terminated;
|
||||
cb.receive = hostapd_nan_de_receive;
|
||||
|
||||
hapd->nan_de = nan_de_init(hapd->own_addr, true, &cb);
|
||||
if (!hapd->nan_de)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_nan_usd_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
nan_de_deinit(hapd->nan_de);
|
||||
hapd->nan_de = NULL;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_nan_usd_rx_sdf(struct hostapd_data *hapd, const u8 *src,
|
||||
unsigned int freq, const u8 *buf, size_t len)
|
||||
{
|
||||
if (!hapd->nan_de)
|
||||
return;
|
||||
nan_de_rx_sdf(hapd->nan_de, src, freq, buf, len);
|
||||
}
|
||||
|
||||
|
||||
void hostapd_nan_usd_flush(struct hostapd_data *hapd)
|
||||
{
|
||||
if (!hapd->nan_de)
|
||||
return;
|
||||
nan_de_flush(hapd->nan_de);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_nan_usd_publish(struct hostapd_data *hapd, const char *service_name,
|
||||
enum nan_service_protocol_type srv_proto_type,
|
||||
const struct wpabuf *ssi,
|
||||
struct nan_publish_params *params)
|
||||
{
|
||||
int publish_id;
|
||||
struct wpabuf *elems = NULL;
|
||||
|
||||
if (!hapd->nan_de)
|
||||
return -1;
|
||||
|
||||
publish_id = nan_de_publish(hapd->nan_de, service_name, srv_proto_type,
|
||||
ssi, elems, params);
|
||||
wpabuf_free(elems);
|
||||
return publish_id;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_nan_usd_cancel_publish(struct hostapd_data *hapd, int publish_id)
|
||||
{
|
||||
if (!hapd->nan_de)
|
||||
return;
|
||||
nan_de_cancel_publish(hapd->nan_de, publish_id);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_nan_usd_update_publish(struct hostapd_data *hapd, int publish_id,
|
||||
const struct wpabuf *ssi)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!hapd->nan_de)
|
||||
return -1;
|
||||
ret = nan_de_update_publish(hapd->nan_de, publish_id, ssi);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_nan_usd_subscribe(struct hostapd_data *hapd,
|
||||
const char *service_name,
|
||||
enum nan_service_protocol_type srv_proto_type,
|
||||
const struct wpabuf *ssi,
|
||||
struct nan_subscribe_params *params)
|
||||
{
|
||||
int subscribe_id;
|
||||
struct wpabuf *elems = NULL;
|
||||
|
||||
if (!hapd->nan_de)
|
||||
return -1;
|
||||
|
||||
subscribe_id = nan_de_subscribe(hapd->nan_de, service_name,
|
||||
srv_proto_type, ssi, elems, params);
|
||||
wpabuf_free(elems);
|
||||
return subscribe_id;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_nan_usd_cancel_subscribe(struct hostapd_data *hapd,
|
||||
int subscribe_id)
|
||||
{
|
||||
if (!hapd->nan_de)
|
||||
return;
|
||||
nan_de_cancel_subscribe(hapd->nan_de, subscribe_id);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_nan_usd_transmit(struct hostapd_data *hapd, int handle,
|
||||
const struct wpabuf *ssi,
|
||||
const struct wpabuf *elems,
|
||||
const u8 *peer_addr, u8 req_instance_id)
|
||||
{
|
||||
if (!hapd->nan_de)
|
||||
return -1;
|
||||
return nan_de_transmit(hapd->nan_de, handle, ssi, elems, peer_addr,
|
||||
req_instance_id);
|
||||
}
|
46
contrib/wpa/src/ap/nan_usd_ap.h
Normal file
46
contrib/wpa/src/ap/nan_usd_ap.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* NAN unsynchronized service discovery (USD)
|
||||
* Copyright (c) 2024, Qualcomm Innovation Center, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef NAN_USD_AP_H
|
||||
#define NAN_USD_AP_H
|
||||
|
||||
struct nan_subscribe_params;
|
||||
struct nan_publish_params;
|
||||
enum nan_service_protocol_type;
|
||||
|
||||
int hostapd_nan_usd_init(struct hostapd_data *hapd);
|
||||
void hostapd_nan_usd_deinit(struct hostapd_data *hapd);
|
||||
void hostapd_nan_usd_rx_sdf(struct hostapd_data *hapd, const u8 *src,
|
||||
unsigned int freq, const u8 *buf, size_t len);
|
||||
void hostapd_nan_usd_flush(struct hostapd_data *hapd);
|
||||
int hostapd_nan_usd_publish(struct hostapd_data *hapd, const char *service_name,
|
||||
enum nan_service_protocol_type srv_proto_type,
|
||||
const struct wpabuf *ssi,
|
||||
struct nan_publish_params *params);
|
||||
void hostapd_nan_usd_cancel_publish(struct hostapd_data *hapd, int publish_id);
|
||||
int hostapd_nan_usd_update_publish(struct hostapd_data *hapd, int publish_id,
|
||||
const struct wpabuf *ssi);
|
||||
int hostapd_nan_usd_subscribe(struct hostapd_data *hapd,
|
||||
const char *service_name,
|
||||
enum nan_service_protocol_type srv_proto_type,
|
||||
const struct wpabuf *ssi,
|
||||
struct nan_subscribe_params *params);
|
||||
void hostapd_nan_usd_cancel_subscribe(struct hostapd_data *hapd,
|
||||
int subscribe_id);
|
||||
int hostapd_nan_usd_transmit(struct hostapd_data *hapd, int handle,
|
||||
const struct wpabuf *ssi,
|
||||
const struct wpabuf *elems,
|
||||
const u8 *peer_addr, u8 req_instance_id);
|
||||
void hostapd_nan_usd_remain_on_channel_cb(struct hostapd_data *hapd,
|
||||
unsigned int freq,
|
||||
unsigned int duration);
|
||||
void hostapd_nan_usd_cancel_remain_on_channel_cb(struct hostapd_data *hapd,
|
||||
unsigned int freq);
|
||||
void hostapd_nan_usd_tx_wait_expire(struct hostapd_data *hapd);
|
||||
|
||||
#endif /* NAN_USD_AP_H */
|
@ -61,6 +61,7 @@ void sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
dl_list_for_each_safe(ip6addr, prev, &sta->ip6addr, struct ip6addr,
|
||||
list) {
|
||||
hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &ip6addr->addr);
|
||||
dl_list_del(&ip6addr->list);
|
||||
os_free(ip6addr);
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
|
||||
|
||||
dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
|
||||
list) {
|
||||
if (os_memcmp(bssid, nr->bssid, ETH_ALEN) == 0 &&
|
||||
if (ether_addr_equal(bssid, nr->bssid) &&
|
||||
(!ssid ||
|
||||
(ssid->ssid_len == nr->ssid.ssid_len &&
|
||||
os_memcmp(ssid->ssid, nr->ssid.ssid,
|
||||
@ -99,7 +99,10 @@ static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
|
||||
nr->civic = NULL;
|
||||
os_memset(nr->bssid, 0, sizeof(nr->bssid));
|
||||
os_memset(&nr->ssid, 0, sizeof(nr->ssid));
|
||||
os_memset(&nr->lci_date, 0, sizeof(nr->lci_date));
|
||||
nr->stationary = 0;
|
||||
nr->short_ssid = 0;
|
||||
nr->bss_parameters = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -136,7 +139,7 @@ int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
|
||||
|
||||
os_memcpy(entry->bssid, bssid, ETH_ALEN);
|
||||
os_memcpy(&entry->ssid, ssid, sizeof(entry->ssid));
|
||||
entry->short_ssid = crc32(ssid->ssid, ssid->ssid_len);
|
||||
entry->short_ssid = ieee80211_crc32(ssid->ssid, ssid->ssid_len);
|
||||
|
||||
entry->nr = wpabuf_dup(nr);
|
||||
if (!entry->nr)
|
||||
@ -165,6 +168,14 @@ int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_neighbor_free(struct hostapd_neighbor_entry *nr)
|
||||
{
|
||||
hostapd_neighbor_clear_entry(nr);
|
||||
dl_list_del(&nr->list);
|
||||
os_free(nr);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
|
||||
const struct wpa_ssid_value *ssid)
|
||||
{
|
||||
@ -174,9 +185,7 @@ int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
|
||||
if (!nr)
|
||||
return -1;
|
||||
|
||||
hostapd_neighbor_clear_entry(nr);
|
||||
dl_list_del(&nr->list);
|
||||
os_free(nr);
|
||||
hostapd_neighbor_free(nr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -188,9 +197,7 @@ void hostapd_free_neighbor_db(struct hostapd_data *hapd)
|
||||
|
||||
dl_list_for_each_safe(nr, prev, &hapd->nr_db,
|
||||
struct hostapd_neighbor_entry, list) {
|
||||
hostapd_neighbor_clear_entry(nr);
|
||||
dl_list_del(&nr->list);
|
||||
os_free(nr);
|
||||
hostapd_neighbor_free(nr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,19 +206,21 @@ void hostapd_free_neighbor_db(struct hostapd_data *hapd)
|
||||
static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
|
||||
int ht, int vht, int he)
|
||||
{
|
||||
u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
|
||||
enum oper_chan_width oper_chwidth;
|
||||
|
||||
oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
|
||||
|
||||
if (!ht && !vht && !he)
|
||||
return NR_CHAN_WIDTH_20;
|
||||
if (!hapd->iconf->secondary_channel)
|
||||
return NR_CHAN_WIDTH_20;
|
||||
if ((!vht && !he) || oper_chwidth == CHANWIDTH_USE_HT)
|
||||
if ((!vht && !he) || oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
|
||||
return NR_CHAN_WIDTH_40;
|
||||
if (oper_chwidth == CHANWIDTH_80MHZ)
|
||||
if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
|
||||
return NR_CHAN_WIDTH_80;
|
||||
if (oper_chwidth == CHANWIDTH_160MHZ)
|
||||
if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ)
|
||||
return NR_CHAN_WIDTH_160;
|
||||
if (oper_chwidth == CHANWIDTH_80P80MHZ)
|
||||
if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
|
||||
return NR_CHAN_WIDTH_80P80;
|
||||
return NR_CHAN_WIDTH_20;
|
||||
}
|
||||
@ -225,6 +234,7 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
|
||||
int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
|
||||
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
|
||||
int he = hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax;
|
||||
bool eht = he && hapd->iconf->ieee80211be && !hapd->conf->disable_11be;
|
||||
struct wpa_ssid_value ssid;
|
||||
u8 channel, op_class;
|
||||
u8 center_freq1_idx = 0, center_freq2_idx = 0;
|
||||
@ -260,10 +270,12 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
|
||||
/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
|
||||
if (vht)
|
||||
bssid_info |= NEI_REP_BSSID_INFO_VHT;
|
||||
if (he)
|
||||
bssid_info |= NEI_REP_BSSID_INFO_HE;
|
||||
}
|
||||
|
||||
if (he)
|
||||
bssid_info |= NEI_REP_BSSID_INFO_HE;
|
||||
if (eht)
|
||||
bssid_info |= NEI_REP_BSSID_INFO_EHT;
|
||||
/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
|
||||
|
||||
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
|
||||
@ -320,3 +332,35 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
|
||||
wpabuf_free(nr);
|
||||
#endif /* NEED_AP_MLME */
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_neighbor_entry *
|
||||
hostapd_neighbor_get_diff_short_ssid(struct hostapd_data *hapd, const u8 *bssid)
|
||||
{
|
||||
struct hostapd_neighbor_entry *nr;
|
||||
|
||||
dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
|
||||
list) {
|
||||
if (ether_addr_equal(bssid, nr->bssid) &&
|
||||
nr->short_ssid != hapd->conf->ssid.short_ssid)
|
||||
return nr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_neighbor_sync_own_report(struct hostapd_data *hapd)
|
||||
{
|
||||
struct hostapd_neighbor_entry *nr;
|
||||
|
||||
nr = hostapd_neighbor_get_diff_short_ssid(hapd, hapd->own_addr);
|
||||
if (!nr)
|
||||
return -1;
|
||||
|
||||
/* Clear old entry due to SSID change */
|
||||
hostapd_neighbor_free(nr);
|
||||
|
||||
hostapd_neighbor_set_own_report(hapd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
|
||||
const struct wpabuf *civic, int stationary,
|
||||
u8 bss_parameters);
|
||||
void hostapd_neighbor_set_own_report(struct hostapd_data *hapd);
|
||||
int hostapd_neighbor_sync_own_report(struct hostapd_data *hapd);
|
||||
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
|
||||
const struct wpa_ssid_value *ssid);
|
||||
void hostapd_free_neighbor_db(struct hostapd_data *hapd);
|
||||
|
@ -40,6 +40,7 @@ static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
|
||||
{
|
||||
os_free(entry->vlan_desc);
|
||||
os_free(entry->identity);
|
||||
os_free(entry->dpp_pkhash);
|
||||
wpabuf_free(entry->cui);
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
radius_free_class(&entry->radius_class);
|
||||
@ -55,7 +56,9 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
|
||||
unsigned int hash;
|
||||
|
||||
pmksa->pmksa_count--;
|
||||
pmksa->free_cb(entry, pmksa->ctx);
|
||||
|
||||
if (pmksa->free_cb)
|
||||
pmksa->free_cb(entry, pmksa->ctx);
|
||||
|
||||
/* unlink from hash list */
|
||||
hash = PMKID_HASH(entry->pmkid);
|
||||
@ -331,6 +334,10 @@ pmksa_cache_auth_create_entry(const u8 *pmk, size_t pmk_len, const u8 *pmkid,
|
||||
return NULL;
|
||||
os_memcpy(entry->pmk, pmk, pmk_len);
|
||||
entry->pmk_len = pmk_len;
|
||||
if (kck && kck_len && kck_len < WPA_KCK_MAX_LEN) {
|
||||
os_memcpy(entry->kck, kck, kck_len);
|
||||
entry->kck_len = kck_len;
|
||||
}
|
||||
if (pmkid)
|
||||
os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
|
||||
else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
|
||||
@ -480,14 +487,14 @@ pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
|
||||
for (entry = pmksa->pmkid[PMKID_HASH(pmkid)]; entry;
|
||||
entry = entry->hnext) {
|
||||
if ((spa == NULL ||
|
||||
os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
|
||||
ether_addr_equal(entry->spa, spa)) &&
|
||||
os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
|
||||
return entry;
|
||||
}
|
||||
} else {
|
||||
for (entry = pmksa->pmksa; entry; entry = entry->next) {
|
||||
if (spa == NULL ||
|
||||
os_memcmp(entry->spa, spa, ETH_ALEN) == 0)
|
||||
ether_addr_equal(entry->spa, spa))
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
@ -514,7 +521,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
|
||||
u8 new_pmkid[PMKID_LEN];
|
||||
|
||||
for (entry = pmksa->pmksa; entry; entry = entry->next) {
|
||||
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
|
||||
if (!ether_addr_equal(entry->spa, spa))
|
||||
continue;
|
||||
if (wpa_key_mgmt_sae(entry->akmp) ||
|
||||
wpa_key_mgmt_fils(entry->akmp)) {
|
||||
@ -522,8 +529,17 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
|
||||
return entry;
|
||||
continue;
|
||||
}
|
||||
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
|
||||
entry->akmp);
|
||||
if (entry->akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 &&
|
||||
entry->kck_len > 0)
|
||||
rsn_pmkid_suite_b_192(entry->kck, entry->kck_len,
|
||||
aa, spa, new_pmkid);
|
||||
else if (wpa_key_mgmt_suite_b(entry->akmp) &&
|
||||
entry->kck_len > 0)
|
||||
rsn_pmkid_suite_b(entry->kck, entry->kck_len, aa, spa,
|
||||
new_pmkid);
|
||||
else
|
||||
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa,
|
||||
new_pmkid, entry->akmp);
|
||||
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
|
||||
return entry;
|
||||
}
|
||||
@ -559,7 +575,7 @@ static int das_attr_match(struct rsn_pmksa_cache_entry *entry,
|
||||
int match = 0;
|
||||
|
||||
if (attr->sta_addr) {
|
||||
if (os_memcmp(attr->sta_addr, entry->spa, ETH_ALEN) != 0)
|
||||
if (!ether_addr_equal(attr->sta_addr, entry->spa))
|
||||
return 0;
|
||||
match++;
|
||||
}
|
||||
@ -701,7 +717,7 @@ int pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr,
|
||||
* <BSSID> <PMKID> <PMK> <expiration in seconds>
|
||||
*/
|
||||
for (entry = pmksa->pmksa; entry; entry = entry->next) {
|
||||
if (addr && os_memcmp(entry->spa, addr, ETH_ALEN) != 0)
|
||||
if (addr && !ether_addr_equal(entry->spa, addr))
|
||||
continue;
|
||||
|
||||
ret = os_snprintf(pos, end - pos, MACSTR " ",
|
||||
|
@ -19,10 +19,14 @@ struct rsn_pmksa_cache_entry {
|
||||
u8 pmkid[PMKID_LEN];
|
||||
u8 pmk[PMK_LEN_MAX];
|
||||
size_t pmk_len;
|
||||
u8 kck[WPA_KCK_MAX_LEN];
|
||||
size_t kck_len;
|
||||
os_time_t expiration;
|
||||
int akmp; /* WPA_KEY_MGMT_* */
|
||||
u8 spa[ETH_ALEN];
|
||||
|
||||
u8 *dpp_pkhash; /* SHA256_MAC_LEN octet hash value of DPP Connector
|
||||
* public key */
|
||||
u8 *identity;
|
||||
size_t identity_len;
|
||||
struct wpabuf *cui;
|
||||
|
@ -58,7 +58,7 @@ static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
|
||||
ethhdr = (struct l2_ethhdr *) buf;
|
||||
hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
|
||||
|
||||
if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
|
||||
if (!ether_addr_equal(ethhdr->h_dest, hapd->own_addr)) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address "
|
||||
MACSTR, MAC2STR(ethhdr->h_dest));
|
||||
return;
|
||||
@ -90,7 +90,7 @@ static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
|
||||
return;
|
||||
sta->preauth_iface = piface;
|
||||
ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
|
||||
len - sizeof(*ethhdr));
|
||||
len - sizeof(*ethhdr), FRAME_ENCRYPTION_UNKNOWN);
|
||||
}
|
||||
|
||||
|
||||
|
@ -334,6 +334,53 @@ static void hostapd_handle_nei_report_req(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_link_mesr_rep_timeout_handler(void *eloop_data,
|
||||
void *user_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_data;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"RRM: Link measurement request (token %u) timed out",
|
||||
hapd->link_measurement_req_token);
|
||||
hapd->link_mesr_req_active = 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_handle_link_mesr_report(struct hostapd_data *hapd,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
|
||||
const struct rrm_link_measurement_report *report;
|
||||
const u8 *pos, *end;
|
||||
char report_msg[2 * 8 + 1];
|
||||
|
||||
end = buf + len;
|
||||
pos = mgmt->u.action.u.rrm.variable;
|
||||
report = (const struct rrm_link_measurement_report *) (pos - 1);
|
||||
if (end - (const u8 *) report < (int) sizeof(*report))
|
||||
return;
|
||||
|
||||
if (!hapd->link_mesr_req_active ||
|
||||
(hapd->link_measurement_req_token != report->dialog_token)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Unexpected Link measurement report, token %u",
|
||||
report->dialog_token);
|
||||
return;
|
||||
}
|
||||
|
||||
hapd->link_mesr_req_active = 0;
|
||||
eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL);
|
||||
|
||||
report_msg[0] = '\0';
|
||||
if (wpa_snprintf_hex(report_msg, sizeof(report_msg),
|
||||
pos, end - pos) < 0)
|
||||
return;
|
||||
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, LINK_MSR_RESP_RX MACSTR " %u %s",
|
||||
MAC2STR(mgmt->sa), report->dialog_token, report_msg);
|
||||
}
|
||||
|
||||
|
||||
void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
@ -356,6 +403,9 @@ void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
|
||||
case WLAN_RRM_NEIGHBOR_REPORT_REQUEST:
|
||||
hostapd_handle_nei_report_req(hapd, buf, len);
|
||||
break;
|
||||
case WLAN_RRM_LINK_MEASUREMENT_REPORT:
|
||||
hostapd_handle_link_mesr_report(hapd, buf, len);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "RRM action %u is not supported",
|
||||
mgmt->u.action.u.rrm.action);
|
||||
@ -563,6 +613,7 @@ void hostapd_clean_rrm(struct hostapd_data *hapd)
|
||||
hapd->lci_req_active = 0;
|
||||
eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
|
||||
hapd->range_req_active = 0;
|
||||
eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -672,3 +723,73 @@ void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
|
||||
" %u ack=%d", MAC2STR(mgmt->da),
|
||||
mgmt->u.action.u.rrm.dialog_token, ok);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_send_link_measurement_req(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
struct sta_info *sta;
|
||||
int ret;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Request Link Measurement: dest addr " MACSTR,
|
||||
MAC2STR(addr));
|
||||
|
||||
if (!(hapd->iface->drv_rrm_flags &
|
||||
WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Request Link Measurement: the driver does not support TX power insertion");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Request Link Measurement: specied STA is not connected");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(sta->rrm_enabled_capa[0] & WLAN_RRM_CAPS_LINK_MEASUREMENT)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Request Link Measurement: destination STA does not support link measurement");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hapd->link_mesr_req_active) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Request Link Measurement: request already in process - overriding");
|
||||
hapd->link_mesr_req_active = 0;
|
||||
eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler,
|
||||
hapd, NULL);
|
||||
}
|
||||
|
||||
/* Action + Action type + token + Tx Power used + Max Tx Power = 5 */
|
||||
buf = wpabuf_alloc(5);
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
hapd->link_measurement_req_token++;
|
||||
if (!hapd->link_measurement_req_token)
|
||||
hapd->link_measurement_req_token++;
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
|
||||
wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REQUEST);
|
||||
wpabuf_put_u8(buf, hapd->link_measurement_req_token);
|
||||
/* NOTE: The driver is expected to fill the Tx Power Used and Max Tx
|
||||
* Power */
|
||||
wpabuf_put_u8(buf, 0);
|
||||
wpabuf_put_u8(buf, 0);
|
||||
|
||||
ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
|
||||
wpabuf_head(buf), wpabuf_len(buf));
|
||||
wpabuf_free(buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
hapd->link_mesr_req_active = 1;
|
||||
|
||||
eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
|
||||
hostapd_link_mesr_rep_timeout_handler, hapd,
|
||||
NULL);
|
||||
|
||||
return hapd->link_measurement_req_token;
|
||||
}
|
||||
|
@ -29,5 +29,7 @@ int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr,
|
||||
void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
|
||||
const struct ieee80211_mgmt *mgmt,
|
||||
size_t len, int ok);
|
||||
int hostapd_send_link_measurement_req(struct hostapd_data *hapd,
|
||||
const u8 *addr);
|
||||
|
||||
#endif /* RRM_H */
|
||||
|
@ -92,7 +92,7 @@ struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr)
|
||||
if (p2p_dev_addr == NULL)
|
||||
continue;
|
||||
|
||||
if (os_memcmp(p2p_dev_addr, addr, ETH_ALEN) == 0)
|
||||
if (ether_addr_equal(p2p_dev_addr, addr))
|
||||
return sta;
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
}
|
||||
|
||||
while (s->hnext != NULL &&
|
||||
os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
|
||||
!ether_addr_equal(s->hnext->addr, sta->addr))
|
||||
s = s->hnext;
|
||||
if (s->hnext != NULL)
|
||||
s->hnext = s->hnext->hnext;
|
||||
@ -180,13 +180,48 @@ void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
sta->pasn->fils.erp_resp = NULL;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
bin_clear_free(sta->pasn, sizeof(*sta->pasn));
|
||||
pasn_data_deinit(sta->pasn);
|
||||
sta->pasn = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PASN */
|
||||
|
||||
|
||||
static void __ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hostapd_sta_is_link_sta(hapd, sta) &&
|
||||
!hostapd_drv_link_sta_remove(hapd, sta->addr))
|
||||
return;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
static void clear_wpa_sm_for_each_partner_link(struct hostapd_data *hapd,
|
||||
struct sta_info *psta)
|
||||
{
|
||||
struct sta_info *lsta;
|
||||
struct hostapd_data *lhapd;
|
||||
|
||||
if (!ap_sta_is_mld(hapd, psta))
|
||||
return;
|
||||
|
||||
for_each_mld_link(lhapd, hapd) {
|
||||
if (lhapd == hapd)
|
||||
continue;
|
||||
|
||||
lsta = ap_get_sta(lhapd, psta->addr);
|
||||
if (lsta)
|
||||
lsta->wpa_sm = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
|
||||
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
int set_beacon = 0;
|
||||
@ -197,7 +232,11 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
hostapd_set_sta_flags(hapd, sta);
|
||||
|
||||
if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
|
||||
if ((sta->flags & WLAN_STA_WDS) ||
|
||||
(sta->flags & WLAN_STA_MULTI_AP &&
|
||||
(hapd->conf->multi_ap & BACKHAUL_BSS) &&
|
||||
hapd->conf->wds_sta &&
|
||||
!(sta->flags & WLAN_STA_WPS)))
|
||||
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
|
||||
|
||||
if (sta->ipaddr)
|
||||
@ -206,7 +245,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
|
||||
if (!hapd->iface->driver_ap_teardown &&
|
||||
!(sta->flags & WLAN_STA_PREAUTH)) {
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
__ap_free_sta(hapd, sta);
|
||||
sta->added_unassoc = 0;
|
||||
}
|
||||
|
||||
@ -287,7 +326,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
if (set_beacon)
|
||||
ieee802_11_set_beacons(hapd->iface);
|
||||
ieee802_11_update_beacons(hapd->iface);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR,
|
||||
__func__, MAC2STR(sta->addr));
|
||||
@ -298,7 +337,23 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
sae_clear_retransmit_timer(hapd, sta);
|
||||
|
||||
ieee802_1x_free_station(hapd, sta);
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (!ap_sta_is_mld(hapd, sta) ||
|
||||
hapd->mld_link_id == sta->mld_assoc_link_id) {
|
||||
wpa_auth_sta_deinit(sta->wpa_sm);
|
||||
/* Remove references from partner links. */
|
||||
clear_wpa_sm_for_each_partner_link(hapd, sta);
|
||||
}
|
||||
|
||||
/* Release group references in case non-association link STA is removed
|
||||
* before association link STA */
|
||||
if (hostapd_sta_is_link_sta(hapd, sta))
|
||||
wpa_release_link_auth_ref(sta->wpa_sm, hapd->mld_link_id);
|
||||
#else /* CONFIG_IEEE80211BE */
|
||||
wpa_auth_sta_deinit(sta->wpa_sm);
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
rsn_preauth_free_station(hapd, sta);
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
if (hapd->radius)
|
||||
@ -339,6 +394,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
#ifdef CONFIG_INTERWORKING
|
||||
if (sta->gas_dialog) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GAS_DIALOG_MAX; i++)
|
||||
gas_serv_dialog_clear(&sta->gas_dialog[i]);
|
||||
os_free(sta->gas_dialog);
|
||||
@ -358,6 +414,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
os_free(sta->vht_operation);
|
||||
os_free(sta->he_capab);
|
||||
os_free(sta->he_6ghz_capab);
|
||||
os_free(sta->eht_capab);
|
||||
hostapd_free_psk_list(sta->psk);
|
||||
os_free(sta->identity);
|
||||
os_free(sta->radius_cui);
|
||||
@ -408,8 +465,13 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
|
||||
os_free(sta->ifname_wds);
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
ap_sta_free_sta_profile(&sta->mld_info);
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
os_free(sta->sae_postponed_commit);
|
||||
forced_memzero(sta->last_tk, WPA_TK_MAX_LEN);
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
os_free(sta);
|
||||
@ -436,6 +498,27 @@ void hostapd_free_stas(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
void hostapd_free_link_stas(struct hostapd_data *hapd)
|
||||
{
|
||||
struct sta_info *sta, *prev;
|
||||
|
||||
sta = hapd->sta_list;
|
||||
while (sta) {
|
||||
prev = sta;
|
||||
sta = sta->next;
|
||||
|
||||
if (!hostapd_sta_is_link_sta(hapd, prev))
|
||||
continue;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Removing link station from MLD " MACSTR,
|
||||
MAC2STR(prev->addr));
|
||||
ap_free_sta(hapd, prev);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
|
||||
/**
|
||||
* ap_handle_timer - Per STA timer handler
|
||||
* @eloop_ctx: struct hostapd_data *
|
||||
@ -450,6 +533,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
struct sta_info *sta = timeout_ctx;
|
||||
unsigned long next_time = 0;
|
||||
int reason;
|
||||
int max_inactivity = hapd->conf->ap_max_inactivity;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
|
||||
hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
|
||||
@ -462,6 +546,9 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
return;
|
||||
}
|
||||
|
||||
if (sta->max_idle_period)
|
||||
max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000;
|
||||
|
||||
if ((sta->flags & WLAN_STA_ASSOC) &&
|
||||
(sta->timeout_next == STA_NULLFUNC ||
|
||||
sta->timeout_next == STA_DISASSOC)) {
|
||||
@ -483,7 +570,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
* Anyway, try again after the next inactivity timeout,
|
||||
* but do not disconnect the station now.
|
||||
*/
|
||||
next_time = hapd->conf->ap_max_inactivity + fuzz;
|
||||
next_time = max_inactivity + fuzz;
|
||||
} else if (inactive_sec == -ENOENT) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"Station " MACSTR " has lost its driver entry",
|
||||
@ -492,20 +579,19 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
/* Avoid sending client probe on removed client */
|
||||
sta->timeout_next = STA_DISASSOC;
|
||||
goto skip_poll;
|
||||
} else if (inactive_sec < hapd->conf->ap_max_inactivity) {
|
||||
} else if (inactive_sec < max_inactivity) {
|
||||
/* station activity detected; reset timeout state */
|
||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"Station " MACSTR " has been active %is ago",
|
||||
MAC2STR(sta->addr), inactive_sec);
|
||||
sta->timeout_next = STA_NULLFUNC;
|
||||
next_time = hapd->conf->ap_max_inactivity + fuzz -
|
||||
inactive_sec;
|
||||
next_time = max_inactivity + fuzz - inactive_sec;
|
||||
} else {
|
||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"Station " MACSTR " has been "
|
||||
"inactive too long: %d sec, max allowed: %d",
|
||||
MAC2STR(sta->addr), inactive_sec,
|
||||
hapd->conf->ap_max_inactivity);
|
||||
max_inactivity);
|
||||
|
||||
if (hapd->conf->skip_inactivity_poll)
|
||||
sta->timeout_next = STA_DISASSOC;
|
||||
@ -521,7 +607,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
/* data nullfunc frame poll did not produce TX errors; assume
|
||||
* station ACKed it */
|
||||
sta->timeout_next = STA_NULLFUNC;
|
||||
next_time = hapd->conf->ap_max_inactivity;
|
||||
next_time = max_inactivity;
|
||||
}
|
||||
|
||||
skip_poll:
|
||||
@ -709,6 +795,7 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
int i;
|
||||
int max_inactivity = hapd->conf->ap_max_inactivity;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta)
|
||||
@ -742,12 +829,15 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||
}
|
||||
sta->supported_rates_len = i;
|
||||
|
||||
if (sta->max_idle_period)
|
||||
max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000;
|
||||
|
||||
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
|
||||
"for " MACSTR " (%d seconds - ap_max_inactivity)",
|
||||
__func__, MAC2STR(addr),
|
||||
hapd->conf->ap_max_inactivity);
|
||||
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
|
||||
max_inactivity);
|
||||
eloop_register_timeout(max_inactivity, 0,
|
||||
ap_handle_timer, hapd, sta);
|
||||
}
|
||||
|
||||
@ -833,12 +923,42 @@ static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 reason)
|
||||
static void ap_sta_disconnect_common(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, unsigned int timeout)
|
||||
{
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
hostapd_set_sta_flags(hapd, sta);
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"reschedule ap_handle_timer timeout (%u sec) for " MACSTR,
|
||||
MAC2STR(sta->addr), timeout);
|
||||
|
||||
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||
eloop_register_timeout(timeout, 0, ap_handle_timer, hapd, sta);
|
||||
accounting_sta_stop(hapd, sta);
|
||||
ieee802_1x_free_station(hapd, sta);
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (!hapd->conf->mld_ap ||
|
||||
hapd->mld_link_id == sta->mld_assoc_link_id) {
|
||||
wpa_auth_sta_deinit(sta->wpa_sm);
|
||||
clear_wpa_sm_for_each_partner_link(hapd, sta);
|
||||
}
|
||||
#else /* CONFIG_IEEE80211BE */
|
||||
wpa_auth_sta_deinit(sta->wpa_sm);
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
sta->wpa_sm = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void ap_sta_handle_disassociate(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u16 reason)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
|
||||
if (hapd->iface->current_mode &&
|
||||
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
|
||||
/* Skip deauthentication in DMG/IEEE 802.11ad */
|
||||
@ -849,20 +969,8 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
|
||||
sta->timeout_next = STA_DEAUTH;
|
||||
}
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
hostapd_set_sta_flags(hapd, sta);
|
||||
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
|
||||
"for " MACSTR " (%d seconds - "
|
||||
"AP_MAX_INACTIVITY_AFTER_DISASSOC)",
|
||||
__func__, MAC2STR(sta->addr),
|
||||
AP_MAX_INACTIVITY_AFTER_DISASSOC);
|
||||
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
|
||||
ap_handle_timer, hapd, sta);
|
||||
accounting_sta_stop(hapd, sta);
|
||||
ieee802_1x_free_station(hapd, sta);
|
||||
wpa_auth_sta_deinit(sta->wpa_sm);
|
||||
sta->wpa_sm = NULL;
|
||||
|
||||
ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DISASSOC);
|
||||
|
||||
sta->disassoc_reason = reason;
|
||||
sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
|
||||
@ -885,8 +993,8 @@ static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 reason)
|
||||
static void ap_sta_handle_deauthenticate(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u16 reason)
|
||||
{
|
||||
if (hapd->iface->current_mode &&
|
||||
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
|
||||
@ -898,21 +1006,11 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
|
||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
hostapd_set_sta_flags(hapd, sta);
|
||||
|
||||
sta->timeout_next = STA_REMOVE;
|
||||
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
|
||||
"for " MACSTR " (%d seconds - "
|
||||
"AP_MAX_INACTIVITY_AFTER_DEAUTH)",
|
||||
__func__, MAC2STR(sta->addr),
|
||||
AP_MAX_INACTIVITY_AFTER_DEAUTH);
|
||||
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
|
||||
ap_handle_timer, hapd, sta);
|
||||
accounting_sta_stop(hapd, sta);
|
||||
ieee802_1x_free_station(hapd, sta);
|
||||
ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DEAUTH);
|
||||
|
||||
sta->deauth_reason = reason;
|
||||
sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
|
||||
@ -923,6 +1021,104 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
|
||||
|
||||
static bool ap_sta_ml_disconnect(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u16 reason,
|
||||
bool disassoc)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
struct hostapd_data *assoc_hapd, *tmp_hapd;
|
||||
struct sta_info *assoc_sta;
|
||||
unsigned int i, link_id;
|
||||
struct hapd_interfaces *interfaces;
|
||||
|
||||
if (!hostapd_is_mld_ap(hapd))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Get the station on which the association was performed, as it holds
|
||||
* the information about all the other links.
|
||||
*/
|
||||
assoc_sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd);
|
||||
if (!assoc_sta)
|
||||
return false;
|
||||
interfaces = assoc_hapd->iface->interfaces;
|
||||
|
||||
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
|
||||
if (!assoc_sta->mld_info.links[link_id].valid)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < interfaces->count; i++) {
|
||||
struct sta_info *tmp_sta;
|
||||
|
||||
tmp_hapd = interfaces->iface[i]->bss[0];
|
||||
|
||||
if (!hostapd_is_ml_partner(tmp_hapd, assoc_hapd))
|
||||
continue;
|
||||
|
||||
for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
|
||||
tmp_sta = tmp_sta->next) {
|
||||
/*
|
||||
* Handle the station on which the association
|
||||
* was done only after all other link station
|
||||
* are removed. Since there is a only a single
|
||||
* station per hapd with the same association
|
||||
* link simply break;
|
||||
*/
|
||||
if (tmp_sta == assoc_sta)
|
||||
break;
|
||||
|
||||
if (tmp_sta->mld_assoc_link_id !=
|
||||
assoc_sta->mld_assoc_link_id ||
|
||||
tmp_sta->aid != assoc_sta->aid)
|
||||
continue;
|
||||
|
||||
if (disassoc)
|
||||
ap_sta_handle_disassociate(tmp_hapd,
|
||||
tmp_sta,
|
||||
reason);
|
||||
else
|
||||
ap_sta_handle_deauthenticate(tmp_hapd,
|
||||
tmp_sta,
|
||||
reason);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Disconnect the station on which the association was performed. */
|
||||
if (disassoc)
|
||||
ap_sta_handle_disassociate(assoc_hapd, assoc_sta, reason);
|
||||
else
|
||||
ap_sta_handle_deauthenticate(assoc_hapd, assoc_sta, reason);
|
||||
|
||||
return true;
|
||||
#else /* CONFIG_IEEE80211BE */
|
||||
return false;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 reason)
|
||||
{
|
||||
if (ap_sta_ml_disconnect(hapd, sta, reason, true))
|
||||
return;
|
||||
|
||||
ap_sta_handle_disassociate(hapd, sta, reason);
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 reason)
|
||||
{
|
||||
if (ap_sta_ml_disconnect(hapd, sta, reason, false))
|
||||
return;
|
||||
|
||||
ap_sta_handle_deauthenticate(hapd, sta, reason);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
int ap_sta_wps_cancel(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, void *ctx)
|
||||
@ -1066,6 +1262,12 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
struct hostapd_vlan *vlan = NULL;
|
||||
int ret;
|
||||
int old_vlanid = sta->vlan_id_bound;
|
||||
int mld_link_id = -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hapd->conf->mld_ap)
|
||||
mld_link_id = hapd->mld_link_id;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
@ -1123,7 +1325,8 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
|
||||
|
||||
ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
|
||||
ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id,
|
||||
mld_link_id);
|
||||
if (ret < 0) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
|
||||
@ -1251,8 +1454,6 @@ const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
|
||||
for (psk = ssid->wpa_psk; psk; psk = psk->next)
|
||||
if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0)
|
||||
break;
|
||||
if (!psk)
|
||||
return NULL;
|
||||
if (!psk || !psk->keyid[0])
|
||||
return NULL;
|
||||
|
||||
@ -1260,8 +1461,44 @@ const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int authorized)
|
||||
const u8 * ap_sta_wpa_get_dpp_pkhash(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
return wpa_auth_get_dpp_pkhash(sta->wpa_sm);
|
||||
}
|
||||
|
||||
|
||||
bool ap_sta_set_authorized_flag(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int authorized)
|
||||
{
|
||||
if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
|
||||
return false;
|
||||
|
||||
if (authorized) {
|
||||
int mld_assoc_link_id = -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (ap_sta_is_mld(hapd, sta)) {
|
||||
if (sta->mld_assoc_link_id == hapd->mld_link_id)
|
||||
mld_assoc_link_id = sta->mld_assoc_link_id;
|
||||
else
|
||||
mld_assoc_link_id = -2;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
if (mld_assoc_link_id != -2)
|
||||
hostapd_prune_associations(hapd, sta->addr,
|
||||
mld_assoc_link_id);
|
||||
sta->flags |= WLAN_STA_AUTHORIZED;
|
||||
} else {
|
||||
sta->flags &= ~WLAN_STA_AUTHORIZED;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_set_authorized_event(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int authorized)
|
||||
{
|
||||
const u8 *dev_addr = NULL;
|
||||
char buf[100];
|
||||
@ -1269,14 +1506,7 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 ip_addr_buf[4];
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
|
||||
return;
|
||||
|
||||
if (authorized)
|
||||
sta->flags |= WLAN_STA_AUTHORIZED;
|
||||
else
|
||||
sta->flags &= ~WLAN_STA_AUTHORIZED;
|
||||
const u8 *ip_ptr = NULL;
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (hapd->p2p_group == NULL) {
|
||||
@ -1293,15 +1523,14 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
#endif /* CONFIG_P2P */
|
||||
os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
|
||||
|
||||
if (hapd->sta_authorized_cb)
|
||||
hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
|
||||
sta->addr, authorized, dev_addr);
|
||||
|
||||
if (authorized) {
|
||||
const u8 *dpp_pkhash;
|
||||
const char *keyid;
|
||||
char dpp_pkhash_buf[100];
|
||||
char keyid_buf[100];
|
||||
char ip_addr[100];
|
||||
|
||||
dpp_pkhash_buf[0] = '\0';
|
||||
keyid_buf[0] = '\0';
|
||||
ip_addr[0] = '\0';
|
||||
#ifdef CONFIG_P2P
|
||||
@ -1310,6 +1539,7 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
" ip_addr=%u.%u.%u.%u",
|
||||
ip_addr_buf[0], ip_addr_buf[1],
|
||||
ip_addr_buf[2], ip_addr_buf[3]);
|
||||
ip_ptr = ip_addr_buf;
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
@ -1319,14 +1549,27 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
" keyid=%s", keyid);
|
||||
}
|
||||
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s",
|
||||
buf, ip_addr, keyid_buf);
|
||||
dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta);
|
||||
if (dpp_pkhash) {
|
||||
const char *prefix = " dpp_pkhash=";
|
||||
size_t plen = os_strlen(prefix);
|
||||
|
||||
os_strlcpy(dpp_pkhash_buf, prefix,
|
||||
sizeof(dpp_pkhash_buf));
|
||||
wpa_snprintf_hex(&dpp_pkhash_buf[plen],
|
||||
sizeof(dpp_pkhash_buf) - plen,
|
||||
dpp_pkhash, SHA256_MAC_LEN);
|
||||
}
|
||||
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s%s",
|
||||
buf, ip_addr, keyid_buf, dpp_pkhash_buf);
|
||||
|
||||
if (hapd->msg_ctx_parent &&
|
||||
hapd->msg_ctx_parent != hapd->msg_ctx)
|
||||
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
|
||||
AP_STA_CONNECTED "%s%s%s",
|
||||
buf, ip_addr, keyid_buf);
|
||||
AP_STA_CONNECTED "%s%s%s%s",
|
||||
buf, ip_addr, keyid_buf,
|
||||
dpp_pkhash_buf);
|
||||
} else {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
|
||||
|
||||
@ -1336,6 +1579,11 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
AP_STA_DISCONNECTED "%s", buf);
|
||||
}
|
||||
|
||||
if (hapd->sta_authorized_cb)
|
||||
hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
|
||||
sta->addr, authorized, dev_addr,
|
||||
ip_ptr);
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
if (hapd->iface->fst) {
|
||||
if (authorized)
|
||||
@ -1348,6 +1596,15 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int authorized)
|
||||
{
|
||||
if (!ap_sta_set_authorized_flag(hapd, sta, authorized))
|
||||
return;
|
||||
ap_sta_set_authorized_event(hapd, sta, authorized);
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *addr, u16 reason)
|
||||
{
|
||||
@ -1461,7 +1718,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
|
||||
|
||||
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",
|
||||
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
|
||||
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
|
||||
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
|
||||
@ -1481,6 +1738,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
|
||||
(flags & WLAN_STA_HT ? "[HT]" : ""),
|
||||
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
|
||||
(flags & WLAN_STA_HE ? "[HE]" : ""),
|
||||
(flags & WLAN_STA_EHT ? "[EHT]" : ""),
|
||||
(flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""),
|
||||
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
|
||||
(flags & WLAN_STA_WNM_SLEEP_MODE ?
|
||||
@ -1512,11 +1770,12 @@ static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx)
|
||||
|
||||
|
||||
void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
struct sta_info *sta,
|
||||
unsigned timeout)
|
||||
{
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"IEEE 802.1X: Force disconnection of " MACSTR
|
||||
" after EAP-Failure in 10 ms", MAC2STR(sta->addr));
|
||||
" after EAP-Failure in %u ms", MAC2STR(sta->addr), timeout);
|
||||
|
||||
/*
|
||||
* Add a small sleep to increase likelihood of previously requested
|
||||
@ -1524,8 +1783,8 @@ void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
|
||||
* operations.
|
||||
*/
|
||||
eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
|
||||
eloop_register_timeout(0, 10000, ap_sta_delayed_1x_auth_fail_cb,
|
||||
hapd, sta);
|
||||
eloop_register_timeout(0, timeout * 1000,
|
||||
ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
@ -1537,8 +1796,37 @@ int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
static void ap_sta_remove_link_sta(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
struct hostapd_data *tmp_hapd;
|
||||
|
||||
for_each_mld_link(tmp_hapd, hapd) {
|
||||
struct sta_info *tmp_sta;
|
||||
|
||||
if (hapd == tmp_hapd)
|
||||
continue;
|
||||
|
||||
for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
|
||||
tmp_sta = tmp_sta->next) {
|
||||
if (tmp_sta == sta ||
|
||||
!ether_addr_equal(tmp_sta->addr, sta->addr))
|
||||
continue;
|
||||
|
||||
ap_free_sta(tmp_hapd, tmp_sta);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
|
||||
int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
const u8 *mld_link_addr = NULL;
|
||||
bool mld_link_sta = false;
|
||||
|
||||
/*
|
||||
* If a station that is already associated to the AP, is trying to
|
||||
* authenticate again, remove the STA entry, in order to make sure the
|
||||
@ -1546,6 +1834,22 @@ int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
* this, station's added_unassoc flag is cleared once the station has
|
||||
* completed association.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (ap_sta_is_mld(hapd, sta)) {
|
||||
u8 mld_link_id = hapd->mld_link_id;
|
||||
|
||||
mld_link_sta = sta->mld_assoc_link_id != mld_link_id;
|
||||
mld_link_addr = sta->mld_info.links[mld_link_id].peer_addr;
|
||||
|
||||
/*
|
||||
* In case the AP is affiliated with an AP MLD, we need to
|
||||
* remove the station from all relevant links/APs.
|
||||
*/
|
||||
ap_sta_remove_link_sta(hapd, sta);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | WLAN_STA_AUTHORIZED);
|
||||
@ -1553,8 +1857,9 @@ 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,
|
||||
sta->flags, 0, 0, 0, 0)) {
|
||||
0, NULL, NULL, NULL, 0, NULL, 0, NULL,
|
||||
sta->flags, 0, 0, 0, 0,
|
||||
mld_link_addr, mld_link_sta)) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_NOTICE,
|
||||
@ -1565,3 +1870,19 @@ int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
sta->added_unassoc = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
void ap_sta_free_sta_profile(struct mld_info *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
|
||||
os_free(info->links[i].resp_sta_profile);
|
||||
info->links[i].resp_sta_profile = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/sae.h"
|
||||
#include "crypto/sha384.h"
|
||||
#include "pasn/pasn_common.h"
|
||||
#include "hostapd.h"
|
||||
|
||||
/* STA flags */
|
||||
#define WLAN_STA_AUTH BIT(0)
|
||||
@ -42,6 +44,7 @@
|
||||
#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)
|
||||
@ -64,43 +67,34 @@ struct mbo_non_pref_chan_info {
|
||||
struct pending_eapol_rx {
|
||||
struct wpabuf *buf;
|
||||
struct os_reltime rx_time;
|
||||
enum frame_encryption encrypted;
|
||||
};
|
||||
|
||||
enum pasn_fils_state {
|
||||
PASN_FILS_STATE_NONE = 0,
|
||||
PASN_FILS_STATE_PENDING_AS,
|
||||
PASN_FILS_STATE_COMPLETE
|
||||
};
|
||||
#define EHT_ML_MAX_STA_PROF_LEN 1024
|
||||
struct mld_info {
|
||||
bool mld_sta;
|
||||
|
||||
struct pasn_fils_data {
|
||||
u8 state;
|
||||
u8 nonce[FILS_NONCE_LEN];
|
||||
u8 anonce[FILS_NONCE_LEN];
|
||||
u8 session[FILS_SESSION_LEN];
|
||||
u8 erp_pmkid[PMKID_LEN];
|
||||
struct ml_common_info {
|
||||
u8 mld_addr[ETH_ALEN];
|
||||
u16 medium_sync_delay;
|
||||
u16 eml_capa;
|
||||
u16 mld_capa;
|
||||
} common_info;
|
||||
|
||||
struct wpabuf *erp_resp;
|
||||
};
|
||||
struct mld_link_info {
|
||||
u8 valid:1;
|
||||
u8 nstr_bitmap_len:2;
|
||||
u8 local_addr[ETH_ALEN];
|
||||
u8 peer_addr[ETH_ALEN];
|
||||
|
||||
struct pasn_data {
|
||||
int akmp;
|
||||
int cipher;
|
||||
u16 group;
|
||||
u8 trans_seq;
|
||||
u8 wrapped_data_format;
|
||||
size_t kdk_len;
|
||||
u8 nstr_bitmap[2];
|
||||
|
||||
u8 hash[SHA384_MAC_LEN];
|
||||
struct wpa_ptk ptk;
|
||||
struct crypto_ecdh *ecdh;
|
||||
u16 capability;
|
||||
|
||||
struct wpabuf *secret;
|
||||
#ifdef CONFIG_SAE
|
||||
struct sae_data sae;
|
||||
#endif /* CONFIG_SAE */
|
||||
#ifdef CONFIG_FILS
|
||||
struct pasn_fils_data fils;
|
||||
#endif /* CONFIG_FILS */
|
||||
u16 status;
|
||||
u16 resp_sta_profile_len;
|
||||
u8 *resp_sta_profile;
|
||||
} links[MAX_NUM_MLD_LINKS];
|
||||
};
|
||||
|
||||
struct sta_info {
|
||||
@ -152,6 +146,7 @@ struct sta_info {
|
||||
unsigned int qos_map_enabled:1;
|
||||
unsigned int remediation:1;
|
||||
unsigned int hs20_deauth_requested:1;
|
||||
unsigned int hs20_deauth_on_ack:1;
|
||||
unsigned int session_timeout_set:1;
|
||||
unsigned int radius_das_match:1;
|
||||
unsigned int ecsa_supported:1;
|
||||
@ -213,6 +208,8 @@ struct sta_info {
|
||||
struct ieee80211_he_capabilities *he_capab;
|
||||
size_t he_capab_len;
|
||||
struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
|
||||
struct ieee80211_eht_capabilities *eht_capab;
|
||||
size_t eht_capab_len;
|
||||
|
||||
int sa_query_count; /* number of pending SA Query requests;
|
||||
* 0 = no SA Query in progress */
|
||||
@ -330,6 +327,14 @@ struct sta_info {
|
||||
#ifdef CONFIG_PASN
|
||||
struct pasn_data *pasn;
|
||||
#endif /* CONFIG_PASN */
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
struct mld_info mld_info;
|
||||
u8 mld_assoc_link_id;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
u16 max_idle_period; /* if nonzero, the granted BSS max idle period in
|
||||
* units of 1000 TUs */
|
||||
};
|
||||
|
||||
|
||||
@ -385,9 +390,15 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
const u8 * ap_sta_wpa_get_dpp_pkhash(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *addr, u16 reason);
|
||||
|
||||
bool ap_sta_set_authorized_flag(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int authorized);
|
||||
void ap_sta_set_authorized_event(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int authorized);
|
||||
void ap_sta_set_authorized(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int authorized);
|
||||
static inline int ap_sta_is_authorized(struct sta_info *sta)
|
||||
@ -402,11 +413,34 @@ void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
|
||||
|
||||
int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
|
||||
void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
struct sta_info *sta,
|
||||
unsigned timeout);
|
||||
int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
|
||||
void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
|
||||
static inline bool ap_sta_is_mld(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
return hapd->conf->mld_ap && sta && sta->mld_info.mld_sta;
|
||||
#else /* CONFIG_IEEE80211BE */
|
||||
return false;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
}
|
||||
|
||||
static inline void ap_sta_set_mld(struct sta_info *sta, bool mld)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (sta)
|
||||
sta->mld_info.mld_sta = mld;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
}
|
||||
|
||||
void ap_sta_free_sta_profile(struct mld_info *info);
|
||||
|
||||
void hostapd_free_link_stas(struct hostapd_data *hapd);
|
||||
|
||||
#endif /* STA_INFO_H */
|
||||
|
@ -43,6 +43,7 @@ int hostapd_register_probereq_cb(struct hostapd_data *hapd,
|
||||
struct prune_data {
|
||||
struct hostapd_data *hapd;
|
||||
const u8 *addr;
|
||||
int mld_assoc_link_id;
|
||||
};
|
||||
|
||||
static int prune_associations(struct hostapd_iface *iface, void *ctx)
|
||||
@ -72,6 +73,12 @@ static int prune_associations(struct hostapd_iface *iface, void *ctx)
|
||||
if (!osta)
|
||||
continue;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (data->mld_assoc_link_id >= 0 &&
|
||||
osta->mld_assoc_link_id == data->mld_assoc_link_id)
|
||||
continue;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
wpa_printf(MSG_INFO, "%s: Prune association for " MACSTR,
|
||||
ohapd->conf->iface, MAC2STR(osta->addr));
|
||||
ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED);
|
||||
@ -84,15 +91,20 @@ static int prune_associations(struct hostapd_iface *iface, void *ctx)
|
||||
* hostapd_prune_associations - Remove extraneous associations
|
||||
* @hapd: Pointer to BSS data for the most recent association
|
||||
* @addr: Associated STA address
|
||||
* @mld_assoc_link_id: MLD link id used for association or -1 for non MLO
|
||||
*
|
||||
* This function looks through all radios and BSS's for previous
|
||||
* (stale) associations of STA. If any are found they are removed.
|
||||
*/
|
||||
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr)
|
||||
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr,
|
||||
int mld_assoc_link_id)
|
||||
{
|
||||
struct prune_data data;
|
||||
|
||||
data.hapd = hapd;
|
||||
data.addr = addr;
|
||||
data.mld_assoc_link_id = mld_assoc_link_id;
|
||||
|
||||
if (hapd->iface->interfaces &&
|
||||
hapd->iface->interfaces->for_each_interface)
|
||||
hapd->iface->interfaces->for_each_interface(
|
||||
|
@ -20,13 +20,6 @@
|
||||
#include "ap_drv_ops.h"
|
||||
#include "wmm.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
|
||||
static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
|
||||
{
|
||||
|
@ -44,6 +44,20 @@ static int ieee80211_11_set_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
|
||||
}
|
||||
|
||||
|
||||
static const u8 * wnm_ap_get_own_addr(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
const u8 *own_addr = hapd->own_addr;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hapd->conf->mld_ap && (!sta || ap_sta_is_mld(hapd, sta)))
|
||||
own_addr = hapd->mld->mld_addr;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
return own_addr;
|
||||
}
|
||||
|
||||
|
||||
/* MLME-SLEEPMODE.response */
|
||||
static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
const u8 *addr, u8 dialog_token,
|
||||
@ -63,6 +77,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
struct sta_info *sta;
|
||||
enum wnm_oper tfs_oper = action_type == WNM_SLEEP_MODE_ENTER ?
|
||||
WNM_SLEEP_TFS_RESP_IE_ADD : WNM_SLEEP_TFS_RESP_IE_NONE;
|
||||
const u8 *own_addr;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta == NULL) {
|
||||
@ -143,9 +158,12 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
res = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
own_addr = wnm_ap_get_own_addr(hapd, sta);
|
||||
|
||||
os_memcpy(mgmt->da, addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, own_addr, ETH_ALEN);
|
||||
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
mgmt->u.action.category = WLAN_ACTION_WNM;
|
||||
@ -366,6 +384,8 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
|
||||
u8 dialog_token)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
const u8 *own_addr;
|
||||
struct sta_info *sta;
|
||||
size_t len;
|
||||
u8 *pos;
|
||||
int res;
|
||||
@ -373,9 +393,13 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
|
||||
mgmt = os_zalloc(sizeof(*mgmt));
|
||||
if (mgmt == NULL)
|
||||
return -1;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
own_addr = wnm_ap_get_own_addr(hapd, sta);
|
||||
|
||||
os_memcpy(mgmt->da, addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, own_addr, ETH_ALEN);
|
||||
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
mgmt->u.action.category = WLAN_ACTION_WNM;
|
||||
@ -409,6 +433,8 @@ static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd,
|
||||
u8 dialog_token, reason;
|
||||
const u8 *pos, *end;
|
||||
int enabled = hapd->conf->bss_transition;
|
||||
char *hex = NULL;
|
||||
size_t hex_len;
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
if (hapd->conf->mbo_enabled)
|
||||
@ -441,6 +467,17 @@ static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd,
|
||||
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
|
||||
pos, end - pos);
|
||||
|
||||
hex_len = 2 * (end - pos) + 1;
|
||||
if (hex_len > 1) {
|
||||
hex = os_malloc(hex_len);
|
||||
if (hex)
|
||||
wpa_snprintf_hex(hex, hex_len, pos, end - pos);
|
||||
}
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO,
|
||||
BSS_TM_QUERY MACSTR " reason=%u%s%s",
|
||||
MAC2STR(addr), reason, hex ? " neighbor=" : "", hex);
|
||||
os_free(hex);
|
||||
|
||||
ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
|
||||
}
|
||||
|
||||
@ -630,6 +667,133 @@ static void ieee802_11_rx_wnm_coloc_intf_report(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const char * wnm_event_type2str(enum wnm_event_report_type wtype)
|
||||
{
|
||||
#define W2S(wtype) case WNM_EVENT_TYPE_ ## wtype: return #wtype;
|
||||
switch (wtype) {
|
||||
W2S(TRANSITION)
|
||||
W2S(RSNA)
|
||||
W2S(P2P_LINK)
|
||||
W2S(WNM_LOG)
|
||||
W2S(BSS_COLOR_COLLISION)
|
||||
W2S(BSS_COLOR_IN_USE)
|
||||
}
|
||||
return "UNKNOWN";
|
||||
#undef W2S
|
||||
}
|
||||
|
||||
|
||||
static void ieee802_11_rx_wnm_event_report(struct hostapd_data *hapd,
|
||||
const u8 *addr, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
u8 dialog_token;
|
||||
struct wnm_event_report_element *report_ie;
|
||||
const u8 *pos = buf, *end = buf + len;
|
||||
const size_t fixed_field_len = 3; /* Event Token/Type/Report Status */
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
const size_t tsf_len = 8;
|
||||
u8 color;
|
||||
u64 bitmap;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
if (end - pos < 1 + 2) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Ignore too short WNM Event Report frame from "
|
||||
MACSTR, MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
dialog_token = *pos++;
|
||||
report_ie = (struct wnm_event_report_element *) pos;
|
||||
|
||||
if (end - pos < 2 + report_ie->len ||
|
||||
report_ie->len < fixed_field_len) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Ignore truncated WNM Event Report frame from "
|
||||
MACSTR, MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
if (report_ie->eid != WLAN_EID_EVENT_REPORT ||
|
||||
report_ie->status != WNM_STATUS_SUCCESSFUL)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: Received WNM Event Report frame from "
|
||||
MACSTR " dialog_token=%u event_token=%u type=%d (%s)",
|
||||
MAC2STR(addr), dialog_token, report_ie->token,
|
||||
report_ie->type, wnm_event_type2str(report_ie->type));
|
||||
|
||||
pos += 2 + fixed_field_len;
|
||||
wpa_hexdump(MSG_MSGDUMP, "WNM: Event Report", pos, end - pos);
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
|
||||
wpa_printf(MSG_DEBUG, "Station " MACSTR
|
||||
" not found for received WNM Event Report",
|
||||
MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (report_ie->type) {
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
case WNM_EVENT_TYPE_BSS_COLOR_COLLISION:
|
||||
if (!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax)
|
||||
return;
|
||||
if (report_ie->len <
|
||||
fixed_field_len + tsf_len + 8) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Too short BSS color collision event report from "
|
||||
MACSTR, MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
bitmap = WPA_GET_LE64(report_ie->u.bss_color_collision.color_bitmap);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: BSS color collision bitmap 0x%llx reported by "
|
||||
MACSTR, (unsigned long long) bitmap, MAC2STR(addr));
|
||||
hostapd_switch_color(hapd->iface->bss[0], bitmap);
|
||||
break;
|
||||
case WNM_EVENT_TYPE_BSS_COLOR_IN_USE:
|
||||
if (!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax)
|
||||
return;
|
||||
if (report_ie->len < fixed_field_len + tsf_len + 1) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Too short BSS color in use event report from "
|
||||
MACSTR, MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
color = report_ie->u.bss_color_in_use.color;
|
||||
if (color > 63) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Invalid BSS color %u report from "
|
||||
MACSTR, color, MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
if (color == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: BSS color use report canceled by "
|
||||
MACSTR, MAC2STR(addr));
|
||||
/* TODO: Clear stored color from the collision bitmap
|
||||
* if there are no other users for it. */
|
||||
return;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "WNM: BSS color %u use report by "
|
||||
MACSTR, color, MAC2STR(addr));
|
||||
hapd->color_collision_bitmap |= 1ULL << color;
|
||||
break;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM Event Report type=%d (%s) not supported",
|
||||
report_ie->type,
|
||||
wnm_event_type2str(report_ie->type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
|
||||
const struct ieee80211_mgmt *mgmt, size_t len)
|
||||
{
|
||||
@ -645,6 +809,10 @@ int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
|
||||
plen = len - IEEE80211_HDRLEN - 2;
|
||||
|
||||
switch (action) {
|
||||
case WNM_EVENT_REPORT:
|
||||
ieee802_11_rx_wnm_event_report(hapd, mgmt->sa, payload,
|
||||
plen);
|
||||
return 0;
|
||||
case WNM_BSS_TRANS_MGMT_QUERY:
|
||||
ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload,
|
||||
plen);
|
||||
@ -677,14 +845,15 @@ int wnm_send_disassoc_imminent(struct hostapd_data *hapd,
|
||||
{
|
||||
u8 buf[1000], *pos;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
const u8 *own_addr = wnm_ap_get_own_addr(hapd, sta);
|
||||
|
||||
os_memset(buf, 0, sizeof(buf));
|
||||
mgmt = (struct ieee80211_mgmt *) buf;
|
||||
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, own_addr, ETH_ALEN);
|
||||
mgmt->u.action.category = WLAN_ACTION_WNM;
|
||||
mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
|
||||
mgmt->u.action.u.bss_tm_req.dialog_token = 1;
|
||||
@ -743,14 +912,15 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
|
||||
u8 buf[1000], *pos;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
size_t url_len;
|
||||
const u8 *own_addr = wnm_ap_get_own_addr(hapd, sta);
|
||||
|
||||
os_memset(buf, 0, sizeof(buf));
|
||||
mgmt = (struct ieee80211_mgmt *) buf;
|
||||
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, own_addr, ETH_ALEN);
|
||||
mgmt->u.action.category = WLAN_ACTION_WNM;
|
||||
mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
|
||||
mgmt->u.action.u.bss_tm_req.dialog_token = 1;
|
||||
@ -795,6 +965,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 *buf, *pos;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
size_t url_len;
|
||||
const u8 *own_addr = wnm_ap_get_own_addr(hapd, sta);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
|
||||
MACSTR
|
||||
@ -808,8 +979,8 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, own_addr, ETH_ALEN);
|
||||
mgmt->u.action.category = WLAN_ACTION_WNM;
|
||||
mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
|
||||
mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token;
|
||||
@ -858,6 +1029,26 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
os_free(buf);
|
||||
|
||||
if (disassoc_timer) {
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (ap_sta_is_mld(hapd, sta)) {
|
||||
int i;
|
||||
unsigned int links = 0;
|
||||
|
||||
for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
|
||||
if (sta->mld_info.links[i].valid)
|
||||
links++;
|
||||
}
|
||||
|
||||
if (links > 1) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Only terminating one link - other links remains associated for "
|
||||
MACSTR,
|
||||
MAC2STR(sta->mld_info.common_info.mld_addr));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
/* send disassociation frame after time-out */
|
||||
set_disassoc_timer(hapd, sta, disassoc_timer);
|
||||
}
|
||||
@ -872,6 +1063,7 @@ int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 buf[100], *pos;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u8 dialog_token = 1;
|
||||
const u8 *own_addr = wnm_ap_get_own_addr(hapd, sta);
|
||||
|
||||
if (auto_report > 3 || timeout > 63)
|
||||
return -1;
|
||||
@ -880,8 +1072,8 @@ int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, own_addr, ETH_ALEN);
|
||||
mgmt->u.action.category = WLAN_ACTION_WNM;
|
||||
mgmt->u.action.u.coloc_intf_req.action =
|
||||
WNM_COLLOCATED_INTERFERENCE_REQ;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd - IEEE 802.11i-2004 / WPA Authenticator
|
||||
* Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -15,6 +15,7 @@
|
||||
#include "common/ieee802_11_defs.h"
|
||||
|
||||
struct vlan_description;
|
||||
struct mld_info;
|
||||
|
||||
#define MAX_OWN_IE_OVERRIDE 256
|
||||
|
||||
@ -197,9 +198,9 @@ struct wpa_auth_config {
|
||||
#ifdef CONFIG_OCV
|
||||
int ocv; /* Operating Channel Validation */
|
||||
#endif /* CONFIG_OCV */
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
u8 ssid[SSID_MAX_LEN];
|
||||
size_t ssid_len;
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
|
||||
u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
|
||||
size_t r0_key_holder_len;
|
||||
@ -240,6 +241,10 @@ struct wpa_auth_config {
|
||||
unsigned int gtk_rsc_override_set:1;
|
||||
unsigned int igtk_rsc_override_set:1;
|
||||
int ft_rsnxe_used;
|
||||
bool delay_eapol_tx;
|
||||
struct wpabuf *eapol_m1_elements;
|
||||
struct wpabuf *eapol_m3_elements;
|
||||
bool eapol_m3_no_encrypt;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
unsigned int oci_freq_override_eapol_m3;
|
||||
unsigned int oci_freq_override_eapol_g1;
|
||||
@ -255,7 +260,7 @@ struct wpa_auth_config {
|
||||
unsigned int fils_cache_id_set:1;
|
||||
u8 fils_cache_id[FILS_CACHE_ID_LEN];
|
||||
#endif /* CONFIG_FILS */
|
||||
int sae_pwe;
|
||||
enum sae_pwe sae_pwe;
|
||||
bool sae_pk;
|
||||
|
||||
unsigned int secure_ltf:1;
|
||||
@ -273,6 +278,23 @@ struct wpa_auth_config {
|
||||
* PTK derivation regardless of advertised capabilities.
|
||||
*/
|
||||
bool force_kdk_derivation;
|
||||
|
||||
bool radius_psk;
|
||||
|
||||
bool no_disconnect_on_group_keyerror;
|
||||
|
||||
/* Pointer to Multi-BSSID transmitted BSS authenticator instance.
|
||||
* Set only in nontransmitted BSSs, i.e., is NULL for transmitted BSS
|
||||
* and in BSSs that are not part of a Multi-BSSID set. */
|
||||
struct wpa_authenticator *tx_bss_auth;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
const u8 *mld_addr;
|
||||
int link_id;
|
||||
struct wpa_authenticator *first_link_auth;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
bool ssid_protection;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
@ -285,6 +307,30 @@ typedef enum {
|
||||
WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx
|
||||
} wpa_eapol_variable;
|
||||
|
||||
struct wpa_auth_ml_key_info {
|
||||
unsigned int n_mld_links;
|
||||
bool mgmt_frame_prot;
|
||||
bool beacon_prot;
|
||||
|
||||
struct wpa_auth_ml_link_key_info {
|
||||
u8 link_id;
|
||||
|
||||
u8 gtkidx;
|
||||
u8 gtk_len;
|
||||
u8 pn[6];
|
||||
const u8 *gtk;
|
||||
|
||||
u8 igtkidx;
|
||||
u8 igtk_len;
|
||||
const u8 *igtk;
|
||||
u8 ipn[6];
|
||||
|
||||
u8 bigtkidx;
|
||||
const u8 *bigtk;
|
||||
u8 bipn[6];
|
||||
} links[MAX_NUM_MLD_LINKS];
|
||||
};
|
||||
|
||||
struct wpa_auth_callbacks {
|
||||
void (*logger)(void *ctx, const u8 *addr, logger_level level,
|
||||
const char *txt);
|
||||
@ -304,6 +350,7 @@ struct wpa_auth_callbacks {
|
||||
int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
|
||||
int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
|
||||
size_t data_len, int encrypt);
|
||||
int (*get_sta_count)(void *ctx);
|
||||
int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm,
|
||||
void *ctx), void *cb_ctx);
|
||||
int (*for_each_auth)(void *ctx, int (*cb)(struct wpa_authenticator *a,
|
||||
@ -320,6 +367,9 @@ struct wpa_auth_callbacks {
|
||||
void (*store_ptksa)(void *ctx, const u8 *addr, int cipher,
|
||||
u32 life_time, const struct wpa_ptk *ptk);
|
||||
void (*clear_ptksa)(void *ctx, const u8 *addr, int cipher);
|
||||
void (*request_radius_psk)(void *ctx, const u8 *addr, int key_mgmt,
|
||||
const u8 *anonce,
|
||||
const u8 *eapol, size_t eapol_len);
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
|
||||
int (*add_sta_ft)(void *ctx, const u8 *sta_addr);
|
||||
@ -345,6 +395,14 @@ struct wpa_auth_callbacks {
|
||||
#ifdef CONFIG_MESH
|
||||
int (*start_ampe)(void *ctx, const u8 *sta_addr);
|
||||
#endif /* CONFIG_MESH */
|
||||
#ifdef CONFIG_PASN
|
||||
int (*set_ltf_keyseed)(void *ctx, const u8 *addr, const u8 *ltf_keyseed,
|
||||
size_t ltf_keyseed_len);
|
||||
#endif /* CONFIG_PASN */
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
int (*get_ml_key_info)(void *ctx, struct wpa_auth_ml_key_info *info);
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
int (*get_drv_flags)(void *ctx, u64 *drv_flags, u64 *drv_flags2);
|
||||
};
|
||||
|
||||
struct wpa_authenticator * wpa_init(const u8 *addr,
|
||||
@ -370,7 +428,8 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
const u8 *rsnxe, size_t rsnxe_len,
|
||||
const u8 *mdie, size_t mdie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len);
|
||||
const u8 *owe_dh, size_t owe_dh_len,
|
||||
struct wpa_state_machine *assoc_sm);
|
||||
int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
const u8 *osen_ie, size_t osen_ie_len);
|
||||
@ -401,6 +460,7 @@ void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
|
||||
int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
|
||||
int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
|
||||
const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len);
|
||||
const u8 * wpa_auth_get_dpp_pkhash(struct wpa_state_machine *sm);
|
||||
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
|
||||
int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
|
||||
int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
|
||||
@ -420,11 +480,12 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
|
||||
int session_timeout,
|
||||
struct eapol_state_machine *eapol);
|
||||
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
const u8 *pmk, const u8 *pmkid);
|
||||
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
|
||||
int akmp);
|
||||
void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid);
|
||||
int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
|
||||
int session_timeout, int akmp);
|
||||
int session_timeout, int akmp, const u8 *dpp_pkhash);
|
||||
void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
|
||||
const u8 *sta_addr);
|
||||
int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
|
||||
@ -434,9 +495,12 @@ int wpa_auth_pmksa_list_mesh(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
char *buf, size_t len);
|
||||
struct rsn_pmksa_cache_entry *
|
||||
wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk,
|
||||
size_t pmk_len, int akmp,
|
||||
const u8 *pmkid, int expiration);
|
||||
int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth,
|
||||
struct rsn_pmksa_cache_entry *entry);
|
||||
struct rsn_pmksa_cache *
|
||||
wpa_auth_get_pmksa_cache(struct wpa_authenticator *wpa_auth);
|
||||
struct rsn_pmksa_cache_entry *
|
||||
wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
|
||||
const u8 *pmkid);
|
||||
@ -446,7 +510,7 @@ wpa_auth_pmksa_get_fils_cache_id(struct wpa_authenticator *wpa_auth,
|
||||
void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
|
||||
struct wpa_state_machine *sm,
|
||||
struct wpa_authenticator *wpa_auth,
|
||||
u8 *pmkid, u8 *pmk);
|
||||
u8 *pmkid, u8 *pmk, size_t *pmk_len);
|
||||
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
|
||||
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, int ack);
|
||||
@ -456,9 +520,9 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||
size_t max_len, int auth_alg,
|
||||
const u8 *req_ies, size_t req_ies_len,
|
||||
int omit_rsnxe);
|
||||
void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
|
||||
void wpa_ft_process_auth(struct wpa_state_machine *sm,
|
||||
u16 auth_transaction, const u8 *ies, size_t ies_len,
|
||||
void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
|
||||
void (*cb)(void *ctx, const u8 *dst,
|
||||
u16 auth_transaction, u16 resp,
|
||||
const u8 *ies, size_t ies_len),
|
||||
void *ctx);
|
||||
@ -524,7 +588,8 @@ int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies,
|
||||
int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth,
|
||||
int ap_seg1_idx, int *bandwidth, int *seg1_idx);
|
||||
|
||||
int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384,
|
||||
int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
u8 *buf, size_t len);
|
||||
void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm,
|
||||
u8 *fils_anonce, u8 *fils_snonce,
|
||||
@ -541,6 +606,7 @@ bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
|
||||
u8 *fd_rsn_info);
|
||||
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
|
||||
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
|
||||
void wpa_auth_set_ssid_protection(struct wpa_state_machine *sm, bool val);
|
||||
void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
|
||||
u8 val);
|
||||
|
||||
@ -572,4 +638,21 @@ void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth,
|
||||
enum wpa_auth_ocv_override_frame frame,
|
||||
unsigned int freq);
|
||||
|
||||
void wpa_auth_sta_radius_psk_resp(struct wpa_state_machine *sm, bool success);
|
||||
|
||||
void wpa_auth_set_ml_info(struct wpa_state_machine *sm,
|
||||
u8 mld_assoc_link_id, struct mld_info *info);
|
||||
void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
|
||||
struct wpa_auth_ml_link_key_info *info,
|
||||
bool mgmt_frame_prot, bool beacon_prot);
|
||||
|
||||
void wpa_release_link_auth_ref(struct wpa_state_machine *sm,
|
||||
int release_link_id);
|
||||
|
||||
#define for_each_sm_auth(sm, link_id) \
|
||||
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) \
|
||||
if (sm->mld_links[link_id].valid && \
|
||||
sm->mld_links[link_id].wpa_auth && \
|
||||
sm->wpa_auth != sm->mld_links[link_id].wpa_auth)
|
||||
|
||||
#endif /* WPA_AUTH_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / WPA authenticator glue code
|
||||
* Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -29,6 +29,7 @@
|
||||
#include "ap_drv_ops.h"
|
||||
#include "ap_config.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "ieee802_11_auth.h"
|
||||
#include "pmksa_cache_auth.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "wpa_auth_glue.h"
|
||||
@ -72,11 +73,12 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
wconf->beacon_prot = conf->beacon_prot;
|
||||
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
|
||||
wconf->sae_require_mfp = conf->sae_require_mfp;
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
wconf->ssid_protection = conf->ssid_protection;
|
||||
wconf->ssid_len = conf->ssid.ssid_len;
|
||||
if (wconf->ssid_len > SSID_MAX_LEN)
|
||||
wconf->ssid_len = SSID_MAX_LEN;
|
||||
os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
os_memcpy(wconf->mobility_domain, conf->mobility_domain,
|
||||
MOBILITY_DOMAIN_ID_LEN);
|
||||
if (conf->nas_identifier &&
|
||||
@ -116,6 +118,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
wconf->corrupt_gtk_rekey_mic_probability =
|
||||
iconf->corrupt_gtk_rekey_mic_probability;
|
||||
wconf->delay_eapol_tx = iconf->delay_eapol_tx;
|
||||
if (conf->own_ie_override &&
|
||||
wpabuf_len(conf->own_ie_override) <= MAX_OWN_IE_OVERRIDE) {
|
||||
wconf->own_ie_override_len = wpabuf_len(conf->own_ie_override);
|
||||
@ -181,6 +184,12 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
wconf->oci_freq_override_ft_assoc = conf->oci_freq_override_ft_assoc;
|
||||
wconf->oci_freq_override_fils_assoc =
|
||||
conf->oci_freq_override_fils_assoc;
|
||||
|
||||
if (conf->eapol_m1_elements)
|
||||
wconf->eapol_m1_elements = wpabuf_dup(conf->eapol_m1_elements);
|
||||
if (conf->eapol_m3_elements)
|
||||
wconf->eapol_m3_elements = wpabuf_dup(conf->eapol_m3_elements);
|
||||
wconf->eapol_m3_no_encrypt = conf->eapol_m3_no_encrypt;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#ifdef CONFIG_P2P
|
||||
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
|
||||
@ -195,10 +204,10 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
#endif /* CONFIG_FILS */
|
||||
wconf->sae_pwe = conf->sae_pwe;
|
||||
sae_pw_id = hostapd_sae_pw_id_in_use(conf);
|
||||
if (sae_pw_id == 2 && wconf->sae_pwe != 3)
|
||||
wconf->sae_pwe = 1;
|
||||
else if (sae_pw_id == 1 && wconf->sae_pwe == 0)
|
||||
wconf->sae_pwe = 2;
|
||||
if (sae_pw_id == 2 && wconf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
|
||||
wconf->sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
|
||||
else if (sae_pw_id == 1 && wconf->sae_pwe == SAE_PWE_HUNT_AND_PECK)
|
||||
wconf->sae_pwe = SAE_PWE_BOTH;
|
||||
#ifdef CONFIG_SAE_PK
|
||||
wconf->sae_pk = hostapd_sae_pk_in_use(conf);
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
@ -214,6 +223,11 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
wconf->force_kdk_derivation = conf->force_kdk_derivation;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#endif /* CONFIG_PASN */
|
||||
|
||||
wconf->radius_psk = conf->wpa_psk_radius == PSK_RADIUS_DURING_4WAY_HS;
|
||||
wconf->no_disconnect_on_group_keyerror =
|
||||
conf->bss_max_idle && conf->ap_max_inactivity &&
|
||||
conf->no_disconnect_on_group_keyerror;
|
||||
}
|
||||
|
||||
|
||||
@ -345,6 +359,8 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
|
||||
if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
|
||||
if (!sta->sae || prev_psk)
|
||||
return NULL;
|
||||
if (psk_len)
|
||||
*psk_len = sta->sae->pmk_len;
|
||||
return sta->sae->pmk;
|
||||
}
|
||||
if (sta && wpa_auth_uses_sae(sta->wpa_sm)) {
|
||||
@ -388,10 +404,14 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
|
||||
psk = sta->psk->psk;
|
||||
for (pos = sta->psk; pos; pos = pos->next) {
|
||||
if (pos->is_passphrase) {
|
||||
pbkdf2_sha1(pos->passphrase,
|
||||
hapd->conf->ssid.ssid,
|
||||
hapd->conf->ssid.ssid_len, 4096,
|
||||
pos->psk, PMK_LEN);
|
||||
if (pbkdf2_sha1(pos->passphrase,
|
||||
hapd->conf->ssid.ssid,
|
||||
hapd->conf->ssid.ssid_len, 4096,
|
||||
pos->psk, PMK_LEN) != 0) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Error in pbkdf2_sha1()");
|
||||
continue;
|
||||
}
|
||||
pos->is_passphrase = 0;
|
||||
}
|
||||
if (pos->psk == prev_psk) {
|
||||
@ -501,7 +521,14 @@ static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx,
|
||||
u8 *seq)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq);
|
||||
int link_id = -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (hapd->conf->mld_ap && idx)
|
||||
link_id = hapd->mld_link_id;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, link_id,
|
||||
seq);
|
||||
}
|
||||
|
||||
|
||||
@ -512,6 +539,11 @@ int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
u32 flags = 0;
|
||||
int link_id = -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
link_id = hapd->conf->mld_ap ? hapd->mld_link_id : -1;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (hapd->ext_eapol_frame_io) {
|
||||
@ -529,11 +561,25 @@ int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta)
|
||||
if (sta) {
|
||||
flags = hostapd_sta_flags_to_drv(sta->flags);
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
if (ap_sta_is_mld(hapd, sta) &&
|
||||
(sta->flags & WLAN_STA_AUTHORIZED))
|
||||
link_id = -1;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
}
|
||||
|
||||
return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len,
|
||||
encrypt, flags);
|
||||
encrypt, flags, link_id);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_get_sta_count(void *ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
return hapd->num_sta;
|
||||
}
|
||||
|
||||
|
||||
@ -632,7 +678,7 @@ static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx)
|
||||
hapd = iface->bss[j];
|
||||
if (hapd == idata->src_hapd ||
|
||||
!hapd->wpa_auth ||
|
||||
os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) != 0)
|
||||
!ether_addr_equal(hapd->own_addr, idata->dst))
|
||||
continue;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
@ -822,7 +868,7 @@ static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx)
|
||||
MOBILITY_DOMAIN_ID_LEN) != 0)
|
||||
continue; /* no matching FT SSID/mobility domain */
|
||||
if (!is_multicast_ether_addr(idata->dst_addr) &&
|
||||
os_memcmp(hapd->own_addr, idata->dst_addr, ETH_ALEN) != 0)
|
||||
!ether_addr_equal(hapd->own_addr, idata->dst_addr))
|
||||
continue; /* destination address does not match */
|
||||
|
||||
/* defer eth_p_oui_deliver until next eloop step as this is
|
||||
@ -925,7 +971,8 @@ static void hostapd_store_ptksa(void *ctx, const u8 *addr,int cipher,
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
ptksa_cache_add(hapd->ptksa, addr, cipher, life_time, ptk);
|
||||
ptksa_cache_add(hapd->ptksa, hapd->own_addr, addr, cipher, life_time,
|
||||
ptk, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -1119,17 +1166,25 @@ static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr,
|
||||
if (!sta || !sta->wpa_sm)
|
||||
return -1;
|
||||
|
||||
if (vlan->notempty &&
|
||||
!hostapd_vlan_valid(hapd->conf->vlan, vlan)) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Invalid VLAN %d%s received from FT",
|
||||
vlan->untagged, vlan->tagged[0] ? "+" : "");
|
||||
return -1;
|
||||
}
|
||||
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
|
||||
if (vlan->notempty &&
|
||||
!hostapd_vlan_valid(hapd->conf->vlan, vlan)) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Invalid VLAN %d%s received from FT",
|
||||
vlan->untagged, vlan->tagged[0] ?
|
||||
"+" : "");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ap_sta_set_vlan(hapd, sta, vlan) < 0)
|
||||
return -1;
|
||||
if (ap_sta_set_vlan(hapd, sta, vlan) < 0)
|
||||
return -1;
|
||||
|
||||
} else {
|
||||
if (vlan->notempty)
|
||||
sta->vlan_id = vlan->untagged;
|
||||
}
|
||||
/* Configure wpa_group for GTK but ignore error due to driver not
|
||||
* knowing this STA. */
|
||||
ap_sta_bind_vlan(hapd, sta);
|
||||
@ -1152,10 +1207,15 @@ static int hostapd_wpa_auth_get_vlan(void *ctx, const u8 *sta_addr,
|
||||
if (!sta)
|
||||
return -1;
|
||||
|
||||
if (sta->vlan_desc)
|
||||
if (sta->vlan_desc) {
|
||||
*vlan = *sta->vlan_desc;
|
||||
else
|
||||
} else if ((hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) &&
|
||||
sta->vlan_id) {
|
||||
vlan->notempty = 1;
|
||||
vlan->untagged = sta->vlan_id;
|
||||
} else {
|
||||
os_memset(vlan, 0, sizeof(*vlan));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1358,7 +1418,7 @@ static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
|
||||
MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest));
|
||||
if (!is_multicast_ether_addr(ethhdr->h_dest) &&
|
||||
os_memcmp(hapd->own_addr, ethhdr->h_dest, ETH_ALEN) != 0)
|
||||
!ether_addr_equal(hapd->own_addr, ethhdr->h_dest))
|
||||
return;
|
||||
wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr),
|
||||
len - sizeof(*ethhdr));
|
||||
@ -1374,7 +1434,7 @@ static void hostapd_rrb_oui_receive(void *ctx, const u8 *src_addr,
|
||||
wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
|
||||
MACSTR, MAC2STR(src_addr), MAC2STR(dst_addr));
|
||||
if (!is_multicast_ether_addr(dst_addr) &&
|
||||
os_memcmp(hapd->own_addr, dst_addr, ETH_ALEN) != 0)
|
||||
!ether_addr_equal(hapd->own_addr, dst_addr))
|
||||
return;
|
||||
wpa_ft_rrb_oui_rx(hapd->wpa_auth, src_addr, dst_addr, oui_suffix, buf,
|
||||
len);
|
||||
@ -1443,6 +1503,106 @@ static void hostapd_wpa_unregister_ft_oui(struct hostapd_data *hapd)
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
static void hostapd_request_radius_psk(void *ctx, const u8 *addr, int key_mgmt,
|
||||
const u8 *anonce,
|
||||
const u8 *eapol, size_t eapol_len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "RADIUS PSK request for " MACSTR " key_mgmt=0x%x",
|
||||
MAC2STR(addr), key_mgmt);
|
||||
wpa_hexdump(MSG_DEBUG, "ANonce", anonce, WPA_NONCE_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "EAPOL", eapol, eapol_len);
|
||||
hostapd_acl_req_radius_psk(hapd, addr, key_mgmt, anonce, eapol,
|
||||
eapol_len);
|
||||
}
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
|
||||
#ifdef CONFIG_PASN
|
||||
static int hostapd_set_ltf_keyseed(void *ctx, const u8 *peer_addr,
|
||||
const u8 *ltf_keyseed,
|
||||
size_t ltf_keyseed_len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
return hostapd_drv_set_secure_ranging_ctx(hapd, hapd->own_addr,
|
||||
peer_addr, 0, 0, NULL,
|
||||
ltf_keyseed_len,
|
||||
ltf_keyseed, 0);
|
||||
}
|
||||
#endif /* CONFIG_PASN */
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
|
||||
static int hostapd_wpa_auth_get_ml_key_info(void *ctx,
|
||||
struct wpa_auth_ml_key_info *info)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
unsigned int i;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPA_AUTH: MLD: Get key info CB: n_mld_links=%u",
|
||||
info->n_mld_links);
|
||||
|
||||
if (!hapd->conf->mld_ap || !hapd->iface || !hapd->iface->interfaces)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < info->n_mld_links; i++) {
|
||||
struct hostapd_data *bss;
|
||||
u8 link_id = info->links[i].link_id;
|
||||
bool link_bss_found = false;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA_AUTH: MLD: Get link info CB: link_id=%u",
|
||||
link_id);
|
||||
|
||||
if (hapd->mld_link_id == link_id) {
|
||||
wpa_auth_ml_get_key_info(hapd->wpa_auth,
|
||||
&info->links[i],
|
||||
info->mgmt_frame_prot,
|
||||
info->beacon_prot);
|
||||
continue;
|
||||
}
|
||||
|
||||
for_each_mld_link(bss, hapd) {
|
||||
if (bss == hapd || bss->mld_link_id != link_id)
|
||||
continue;
|
||||
|
||||
wpa_auth_ml_get_key_info(bss->wpa_auth,
|
||||
&info->links[i],
|
||||
info->mgmt_frame_prot,
|
||||
info->beacon_prot);
|
||||
link_bss_found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!link_bss_found)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA_AUTH: MLD: link=%u not found", link_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_get_drv_flags(void *ctx,
|
||||
u64 *drv_flags, u64 *drv_flags2)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
if (drv_flags)
|
||||
*drv_flags = hapd->iface->drv_flags;
|
||||
if (drv_flags2)
|
||||
*drv_flags2 = hapd->iface->drv_flags2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
{
|
||||
struct wpa_auth_config _conf;
|
||||
@ -1458,6 +1618,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
.set_key = hostapd_wpa_auth_set_key,
|
||||
.get_seqnum = hostapd_wpa_auth_get_seqnum,
|
||||
.send_eapol = hostapd_wpa_auth_send_eapol,
|
||||
.get_sta_count = hostapd_wpa_auth_get_sta_count,
|
||||
.for_each_sta = hostapd_wpa_auth_for_each_sta,
|
||||
.for_each_auth = hostapd_wpa_auth_for_each_auth,
|
||||
.send_ether = hostapd_wpa_auth_send_ether,
|
||||
@ -1486,12 +1647,26 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
.set_session_timeout = hostapd_wpa_auth_set_session_timeout,
|
||||
.get_session_timeout = hostapd_wpa_auth_get_session_timeout,
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
.request_radius_psk = hostapd_request_radius_psk,
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
#ifdef CONFIG_PASN
|
||||
.set_ltf_keyseed = hostapd_set_ltf_keyseed,
|
||||
#endif /* CONFIG_PASN */
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
.get_ml_key_info = hostapd_wpa_auth_get_ml_key_info,
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
.get_drv_flags = hostapd_wpa_auth_get_drv_flags,
|
||||
};
|
||||
const u8 *wpa_ie;
|
||||
size_t wpa_ie_len;
|
||||
struct hostapd_data *tx_bss;
|
||||
|
||||
hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf);
|
||||
_conf.msg_ctx = hapd->msg_ctx;
|
||||
tx_bss = hostapd_mbssid_get_tx_bss(hapd);
|
||||
if (tx_bss != hapd)
|
||||
_conf.tx_bss_auth = tx_bss->wpa_auth;
|
||||
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
|
||||
_conf.tx_status = 1;
|
||||
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
|
||||
@ -1522,11 +1697,33 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
_conf.secure_ltf =
|
||||
!!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF);
|
||||
!!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP);
|
||||
_conf.secure_rtt =
|
||||
!!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT);
|
||||
!!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_AP);
|
||||
_conf.prot_range_neg =
|
||||
!!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG);
|
||||
!!(hapd->iface->drv_flags2 &
|
||||
WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP);
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
_conf.mld_addr = NULL;
|
||||
_conf.link_id = -1;
|
||||
_conf.first_link_auth = NULL;
|
||||
|
||||
if (hapd->conf->mld_ap) {
|
||||
struct hostapd_data *lhapd;
|
||||
|
||||
_conf.mld_addr = hapd->mld->mld_addr;
|
||||
_conf.link_id = hapd->mld_link_id;
|
||||
|
||||
for_each_mld_link(lhapd, hapd) {
|
||||
if (lhapd == hapd)
|
||||
continue;
|
||||
|
||||
if (lhapd->wpa_auth)
|
||||
_conf.first_link_auth = lhapd->wpa_auth;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
|
||||
if (hapd->wpa_auth == NULL) {
|
||||
@ -1631,4 +1828,10 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd)
|
||||
hapd->l2 = NULL;
|
||||
hostapd_wpa_unregister_ft_oui(hapd);
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
forced_memzero(hapd->last_gtk, WPA_GTK_MAX_LEN);
|
||||
forced_memzero(hapd->last_igtk, WPA_IGTK_MAX_LEN);
|
||||
forced_memzero(hapd->last_bigtk, WPA_BIGTK_MAX_LEN);
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
}
|
||||
|
@ -86,9 +86,11 @@ struct wpa_state_machine {
|
||||
unsigned int pending_deinit:1;
|
||||
unsigned int started:1;
|
||||
unsigned int mgmt_frame_prot:1;
|
||||
unsigned int mfpr:1;
|
||||
unsigned int rx_eapol_key_secure:1;
|
||||
unsigned int update_snonce:1;
|
||||
unsigned int alt_snonce_valid:1;
|
||||
unsigned int waiting_radius_psk:1;
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
unsigned int ft_completed:1;
|
||||
unsigned int pmk_r1_name_valid:1;
|
||||
@ -96,6 +98,8 @@ struct wpa_state_machine {
|
||||
unsigned int is_wnmsleep:1;
|
||||
unsigned int pmkid_set:1;
|
||||
|
||||
unsigned int ptkstart_without_success;
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
int ocv_enabled;
|
||||
#endif /* CONFIG_OCV */
|
||||
@ -130,11 +134,9 @@ struct wpa_state_machine {
|
||||
* Request */
|
||||
u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */
|
||||
size_t r0kh_id_len;
|
||||
u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key
|
||||
* message 2/4 */
|
||||
u8 *assoc_resp_ftie;
|
||||
|
||||
void (*ft_pending_cb)(void *ctx, const u8 *dst, const u8 *bssid,
|
||||
void (*ft_pending_cb)(void *ctx, const u8 *dst,
|
||||
u16 auth_transaction, u16 status,
|
||||
const u8 *ies, size_t ies_len);
|
||||
void *ft_pending_cb_ctx;
|
||||
@ -149,6 +151,7 @@ struct wpa_state_machine {
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
u8 ip_addr[4];
|
||||
unsigned int ip_addr_bit;
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
@ -167,6 +170,21 @@ struct wpa_state_machine {
|
||||
void *eapol_status_cb_ctx1;
|
||||
void *eapol_status_cb_ctx2;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
u8 peer_mld_addr[ETH_ALEN];
|
||||
s8 mld_assoc_link_id;
|
||||
u8 n_mld_affiliated_links;
|
||||
|
||||
struct mld_link {
|
||||
bool valid;
|
||||
u8 peer_addr[ETH_ALEN];
|
||||
|
||||
struct wpa_authenticator *wpa_auth;
|
||||
} mld_links[MAX_NUM_MLD_LINKS];
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
|
||||
bool ssid_protection;
|
||||
};
|
||||
|
||||
|
||||
@ -199,6 +217,8 @@ struct wpa_group {
|
||||
u8 BIGTK[2][WPA_IGTK_MAX_LEN];
|
||||
int GN_igtk, GM_igtk;
|
||||
int GN_bigtk, GM_bigtk;
|
||||
bool bigtk_set;
|
||||
bool bigtk_configured;
|
||||
/* Number of references except those in struct wpa_group->next */
|
||||
unsigned int references;
|
||||
unsigned int num_setup_iface;
|
||||
@ -234,9 +254,18 @@ struct wpa_authenticator {
|
||||
struct rsn_pmksa_cache *pmksa;
|
||||
struct wpa_ft_pmk_cache *ft_pmk_cache;
|
||||
|
||||
bool non_tx_beacon_prot;
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
struct bitfield *ip_pool;
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
bool is_ml;
|
||||
u8 mld_addr[ETH_ALEN];
|
||||
u8 link_id;
|
||||
bool primary_auth;
|
||||
#endif /* CONFIG_IEEE80211BE */
|
||||
};
|
||||
|
||||
|
||||
@ -291,15 +320,23 @@ int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
|
||||
int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
|
||||
int (*cb)(struct wpa_authenticator *a, void *ctx),
|
||||
void *cb_ctx);
|
||||
void wpa_auth_store_ptksa(struct wpa_authenticator *wpa_auth,
|
||||
const u8 *addr, int cipher,
|
||||
u32 life_time, const struct wpa_ptk *ptk);
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
|
||||
int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
|
||||
int wpa_write_ftie(struct wpa_auth_config *conf, int key_mgmt, size_t key_len,
|
||||
const u8 *r0kh_id, size_t r0kh_id_len,
|
||||
const u8 *anonce, const u8 *snonce,
|
||||
u8 *buf, size_t len, const u8 *subelem,
|
||||
size_t subelem_len, int rsnxe_used);
|
||||
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk);
|
||||
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk,
|
||||
u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
|
||||
size_t *key_len, size_t kdk_len);
|
||||
void wpa_auth_ft_store_keys(struct wpa_state_machine *sm, const u8 *pmk_r0,
|
||||
const u8 *pmk_r1, const u8 *pmk_r0_name,
|
||||
size_t key_len);
|
||||
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
|
||||
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
|
||||
void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry);
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "eapol_auth/eapol_auth_sm.h"
|
||||
#include "ap_config.h"
|
||||
#include "ieee802_11.h"
|
||||
@ -212,6 +213,13 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_SHA384
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA384);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_SHA384 */
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
@ -228,11 +236,21 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
|
||||
@ -391,11 +409,13 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
|
||||
int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
|
||||
{
|
||||
u8 *pos = buf;
|
||||
u16 capab = 0;
|
||||
u32 capab = 0, tmp;
|
||||
size_t flen;
|
||||
|
||||
if (wpa_key_mgmt_sae(conf->wpa_key_mgmt) &&
|
||||
(conf->sae_pwe == 1 || conf->sae_pwe == 2 || conf->sae_pk)) {
|
||||
(conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
|
||||
conf->sae_pwe == SAE_PWE_BOTH || conf->sae_pk ||
|
||||
wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt))) {
|
||||
capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
|
||||
#ifdef CONFIG_SAE_PK
|
||||
if (conf->sae_pk)
|
||||
@ -408,21 +428,28 @@ int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
|
||||
if (conf->secure_rtt)
|
||||
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
|
||||
if (conf->prot_range_neg)
|
||||
capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
|
||||
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
|
||||
if (conf->ssid_protection)
|
||||
capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION);
|
||||
|
||||
flen = (capab & 0xff00) ? 2 : 1;
|
||||
if (!capab)
|
||||
return 0; /* no supported extended RSN capabilities */
|
||||
tmp = capab;
|
||||
flen = 0;
|
||||
while (tmp) {
|
||||
flen++;
|
||||
tmp >>= 8;
|
||||
}
|
||||
if (len < 2 + flen)
|
||||
return -1;
|
||||
capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
|
||||
|
||||
*pos++ = WLAN_EID_RSNX;
|
||||
*pos++ = flen;
|
||||
*pos++ = capab & 0x00ff;
|
||||
capab >>= 8;
|
||||
if (capab)
|
||||
*pos++ = capab;
|
||||
while (capab) {
|
||||
*pos++ = capab & 0xff;
|
||||
capab >>= 8;
|
||||
}
|
||||
|
||||
return pos - buf;
|
||||
}
|
||||
@ -588,7 +615,8 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
const u8 *rsnxe, size_t rsnxe_len,
|
||||
const u8 *mdie, size_t mdie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len)
|
||||
const u8 *owe_dh, size_t owe_dh_len,
|
||||
struct wpa_state_machine *assoc_sm)
|
||||
{
|
||||
struct wpa_auth_config *conf = &wpa_auth->conf;
|
||||
struct wpa_ie_data data;
|
||||
@ -670,8 +698,12 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
#ifdef CONFIG_SAE
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
|
||||
selector = RSN_AUTH_KEY_MGMT_SAE;
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY)
|
||||
selector = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY;
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE)
|
||||
selector = RSN_AUTH_KEY_MGMT_FT_SAE;
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY)
|
||||
selector = RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY;
|
||||
#endif /* CONFIG_SAE */
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
|
||||
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
|
||||
@ -689,6 +721,10 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_OSEN)
|
||||
selector = RSN_AUTH_KEY_MGMT_OSEN;
|
||||
#endif /* CONFIG_HS20 */
|
||||
#ifdef CONFIG_SHA384
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384)
|
||||
selector = RSN_AUTH_KEY_MGMT_802_1X_SHA384;
|
||||
#endif /* CONFIG_SHA384 */
|
||||
wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
|
||||
|
||||
selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
|
||||
@ -771,6 +807,10 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_SHA384
|
||||
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA384;
|
||||
#endif /* CONFIG_SHA384 */
|
||||
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
|
||||
else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
|
||||
@ -778,8 +818,12 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
#ifdef CONFIG_SAE
|
||||
else if (key_mgmt & WPA_KEY_MGMT_SAE)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
|
||||
else if (key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY;
|
||||
else if (key_mgmt & WPA_KEY_MGMT_FT_SAE)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE;
|
||||
else if (key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE_EXT_KEY;
|
||||
#endif /* CONFIG_SAE */
|
||||
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
|
||||
@ -864,6 +908,7 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
sm->mgmt_frame_prot = 0;
|
||||
else
|
||||
sm->mgmt_frame_prot = 1;
|
||||
sm->mfpr = !!(data.capabilities & WPA_CAPABILITY_MFPR);
|
||||
|
||||
if (sm->mgmt_frame_prot && (ciphers & WPA_CIPHER_TKIP)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
@ -919,6 +964,15 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
else
|
||||
sm->wpa = WPA_VERSION_WPA;
|
||||
|
||||
if (assoc_sm) {
|
||||
/* For ML association link STA cannot choose a different
|
||||
* AKM or pairwise cipher from association STA */
|
||||
if (sm->wpa_key_mgmt != assoc_sm->wpa_key_mgmt)
|
||||
return WPA_INVALID_AKMP;
|
||||
if (sm->pairwise != assoc_sm->pairwise)
|
||||
return WPA_INVALID_PAIRWISE;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IEEE80211R_AP) && defined(CONFIG_FILS)
|
||||
if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256 ||
|
||||
sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384) &&
|
||||
@ -977,11 +1031,24 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE && data.num_pmkid &&
|
||||
!sm->pmksa) {
|
||||
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||
"No PMKSA cache entry found for SAE");
|
||||
return WPA_INVALID_PMKID;
|
||||
if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE ||
|
||||
sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE_EXT_KEY) {
|
||||
u64 drv_flags = 0;
|
||||
u64 drv_flags2 = 0;
|
||||
bool ap_sae_offload = false;
|
||||
|
||||
if (wpa_auth->cb->get_drv_flags &&
|
||||
wpa_auth->cb->get_drv_flags(wpa_auth->cb_ctx, &drv_flags,
|
||||
&drv_flags2) == 0)
|
||||
ap_sae_offload =
|
||||
!!(drv_flags2 &
|
||||
WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP);
|
||||
|
||||
if (!ap_sae_offload && data.num_pmkid && !sm->pmksa) {
|
||||
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||
"No PMKSA cache entry found for SAE");
|
||||
return WPA_INVALID_PMKID;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
|
@ -138,7 +138,6 @@ static unsigned int conf_offset_val(enum confidentiality_offset co)
|
||||
switch (co) {
|
||||
case CONFIDENTIALITY_OFFSET_30:
|
||||
return 30;
|
||||
break;
|
||||
case CONFIDENTIALITY_OFFSET_50:
|
||||
return 50;
|
||||
default:
|
||||
@ -328,8 +327,11 @@ int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
|
||||
res = ieee802_1x_kay_init(kay_ctx, policy,
|
||||
hapd->conf->macsec_replay_protect,
|
||||
hapd->conf->macsec_replay_window,
|
||||
hapd->conf->macsec_offload,
|
||||
hapd->conf->macsec_port,
|
||||
hapd->conf->mka_priority, hapd->conf->iface,
|
||||
hapd->conf->mka_priority,
|
||||
hapd->conf->macsec_csindex,
|
||||
hapd->conf->iface,
|
||||
hapd->own_addr);
|
||||
/* ieee802_1x_kay_init() frees kay_ctx on failure */
|
||||
if (!res)
|
||||
@ -351,33 +353,6 @@ void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
|
||||
static int ieee802_1x_auth_get_session_id(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u8 *sid,
|
||||
size_t *len)
|
||||
{
|
||||
const u8 *session_id;
|
||||
size_t id_len, need_len;
|
||||
|
||||
session_id = ieee802_1x_get_session_id(sta->eapol_sm, &id_len);
|
||||
if (!session_id) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MACsec: Failed to get SessionID from EAPOL state machines");
|
||||
return -1;
|
||||
}
|
||||
|
||||
need_len = 1 + 2 * 32 /* random size */;
|
||||
if (need_len > id_len) {
|
||||
wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy(sid, session_id, need_len);
|
||||
*len = need_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ieee802_1x_auth_get_msk(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u8 *msk, size_t *len)
|
||||
{
|
||||
@ -409,8 +384,8 @@ static int ieee802_1x_auth_get_msk(struct hostapd_data *hapd,
|
||||
void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
u8 *sid;
|
||||
size_t sid_len = 128;
|
||||
const u8 *sid;
|
||||
size_t sid_len;
|
||||
struct mka_key_name *ckn;
|
||||
struct mka_key *cak;
|
||||
struct mka_key *msk;
|
||||
@ -424,10 +399,9 @@ void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
|
||||
MACSTR, MAC2STR(sta->addr));
|
||||
|
||||
msk = os_zalloc(sizeof(*msk));
|
||||
sid = os_zalloc(sid_len);
|
||||
ckn = os_zalloc(sizeof(*ckn));
|
||||
cak = os_zalloc(sizeof(*cak));
|
||||
if (!msk || !sid || !ckn || !cak)
|
||||
if (!msk || !ckn || !cak)
|
||||
goto fail;
|
||||
|
||||
msk->len = DEFAULT_KEY_LEN;
|
||||
@ -436,8 +410,8 @@ void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ieee802_1x_auth_get_session_id(hapd, sta, sid, &sid_len))
|
||||
{
|
||||
sid = ieee802_1x_get_session_id(sta->eapol_sm, &sid_len);
|
||||
if (!sid) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"IEEE 802.1X: Could not get EAP Session Id");
|
||||
goto fail;
|
||||
@ -469,7 +443,6 @@ void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
|
||||
|
||||
fail:
|
||||
bin_clear_free(msk, sizeof(*msk));
|
||||
os_free(sid);
|
||||
os_free(ckn);
|
||||
bin_clear_free(cak, sizeof(*cak));
|
||||
|
||||
|
@ -288,7 +288,7 @@ static int hostapd_wps_lookup_pskfile_cb(void *ctx, const u8 *mac_addr,
|
||||
any_psk = wpa_psk->psk;
|
||||
|
||||
if (mac_addr && !dev_psk &&
|
||||
os_memcmp(mac_addr, wpa_psk->addr, ETH_ALEN) == 0) {
|
||||
ether_addr_equal(mac_addr, wpa_psk->addr)) {
|
||||
dev_psk = wpa_psk->psk;
|
||||
break;
|
||||
}
|
||||
@ -1069,10 +1069,11 @@ static void hostapd_free_wps(struct wps_context *wps)
|
||||
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
|
||||
wpabuf_free(wps->dev.vendor_ext[i]);
|
||||
wps_device_data_free(&wps->dev);
|
||||
os_free(wps->network_key);
|
||||
bin_clear_free(wps->network_key, wps->network_key_len);
|
||||
hostapd_wps_nfc_clear(wps);
|
||||
wpabuf_free(wps->dh_pubkey);
|
||||
wpabuf_free(wps->dh_privkey);
|
||||
forced_memzero(wps->psk, sizeof(wps->psk));
|
||||
os_free(wps);
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,8 @@ int x_snoop_init(struct hostapd_data *hapd)
|
||||
return -1;
|
||||
}
|
||||
|
||||
hapd->x_snoop_initialized = true;
|
||||
|
||||
if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE,
|
||||
1)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
@ -125,7 +127,10 @@ void x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd,
|
||||
|
||||
void x_snoop_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
if (!hapd->x_snoop_initialized)
|
||||
return;
|
||||
hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0);
|
||||
hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0);
|
||||
hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0);
|
||||
hapd->x_snoop_initialized = false;
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ endif
|
||||
_DIRS := $(BUILDDIR)/$(PROJ)
|
||||
.PHONY: _make_dirs
|
||||
_make_dirs:
|
||||
@mkdir -p $(_DIRS)
|
||||
@mkdir -p $(sort $(_DIRS))
|
||||
|
||||
$(BUILDDIR)/$(PROJ)/src/%.o: $(ROOTDIR)src/%.c $(CONFIG_FILE) | _make_dirs
|
||||
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
|
||||
|
@ -40,15 +40,15 @@
|
||||
* @BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS: Set some connect parameters.
|
||||
* Used for the case that FW handle SAE.
|
||||
*
|
||||
* @BRCM_VENDOR_SCMD_SET_START_AP_PARAMS: Set SoftAP paramters.
|
||||
* @BRCM_VENDOR_SCMD_SET_START_AP_PARAMS: Set SoftAP parameters.
|
||||
* Used for the case that FW handle SAE.
|
||||
*
|
||||
* @BRCM_VENDOR_SCMD_ACS: ACS command/event which is used to
|
||||
* invoke the ACS function in device and pass selected channels to
|
||||
* hostapd. Uses enum qca_wlan_vendor_attr_acs_offload attributes.
|
||||
*
|
||||
* @BRCM_VENDOR_SCMD_MAX: This acts as a the tail of cmds list.
|
||||
* Make sure it located at the end of the list.
|
||||
* @BRCM_VENDOR_SCMD_MAX: This acts as a tail of cmds list.
|
||||
* Make sure it is located at the end of the list.
|
||||
*
|
||||
*/
|
||||
enum brcm_nl80211_vendor_subcmds {
|
||||
@ -66,7 +66,7 @@ enum brcm_nl80211_vendor_subcmds {
|
||||
};
|
||||
|
||||
/**
|
||||
* enum brcm_nl80211_vendor_events - BRCM nl80211 asynchoronous event identifiers
|
||||
* enum brcm_nl80211_vendor_events - BRCM nl80211 asynchronous event identifiers
|
||||
*
|
||||
* @BRCM_VENDOR_EVENT_UNSPEC: Reserved value 0
|
||||
*
|
||||
|
@ -428,7 +428,7 @@ static int sae_tests(void)
|
||||
}
|
||||
|
||||
if (sae_parse_commit(&sae, peer_commit, sizeof(peer_commit), NULL, NULL,
|
||||
NULL, 0) != 0 ||
|
||||
NULL, 0, NULL) != 0 ||
|
||||
sae_process_commit(&sae) < 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -50,12 +50,16 @@
|
||||
#define WPA_KEY_MGMT_DPP BIT(23)
|
||||
#define WPA_KEY_MGMT_FT_IEEE8021X_SHA384 BIT(24)
|
||||
#define WPA_KEY_MGMT_PASN BIT(25)
|
||||
#define WPA_KEY_MGMT_SAE_EXT_KEY BIT(26)
|
||||
#define WPA_KEY_MGMT_FT_SAE_EXT_KEY BIT(27)
|
||||
#define WPA_KEY_MGMT_IEEE8021X_SHA384 BIT(28)
|
||||
|
||||
|
||||
#define WPA_KEY_MGMT_FT (WPA_KEY_MGMT_FT_PSK | \
|
||||
WPA_KEY_MGMT_FT_IEEE8021X | \
|
||||
WPA_KEY_MGMT_FT_IEEE8021X_SHA384 | \
|
||||
WPA_KEY_MGMT_FT_SAE | \
|
||||
WPA_KEY_MGMT_FT_SAE_EXT_KEY | \
|
||||
WPA_KEY_MGMT_FT_FILS_SHA256 | \
|
||||
WPA_KEY_MGMT_FT_FILS_SHA384)
|
||||
|
||||
@ -72,7 +76,8 @@ static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
|
||||
WPA_KEY_MGMT_FILS_SHA256 |
|
||||
WPA_KEY_MGMT_FILS_SHA384 |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA256 |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA384));
|
||||
WPA_KEY_MGMT_FT_FILS_SHA384 |
|
||||
WPA_KEY_MGMT_IEEE8021X_SHA384));
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_wpa_psk_no_sae(int akm)
|
||||
@ -88,7 +93,9 @@ static inline int wpa_key_mgmt_wpa_psk(int akm)
|
||||
WPA_KEY_MGMT_FT_PSK |
|
||||
WPA_KEY_MGMT_PSK_SHA256 |
|
||||
WPA_KEY_MGMT_SAE |
|
||||
WPA_KEY_MGMT_FT_SAE));
|
||||
WPA_KEY_MGMT_SAE_EXT_KEY |
|
||||
WPA_KEY_MGMT_FT_SAE |
|
||||
WPA_KEY_MGMT_FT_SAE_EXT_KEY));
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_ft(int akm)
|
||||
@ -111,7 +118,15 @@ static inline int wpa_key_mgmt_ft_psk(int akm)
|
||||
static inline int wpa_key_mgmt_sae(int akm)
|
||||
{
|
||||
return !!(akm & (WPA_KEY_MGMT_SAE |
|
||||
WPA_KEY_MGMT_FT_SAE));
|
||||
WPA_KEY_MGMT_SAE_EXT_KEY |
|
||||
WPA_KEY_MGMT_FT_SAE |
|
||||
WPA_KEY_MGMT_FT_SAE_EXT_KEY));
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_sae_ext_key(int akm)
|
||||
{
|
||||
return !!(akm & (WPA_KEY_MGMT_SAE_EXT_KEY |
|
||||
WPA_KEY_MGMT_FT_SAE_EXT_KEY));
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_fils(int akm)
|
||||
@ -124,7 +139,8 @@ static inline int wpa_key_mgmt_fils(int akm)
|
||||
|
||||
static inline int wpa_key_mgmt_sha256(int akm)
|
||||
{
|
||||
return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
|
||||
return !!(akm & (WPA_KEY_MGMT_FT_IEEE8021X |
|
||||
WPA_KEY_MGMT_PSK_SHA256 |
|
||||
WPA_KEY_MGMT_IEEE8021X_SHA256 |
|
||||
WPA_KEY_MGMT_SAE |
|
||||
WPA_KEY_MGMT_FT_SAE |
|
||||
@ -139,7 +155,8 @@ static inline int wpa_key_mgmt_sha384(int akm)
|
||||
return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 |
|
||||
WPA_KEY_MGMT_FT_IEEE8021X_SHA384 |
|
||||
WPA_KEY_MGMT_FILS_SHA384 |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA384));
|
||||
WPA_KEY_MGMT_FT_FILS_SHA384 |
|
||||
WPA_KEY_MGMT_IEEE8021X_SHA384));
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_suite_b(int akm)
|
||||
@ -168,6 +185,13 @@ static inline int wpa_key_mgmt_cckm(int akm)
|
||||
return akm == WPA_KEY_MGMT_CCKM;
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_cross_akm(int akm)
|
||||
{
|
||||
return !!(akm & (WPA_KEY_MGMT_PSK |
|
||||
WPA_KEY_MGMT_PSK_SHA256 |
|
||||
WPA_KEY_MGMT_SAE |
|
||||
WPA_KEY_MGMT_SAE_EXT_KEY));
|
||||
}
|
||||
|
||||
#define WPA_PROTO_WPA BIT(0)
|
||||
#define WPA_PROTO_RSN BIT(1)
|
||||
@ -429,9 +453,26 @@ enum chan_width {
|
||||
CHAN_WIDTH_4320,
|
||||
CHAN_WIDTH_6480,
|
||||
CHAN_WIDTH_8640,
|
||||
CHAN_WIDTH_320,
|
||||
CHAN_WIDTH_UNKNOWN
|
||||
};
|
||||
|
||||
/* VHT/EDMG/etc. channel widths
|
||||
* Note: The first four values are used in hostapd.conf and as such, must
|
||||
* maintain their defined values. Other values are used internally. */
|
||||
enum oper_chan_width {
|
||||
CONF_OPER_CHWIDTH_USE_HT = 0,
|
||||
CONF_OPER_CHWIDTH_80MHZ = 1,
|
||||
CONF_OPER_CHWIDTH_160MHZ = 2,
|
||||
CONF_OPER_CHWIDTH_80P80MHZ = 3,
|
||||
CONF_OPER_CHWIDTH_2160MHZ,
|
||||
CONF_OPER_CHWIDTH_4320MHZ,
|
||||
CONF_OPER_CHWIDTH_6480MHZ,
|
||||
CONF_OPER_CHWIDTH_8640MHZ,
|
||||
CONF_OPER_CHWIDTH_40MHZ_6GHZ,
|
||||
CONF_OPER_CHWIDTH_320MHZ,
|
||||
};
|
||||
|
||||
enum key_flag {
|
||||
KEY_FLAG_MODIFY = BIT(0),
|
||||
KEY_FLAG_DEFAULT = BIT(1),
|
||||
@ -475,4 +516,20 @@ enum ptk0_rekey_handling {
|
||||
PTK0_REKEY_ALLOW_NEVER
|
||||
};
|
||||
|
||||
enum frame_encryption {
|
||||
FRAME_ENCRYPTION_UNKNOWN = -1,
|
||||
FRAME_NOT_ENCRYPTED = 0,
|
||||
FRAME_ENCRYPTED = 1
|
||||
};
|
||||
|
||||
#define MAX_NUM_MLD_LINKS 15
|
||||
|
||||
enum sae_pwe {
|
||||
SAE_PWE_HUNT_AND_PECK = 0,
|
||||
SAE_PWE_HASH_TO_ELEMENT = 1,
|
||||
SAE_PWE_BOTH = 2,
|
||||
SAE_PWE_FORCE_HUNT_AND_PECK = 3,
|
||||
SAE_PWE_NOT_SET = 4,
|
||||
};
|
||||
|
||||
#endif /* DEFS_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@
|
||||
* DPP functionality shared between hostapd and wpa_supplicant
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018-2020, The Linux Foundation
|
||||
* Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -55,6 +56,11 @@ enum dpp_public_action_frame_type {
|
||||
DPP_PA_RECONFIG_AUTH_RESP = 16,
|
||||
DPP_PA_RECONFIG_AUTH_CONF = 17,
|
||||
DPP_PA_PKEX_EXCHANGE_REQ = 18,
|
||||
DPP_PA_PB_PRESENCE_ANNOUNCEMENT = 19,
|
||||
DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP = 20,
|
||||
DPP_PA_PRIV_PEER_INTRO_QUERY = 21,
|
||||
DPP_PA_PRIV_PEER_INTRO_NOTIFY = 22,
|
||||
DPP_PA_PRIV_PEER_INTRO_UPDATE = 23,
|
||||
};
|
||||
|
||||
enum dpp_attribute_id {
|
||||
@ -109,6 +115,7 @@ enum dpp_status_error {
|
||||
DPP_STATUS_CONFIGURE_PENDING = 11,
|
||||
DPP_STATUS_CSR_NEEDED = 12,
|
||||
DPP_STATUS_CSR_BAD = 13,
|
||||
DPP_STATUS_NEW_KEY_NEEDED = 14,
|
||||
};
|
||||
|
||||
/* DPP Reconfig Flags object - connectorKey values */
|
||||
@ -144,6 +151,15 @@ enum dpp_bootstrap_type {
|
||||
DPP_BOOTSTRAP_NFC_URI,
|
||||
};
|
||||
|
||||
enum dpp_bootstrap_supported_curves {
|
||||
DPP_BOOTSTRAP_CURVE_P_256 = 0,
|
||||
DPP_BOOTSTRAP_CURVE_P_384 = 1,
|
||||
DPP_BOOTSTRAP_CURVE_P_521 = 2,
|
||||
DPP_BOOTSTRAP_CURVE_BP_256 = 3,
|
||||
DPP_BOOTSTRAP_CURVE_BP_384 = 4,
|
||||
DPP_BOOTSTRAP_CURVE_BP_512 = 5,
|
||||
};
|
||||
|
||||
struct dpp_bootstrap_info {
|
||||
struct dl_list list;
|
||||
unsigned int id;
|
||||
@ -152,11 +168,14 @@ struct dpp_bootstrap_info {
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
char *chan;
|
||||
char *info;
|
||||
struct hostapd_ip_addr *host;
|
||||
unsigned int port;
|
||||
char *pk;
|
||||
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
|
||||
unsigned int num_freq;
|
||||
bool channels_listed;
|
||||
u8 version;
|
||||
u8 supported_curves; /* enum dpp_bootstrap_supported_curves bitmap */
|
||||
int own;
|
||||
struct crypto_ec_key *pubkey;
|
||||
u8 pubkey_hash[SHA256_MAC_LEN];
|
||||
@ -167,21 +186,32 @@ struct dpp_bootstrap_info {
|
||||
int nfc_negotiated; /* whether this has been used in NFC negotiated
|
||||
* connection handover */
|
||||
char *configurator_params;
|
||||
u8 peer_pubkey_hash[SHA256_MAC_LEN]; /* for enforcing a specific
|
||||
* peer bootstrapping key with
|
||||
* PKEX */
|
||||
};
|
||||
|
||||
#define PKEX_COUNTER_T_LIMIT 5
|
||||
|
||||
enum dpp_pkex_ver {
|
||||
PKEX_VER_AUTO,
|
||||
PKEX_VER_ONLY_1,
|
||||
PKEX_VER_ONLY_2,
|
||||
};
|
||||
|
||||
struct dpp_pkex {
|
||||
void *msg_ctx;
|
||||
unsigned int initiator:1;
|
||||
unsigned int exchange_done:1;
|
||||
unsigned int failed:1;
|
||||
unsigned int v2:1;
|
||||
unsigned int forced_ver:1;
|
||||
struct dpp_bootstrap_info *own_bi;
|
||||
u8 own_mac[ETH_ALEN];
|
||||
u8 peer_mac[ETH_ALEN];
|
||||
char *identifier;
|
||||
char *code;
|
||||
size_t code_len;
|
||||
struct crypto_ec_key *x;
|
||||
struct crypto_ec_key *y;
|
||||
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
@ -195,6 +225,7 @@ struct dpp_pkex {
|
||||
unsigned int exch_req_tries;
|
||||
unsigned int freq;
|
||||
u8 peer_version;
|
||||
struct wpabuf *enc_key;
|
||||
};
|
||||
|
||||
enum dpp_akm {
|
||||
@ -233,6 +264,8 @@ struct dpp_configuration {
|
||||
int psk_set;
|
||||
|
||||
char *csrattrs;
|
||||
char *extra_name;
|
||||
char *extra_value;
|
||||
};
|
||||
|
||||
struct dpp_asymmetric_key {
|
||||
@ -250,6 +283,7 @@ struct dpp_authentication {
|
||||
void *msg_ctx;
|
||||
u8 peer_version;
|
||||
const struct dpp_curve_params *curve;
|
||||
const struct dpp_curve_params *new_curve;
|
||||
struct dpp_bootstrap_info *peer_bi;
|
||||
struct dpp_bootstrap_info *own_bi;
|
||||
struct dpp_bootstrap_info *tmp_own_bi;
|
||||
@ -350,8 +384,15 @@ struct dpp_authentication {
|
||||
char *trusted_eap_server_name;
|
||||
struct wpabuf *cacert;
|
||||
struct wpabuf *certbag;
|
||||
void *cert_resp_ctx;
|
||||
bool waiting_new_key;
|
||||
bool new_key_received;
|
||||
void *config_resp_ctx;
|
||||
void *gas_server_ctx;
|
||||
bool use_config_query;
|
||||
bool waiting_config;
|
||||
char *e_name;
|
||||
char *e_mud_url;
|
||||
int *e_band_support;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
char *config_obj_override;
|
||||
char *discovery_override;
|
||||
@ -368,6 +409,7 @@ struct dpp_configurator {
|
||||
u8 kid_hash[SHA256_MAC_LEN];
|
||||
char *kid;
|
||||
const struct dpp_curve_params *curve;
|
||||
const struct dpp_curve_params *net_access_key_curve;
|
||||
char *connector; /* own Connector for reconfiguration */
|
||||
struct crypto_ec_key *connector_key;
|
||||
struct crypto_ec_key *pp_key;
|
||||
@ -378,6 +420,10 @@ struct dpp_introduction {
|
||||
u8 pmk[PMK_LEN_MAX];
|
||||
size_t pmk_len;
|
||||
int peer_version;
|
||||
struct crypto_ec_key *peer_key;
|
||||
enum hpke_kem_id kem_id;
|
||||
enum hpke_kdf_id kdf_id;
|
||||
enum hpke_aead_id aead_id;
|
||||
};
|
||||
|
||||
struct dpp_relay_config {
|
||||
@ -401,6 +447,14 @@ struct dpp_controller_config {
|
||||
void *msg_ctx;
|
||||
void *cb_ctx;
|
||||
int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
|
||||
bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth);
|
||||
};
|
||||
|
||||
#define DPP_PB_INFO_COUNT 2
|
||||
|
||||
struct dpp_pb_info {
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
struct os_reltime rx_time;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
@ -499,6 +553,13 @@ enum dpp_test_behavior {
|
||||
DPP_TEST_REJECT_CONFIG = 91,
|
||||
DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_REQ = 92,
|
||||
DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_RESP = 93,
|
||||
DPP_TEST_INVALID_PROTOCOL_VERSION_PEER_DISC_REQ = 94,
|
||||
DPP_TEST_INVALID_PROTOCOL_VERSION_PEER_DISC_RESP = 95,
|
||||
DPP_TEST_INVALID_PROTOCOL_VERSION_RECONFIG_AUTH_REQ = 96,
|
||||
DPP_TEST_NO_PROTOCOL_VERSION_RECONFIG_AUTH_REQ = 97,
|
||||
DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_REQ = 98,
|
||||
DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_PB_RESP = 99,
|
||||
DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_RESP = 100,
|
||||
};
|
||||
|
||||
extern enum dpp_test_behavior dpp_test;
|
||||
@ -520,6 +581,7 @@ int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac);
|
||||
int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info);
|
||||
int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
|
||||
struct dpp_bootstrap_info *peer_bi);
|
||||
const char * dpp_netrole_str(enum dpp_netrole netrole);
|
||||
struct dpp_authentication *
|
||||
dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx);
|
||||
struct hostapd_hw_modes;
|
||||
@ -544,11 +606,18 @@ struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
|
||||
struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
|
||||
const char *name,
|
||||
enum dpp_netrole netrole,
|
||||
const char *mud_url, int *opclasses);
|
||||
const char *mud_url, int *opclasses,
|
||||
const char *extra_name,
|
||||
const char *extra_value);
|
||||
int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len);
|
||||
int dpp_notify_new_qr_code(struct dpp_authentication *auth,
|
||||
struct dpp_bootstrap_info *peer_bi);
|
||||
void dpp_controller_pkex_add(struct dpp_global *dpp,
|
||||
struct dpp_bootstrap_info *bi,
|
||||
const char *code, const char *identifier);
|
||||
bool dpp_controller_is_own_pkex_req(struct dpp_global *dpp,
|
||||
const u8 *buf, size_t len);
|
||||
struct dpp_configuration * dpp_configuration_alloc(const char *type);
|
||||
int dpp_akm_psk(enum dpp_akm akm);
|
||||
int dpp_akm_sae(enum dpp_akm akm);
|
||||
@ -600,18 +669,19 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
|
||||
const u8 *net_access_key, size_t net_access_key_len,
|
||||
const u8 *csign_key, size_t csign_key_len,
|
||||
const u8 *peer_connector, size_t peer_connector_len,
|
||||
os_time_t *expiry);
|
||||
os_time_t *expiry, u8 *peer_key_hash);
|
||||
void dpp_peer_intro_deinit(struct dpp_introduction *intro);
|
||||
int dpp_get_connector_version(const char *connector);
|
||||
struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
|
||||
const u8 *own_mac,
|
||||
const char *identifier, const char *code,
|
||||
bool v2);
|
||||
size_t code_len, bool v2);
|
||||
struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
|
||||
struct dpp_bootstrap_info *bi,
|
||||
const u8 *own_mac,
|
||||
const u8 *peer_mac,
|
||||
const char *identifier,
|
||||
const char *code,
|
||||
const char *code, size_t code_len,
|
||||
const u8 *buf, size_t len, bool v2);
|
||||
struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
|
||||
const u8 *peer_mac,
|
||||
@ -638,6 +708,11 @@ struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
|
||||
int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len);
|
||||
void dpp_pfs_free(struct dpp_pfs *pfs);
|
||||
|
||||
struct crypto_ec_key * dpp_set_keypair(const struct dpp_curve_params **curve,
|
||||
const u8 *privkey, size_t privkey_len);
|
||||
int dpp_hpke_suite(int iana_group, enum hpke_kem_id *kem_id,
|
||||
enum hpke_kdf_id *kdf_id, enum hpke_aead_id *aead_id);
|
||||
|
||||
struct wpabuf * dpp_build_csr(struct dpp_authentication *auth,
|
||||
const char *name);
|
||||
int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr);
|
||||
@ -664,6 +739,7 @@ void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
|
||||
struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
|
||||
const u8 *hash);
|
||||
int dpp_configurator_add(struct dpp_global *dpp, const char *cmd);
|
||||
int dpp_configurator_set(struct dpp_global *dpp, const char *cmd);
|
||||
int dpp_configurator_remove(struct dpp_global *dpp, const char *id);
|
||||
int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
|
||||
char *buf, size_t buflen);
|
||||
@ -673,31 +749,69 @@ struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp,
|
||||
const u8 *kid);
|
||||
int dpp_relay_add_controller(struct dpp_global *dpp,
|
||||
struct dpp_relay_config *config);
|
||||
void dpp_relay_remove_controller(struct dpp_global *dpp,
|
||||
const struct hostapd_ip_addr *addr);
|
||||
int dpp_relay_listen(struct dpp_global *dpp, int port,
|
||||
struct dpp_relay_config *config);
|
||||
void dpp_relay_stop_listen(struct dpp_global *dpp);
|
||||
int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
|
||||
const u8 *buf, size_t len, unsigned int freq,
|
||||
const u8 *i_bootstrap, const u8 *r_bootstrap,
|
||||
void *cb_ctx);
|
||||
int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
|
||||
size_t data_len);
|
||||
bool dpp_relay_controller_available(struct dpp_global *dpp);
|
||||
int dpp_controller_start(struct dpp_global *dpp,
|
||||
struct dpp_controller_config *config);
|
||||
int dpp_controller_set_params(struct dpp_global *dpp,
|
||||
const char *configurator_params);
|
||||
void dpp_controller_stop(struct dpp_global *dpp);
|
||||
void dpp_controller_stop_for_ctx(struct dpp_global *dpp, void *cb_ctx);
|
||||
struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp,
|
||||
unsigned int id);
|
||||
void dpp_controller_new_qr_code(struct dpp_global *dpp,
|
||||
struct dpp_bootstrap_info *bi);
|
||||
int dpp_tcp_pkex_init(struct dpp_global *dpp, struct dpp_pkex *pkex,
|
||||
const struct hostapd_ip_addr *addr, int port,
|
||||
void *msg_ctx, void *cb_ctx,
|
||||
int (*pkex_done)(void *ctx, void *conn,
|
||||
struct dpp_bootstrap_info *bi));
|
||||
int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
|
||||
const struct hostapd_ip_addr *addr, int port,
|
||||
const char *name, enum dpp_netrole netrole, void *msg_ctx,
|
||||
void *cb_ctx,
|
||||
const char *name, enum dpp_netrole netrole,
|
||||
const char *mud_url,
|
||||
const char *extra_conf_req_name,
|
||||
const char *extra_conf_req_value,
|
||||
void *msg_ctx, void *cb_ctx,
|
||||
int (*process_conf_obj)(void *ctx,
|
||||
struct dpp_authentication *auth));
|
||||
struct dpp_authentication *auth),
|
||||
bool (*tcp_msg_sent)(void *ctx,
|
||||
struct dpp_authentication *auth));
|
||||
int dpp_tcp_auth(struct dpp_global *dpp, void *_conn,
|
||||
struct dpp_authentication *auth, const char *name,
|
||||
enum dpp_netrole netrole, const char *mud_url,
|
||||
const char *extra_conf_req_name,
|
||||
const char *extra_conf_req_value,
|
||||
int (*process_conf_obj)(void *ctx,
|
||||
struct dpp_authentication *auth),
|
||||
bool (*tcp_msg_sent)(void *ctx,
|
||||
struct dpp_authentication *auth));
|
||||
bool dpp_tcp_conn_status_requested(struct dpp_global *dpp);
|
||||
void dpp_tcp_send_conn_status(struct dpp_global *dpp,
|
||||
enum dpp_status_error result,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const char *channel_list);
|
||||
|
||||
struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi);
|
||||
void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
|
||||
unsigned int freq, const u8 *hash);
|
||||
|
||||
struct wpabuf * dpp_build_pb_announcement(struct dpp_bootstrap_info *bi);
|
||||
struct wpabuf * dpp_build_pb_announcement_resp(struct dpp_bootstrap_info *bi,
|
||||
const u8 *e_hash,
|
||||
const u8 *c_nonce,
|
||||
size_t c_nonce_len);
|
||||
|
||||
struct dpp_global_config {
|
||||
void *cb_ctx;
|
||||
void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
|
||||
@ -706,6 +820,7 @@ struct dpp_global_config {
|
||||
struct dpp_global * dpp_global_init(struct dpp_global_config *config);
|
||||
void dpp_global_clear(struct dpp_global *dpp);
|
||||
void dpp_global_deinit(struct dpp_global *dpp);
|
||||
void dpp_notify_auth_success(struct dpp_authentication *auth, int initiator);
|
||||
|
||||
/* dpp_reconfig.c */
|
||||
|
||||
@ -738,6 +853,7 @@ struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
|
||||
size_t pp_key_len);
|
||||
int dpp_update_reconfig_id(struct dpp_reconfig_id *id);
|
||||
void dpp_free_reconfig_id(struct dpp_reconfig_id *id);
|
||||
int dpp_get_pubkey_hash(struct crypto_ec_key *key, u8 *hash);
|
||||
|
||||
#endif /* CONFIG_DPP */
|
||||
#endif /* DPP_H */
|
||||
|
@ -246,6 +246,27 @@ struct crypto_ec_key * dpp_set_pubkey_point(struct crypto_ec_key *group_key,
|
||||
}
|
||||
|
||||
|
||||
int dpp_get_pubkey_hash(struct crypto_ec_key *key, u8 *hash)
|
||||
{
|
||||
struct wpabuf *uncomp;
|
||||
const u8 *addr[1];
|
||||
size_t len[1];
|
||||
int res;
|
||||
|
||||
if (!key)
|
||||
return -1;
|
||||
|
||||
uncomp = crypto_ec_key_get_pubkey_point(key, 1);
|
||||
if (!uncomp)
|
||||
return -1;
|
||||
addr[0] = wpabuf_head(uncomp);
|
||||
len[0] = wpabuf_len(uncomp);
|
||||
res = sha256_vector(1, addr, len, hash);
|
||||
wpabuf_free(uncomp);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
struct crypto_ec_key * dpp_gen_keypair(const struct dpp_curve_params *curve)
|
||||
{
|
||||
struct crypto_ec_key *key;
|
||||
@ -1035,10 +1056,9 @@ int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
|
||||
int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
|
||||
{
|
||||
struct crypto_ec *ec;
|
||||
struct crypto_ec_point *L = NULL;
|
||||
const struct crypto_ec_point *BI;
|
||||
const struct crypto_bignum *bR, *pR, *q;
|
||||
struct crypto_bignum *sum = NULL, *lx = NULL;
|
||||
struct crypto_ec_point *L = NULL, *BI = NULL;
|
||||
const struct crypto_bignum *q;
|
||||
struct crypto_bignum *sum = NULL, *lx = NULL, *bR = NULL, *pR = NULL;
|
||||
int ret = -1;
|
||||
|
||||
/* L = ((bR + pR) modulo q) * BI */
|
||||
@ -1068,7 +1088,10 @@ int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
|
||||
fail:
|
||||
crypto_bignum_deinit(lx, 1);
|
||||
crypto_bignum_deinit(sum, 1);
|
||||
crypto_bignum_deinit(bR, 1);
|
||||
crypto_bignum_deinit(pR, 1);
|
||||
crypto_ec_point_deinit(L, 1);
|
||||
crypto_ec_point_deinit(BI, 1);
|
||||
crypto_ec_deinit(ec);
|
||||
return ret;
|
||||
}
|
||||
@ -1077,10 +1100,8 @@ int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
|
||||
int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
|
||||
{
|
||||
struct crypto_ec *ec;
|
||||
struct crypto_ec_point *L = NULL, *sum = NULL;
|
||||
const struct crypto_ec_point *BR, *PR;
|
||||
const struct crypto_bignum *bI;
|
||||
struct crypto_bignum *lx = NULL;
|
||||
struct crypto_ec_point *L = NULL, *sum = NULL, *BR = NULL, *PR = NULL;
|
||||
struct crypto_bignum *lx = NULL, *bI = NULL;
|
||||
int ret = -1;
|
||||
|
||||
/* L = bI * (BR + PR) */
|
||||
@ -1108,8 +1129,11 @@ int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
|
||||
ret = 0;
|
||||
fail:
|
||||
crypto_bignum_deinit(lx, 1);
|
||||
crypto_bignum_deinit(bI, 1);
|
||||
crypto_ec_point_deinit(sum, 1);
|
||||
crypto_ec_point_deinit(L, 1);
|
||||
crypto_ec_point_deinit(BR, 1);
|
||||
crypto_ec_point_deinit(PR, 1);
|
||||
crypto_ec_deinit(ec);
|
||||
return ret;
|
||||
}
|
||||
@ -1434,16 +1458,15 @@ dpp_pkex_get_role_elem(const struct dpp_curve_params *curve, int init)
|
||||
|
||||
struct crypto_ec_point *
|
||||
dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
|
||||
const char *code, const char *identifier,
|
||||
const char *code, size_t code_len, const char *identifier,
|
||||
struct crypto_ec **ret_ec)
|
||||
{
|
||||
u8 hash[DPP_MAX_HASH_LEN];
|
||||
const u8 *addr[3];
|
||||
size_t len[3];
|
||||
unsigned int num_elem = 0;
|
||||
struct crypto_ec_point *Qi = NULL;
|
||||
struct crypto_ec_point *Qi = NULL, *Pi = NULL;
|
||||
struct crypto_ec_key *Pi_key = NULL;
|
||||
const struct crypto_ec_point *Pi = NULL;
|
||||
struct crypto_bignum *hash_bn = NULL;
|
||||
struct crypto_ec *ec = NULL;
|
||||
|
||||
@ -1463,9 +1486,9 @@ dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
|
||||
len[num_elem] = os_strlen(identifier);
|
||||
num_elem++;
|
||||
}
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, code_len);
|
||||
addr[num_elem] = (const u8 *) code;
|
||||
len[num_elem] = os_strlen(code);
|
||||
len[num_elem] = code_len;
|
||||
num_elem++;
|
||||
if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
|
||||
goto fail;
|
||||
@ -1494,6 +1517,7 @@ dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
|
||||
crypto_ec_point_debug_print(ec, Qi, "DPP: Qi");
|
||||
out:
|
||||
crypto_ec_key_deinit(Pi_key);
|
||||
crypto_ec_point_deinit(Pi, 1);
|
||||
crypto_bignum_deinit(hash_bn, 1);
|
||||
if (ret_ec && Qi)
|
||||
*ret_ec = ec;
|
||||
@ -1509,16 +1533,15 @@ dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
|
||||
|
||||
struct crypto_ec_point *
|
||||
dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
|
||||
const char *code, const char *identifier,
|
||||
const char *code, size_t code_len, const char *identifier,
|
||||
struct crypto_ec **ret_ec)
|
||||
{
|
||||
u8 hash[DPP_MAX_HASH_LEN];
|
||||
const u8 *addr[3];
|
||||
size_t len[3];
|
||||
unsigned int num_elem = 0;
|
||||
struct crypto_ec_point *Qr = NULL;
|
||||
struct crypto_ec_point *Qr = NULL, *Pr = NULL;
|
||||
struct crypto_ec_key *Pr_key = NULL;
|
||||
const struct crypto_ec_point *Pr = NULL;
|
||||
struct crypto_bignum *hash_bn = NULL;
|
||||
struct crypto_ec *ec = NULL;
|
||||
|
||||
@ -1538,9 +1561,9 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
|
||||
len[num_elem] = os_strlen(identifier);
|
||||
num_elem++;
|
||||
}
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, code_len);
|
||||
addr[num_elem] = (const u8 *) code;
|
||||
len[num_elem] = os_strlen(code);
|
||||
len[num_elem] = code_len;
|
||||
num_elem++;
|
||||
if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
|
||||
goto fail;
|
||||
@ -1570,6 +1593,7 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
|
||||
|
||||
out:
|
||||
crypto_ec_key_deinit(Pr_key);
|
||||
crypto_ec_point_deinit(Pr, 1);
|
||||
crypto_bignum_deinit(hash_bn, 1);
|
||||
if (ret_ec && Qr)
|
||||
*ret_ec = ec;
|
||||
@ -1587,7 +1611,7 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
|
||||
u8 ver_init, u8 ver_resp,
|
||||
const u8 *Mx, size_t Mx_len,
|
||||
const u8 *Nx, size_t Nx_len,
|
||||
const char *code,
|
||||
const char *code, size_t code_len,
|
||||
const u8 *Kx, size_t Kx_len,
|
||||
u8 *z, unsigned int hash_len)
|
||||
{
|
||||
@ -1612,7 +1636,7 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
|
||||
info_len = 2 * ETH_ALEN;
|
||||
else
|
||||
info_len = 2;
|
||||
info_len += Mx_len + Nx_len + os_strlen(code);
|
||||
info_len += Mx_len + Nx_len + code_len;
|
||||
info = os_malloc(info_len);
|
||||
if (!info)
|
||||
return -1;
|
||||
@ -1630,7 +1654,7 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
|
||||
pos += Mx_len;
|
||||
os_memcpy(pos, Nx, Nx_len);
|
||||
pos += Nx_len;
|
||||
os_memcpy(pos, code, os_strlen(code));
|
||||
os_memcpy(pos, code, code_len);
|
||||
|
||||
/* HKDF-Expand(PRK, info, L) */
|
||||
if (hash_len == 32)
|
||||
@ -1661,11 +1685,10 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
|
||||
struct json_token *peer_net_access_key)
|
||||
{
|
||||
struct crypto_ec_key *own_key = NULL, *peer_key = NULL;
|
||||
struct crypto_bignum *sum = NULL;
|
||||
const struct crypto_bignum *q, *cR, *pR;
|
||||
struct crypto_bignum *sum = NULL, *cR = NULL, *pR = NULL;
|
||||
const struct crypto_bignum *q;
|
||||
struct crypto_ec *ec = NULL;
|
||||
struct crypto_ec_point *M = NULL;
|
||||
const struct crypto_ec_point *CI;
|
||||
struct crypto_ec_point *M = NULL, *CI = NULL;
|
||||
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
u8 prk[DPP_MAX_HASH_LEN];
|
||||
const struct dpp_curve_params *curve;
|
||||
@ -1748,7 +1771,10 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
|
||||
forced_memzero(prk, sizeof(prk));
|
||||
forced_memzero(Mx, sizeof(Mx));
|
||||
crypto_ec_point_deinit(M, 1);
|
||||
crypto_ec_point_deinit(CI, 1);
|
||||
crypto_bignum_deinit(sum, 1);
|
||||
crypto_bignum_deinit(cR, 1);
|
||||
crypto_bignum_deinit(pR, 1);
|
||||
crypto_ec_key_deinit(own_key);
|
||||
crypto_ec_key_deinit(peer_key);
|
||||
crypto_ec_deinit(ec);
|
||||
@ -1761,10 +1787,9 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
|
||||
struct json_token *net_access_key)
|
||||
{
|
||||
struct crypto_ec_key *pr = NULL, *peer_key = NULL;
|
||||
const struct crypto_ec_point *CR, *PR;
|
||||
const struct crypto_bignum *cI;
|
||||
struct crypto_bignum *cI = NULL;
|
||||
struct crypto_ec *ec = NULL;
|
||||
struct crypto_ec_point *sum = NULL, *M = NULL;
|
||||
struct crypto_ec_point *sum = NULL, *M = NULL, *CR = NULL, *PR = NULL;
|
||||
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
u8 prk[DPP_MAX_HASH_LEN];
|
||||
int res = -1;
|
||||
@ -1835,10 +1860,13 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
|
||||
fail:
|
||||
forced_memzero(prk, sizeof(prk));
|
||||
forced_memzero(Mx, sizeof(Mx));
|
||||
crypto_bignum_deinit(cI, 1);
|
||||
crypto_ec_key_deinit(pr);
|
||||
crypto_ec_key_deinit(peer_key);
|
||||
crypto_ec_point_deinit(sum, 1);
|
||||
crypto_ec_point_deinit(M, 1);
|
||||
crypto_ec_point_deinit(CR, 1);
|
||||
crypto_ec_point_deinit(PR, 1);
|
||||
crypto_ec_deinit(ec);
|
||||
return res;
|
||||
}
|
||||
@ -2059,7 +2087,7 @@ struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name)
|
||||
struct wpabuf *priv_key;
|
||||
u8 cp[DPP_CP_LEN];
|
||||
char *password = NULL;
|
||||
size_t password_len;
|
||||
size_t password_len = 0;
|
||||
int hash_sign_algo;
|
||||
|
||||
/* TODO: use auth->csrattrs */
|
||||
@ -2259,8 +2287,8 @@ int dpp_update_reconfig_id(struct dpp_reconfig_id *id)
|
||||
{
|
||||
const struct crypto_bignum *q;
|
||||
struct crypto_bignum *bn;
|
||||
const struct crypto_ec_point *pp, *generator;
|
||||
struct crypto_ec_point *e_prime_id, *a_nonce;
|
||||
const struct crypto_ec_point *generator;
|
||||
struct crypto_ec_point *e_prime_id, *a_nonce, *pp;
|
||||
int ret = -1;
|
||||
|
||||
pp = crypto_ec_key_get_public_key(id->pp_key);
|
||||
@ -2297,6 +2325,7 @@ int dpp_update_reconfig_id(struct dpp_reconfig_id *id)
|
||||
fail:
|
||||
crypto_ec_point_deinit(e_prime_id, 1);
|
||||
crypto_ec_point_deinit(a_nonce, 1);
|
||||
crypto_ec_point_deinit(pp, 1);
|
||||
crypto_bignum_deinit(bn, 1);
|
||||
return ret;
|
||||
}
|
||||
@ -2321,9 +2350,9 @@ struct crypto_ec_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey,
|
||||
struct crypto_ec_key *e_prime_id)
|
||||
{
|
||||
struct crypto_ec *ec;
|
||||
const struct crypto_bignum *pp;
|
||||
struct crypto_bignum *pp = NULL;
|
||||
struct crypto_ec_point *e_id = NULL;
|
||||
const struct crypto_ec_point *a_nonce_point, *e_prime_id_point;
|
||||
struct crypto_ec_point *a_nonce_point, *e_prime_id_point;
|
||||
|
||||
if (!ppkey)
|
||||
return NULL;
|
||||
@ -2348,6 +2377,9 @@ struct crypto_ec_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey,
|
||||
crypto_ec_point_debug_print(ec, e_id, "DPP: Decrypted E-id");
|
||||
|
||||
fail:
|
||||
crypto_ec_point_deinit(a_nonce_point, 1);
|
||||
crypto_ec_point_deinit(e_prime_id_point, 1);
|
||||
crypto_bignum_deinit(pp, 1);
|
||||
crypto_ec_deinit(ec);
|
||||
return e_id;
|
||||
}
|
||||
@ -2355,6 +2387,139 @@ struct crypto_ec_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey,
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP3
|
||||
|
||||
int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i)
|
||||
{
|
||||
int ret = -1, res;
|
||||
u8 Sx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
size_t Sx_len;
|
||||
unsigned int hash_len;
|
||||
const char *info = "New DPP Protocol Key";
|
||||
const u8 *addr[3];
|
||||
size_t len[3];
|
||||
u8 tmp[DPP_MAX_HASH_LEN], k[DPP_MAX_HASH_LEN];
|
||||
struct wpabuf *pcx = NULL, *pex = NULL;
|
||||
|
||||
hash_len = auth->curve->hash_len;
|
||||
|
||||
/*
|
||||
* Configurator: S = pc * Pe
|
||||
* Enrollee: S = pe * Pc
|
||||
* k = HKDF(bk, "New DPP Protocol Key", S.x)
|
||||
* = HKDF-Expand(HKDF-Extract(bk, S.X), "New DPP Protocol Key",
|
||||
* len(new-curve-hash-out))
|
||||
* Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x)
|
||||
*
|
||||
* auth->own_protocol_key and auth->peer_protocol_key have already been
|
||||
* updated to use the new keys. The new curve determines the size of
|
||||
* the (new) protocol keys and S.x. The other parameters (bk, hash
|
||||
* algorithm, k) are determined based on the initially determined curve
|
||||
* during the (re)authentication exchange.
|
||||
*/
|
||||
|
||||
if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
|
||||
Sx, &Sx_len) < 0)
|
||||
goto fail;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "DPP: S.x", Sx, Sx_len);
|
||||
|
||||
/* tmp = HKDF-Extract(bk, S.x) */
|
||||
addr[0] = Sx;
|
||||
len[0] = Sx_len;
|
||||
res = dpp_hmac_vector(hash_len, auth->bk, hash_len, 1, addr, len, tmp);
|
||||
if (res < 0)
|
||||
goto fail;
|
||||
wpa_hexdump_key(MSG_DEBUG, "DPP: HKDF-Extract(bk, S.x)",
|
||||
tmp, hash_len);
|
||||
/* k = HKDF-Expand(tmp, "New DPP Protocol Key", len(hash-output))
|
||||
*/
|
||||
res = dpp_hkdf_expand(hash_len, tmp, hash_len, info, k, hash_len);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG,
|
||||
"DPP: k = HKDF-Expand(\"New DPP Protocol Key\")",
|
||||
k, hash_len);
|
||||
|
||||
/* Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x) */
|
||||
addr[0] = auth->e_nonce;
|
||||
len[0] = auth->curve->nonce_len;
|
||||
|
||||
if (auth->configurator) {
|
||||
pcx = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
|
||||
pex = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
|
||||
0);
|
||||
} else {
|
||||
pcx = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
|
||||
0);
|
||||
pex = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
|
||||
}
|
||||
if (!pcx || !pex)
|
||||
goto fail;
|
||||
addr[1] = wpabuf_head(pcx);
|
||||
len[1] = wpabuf_len(pcx) / 2;
|
||||
addr[2] = wpabuf_head(pex);
|
||||
len[2] = wpabuf_len(pex) / 2;
|
||||
|
||||
if (dpp_hmac_vector(hash_len, k, hash_len, 3, addr, len, auth_i) < 0)
|
||||
goto fail;
|
||||
wpa_hexdump_key(MSG_DEBUG,
|
||||
"DPP: Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x)",
|
||||
auth_i, hash_len);
|
||||
ret = 0;
|
||||
fail:
|
||||
forced_memzero(Sx, sizeof(Sx));
|
||||
forced_memzero(tmp, sizeof(tmp));
|
||||
forced_memzero(k, sizeof(k));
|
||||
wpabuf_free(pcx);
|
||||
wpabuf_free(pex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int dpp_hpke_suite(int iana_group, enum hpke_kem_id *kem_id,
|
||||
enum hpke_kdf_id *kdf_id, enum hpke_aead_id *aead_id)
|
||||
{
|
||||
switch (iana_group) {
|
||||
case 19:
|
||||
*kem_id = HPKE_DHKEM_P256_HKDF_SHA256;
|
||||
*kdf_id = HPKE_KDF_HKDF_SHA256;
|
||||
*aead_id = HPKE_AEAD_AES_128_GCM;
|
||||
return 0;
|
||||
case 20:
|
||||
*kem_id = HPKE_DHKEM_P384_HKDF_SHA384;
|
||||
*kdf_id = HPKE_KDF_HKDF_SHA384;
|
||||
*aead_id = HPKE_AEAD_AES_256_GCM;
|
||||
return 0;
|
||||
case 21:
|
||||
*kem_id = HPKE_DHKEM_P521_HKDF_SHA512;
|
||||
*kdf_id = HPKE_KDF_HKDF_SHA512;
|
||||
*aead_id = HPKE_AEAD_AES_256_GCM;
|
||||
return 0;
|
||||
case 28:
|
||||
*kem_id = HPKE_DHKEM_P256_HKDF_SHA256;
|
||||
*kdf_id = HPKE_KDF_HKDF_SHA256;
|
||||
*aead_id = HPKE_AEAD_AES_128_GCM;
|
||||
return 0;
|
||||
case 29:
|
||||
*kem_id = HPKE_DHKEM_P384_HKDF_SHA384;
|
||||
*kdf_id = HPKE_KDF_HKDF_SHA384;
|
||||
*aead_id = HPKE_AEAD_AES_256_GCM;
|
||||
return 0;
|
||||
case 30:
|
||||
*kem_id = HPKE_DHKEM_P521_HKDF_SHA512;
|
||||
*kdf_id = HPKE_KDF_HKDF_SHA512;
|
||||
*aead_id = HPKE_AEAD_AES_256_GCM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DPP3 */
|
||||
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
|
||||
int dpp_test_gen_invalid_key(struct wpabuf *msg,
|
||||
@ -2362,8 +2527,7 @@ int dpp_test_gen_invalid_key(struct wpabuf *msg,
|
||||
{
|
||||
struct crypto_ec *ec;
|
||||
struct crypto_ec_key *key = NULL;
|
||||
const struct crypto_ec_point *pub_key;
|
||||
struct crypto_ec_point *p = NULL;
|
||||
struct crypto_ec_point *p = NULL, *pub_key = NULL;
|
||||
u8 *x, *y;
|
||||
int ret = -1;
|
||||
|
||||
@ -2381,11 +2545,9 @@ int dpp_test_gen_invalid_key(struct wpabuf *msg,
|
||||
|
||||
/* Retrieve public key coordinates */
|
||||
pub_key = crypto_ec_key_get_public_key(key);
|
||||
if (!pub_key)
|
||||
if (!pub_key || crypto_ec_point_to_bin(ec, pub_key, x, y))
|
||||
goto fail;
|
||||
|
||||
crypto_ec_point_to_bin(ec, pub_key, x, y);
|
||||
|
||||
/* And corrupt them */
|
||||
y[curve->prime_len - 1] ^= 0x01;
|
||||
p = crypto_ec_point_from_bin(ec, x);
|
||||
@ -2398,6 +2560,7 @@ int dpp_test_gen_invalid_key(struct wpabuf *msg,
|
||||
ret = 0;
|
||||
fail:
|
||||
crypto_ec_point_deinit(p, 0);
|
||||
crypto_ec_point_deinit(pub_key, 0);
|
||||
crypto_ec_key_deinit(key);
|
||||
crypto_ec_deinit(ec);
|
||||
return ret;
|
||||
|
@ -2,6 +2,7 @@
|
||||
* DPP module internal definitions
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018-2020, The Linux Foundation
|
||||
* Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -18,10 +19,19 @@ struct dpp_global {
|
||||
struct dl_list configurator; /* struct dpp_configurator */
|
||||
#ifdef CONFIG_DPP2
|
||||
struct dl_list controllers; /* struct dpp_relay_controller */
|
||||
struct dpp_relay_controller *tmp_controller;
|
||||
struct dpp_controller *controller;
|
||||
struct dl_list tcp_init; /* struct dpp_connection */
|
||||
int relay_sock;
|
||||
void *relay_msg_ctx;
|
||||
void *relay_cb_ctx;
|
||||
void (*relay_tx)(void *ctx, const u8 *addr, unsigned int freq,
|
||||
const u8 *msg, size_t len);
|
||||
void (*relay_gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token,
|
||||
int prot, struct wpabuf *buf);
|
||||
void *cb_ctx;
|
||||
int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
|
||||
bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth);
|
||||
void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
|
||||
#endif /* CONFIG_DPP2 */
|
||||
};
|
||||
@ -95,8 +105,6 @@ int dpp_get_subject_public_key(struct dpp_bootstrap_info *bi,
|
||||
int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
|
||||
int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
|
||||
const u8 *privkey, size_t privkey_len);
|
||||
struct crypto_ec_key * dpp_set_keypair(const struct dpp_curve_params **curve,
|
||||
const u8 *privkey, size_t privkey_len);
|
||||
struct crypto_ec_key * dpp_gen_keypair(const struct dpp_curve_params *curve);
|
||||
int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, unsigned int hash_len);
|
||||
int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, unsigned int hash_len);
|
||||
@ -111,17 +119,17 @@ int dpp_derive_pmkid(const struct dpp_curve_params *curve,
|
||||
struct crypto_ec_key *peer_key, u8 *pmkid);
|
||||
struct crypto_ec_point *
|
||||
dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
|
||||
const char *code, const char *identifier,
|
||||
const char *code, size_t code_len, const char *identifier,
|
||||
struct crypto_ec **ret_ec);
|
||||
struct crypto_ec_point *
|
||||
dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
|
||||
const char *code, const char *identifier,
|
||||
const char *code, size_t code_len, const char *identifier,
|
||||
struct crypto_ec **ret_ec);
|
||||
int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
|
||||
u8 ver_init, u8 ver_resp,
|
||||
const u8 *Mx, size_t Mx_len,
|
||||
const u8 *Nx, size_t Nx_len,
|
||||
const char *code,
|
||||
const char *code, size_t code_len,
|
||||
const u8 *Kx, size_t Kx_len,
|
||||
u8 *z, unsigned int hash_len);
|
||||
int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
|
||||
@ -134,6 +142,7 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
|
||||
struct crypto_ec_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey,
|
||||
struct crypto_ec_key *a_nonce,
|
||||
struct crypto_ec_key *e_prime_id);
|
||||
int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i);
|
||||
char * dpp_sign_connector(struct dpp_configurator *conf,
|
||||
const struct wpabuf *dppcon);
|
||||
int dpp_test_gen_invalid_key(struct wpabuf *msg,
|
||||
|
@ -30,8 +30,7 @@ static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex,
|
||||
bool v2)
|
||||
{
|
||||
struct crypto_ec *ec = NULL;
|
||||
const struct crypto_ec_point *X;
|
||||
struct crypto_ec_point *Qi = NULL, *M = NULL;
|
||||
struct crypto_ec_point *Qi = NULL, *M = NULL, *X = NULL;
|
||||
u8 *Mx, *My;
|
||||
struct wpabuf *msg = NULL;
|
||||
size_t attr_len;
|
||||
@ -42,7 +41,7 @@ static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex,
|
||||
|
||||
/* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
|
||||
Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : pkex->own_mac, pkex->code,
|
||||
pkex->identifier, &ec);
|
||||
pkex->code_len, pkex->identifier, &ec);
|
||||
if (!Qi)
|
||||
goto fail;
|
||||
|
||||
@ -146,10 +145,13 @@ static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex,
|
||||
My = wpabuf_put(msg, curve->prime_len);
|
||||
if (crypto_ec_point_to_bin(ec, M, Mx, My))
|
||||
goto fail;
|
||||
wpabuf_free(pkex->enc_key);
|
||||
pkex->enc_key = wpabuf_alloc_copy(Mx, 2 * curve->prime_len);
|
||||
|
||||
os_memcpy(pkex->Mx, Mx, curve->prime_len);
|
||||
|
||||
out:
|
||||
crypto_ec_point_deinit(X, 1);
|
||||
crypto_ec_point_deinit(M, 1);
|
||||
crypto_ec_point_deinit(Qi, 1);
|
||||
crypto_ec_deinit(ec);
|
||||
@ -171,7 +173,7 @@ static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
|
||||
struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
|
||||
const u8 *own_mac,
|
||||
const char *identifier, const char *code,
|
||||
bool v2)
|
||||
size_t code_len, bool v2)
|
||||
{
|
||||
struct dpp_pkex *pkex;
|
||||
|
||||
@ -196,9 +198,10 @@ struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
|
||||
if (!pkex->identifier)
|
||||
goto fail;
|
||||
}
|
||||
pkex->code = os_strdup(code);
|
||||
pkex->code = os_memdup(code, code_len);
|
||||
if (!pkex->code)
|
||||
goto fail;
|
||||
pkex->code_len = code_len;
|
||||
pkex->exchange_req = dpp_pkex_build_exchange_req(pkex, v2);
|
||||
if (!pkex->exchange_req)
|
||||
goto fail;
|
||||
@ -340,7 +343,7 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
|
||||
const u8 *own_mac,
|
||||
const u8 *peer_mac,
|
||||
const char *identifier,
|
||||
const char *code,
|
||||
const char *code, size_t code_len,
|
||||
const u8 *buf, size_t len, bool v2)
|
||||
{
|
||||
const u8 *attr_group, *attr_id, *attr_key;
|
||||
@ -349,9 +352,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
|
||||
u16 ike_group;
|
||||
struct dpp_pkex *pkex = NULL;
|
||||
struct crypto_ec_point *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL,
|
||||
*N = NULL;
|
||||
*N = NULL, *Y = NULL;
|
||||
struct crypto_ec *ec = NULL;
|
||||
const struct crypto_ec_point *Y;
|
||||
u8 *x_coord = NULL, *y_coord = NULL;
|
||||
u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
size_t Kx_len;
|
||||
@ -438,8 +440,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
|
||||
}
|
||||
|
||||
/* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
|
||||
Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, identifier,
|
||||
&ec);
|
||||
Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, code_len,
|
||||
identifier, &ec);
|
||||
if (!Qi)
|
||||
goto fail;
|
||||
|
||||
@ -469,16 +471,19 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
|
||||
pkex->t = bi->pkex_t;
|
||||
pkex->msg_ctx = msg_ctx;
|
||||
pkex->own_bi = bi;
|
||||
os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
|
||||
os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
|
||||
if (own_mac)
|
||||
os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
|
||||
if (peer_mac)
|
||||
os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
|
||||
if (identifier) {
|
||||
pkex->identifier = os_strdup(identifier);
|
||||
if (!pkex->identifier)
|
||||
goto fail;
|
||||
}
|
||||
pkex->code = os_strdup(code);
|
||||
pkex->code = os_memdup(code, code_len);
|
||||
if (!pkex->code)
|
||||
goto fail;
|
||||
pkex->code_len = code_len;
|
||||
|
||||
os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
|
||||
|
||||
@ -494,8 +499,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
|
||||
goto fail;
|
||||
|
||||
/* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
|
||||
Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, identifier,
|
||||
NULL);
|
||||
Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, code_len,
|
||||
identifier, NULL);
|
||||
if (!Qr)
|
||||
goto fail;
|
||||
|
||||
@ -549,7 +554,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
|
||||
pkex->peer_version, DPP_VERSION,
|
||||
pkex->Mx, curve->prime_len,
|
||||
pkex->Nx, curve->prime_len, pkex->code,
|
||||
Kx, Kx_len, pkex->z, curve->hash_len);
|
||||
pkex->code_len, Kx, Kx_len, pkex->z,
|
||||
curve->hash_len);
|
||||
os_memset(Kx, 0, Kx_len);
|
||||
if (res < 0)
|
||||
goto fail;
|
||||
@ -564,6 +570,7 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
|
||||
crypto_ec_point_deinit(M, 1);
|
||||
crypto_ec_point_deinit(N, 1);
|
||||
crypto_ec_point_deinit(X, 1);
|
||||
crypto_ec_point_deinit(Y, 1);
|
||||
crypto_ec_deinit(ec);
|
||||
return pkex;
|
||||
fail:
|
||||
@ -742,7 +749,8 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
|
||||
}
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
|
||||
if (peer_mac)
|
||||
os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
|
||||
|
||||
attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
|
||||
&attr_status_len);
|
||||
@ -788,7 +796,8 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
|
||||
|
||||
/* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
|
||||
Qr = dpp_pkex_derive_Qr(curve, pkex->v2 ? NULL : pkex->peer_mac,
|
||||
pkex->code, pkex->identifier, &ec);
|
||||
pkex->code, pkex->code_len, pkex->identifier,
|
||||
&ec);
|
||||
if (!Qr)
|
||||
goto fail;
|
||||
|
||||
@ -866,7 +875,7 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
|
||||
DPP_VERSION, pkex->peer_version,
|
||||
pkex->Mx, curve->prime_len,
|
||||
attr_key /* N.x */, attr_key_len / 2,
|
||||
pkex->code, Kx, Kx_len,
|
||||
pkex->code, pkex->code_len, Kx, Kx_len,
|
||||
pkex->z, curve->hash_len);
|
||||
os_memset(Kx, 0, Kx_len);
|
||||
if (res < 0)
|
||||
@ -1341,9 +1350,12 @@ dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
|
||||
return NULL;
|
||||
bi->id = dpp_next_id(dpp);
|
||||
bi->type = DPP_BOOTSTRAP_PKEX;
|
||||
os_memcpy(bi->mac_addr, peer, ETH_ALEN);
|
||||
bi->num_freq = 1;
|
||||
bi->freq[0] = freq;
|
||||
if (peer)
|
||||
os_memcpy(bi->mac_addr, peer, ETH_ALEN);
|
||||
if (freq) {
|
||||
bi->num_freq = 1;
|
||||
bi->freq[0] = freq;
|
||||
}
|
||||
bi->curve = pkex->own_bi->curve;
|
||||
bi->pubkey = pkex->peer_bootstrap_key;
|
||||
pkex->peer_bootstrap_key = NULL;
|
||||
@ -1351,6 +1363,8 @@ dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
|
||||
dpp_bootstrap_info_free(bi);
|
||||
return NULL;
|
||||
}
|
||||
os_memcpy(pkex->own_bi->peer_pubkey_hash, bi->pubkey_hash,
|
||||
SHA256_MAC_LEN);
|
||||
dpp_pkex_free(pkex);
|
||||
dl_list_add(&dpp->bootstrap, &bi->list);
|
||||
return bi;
|
||||
@ -1369,5 +1383,6 @@ void dpp_pkex_free(struct dpp_pkex *pkex)
|
||||
crypto_ec_key_deinit(pkex->peer_bootstrap_key);
|
||||
wpabuf_free(pkex->exchange_req);
|
||||
wpabuf_free(pkex->exchange_resp);
|
||||
wpabuf_free(pkex->enc_key);
|
||||
os_free(pkex);
|
||||
}
|
||||
|
@ -131,6 +131,7 @@ static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth)
|
||||
{
|
||||
struct wpabuf *msg;
|
||||
size_t attr_len;
|
||||
u8 ver = DPP_VERSION;
|
||||
|
||||
/* Build DPP Reconfig Authentication Request frame attributes */
|
||||
attr_len = 4 + 1 + 4 + 1 + 4 + os_strlen(auth->conf->connector) +
|
||||
@ -144,10 +145,25 @@ static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth)
|
||||
wpabuf_put_le16(msg, 1);
|
||||
wpabuf_put_u8(msg, auth->transaction_id);
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) {
|
||||
wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version");
|
||||
goto skip_proto_ver;
|
||||
}
|
||||
if (dpp_test == DPP_TEST_INVALID_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) {
|
||||
wpa_printf(MSG_INFO, "DPP: TESTING - invalid Protocol Version");
|
||||
ver = 1;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
/* Protocol Version */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
|
||||
wpabuf_put_le16(msg, 1);
|
||||
wpabuf_put_u8(msg, DPP_VERSION);
|
||||
wpabuf_put_u8(msg, ver);
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
skip_proto_ver:
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
/* DPP Connector */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -67,12 +67,15 @@ int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime,
|
||||
}
|
||||
|
||||
res = crypto_bignum_legendre(tmp, prime);
|
||||
if (res == 1 && !(*qr))
|
||||
if (res == 1 && !(*qr)) {
|
||||
*qr = tmp;
|
||||
else if (res == -1 && !(*qnr))
|
||||
} else if (res == -1 && !(*qnr)) {
|
||||
*qnr = tmp;
|
||||
else
|
||||
} else {
|
||||
crypto_bignum_deinit(tmp, 0);
|
||||
if (res == -2)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*qr && *qnr)
|
||||
|
@ -2,6 +2,7 @@
|
||||
* Generic advertisement service (GAS) server
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2020, The Linux Foundation
|
||||
* Copyright (c) 2022, Qualcomm Innovation Center, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -18,7 +19,7 @@
|
||||
|
||||
|
||||
#define MAX_ADV_PROTO_ID_LEN 10
|
||||
#define GAS_QUERY_TIMEOUT 10
|
||||
#define GAS_QUERY_TIMEOUT 60
|
||||
|
||||
struct gas_server_handler {
|
||||
struct dl_list list;
|
||||
@ -26,7 +27,7 @@ struct gas_server_handler {
|
||||
u8 adv_proto_id_len;
|
||||
struct wpabuf * (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
|
||||
const u8 *query, size_t query_len,
|
||||
u16 *comeback_delay);
|
||||
int *comeback_delay);
|
||||
void (*status_cb)(void *ctx, struct wpabuf *resp, int ok);
|
||||
void *ctx;
|
||||
struct gas_server *gas;
|
||||
@ -42,6 +43,7 @@ struct gas_server_response {
|
||||
u8 dialog_token;
|
||||
struct gas_server_handler *handler;
|
||||
u16 comeback_delay;
|
||||
bool initial_resp_sent;
|
||||
};
|
||||
|
||||
struct gas_server {
|
||||
@ -86,25 +88,22 @@ static void gas_server_free_response(struct gas_server_response *response)
|
||||
|
||||
|
||||
static void
|
||||
gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
|
||||
gas_server_send_resp(struct gas_server *gas,
|
||||
struct gas_server_response *response,
|
||||
const u8 *da, int freq, u8 dialog_token,
|
||||
struct wpabuf *query_resp, u16 comeback_delay)
|
||||
{
|
||||
size_t max_len = (freq > 56160) ? 928 : 1400;
|
||||
struct gas_server_handler *handler = response->handler;
|
||||
size_t max_len = (response->freq > 56160) ? 928 : 1400;
|
||||
size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2;
|
||||
size_t resp_frag_len;
|
||||
struct wpabuf *resp;
|
||||
|
||||
if (comeback_delay == 0 && !query_resp) {
|
||||
dl_list_del(&response->list);
|
||||
gas_server_free_response(response);
|
||||
return;
|
||||
}
|
||||
|
||||
response->freq = freq;
|
||||
response->handler = handler;
|
||||
os_memcpy(response->dst, da, ETH_ALEN);
|
||||
response->dialog_token = dialog_token;
|
||||
if (comeback_delay) {
|
||||
/* Need more time to prepare the response */
|
||||
resp_frag_len = 0;
|
||||
@ -119,12 +118,14 @@ gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
|
||||
resp_frag_len = wpabuf_len(query_resp);
|
||||
}
|
||||
|
||||
resp = gas_build_initial_resp(dialog_token, WLAN_STATUS_SUCCESS,
|
||||
resp = gas_build_initial_resp(response->dialog_token,
|
||||
WLAN_STATUS_SUCCESS,
|
||||
comeback_delay,
|
||||
handler->adv_proto_id_len +
|
||||
resp_frag_len);
|
||||
if (!resp) {
|
||||
wpabuf_free(query_resp);
|
||||
dl_list_del(&response->list);
|
||||
gas_server_free_response(response);
|
||||
return;
|
||||
}
|
||||
@ -152,8 +153,9 @@ gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
|
||||
}
|
||||
response->offset = resp_frag_len;
|
||||
response->resp = query_resp;
|
||||
dl_list_add(&gas->responses, &response->list);
|
||||
gas->tx(gas->ctx, freq, da, resp, comeback_delay ? 2000 : 0);
|
||||
response->initial_resp_sent = true;
|
||||
gas->tx(gas->ctx, response->freq, response->dst, resp,
|
||||
comeback_delay ? 2000 : 0);
|
||||
wpabuf_free(resp);
|
||||
eloop_register_timeout(GAS_QUERY_TIMEOUT, 0,
|
||||
gas_server_response_timeout, response, NULL);
|
||||
@ -223,25 +225,35 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
|
||||
wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
|
||||
dl_list_for_each(handler, &gas->handlers, struct gas_server_handler,
|
||||
list) {
|
||||
u16 comeback_delay = 0;
|
||||
int comeback_delay = 0;
|
||||
|
||||
if (adv_proto_len < 1 + handler->adv_proto_id_len ||
|
||||
os_memcmp(adv_proto + 1, handler->adv_proto_id,
|
||||
handler->adv_proto_id_len) != 0)
|
||||
continue;
|
||||
|
||||
response->freq = freq;
|
||||
response->handler = handler;
|
||||
os_memcpy(response->dst, sa, ETH_ALEN);
|
||||
response->dialog_token = dialog_token;
|
||||
dl_list_add(&gas->responses, &response->list);
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Calling handler for the requested Advertisement Protocol ID");
|
||||
resp = handler->req_cb(handler->ctx, response, sa, query_req,
|
||||
query_req_len, &comeback_delay);
|
||||
wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler",
|
||||
resp);
|
||||
if (comeback_delay < 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Handler requested short delay before sending out the initial response");
|
||||
return 0;
|
||||
}
|
||||
if (comeback_delay)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Handler requested comeback delay: %u TU",
|
||||
comeback_delay);
|
||||
gas_server_send_resp(gas, handler, response, sa, freq,
|
||||
dialog_token, resp, comeback_delay);
|
||||
gas_server_send_resp(gas, response, resp, comeback_delay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -340,7 +352,7 @@ gas_server_rx_comeback_req(struct gas_server *gas, const u8 *da, const u8 *sa,
|
||||
dl_list_for_each(response, &gas->responses, struct gas_server_response,
|
||||
list) {
|
||||
if (response->dialog_token != dialog_token ||
|
||||
os_memcmp(sa, response->dst, ETH_ALEN) != 0)
|
||||
!ether_addr_equal(sa, response->dst))
|
||||
continue;
|
||||
gas_server_handle_rx_comeback_req(response);
|
||||
return 0;
|
||||
@ -458,7 +470,7 @@ void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
|
||||
dl_list_for_each(response, &gas->responses, struct gas_server_response,
|
||||
list) {
|
||||
if (response->dialog_token != dialog_token ||
|
||||
os_memcmp(dst, response->dst, ETH_ALEN) != 0)
|
||||
!ether_addr_equal(dst, response->dst))
|
||||
continue;
|
||||
gas_server_handle_tx_status(response, ack);
|
||||
return;
|
||||
@ -484,11 +496,42 @@ int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
|
||||
if (!response || response->resp)
|
||||
return -1;
|
||||
|
||||
if (!response->initial_resp_sent) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Send the delayed initial response");
|
||||
gas_server_send_resp(gas, response, resp, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
response->resp = resp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int gas_server_set_comeback_delay(struct gas_server *gas, void *resp_ctx,
|
||||
u16 comeback_delay)
|
||||
{
|
||||
struct gas_server_response *tmp, *response = NULL;
|
||||
|
||||
dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
|
||||
list) {
|
||||
if (tmp == resp_ctx) {
|
||||
response = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!response || response->initial_resp_sent)
|
||||
return -1;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Send the delayed initial response with comeback delay %u",
|
||||
comeback_delay);
|
||||
gas_server_send_resp(gas, response, NULL, comeback_delay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx)
|
||||
{
|
||||
struct gas_server_response *tmp;
|
||||
@ -552,7 +595,7 @@ int gas_server_register(struct gas_server *gas,
|
||||
struct wpabuf *
|
||||
(*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
|
||||
const u8 *query, size_t query_len,
|
||||
u16 *comeback_delay),
|
||||
int *comeback_delay),
|
||||
void (*status_cb)(void *ctx, struct wpabuf *resp,
|
||||
int ok),
|
||||
void *ctx)
|
||||
|
@ -2,6 +2,7 @@
|
||||
* Generic advertisement service (GAS) server
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2020, The Linux Foundation
|
||||
* Copyright (c) 2022, Qualcomm Innovation Center, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -25,7 +26,7 @@ int gas_server_register(struct gas_server *gas,
|
||||
struct wpabuf *
|
||||
(*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
|
||||
const u8 *query, size_t query_len,
|
||||
u16 *comeback_delay),
|
||||
int *comeback_delay),
|
||||
void (*status_cb)(void *ctx, struct wpabuf *resp,
|
||||
int ok),
|
||||
void *ctx);
|
||||
@ -34,6 +35,8 @@ int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
|
||||
int freq);
|
||||
void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
|
||||
size_t data_len, int ack);
|
||||
int gas_server_set_comeback_delay(struct gas_server *gas, void *resp_ctx,
|
||||
u16 comeback_delay);
|
||||
int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
|
||||
struct wpabuf *resp);
|
||||
bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx);
|
||||
|
@ -183,8 +183,8 @@ void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan)
|
||||
|
||||
*pri_chan = *sec_chan = 0;
|
||||
|
||||
ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
|
||||
if (elems.ht_operation) {
|
||||
if (ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0) !=
|
||||
ParseFailed && elems.ht_operation) {
|
||||
oper = (struct ieee80211_ht_operation *) elems.ht_operation;
|
||||
*pri_chan = oper->primary_chan;
|
||||
if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) {
|
||||
@ -273,7 +273,10 @@ static int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start,
|
||||
if (bss->freq < start || bss->freq > end || bss->freq == pri_freq)
|
||||
return 0;
|
||||
|
||||
ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
|
||||
if (ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0) ==
|
||||
ParseFailed)
|
||||
return 0;
|
||||
|
||||
if (!elems.ht_capabilities) {
|
||||
wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: "
|
||||
MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
|
||||
@ -357,9 +360,9 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
|
||||
}
|
||||
}
|
||||
|
||||
ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
|
||||
0);
|
||||
if (elems.ht_capabilities) {
|
||||
if (ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len,
|
||||
&elems, 0) != ParseFailed &&
|
||||
elems.ht_capabilities) {
|
||||
struct ieee80211_ht_capabilities *ht_cap =
|
||||
(struct ieee80211_ht_capabilities *)
|
||||
elems.ht_capabilities;
|
||||
@ -378,18 +381,95 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
|
||||
}
|
||||
|
||||
|
||||
static void punct_update_legacy_bw_80(u8 bitmap, u8 pri_chan, u8 *seg0)
|
||||
{
|
||||
u8 first_chan = *seg0 - 6, sec_chan;
|
||||
|
||||
switch (bitmap) {
|
||||
case 0x6:
|
||||
*seg0 = 0;
|
||||
return;
|
||||
case 0x8:
|
||||
case 0x4:
|
||||
case 0x2:
|
||||
case 0x1:
|
||||
case 0xC:
|
||||
case 0x3:
|
||||
if (pri_chan < *seg0)
|
||||
*seg0 -= 4;
|
||||
else
|
||||
*seg0 += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pri_chan < *seg0)
|
||||
sec_chan = pri_chan + 4;
|
||||
else
|
||||
sec_chan = pri_chan - 4;
|
||||
|
||||
if (bitmap & BIT((sec_chan - first_chan) / 4))
|
||||
*seg0 = 0;
|
||||
}
|
||||
|
||||
|
||||
static void punct_update_legacy_bw_160(u8 bitmap, u8 pri,
|
||||
enum oper_chan_width *width, u8 *seg0)
|
||||
{
|
||||
if (pri < *seg0) {
|
||||
*seg0 -= 8;
|
||||
if (bitmap & 0x0F) {
|
||||
*width = 0;
|
||||
punct_update_legacy_bw_80(bitmap & 0xF, pri, seg0);
|
||||
}
|
||||
} else {
|
||||
*seg0 += 8;
|
||||
if (bitmap & 0xF0) {
|
||||
*width = 0;
|
||||
punct_update_legacy_bw_80((bitmap & 0xF0) >> 4, pri,
|
||||
seg0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void punct_update_legacy_bw(u16 bitmap, u8 pri, enum oper_chan_width *width,
|
||||
u8 *seg0, u8 *seg1)
|
||||
{
|
||||
if (*width == CONF_OPER_CHWIDTH_80MHZ && (bitmap & 0xF)) {
|
||||
*width = CONF_OPER_CHWIDTH_USE_HT;
|
||||
punct_update_legacy_bw_80(bitmap & 0xF, pri, seg0);
|
||||
}
|
||||
|
||||
if (*width == CONF_OPER_CHWIDTH_160MHZ && (bitmap & 0xFF)) {
|
||||
*width = CONF_OPER_CHWIDTH_80MHZ;
|
||||
*seg1 = 0;
|
||||
punct_update_legacy_bw_160(bitmap & 0xFF, pri, width, seg0);
|
||||
}
|
||||
|
||||
/* TODO: 320 MHz */
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
enum hostapd_hw_mode mode,
|
||||
int freq, int channel, int enable_edmg,
|
||||
u8 edmg_channel, int ht_enabled,
|
||||
int vht_enabled, int he_enabled,
|
||||
int sec_channel_offset,
|
||||
int oper_chwidth, int center_segment0,
|
||||
bool eht_enabled, int sec_channel_offset,
|
||||
enum oper_chan_width oper_chwidth,
|
||||
int center_segment0,
|
||||
int center_segment1, u32 vht_caps,
|
||||
struct he_capabilities *he_cap)
|
||||
struct he_capabilities *he_cap,
|
||||
struct eht_capabilities *eht_cap,
|
||||
u16 punct_bitmap)
|
||||
{
|
||||
enum oper_chan_width oper_chwidth_legacy;
|
||||
u8 seg0_legacy, seg1_legacy;
|
||||
|
||||
if (!he_cap || !he_cap->he_supported)
|
||||
he_enabled = 0;
|
||||
if (!eht_cap || !eht_cap->eht_supported)
|
||||
eht_enabled = 0;
|
||||
os_memset(data, 0, sizeof(*data));
|
||||
data->mode = mode;
|
||||
data->freq = freq;
|
||||
@ -397,14 +477,17 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
data->ht_enabled = ht_enabled;
|
||||
data->vht_enabled = vht_enabled;
|
||||
data->he_enabled = he_enabled;
|
||||
data->eht_enabled = eht_enabled;
|
||||
data->sec_channel_offset = sec_channel_offset;
|
||||
data->center_freq1 = freq + sec_channel_offset * 10;
|
||||
data->center_freq2 = 0;
|
||||
if (oper_chwidth == CHANWIDTH_80MHZ)
|
||||
if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
|
||||
data->bandwidth = 80;
|
||||
else if (oper_chwidth == CHANWIDTH_160MHZ ||
|
||||
oper_chwidth == CHANWIDTH_80P80MHZ)
|
||||
else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
|
||||
oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
|
||||
data->bandwidth = 160;
|
||||
else if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ)
|
||||
data->bandwidth = 320;
|
||||
else if (sec_channel_offset)
|
||||
data->bandwidth = 40;
|
||||
else
|
||||
@ -415,9 +498,9 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
&data->edmg);
|
||||
|
||||
if (is_6ghz_freq(freq)) {
|
||||
if (!data->he_enabled) {
|
||||
if (!data->he_enabled && !data->eht_enabled) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Can't set 6 GHz mode - HE isn't enabled");
|
||||
"Can't set 6 GHz mode - HE or EHT aren't enabled");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -438,6 +521,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
} else {
|
||||
int freq1, freq2 = 0;
|
||||
int bw = center_idx_to_bw_6ghz(center_segment0);
|
||||
int opclass;
|
||||
|
||||
if (bw < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
@ -445,7 +529,10 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
return -1;
|
||||
}
|
||||
|
||||
freq1 = ieee80211_chan_to_freq(NULL, 131,
|
||||
/* The 6 GHz channel 2 uses a different operating class
|
||||
*/
|
||||
opclass = center_segment0 == 2 ? 136 : 131;
|
||||
freq1 = ieee80211_chan_to_freq(NULL, opclass,
|
||||
center_segment0);
|
||||
if (freq1 < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
@ -480,13 +567,27 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data->he_enabled) switch (oper_chwidth) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
if (data->eht_enabled) switch (oper_chwidth) {
|
||||
case CONF_OPER_CHWIDTH_320MHZ:
|
||||
if (!(eht_cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
|
||||
EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"320 MHz channel width is not supported in 5 or 6 GHz");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (data->he_enabled || data->eht_enabled) switch (oper_chwidth) {
|
||||
case CONF_OPER_CHWIDTH_USE_HT:
|
||||
if (sec_channel_offset == 0)
|
||||
break;
|
||||
|
||||
if (mode == HOSTAPD_MODE_IEEE80211G) {
|
||||
if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
|
||||
if (he_cap &&
|
||||
!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
|
||||
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"40 MHz channel width is not supported in 2.4 GHz");
|
||||
@ -495,9 +596,10 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case CHANWIDTH_80MHZ:
|
||||
case CONF_OPER_CHWIDTH_80MHZ:
|
||||
if (mode == HOSTAPD_MODE_IEEE80211A) {
|
||||
if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
|
||||
if (he_cap &&
|
||||
!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
|
||||
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"40/80 MHz channel width is not supported in 5/6 GHz");
|
||||
@ -505,35 +607,39 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
|
||||
case CONF_OPER_CHWIDTH_80P80MHZ:
|
||||
if (he_cap &&
|
||||
!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
|
||||
HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"80+80 MHz channel width is not supported in 5/6 GHz");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
|
||||
case CONF_OPER_CHWIDTH_160MHZ:
|
||||
if (he_cap &&
|
||||
!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
|
||||
HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"160 MHz channel width is not supported in 5 / 6GHz");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
} else if (data->vht_enabled) switch (oper_chwidth) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
default:
|
||||
break;
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
} else if (data->vht_enabled) switch (oper_chwidth) {
|
||||
case CONF_OPER_CHWIDTH_USE_HT:
|
||||
break;
|
||||
case CONF_OPER_CHWIDTH_80P80MHZ:
|
||||
if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"80+80 channel width is not supported!");
|
||||
return -1;
|
||||
}
|
||||
/* fall through */
|
||||
case CHANWIDTH_80MHZ:
|
||||
case CONF_OPER_CHWIDTH_80MHZ:
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
case CONF_OPER_CHWIDTH_160MHZ:
|
||||
if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
|
||||
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
@ -541,10 +647,21 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (data->he_enabled || data->vht_enabled) switch (oper_chwidth) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
oper_chwidth_legacy = oper_chwidth;
|
||||
seg0_legacy = center_segment0;
|
||||
seg1_legacy = center_segment1;
|
||||
if (punct_bitmap)
|
||||
punct_update_legacy_bw(punct_bitmap, channel,
|
||||
&oper_chwidth_legacy,
|
||||
&seg0_legacy, &seg1_legacy);
|
||||
|
||||
if (data->eht_enabled || data->he_enabled ||
|
||||
data->vht_enabled) switch (oper_chwidth) {
|
||||
case CONF_OPER_CHWIDTH_USE_HT:
|
||||
if (center_segment1 ||
|
||||
(center_segment0 != 0 &&
|
||||
5000 + center_segment0 * 5 != data->center_freq1 &&
|
||||
@ -555,7 +672,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
case CONF_OPER_CHWIDTH_80P80MHZ:
|
||||
if (center_segment1 == center_segment0 + 4 ||
|
||||
center_segment1 == center_segment0 - 4) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
@ -564,19 +681,22 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
}
|
||||
data->center_freq2 = 5000 + center_segment1 * 5;
|
||||
/* fall through */
|
||||
case CHANWIDTH_80MHZ:
|
||||
case CONF_OPER_CHWIDTH_80MHZ:
|
||||
data->bandwidth = 80;
|
||||
if (!sec_channel_offset) {
|
||||
if (!sec_channel_offset &&
|
||||
oper_chwidth_legacy != CONF_OPER_CHWIDTH_USE_HT) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"80/80+80 MHz: no second channel offset");
|
||||
return -1;
|
||||
}
|
||||
if (oper_chwidth == CHANWIDTH_80MHZ && center_segment1) {
|
||||
if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ &&
|
||||
center_segment1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"80 MHz: center segment 1 configured");
|
||||
return -1;
|
||||
}
|
||||
if (oper_chwidth == CHANWIDTH_80P80MHZ && !center_segment1) {
|
||||
if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ &&
|
||||
!center_segment1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"80+80 MHz: center segment 1 not configured");
|
||||
return -1;
|
||||
@ -615,14 +735,15 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
case CONF_OPER_CHWIDTH_160MHZ:
|
||||
data->bandwidth = 160;
|
||||
if (center_segment1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"160 MHz: center segment 1 should not be set");
|
||||
return -1;
|
||||
}
|
||||
if (!sec_channel_offset) {
|
||||
if (!sec_channel_offset &&
|
||||
oper_chwidth_legacy != CONF_OPER_CHWIDTH_USE_HT) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"160 MHz: second channel offset not set");
|
||||
return -1;
|
||||
@ -646,6 +767,43 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CONF_OPER_CHWIDTH_320MHZ:
|
||||
data->bandwidth = 320;
|
||||
if (!data->eht_enabled || !is_6ghz_freq(freq)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"320 MHz: EHT not enabled or not a 6 GHz channel");
|
||||
return -1;
|
||||
}
|
||||
if (center_segment1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"320 MHz: center segment 1 should not be set");
|
||||
return -1;
|
||||
}
|
||||
if (center_segment0 == channel + 30 ||
|
||||
center_segment0 == channel + 26 ||
|
||||
center_segment0 == channel + 22 ||
|
||||
center_segment0 == channel + 18 ||
|
||||
center_segment0 == channel + 14 ||
|
||||
center_segment0 == channel + 10 ||
|
||||
center_segment0 == channel + 6 ||
|
||||
center_segment0 == channel + 2 ||
|
||||
center_segment0 == channel - 2 ||
|
||||
center_segment0 == channel - 6 ||
|
||||
center_segment0 == channel - 10 ||
|
||||
center_segment0 == channel - 14 ||
|
||||
center_segment0 == channel - 18 ||
|
||||
center_segment0 == channel - 22 ||
|
||||
center_segment0 == channel - 26 ||
|
||||
center_segment0 == channel - 30)
|
||||
data->center_freq1 = 5000 + center_segment0 * 5;
|
||||
else {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"320 MHz: wrong center segment 0");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -756,6 +914,7 @@ u32 num_chan_to_bw(int num_chans)
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
case 16:
|
||||
return num_chans * 20;
|
||||
default:
|
||||
return 20;
|
||||
@ -789,6 +948,9 @@ int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
|
||||
case 160:
|
||||
bw_mask = HOSTAPD_CHAN_WIDTH_160;
|
||||
break;
|
||||
case 320:
|
||||
bw_mask = HOSTAPD_CHAN_WIDTH_320;
|
||||
break;
|
||||
default:
|
||||
bw_mask = 0;
|
||||
break;
|
||||
@ -804,3 +966,70 @@ int chan_pri_allowed(const struct hostapd_channel_data *chan)
|
||||
return !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
|
||||
(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_20);
|
||||
}
|
||||
|
||||
|
||||
/* IEEE P802.11be/D3.0, Table 36-30 - Definition of the Punctured Channel
|
||||
* Information field in the U-SIG for an EHT MU PPDU using non-OFDMA
|
||||
* transmissions */
|
||||
static const u16 punct_bitmap_80[] = { 0xF, 0xE, 0xD, 0xB, 0x7 };
|
||||
static const u16 punct_bitmap_160[] = {
|
||||
0xFF, 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF,
|
||||
0x7F, 0xFC, 0xF3, 0xCF, 0x3F
|
||||
};
|
||||
static const u16 punct_bitmap_320[] = {
|
||||
0xFFFF, 0xFFFC, 0xFFF3, 0xFFCF, 0xFF3F, 0xFCFF, 0xF3FF, 0xCFFF,
|
||||
0x3FFF, 0xFFF0, 0xFF0F, 0xF0FF, 0x0FFF, 0xFFC0, 0xFF30, 0xFCF0,
|
||||
0xF3F0, 0xCFF0, 0x3FF0, 0x0FFC, 0x0FF3, 0x0FCF, 0x0F3F, 0x0CFF,
|
||||
0x03FF
|
||||
};
|
||||
|
||||
|
||||
bool is_punct_bitmap_valid(u16 bw, u16 pri_ch_bit_pos, u16 punct_bitmap)
|
||||
{
|
||||
u8 i, count;
|
||||
u16 bitmap;
|
||||
const u16 *valid_bitmaps;
|
||||
|
||||
if (!punct_bitmap) /* All channels active */
|
||||
return true;
|
||||
|
||||
bitmap = ~punct_bitmap;
|
||||
|
||||
switch (bw) {
|
||||
case 80:
|
||||
bitmap &= 0xF;
|
||||
valid_bitmaps = punct_bitmap_80;
|
||||
count = ARRAY_SIZE(punct_bitmap_80);
|
||||
break;
|
||||
|
||||
case 160:
|
||||
bitmap &= 0xFF;
|
||||
valid_bitmaps = punct_bitmap_160;
|
||||
count = ARRAY_SIZE(punct_bitmap_160);
|
||||
break;
|
||||
|
||||
case 320:
|
||||
bitmap &= 0xFFFF;
|
||||
valid_bitmaps = punct_bitmap_320;
|
||||
count = ARRAY_SIZE(punct_bitmap_320);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bitmap) /* No channel active */
|
||||
return false;
|
||||
|
||||
if (!(bitmap & BIT(pri_ch_bit_pos))) {
|
||||
wpa_printf(MSG_DEBUG, "Primary channel cannot be punctured");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (valid_bitmaps[i] == bitmap)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user