1
0
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:
Cy Schubert 2024-07-21 11:59:44 -07:00
commit a90b9d0159
366 changed files with 65940 additions and 12397 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'",

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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())

View File

@ -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);

View File

@ -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(&params, 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;

View File

@ -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)

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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:

View File

@ -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], &params);
os_free(params.freqs);
if (hostapd_driver_scan(iface->bss[0], &params) < 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;
}

View File

@ -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)

View File

@ -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;

View File

@ -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++;
}
}
}

View File

@ -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 APs 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 */

View File

@ -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, &params);
}
@ -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, &params);
}
@ -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(&params, 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(&params, 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, &params);
}
#endif /* CONFIG_PASN */

View File

@ -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 */

View File

@ -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;

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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;

View 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) */

View 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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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,

View File

@ -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

View File

@ -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 */

View File

@ -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, &params);
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], &params);
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, &params);
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], &params);
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);

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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);

View 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);
}

View 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 */

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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 " ",

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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(

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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 */
}

View File

@ -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);

View File

@ -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 */

View File

@ -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));

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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) $<

View File

@ -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
*

View File

@ -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;

View File

@ -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

View File

@ -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 */

View File

@ -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;

View File

@ -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,

View File

@ -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);
}

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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