Merge "[wpa_supplicant] Cumulative patch from 9fde14607"
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index ecfcaf5..24f1403 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -216,18 +216,12 @@
L_CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
-ifdef CONFIG_IAPP
-L_CFLAGS += -DCONFIG_IAPP
-OBJS += src/ap/iapp.c
-endif
-
ifdef CONFIG_RSN_PREAUTH
L_CFLAGS += -DCONFIG_RSN_PREAUTH
CONFIG_L2_PACKET=y
endif
ifdef CONFIG_HS20
-NEED_AES_OMAC1=y
CONFIG_PROXYARP=y
endif
@@ -237,8 +231,6 @@
ifdef CONFIG_SUITEB
L_CFLAGS += -DCONFIG_SUITEB
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_SUITEB192
@@ -249,24 +241,14 @@
ifdef CONFIG_OCV
L_CFLAGS += -DCONFIG_OCV
OBJS += src/common/ocv.c
-CONFIG_IEEE80211W=y
-endif
-
-ifdef CONFIG_IEEE80211W
-L_CFLAGS += -DCONFIG_IEEE80211W
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_IEEE80211R
L_CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP
OBJS += src/ap/wpa_auth_ft.c
-NEED_SHA256=y
-NEED_AES_OMAC1=y
NEED_AES_UNWRAP=y
NEED_AES_SIV=y
NEED_ETH_P_OUI=y
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -289,7 +271,6 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
endif
@@ -424,7 +405,6 @@
L_CFLAGS += -DEAP_SERVER_AKA
OBJS += src/eap_server/eap_server_aka.c
CONFIG_EAP_SIM_COMMON=y
-NEED_SHA256=y
NEED_AES_CBC=y
endif
@@ -449,7 +429,6 @@
ifdef CONFIG_EAP_PSK
L_CFLAGS += -DEAP_SERVER_PSK
OBJS += src/eap_server/eap_server_psk.c src/eap_common/eap_psk_common.c
-NEED_AES_OMAC1=y
NEED_AES_ENCBLOCK=y
NEED_AES_EAX=y
endif
@@ -465,14 +444,11 @@
ifdef CONFIG_EAP_GPSK_SHA256
L_CFLAGS += -DEAP_GPSK_SHA256
endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_EAP_PWD
L_CFLAGS += -DEAP_SERVER_PWD
OBJS += src/eap_server/eap_server_pwd.c src/eap_common/eap_pwd_common.c
-NEED_SHA256=y
NEED_ECC=y
NEED_DRAGONFLY=y
endif
@@ -505,6 +481,8 @@
TLS_FUNCS=y
NEED_T_PRF=y
NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
NEED_AES_UNWRAP=y
endif
@@ -522,7 +500,6 @@
OBJS += src/wps/wps_enrollee.c
OBJS += src/wps/wps_registrar.c
NEED_DH_GROUPS=y
-NEED_SHA256=y
NEED_BASE64=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -571,9 +548,9 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_ECC=y
NEED_JSON=y
NEED_GAS=y
NEED_BASE64=y
@@ -650,7 +627,6 @@
ifdef CONFIG_TLSV12
L_CFLAGS += -DCONFIG_TLSV12
-NEED_SHA256=y
endif
ifeq ($(CONFIG_TLS), openssl)
@@ -664,7 +640,6 @@
ifdef NEED_FIPS186_2_PRF
OBJS += src/crypto/fips_prf_openssl.c
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_h += -lcrypto
@@ -722,7 +697,6 @@
OBJS += src/tls/pkcs1.c
OBJS += src/tls/pkcs5.c
OBJS += src/tls/pkcs8.c
-NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -817,12 +791,10 @@
ifdef NEED_AES_EAX
AESOBJS += src/crypto/aes-eax.c
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_SIV
AESOBJS += src/crypto/aes-siv.c
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_CTR
AESOBJS += src/crypto/aes-ctr.c
@@ -830,9 +802,7 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += src/crypto/aes-encblock.c
endif
-ifdef NEED_AES_OMAC1
AESOBJS += src/crypto/aes-omac1.c
-endif
ifdef NEED_AES_UNWRAP
ifneq ($(CONFIG_TLS), openssl)
NEED_AES_DEC=y
@@ -920,7 +890,6 @@
endif
endif
-ifdef NEED_SHA256
L_CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), gnutls)
@@ -934,6 +903,9 @@
ifdef NEED_TLS_PRF_SHA256
OBJS += src/crypto/sha256-tlsprf.c
endif
+ifdef NEED_TLS_PRF_SHA384
+OBJS += src/crypto/sha384-tlsprf.c
+endif
ifdef NEED_HMAC_SHA256_KDF
OBJS += src/crypto/sha256-kdf.c
endif
@@ -943,7 +915,6 @@
ifdef NEED_HMAC_SHA512_KDF
OBJS += src/crypto/sha512-kdf.c
endif
-endif
ifdef NEED_SHA384
L_CFLAGS += -DCONFIG_SHA384
ifneq ($(CONFIG_TLS), openssl)
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index 327ee3b..6c4410e 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,5 +1,29 @@
ChangeLog for hostapd
+2019-08-07 - v2.9
+ * SAE changes
+ - disable use of groups using Brainpool curves
+ - improved protection against side channel attacks
+ [https://w1.fi/security/2019-6/]
+ * EAP-pwd changes
+ - disable use of groups using Brainpool curves
+ - improved protection against side channel attacks
+ [https://w1.fi/security/2019-6/]
+ * fixed FT-EAP initial mobility domain association using PMKSA caching
+ * added configuration of airtime policy
+ * fixed FILS to and RSNE into (Re)Association Response frames
+ * fixed DPP bootstrapping URI parser of channel list
+ * added support for regulatory WMM limitation (for ETSI)
+ * added support for MACsec Key Agreement using IEEE 802.1X/PSK
+ * added experimental support for EAP-TEAP server (RFC 7170)
+ * added experimental support for EAP-TLS server with TLS v1.3
+ * added support for two server certificates/keys (RSA/ECC)
+ * added AKMSuiteSelector into "STA <addr>" control interface data to
+ determine with AKM was used for an association
+ * added eap_sim_id parameter to allow EAP-SIM/AKA server pseudonym and
+ fast reauthentication use to be disabled
+ * fixed an ECDH operation corner case with OpenSSL
+
2019-04-21 - v2.8
* SAE changes
- added support for SAE Password Identifier
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 2a6bd7a..955e278 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -121,6 +121,7 @@
LIBS += -lbfd -ldl -liberty -lz
LIBS_c += -lbfd -ldl -liberty -lz
LIBS_h += -lbfd -ldl -liberty -lz
+LIBS_n += -lbfd -ldl -liberty -lz
endif
endif
@@ -248,18 +249,12 @@
CFLAGS += -DCONFIG_CTRL_IFACE
endif
-ifdef CONFIG_IAPP
-CFLAGS += -DCONFIG_IAPP
-OBJS += ../src/ap/iapp.o
-endif
-
ifdef CONFIG_RSN_PREAUTH
CFLAGS += -DCONFIG_RSN_PREAUTH
CONFIG_L2_PACKET=y
endif
ifdef CONFIG_HS20
-NEED_AES_OMAC1=y
CONFIG_PROXYARP=y
endif
@@ -269,8 +264,6 @@
ifdef CONFIG_SUITEB
CFLAGS += -DCONFIG_SUITEB
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_SUITEB192
@@ -281,24 +274,14 @@
ifdef CONFIG_OCV
CFLAGS += -DCONFIG_OCV
OBJS += ../src/common/ocv.o
-CONFIG_IEEE80211W=y
-endif
-
-ifdef CONFIG_IEEE80211W
-CFLAGS += -DCONFIG_IEEE80211W
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_IEEE80211R
CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP
OBJS += ../src/ap/wpa_auth_ft.o
-NEED_SHA256=y
-NEED_AES_OMAC1=y
NEED_AES_UNWRAP=y
NEED_AES_SIV=y
NEED_ETH_P_OUI=y
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -322,7 +305,6 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
endif
@@ -391,7 +373,6 @@
ifdef CONFIG_ERP
CFLAGS += -DCONFIG_ERP
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -452,7 +433,6 @@
CFLAGS += -DEAP_SERVER_AKA
OBJS += ../src/eap_server/eap_server_aka.o
CONFIG_EAP_SIM_COMMON=y
-NEED_SHA256=y
NEED_AES_CBC=y
endif
@@ -477,7 +457,6 @@
ifdef CONFIG_EAP_PSK
CFLAGS += -DEAP_SERVER_PSK
OBJS += ../src/eap_server/eap_server_psk.o ../src/eap_common/eap_psk_common.o
-NEED_AES_OMAC1=y
NEED_AES_ENCBLOCK=y
NEED_AES_EAX=y
endif
@@ -493,14 +472,11 @@
ifdef CONFIG_EAP_GPSK_SHA256
CFLAGS += -DEAP_GPSK_SHA256
endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_EAP_PWD
CFLAGS += -DEAP_SERVER_PWD
OBJS += ../src/eap_server/eap_server_pwd.o ../src/eap_common/eap_pwd_common.o
-NEED_SHA256=y
NEED_ECC=y
NEED_DRAGONFLY=y
endif
@@ -533,6 +509,8 @@
TLS_FUNCS=y
NEED_T_PRF=y
NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
NEED_AES_UNWRAP=y
endif
@@ -550,7 +528,6 @@
OBJS += ../src/wps/wps_enrollee.o
OBJS += ../src/wps/wps_registrar.o
NEED_DH_GROUPS=y
-NEED_SHA256=y
NEED_BASE64=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -599,9 +576,9 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_ECC=y
NEED_JSON=y
NEED_GAS=y
NEED_BASE64=y
@@ -687,7 +664,6 @@
ifdef CONFIG_TLSV12
CFLAGS += -DCONFIG_TLSV12
-NEED_SHA256=y
endif
ifeq ($(CONFIG_TLS), wolfssl)
@@ -701,7 +677,6 @@
ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_wolfssl.o
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lwolfssl -lm
LIBS_h += -lwolfssl -lm
@@ -723,7 +698,6 @@
ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_openssl.o
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_h += -lcrypto
@@ -787,7 +761,6 @@
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
-NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -864,7 +837,6 @@
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
-NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -925,12 +897,10 @@
ifdef NEED_AES_EAX
AESOBJS += ../src/crypto/aes-eax.o
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_SIV
AESOBJS += ../src/crypto/aes-siv.o
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_CTR
AESOBJS += ../src/crypto/aes-ctr.o
@@ -938,13 +908,11 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += ../src/crypto/aes-encblock.o
endif
-ifdef NEED_AES_OMAC1
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)
@@ -1050,7 +1018,6 @@
endif
endif
-ifdef NEED_SHA256
CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
@@ -1068,6 +1035,9 @@
ifdef NEED_TLS_PRF_SHA256
OBJS += ../src/crypto/sha256-tlsprf.o
endif
+ifdef NEED_TLS_PRF_SHA384
+OBJS += ../src/crypto/sha384-tlsprf.o
+endif
ifdef NEED_HMAC_SHA256_KDF
OBJS += ../src/crypto/sha256-kdf.o
endif
@@ -1077,7 +1047,6 @@
ifdef NEED_HMAC_SHA512_KDF
OBJS += ../src/crypto/sha512-kdf.o
endif
-endif
ifdef NEED_SHA384
CFLAGS += -DCONFIG_SHA384
ifneq ($(CONFIG_TLS), openssl)
@@ -1345,7 +1314,6 @@
NOBJS += ../src/utils/wpabuf.o
ifdef CONFIG_WPA_TRACE
NOBJS += ../src/utils/trace.o
-LIBS_n += -lbfd
endif
HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o
diff --git a/hostapd/android.config b/hostapd/android.config
index 4502a60..f19f62f 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -38,18 +38,9 @@
# Driver interface for no driver (e.g., RADIUS server only)
#CONFIG_DRIVER_NONE=y
-# IEEE 802.11F/IAPP
-#CONFIG_IAPP=y
-
# WPA2/IEEE 802.11i RSN pre-authentication
#CONFIG_RSN_PREAUTH=y
-# IEEE 802.11w (management frame protection)
-# This version is an experimental implementation based on IEEE 802.11w/D1.0
-# draft and is subject to change since the standard has not yet been finalized.
-# Driver support is also needed for IEEE 802.11w.
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index df41f14..40066ad 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -24,14 +24,6 @@
#include "config_file.h"
-#ifndef CONFIG_NO_RADIUS
-#ifdef EAP_SERVER
-static struct hostapd_radius_attr *
-hostapd_parse_radius_attr(const char *value);
-#endif /* EAP_SERVER */
-#endif /* CONFIG_NO_RADIUS */
-
-
#ifndef CONFIG_NO_VLAN
static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
const char *fname)
@@ -660,75 +652,6 @@
}
-static struct hostapd_radius_attr *
-hostapd_parse_radius_attr(const char *value)
-{
- const char *pos;
- char syntax;
- struct hostapd_radius_attr *attr;
- size_t len;
-
- attr = os_zalloc(sizeof(*attr));
- if (attr == NULL)
- return NULL;
-
- attr->type = atoi(value);
-
- pos = os_strchr(value, ':');
- if (pos == NULL) {
- attr->val = wpabuf_alloc(1);
- if (attr->val == NULL) {
- os_free(attr);
- return NULL;
- }
- wpabuf_put_u8(attr->val, 0);
- return attr;
- }
-
- pos++;
- if (pos[0] == '\0' || pos[1] != ':') {
- os_free(attr);
- return NULL;
- }
- syntax = *pos++;
- pos++;
-
- switch (syntax) {
- case 's':
- attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
- break;
- case 'x':
- len = os_strlen(pos);
- if (len & 1)
- break;
- len /= 2;
- attr->val = wpabuf_alloc(len);
- if (attr->val == NULL)
- break;
- if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
- wpabuf_free(attr->val);
- os_free(attr);
- return NULL;
- }
- break;
- case 'd':
- attr->val = wpabuf_alloc(4);
- if (attr->val)
- wpabuf_put_be32(attr->val, atoi(pos));
- break;
- default:
- os_free(attr);
- return NULL;
- }
-
- if (attr->val == NULL) {
- os_free(attr);
- return NULL;
- }
-
- return attr;
-}
-
static int hostapd_parse_das_client(struct hostapd_bss_config *bss, char *val)
{
@@ -788,12 +711,10 @@
val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
val |= WPA_KEY_MGMT_PSK_SHA256;
else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (os_strcmp(start, "SAE") == 0)
val |= WPA_KEY_MGMT_SAE;
@@ -2624,6 +2545,10 @@
bss->tls_session_lifetime = atoi(pos);
} else if (os_strcmp(buf, "tls_flags") == 0) {
bss->tls_flags = parse_tls_flags(pos);
+ } else if (os_strcmp(buf, "max_auth_rounds") == 0) {
+ bss->max_auth_rounds = atoi(pos);
+ } else if (os_strcmp(buf, "max_auth_rounds_short") == 0) {
+ bss->max_auth_rounds_short = atoi(pos);
} else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
os_free(bss->ocsp_stapling_response);
bss->ocsp_stapling_response = os_strdup(pos);
@@ -2697,6 +2622,10 @@
bss->eap_teap_auth = val;
} else if (os_strcmp(buf, "eap_teap_pac_no_inner") == 0) {
bss->eap_teap_pac_no_inner = atoi(pos);
+ } else if (os_strcmp(buf, "eap_teap_separate_result") == 0) {
+ bss->eap_teap_separate_result = atoi(pos);
+ } else if (os_strcmp(buf, "eap_teap_id") == 0) {
+ bss->eap_teap_id = atoi(pos);
#endif /* EAP_SERVER_TEAP */
#ifdef EAP_SERVER_SIM
} else if (os_strcmp(buf, "eap_sim_db") == 0) {
@@ -2706,6 +2635,8 @@
bss->eap_sim_db_timeout = atoi(pos);
} else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
bss->eap_sim_aka_result_ind = atoi(pos);
+ } else if (os_strcmp(buf, "eap_sim_id") == 0) {
+ bss->eap_sim_id = atoi(pos);
#endif /* EAP_SERVER_SIM */
#ifdef EAP_SERVER_TNC
} else if (os_strcmp(buf, "tnc") == 0) {
@@ -2781,8 +2712,7 @@
bss->eapol_key_index_workaround = atoi(pos);
#ifdef CONFIG_IAPP
} else if (os_strcmp(buf, "iapp_interface") == 0) {
- bss->ieee802_11f = 1;
- os_strlcpy(bss->iapp_iface, pos, sizeof(bss->iapp_iface));
+ wpa_printf(MSG_INFO, "DEPRECATED: iapp_interface not used");
#endif /* CONFIG_IAPP */
} else if (os_strcmp(buf, "own_ip_addr") == 0) {
if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
@@ -2909,6 +2839,9 @@
a = a->next;
a->next = attr;
}
+ } else if (os_strcmp(buf, "radius_req_attr_sqlite") == 0) {
+ os_free(bss->radius_req_attr_sqlite);
+ bss->radius_req_attr_sqlite = os_strdup(pos);
} else if (os_strcmp(buf, "radius_das_port") == 0) {
bss->radius_das_port = atoi(pos);
} else if (os_strcmp(buf, "radius_das_client") == 0) {
@@ -3203,6 +3136,8 @@
}
} else if (os_strcmp(buf, "acs_exclude_dfs") == 0) {
conf->acs_exclude_dfs = atoi(pos);
+ } else if (os_strcmp(buf, "op_class") == 0) {
+ conf->op_class = atoi(pos);
} else if (os_strcmp(buf, "channel") == 0) {
if (os_strcmp(pos, "acs_survey") == 0) {
#ifndef CONFIG_ACS
@@ -3217,6 +3152,10 @@
conf->channel = atoi(pos);
conf->acs = conf->channel == 0;
}
+ } else if (os_strcmp(buf, "edmg_channel") == 0) {
+ conf->edmg_channel = atoi(pos);
+ } else if (os_strcmp(buf, "enable_edmg") == 0) {
+ conf->enable_edmg = atoi(pos);
} else if (os_strcmp(buf, "chanlist") == 0) {
if (hostapd_parse_chanlist(conf, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
@@ -3444,7 +3383,6 @@
}
} else if (os_strcmp(buf, "use_driver_iface_addr") == 0) {
conf->use_driver_iface_addr = atoi(pos);
-#ifdef CONFIG_IEEE80211W
} else if (os_strcmp(buf, "ieee80211w") == 0) {
bss->ieee80211w = atoi(pos);
} else if (os_strcmp(buf, "group_mgmt_cipher") == 0) {
@@ -3475,7 +3413,6 @@
line);
return 1;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
} else if (os_strcmp(buf, "ocv") == 0) {
bss->ocv = atoi(pos);
@@ -4247,6 +4184,10 @@
}
} else if (os_strcmp(buf, "sae_require_mfp") == 0) {
bss->sae_require_mfp = atoi(pos);
+ } else if (os_strcmp(buf, "sae_confirm_immediate") == 0) {
+ bss->sae_confirm_immediate = atoi(pos);
+ } else if (os_strcmp(buf, "sae_pwe") == 0) {
+ bss->sae_pwe = atoi(pos);
} else if (os_strcmp(buf, "local_pwr_constraint") == 0) {
int val = atoi(pos);
if (val < 0 || val > 255) {
@@ -4396,6 +4337,12 @@
} else if (os_strcmp(buf, "broadcast_deauth") == 0) {
bss->broadcast_deauth = atoi(pos);
#ifdef CONFIG_DPP
+ } else if (os_strcmp(buf, "dpp_name") == 0) {
+ os_free(bss->dpp_name);
+ bss->dpp_name = os_strdup(pos);
+ } 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_connector") == 0) {
os_free(bss->dpp_connector);
bss->dpp_connector = os_strdup(pos);
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 0f6dfa1..2c44d1e 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -130,7 +130,6 @@
}
-#ifdef CONFIG_IEEE80211W
#ifdef NEED_AP_MLME
static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
const char *txtaddr)
@@ -149,7 +148,6 @@
return 0;
}
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
@@ -1098,7 +1096,6 @@
}
#endif /* CONFIG_FILS */
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
if (os_snprintf_error(end - pos, ret))
@@ -1111,7 +1108,6 @@
return pos - buf;
pos += ret;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
ret = os_snprintf(pos, end - pos, "SAE ");
@@ -1428,6 +1424,11 @@
if (ieee802_11_update_beacons(hapd->iface))
wpa_printf(MSG_DEBUG,
"Failed to update beacons with WMM parameters");
+ } else if (os_strcmp(cmd, "wpa_passphrase") == 0 ||
+ os_strcmp(cmd, "sae_password") == 0 ||
+ os_strcmp(cmd, "sae_pwe") == 0) {
+ if (hapd->started)
+ hostapd_setup_sae_pt(hapd->conf);
}
}
@@ -2109,7 +2110,6 @@
if (hwaddr_aton(cmd, addr))
return -1;
-#ifdef CONFIG_IEEE80211W
if (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) {
if (hapd->last_igtk_alg == WPA_ALG_NONE)
return -1;
@@ -2133,7 +2133,6 @@
hapd->last_igtk,
hapd->last_igtk_len);
}
-#endif /* CONFIG_IEEE80211W */
if (is_broadcast_ether_addr(addr)) {
if (hapd->last_gtk_alg == WPA_ALG_NONE)
@@ -3032,13 +3031,11 @@
} else if (os_strcmp(buf, "STOP_AP") == 0) {
if (hostapd_ctrl_iface_stop_ap(hapd))
reply_len = -1;
-#ifdef CONFIG_IEEE80211W
#ifdef NEED_AP_MLME
} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
reply_len = -1;
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 01871c9..1a3d9f9 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -44,15 +44,9 @@
# Driver interface for no driver (e.g., RADIUS server only)
#CONFIG_DRIVER_NONE=y
-# IEEE 802.11F/IAPP
-CONFIG_IAPP=y
-
# WPA2/IEEE 802.11i RSN pre-authentication
CONFIG_RSN_PREAUTH=y
-# IEEE 802.11w (management frame protection)
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index f2d5873..4cbe451 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -41,7 +41,6 @@
# bit 2 (4) = RADIUS
# bit 3 (8) = WPA
# bit 4 (16) = driver interface
-# bit 5 (32) = IAPP
# bit 6 (64) = MLME
#
# Levels (minimum value for logged events):
@@ -147,7 +146,8 @@
# Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz),
# g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used
# with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this
-# needs to be set to hw_mode=a. When using ACS (see channel parameter), a
+# needs to be set to hw_mode=a. For IEEE 802.11ax (HE) on 6 GHz this needs
+# to be set to hw_mode=a. When using ACS (see channel parameter), a
# special value "any" can be used to indicate that any support band can be used.
# This special case is currently supported only with drivers with which
# offloaded ACS is used.
@@ -164,6 +164,12 @@
# which will enable the ACS survey based algorithm.
channel=1
+# Global operating class (IEEE 802.11, Annex E, Table E-4)
+# This option allows hostapd to specify the operating class of the channel
+# configured with the channel parameter. channel and op_class together can
+# uniquely identify channels across different bands, including the 6 GHz band.
+#op_class=131
+
# ACS tuning - Automatic Channel Selection
# See: http://wireless.kernel.org/en/users/Documentation/acs
#
@@ -800,6 +806,11 @@
#he_rts_threshold=0
# HE operating channel information; see matching vht_* parameters for details.
+# On the 6 GHz band the center freq calculation starts from 5.940 GHz offset.
+# For example idx=3 would result in 5955 MHz center frequency. In addition,
+# he_oper_chwidth is ignored, and the channel width is derived from the
+# configured operating class or center frequency indexes (see
+# IEEE P802.11ax/D4.3 Annex E, Table E-4).
#he_oper_chwidth
#he_oper_centr_freq_seg0_idx
#he_oper_centr_freq_seg1_idx
@@ -1012,7 +1023,7 @@
#check_crl=1
# Specify whether to ignore certificate CRL validity time mismatches with
-# errors X509_V_ERR_CERT_HAS_EXPIRED and X509_V_ERR_CERT_NOT_YET_VALID.
+# errors X509_V_ERR_CRL_HAS_EXPIRED and X509_V_ERR_CRL_NOT_YET_VALID.
#
# 0 = ignore errors
# 1 = do not ignore errors (default)
@@ -1081,6 +1092,12 @@
# [ENABLE-TLSv1.3] = enable TLSv1.3 (experimental - disabled by default)
#tls_flags=[flag1][flag2]...
+# Maximum number of EAP message rounds with data (default: 100)
+#max_auth_rounds=100
+
+# Maximum number of short EAP message rounds (default: 50)
+#max_auth_rounds_short=50
+
# Cached OCSP stapling response (DER encoded)
# If set, this file is sent as a certificate status response by the EAP server
# if the EAP peer requests certificate status in the ClientHello message.
@@ -1201,10 +1218,31 @@
# 1 = skip inner authentication (inner EAP/Basic-Password-Auth)
#eap_teap_pac_no_inner=0
+# EAP-TEAP behavior with Result TLV
+# 0 = include with Intermediate-Result TLV (default)
+# 1 = send in a separate message (for testing purposes)
+#eap_teap_separate_result=0
+
+# EAP-TEAP identities
+# 0 = allow any identity type (default)
+# 1 = require user identity
+# 2 = require machine identity
+# 3 = request user identity; accept either user or machine identity
+# 4 = request machine identity; accept either user or machine identity
+# 5 = require both user and machine identity
+#eap_teap_id=0
+
# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
# (default: 0 = disabled).
#eap_sim_aka_result_ind=1
+# EAP-SIM and EAP-AKA identity options
+# 0 = do not use pseudonyms or fast reauthentication
+# 1 = use pseudonyms, but not fast reauthentication
+# 2 = do not use pseudonyms, but use fast reauthentication
+# 3 = use pseudonyms and use fast reauthentication (default)
+#eap_sim_id=3
+
# 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
@@ -1216,11 +1254,6 @@
# Whether to enable ERP on the EAP server.
#eap_server_erp=1
-##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
-
-# Interface to be used for IAPP broadcast packets
-#iapp_interface=eth0
-
##### RADIUS client configuration #############################################
# for IEEE 802.1X with external Authentication Server, IEEE 802.11
@@ -1384,6 +1417,17 @@
# Operator-Name = "Operator"
#radius_acct_req_attr=126:s:Operator
+# If SQLite support is included, path to a database from which additional
+# RADIUS request attributes are extracted based on the station MAC address.
+#
+# The schema for the radius_attributes table is:
+# id | sta | reqtype | attr : multi-key (sta, reqtype)
+# id = autonumber
+# sta = station MAC address in `11:22:33:44:55:66` format.
+# type = `auth` | `acct` | NULL (match any)
+# attr = existing config file format, e.g. `126:s:Test Operator`
+#radius_req_attr_sqlite=radius_attr.sqlite
+
# Dynamic Authorization Extensions (RFC 5176)
# This mechanism can be used to allow dynamic changes to user session based on
# commands from a RADIUS server (or some other disconnect client that has the
@@ -1686,7 +1730,7 @@
#sae_anti_clogging_threshold=5
# Maximum number of SAE synchronization errors (dot11RSNASAESync)
-# The offending SAe peer will be disconnected if more than this many
+# The offending SAE peer will be disconnected if more than this many
# synchronization errors happen.
#sae_sync=5
@@ -1711,6 +1755,21 @@
# MFP while SAE stations are required to negotiate MFP if sae_require_mfp=1.
#sae_require_mfp=0
+# SAE Confirm behavior
+# By default, AP will send out only SAE Commit message in response to a received
+# SAE Commit message. This parameter can be set to 1 to override that behavior
+# to send both SAE Commit and SAE Confirm messages without waiting for the STA
+# to send its SAE Confirm message first.
+#sae_confirm_immediate=0
+
+# SAE mechanism for PWE derivation
+# 0 = hunting-and-pecking loop only (default)
+# 1 = hash-to-element only
+# 2 = both hunting-and-pecking loop and hash-to-element enabled
+# Note: The default value is likely to change from 0 to 2 once the new
+# hash-to-element mechanism has received more interoperability testing.
+#sae_pwe=0
+
# FILS Cache Identifier (16-bit value in hexdump format)
#fils_cache_id=0011
@@ -2133,6 +2192,20 @@
# Allow cross connection
#allow_cross_connection=1
+##### Device Provisioning Protocol (DPP) ######################################
+
+# Name for Enrollee's DPP Configuration Request
+#dpp_name=Test
+
+# MUD URL for Enrollee's DPP Configuration Request (optional)
+#dpp_mud_url=https://example.com/mud
+
+#dpp_connector
+#dpp_netaccesskey
+#dpp_netaccesskey_expiry
+#dpp_csign
+#dpp_controller
+
#### TDLS (IEEE 802.11z-2010) #################################################
# Prohibit use of TDLS in this BSS
@@ -2620,6 +2693,19 @@
# airtime.
#airtime_bss_limit=1
+##### EDMG support ############################################################
+#
+# Enable EDMG capability for AP mode in the 60 GHz band. Default value is false.
+# To configure channel bonding for an EDMG AP use edmg_channel below.
+# If enable_edmg is set and edmg_channel is not set, EDMG CB1 will be
+# configured.
+#enable_edmg=1
+#
+# Configure channel bonding for AP mode in the 60 GHz band.
+# This parameter is relevant only if enable_edmg is set.
+# Default value is 0 (no channel bonding).
+#edmg_channel=9
+
##### TESTING OPTIONS #########################################################
#
# The options in this section are only available when the build configuration
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 0460243..42edb7b 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -401,7 +401,6 @@
#endif /* CONFIG_TAXONOMY */
-#ifdef CONFIG_IEEE80211W
static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -414,7 +413,6 @@
snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
@@ -1542,10 +1540,8 @@
{ "signature", hostapd_cli_cmd_signature, hostapd_complete_stations,
"<addr> = get taxonomy signature for a station" },
#endif /* CONFIG_TAXONOMY */
-#ifdef CONFIG_IEEE80211W
{ "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations,
"<addr> = send SA Query to a station" },
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
{ "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
"<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
diff --git a/hostapd/main.c b/hostapd/main.c
index 11a1515..f08d60e 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -83,9 +83,6 @@
case HOSTAPD_MODULE_DRIVER:
module_str = "DRIVER";
break;
- case HOSTAPD_MODULE_IAPP:
- module_str = "IAPP";
- break;
case HOSTAPD_MODULE_MLME:
module_str = "MLME";
break;
diff --git a/src/ap/Makefile b/src/ap/Makefile
index 48f8f23..54e48a0 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -15,11 +15,9 @@
CFLAGS += -DCONFIG_INTERWORKING
CFLAGS += -DCONFIG_IEEE80211R
CFLAGS += -DCONFIG_IEEE80211R_AP
-CFLAGS += -DCONFIG_IEEE80211W
CFLAGS += -DCONFIG_WPS
CFLAGS += -DCONFIG_PROXYARP
CFLAGS += -DCONFIG_IPV6
-CFLAGS += -DCONFIG_IAPP
CFLAGS += -DCONFIG_AIRTIME_POLICY
LIB_OBJS= \
@@ -42,7 +40,6 @@
hostapd.o \
hs20.o \
hw_features.o \
- iapp.o \
ieee802_11_auth.o \
ieee802_11.o \
ieee802_11_ht.o \
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 0aacc3c..9fc1886 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -97,6 +97,9 @@
msg) < 0)
goto fail;
+ if (sta && add_sqlite_radius_attr(hapd, sta, msg, 1) < 0)
+ goto fail;
+
if (sta) {
for (i = 0; ; i++) {
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index a061bd8..58fc3e9 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -16,6 +16,7 @@
#include "common/ieee802_1x_defs.h"
#include "common/eapol_common.h"
#include "common/dhcp.h"
+#include "common/sae.h"
#include "eap_common/eap_wsc_common.h"
#include "eap_server/eap.h"
#include "wpa_auth.h"
@@ -78,6 +79,7 @@
bss->radius_server_auth_port = 1812;
bss->eap_sim_db_timeout = 1;
+ bss->eap_sim_id = 3;
bss->ap_max_inactivity = AP_MAX_INACTIVITY;
bss->eapol_version = EAPOL_VERSION;
@@ -85,11 +87,9 @@
bss->pwd_group = 19; /* ECC: GF(p=256) */
-#ifdef CONFIG_IEEE80211W
bss->assoc_sa_query_max_timeout = 1000;
bss->assoc_sa_query_retry_timeout = 201;
bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
-#endif /* CONFIG_IEEE80211W */
#ifdef EAP_SERVER_FAST
/* both anonymous and authenticated provisioning */
bss->eap_fast_prov = 3;
@@ -134,6 +134,9 @@
* completed and tested with other implementations. */
bss->tls_flags = TLS_CONN_DISABLE_TLSv1_3;
+ bss->max_auth_rounds = 100;
+ bss->max_auth_rounds_short = 50;
+
bss->send_probe_response = 1;
#ifdef CONFIG_HS20
@@ -432,10 +435,50 @@
}
+int hostapd_setup_sae_pt(struct hostapd_bss_config *conf)
+{
+#ifdef CONFIG_SAE
+ struct hostapd_ssid *ssid = &conf->ssid;
+ struct sae_password_entry *pw;
+
+ if (conf->sae_pwe == 0)
+ return 0; /* PT not needed */
+
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ if (ssid->wpa_passphrase) {
+ ssid->pt = sae_derive_pt(conf->sae_groups, ssid->ssid,
+ ssid->ssid_len,
+ (const u8 *) ssid->wpa_passphrase,
+ os_strlen(ssid->wpa_passphrase),
+ NULL);
+ if (!ssid->pt)
+ return -1;
+ }
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ sae_deinit_pt(pw->pt);
+ pw->pt = sae_derive_pt(conf->sae_groups, ssid->ssid,
+ ssid->ssid_len,
+ (const u8 *) pw->password,
+ os_strlen(pw->password),
+ pw->identifier);
+ if (!pw->pt)
+ return -1;
+ }
+#endif /* CONFIG_SAE */
+
+ return 0;
+}
+
+
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
{
struct hostapd_ssid *ssid = &conf->ssid;
+ if (hostapd_setup_sae_pt(conf) < 0)
+ return -1;
+
if (ssid->wpa_passphrase != NULL) {
if (ssid->wpa_psk != NULL) {
wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK "
@@ -476,7 +519,76 @@
}
-static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
+struct hostapd_radius_attr * hostapd_parse_radius_attr(const char *value)
+{
+ const char *pos;
+ char syntax;
+ struct hostapd_radius_attr *attr;
+ size_t len;
+
+ attr = os_zalloc(sizeof(*attr));
+ if (!attr)
+ return NULL;
+
+ attr->type = atoi(value);
+
+ pos = os_strchr(value, ':');
+ if (!pos) {
+ attr->val = wpabuf_alloc(1);
+ if (!attr->val) {
+ os_free(attr);
+ return NULL;
+ }
+ wpabuf_put_u8(attr->val, 0);
+ return attr;
+ }
+
+ pos++;
+ if (pos[0] == '\0' || pos[1] != ':') {
+ os_free(attr);
+ return NULL;
+ }
+ syntax = *pos++;
+ pos++;
+
+ switch (syntax) {
+ case 's':
+ attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
+ break;
+ case 'x':
+ len = os_strlen(pos);
+ if (len & 1)
+ break;
+ len /= 2;
+ attr->val = wpabuf_alloc(len);
+ if (!attr->val)
+ break;
+ if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
+ wpabuf_free(attr->val);
+ os_free(attr);
+ return NULL;
+ }
+ break;
+ case 'd':
+ attr->val = wpabuf_alloc(4);
+ if (attr->val)
+ wpabuf_put_be32(attr->val, atoi(pos));
+ break;
+ default:
+ os_free(attr);
+ return NULL;
+ }
+
+ if (!attr->val) {
+ os_free(attr);
+ return NULL;
+ }
+
+ return attr;
+}
+
+
+void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
{
struct hostapd_radius_attr *prev;
@@ -572,6 +684,9 @@
pw = pw->next;
str_clear_free(tmp->password);
os_free(tmp->identifier);
+#ifdef CONFIG_SAE
+ sae_deinit_pt(tmp->pt);
+#endif /* CONFIG_SAE */
os_free(tmp);
}
}
@@ -608,6 +723,9 @@
#ifdef CONFIG_FULL_DYNAMIC_VLAN
os_free(conf->ssid.vlan_tagged_interface);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+#ifdef CONFIG_SAE
+ sae_deinit_pt(conf->ssid.pt);
+#endif /* CONFIG_SAE */
hostapd_config_free_eap_users(conf->eap_user);
os_free(conf->eap_user_sqlite);
@@ -625,6 +743,7 @@
}
hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
+ os_free(conf->radius_req_attr_sqlite);
os_free(conf->rsn_preauth_interfaces);
os_free(conf->ctrl_interface);
os_free(conf->ca_cert);
@@ -769,6 +888,8 @@
hostapd_config_free_fils_realms(conf);
#ifdef CONFIG_DPP
+ os_free(conf->dpp_name);
+ os_free(conf->dpp_mud_url);
os_free(conf->dpp_connector);
wpabuf_free(conf->dpp_netaccesskey);
wpabuf_free(conf->dpp_csign);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index eebf898..2a0c984 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -99,6 +99,7 @@
struct hostapd_wpa_psk *wpa_psk;
char *wpa_passphrase;
char *wpa_psk_file;
+ struct sae_pt *pt;
struct hostapd_wep_keys wep;
@@ -251,6 +252,7 @@
char *identifier;
u8 peer_addr[ETH_ALEN];
int vlan_id;
+ struct sae_pt *pt;
};
struct dpp_controller_conf {
@@ -301,6 +303,7 @@
int radius_request_cui;
struct hostapd_radius_attr *radius_auth_req_attr;
struct hostapd_radius_attr *radius_acct_req_attr;
+ char *radius_req_attr_sqlite;
int radius_das_port;
unsigned int radius_das_time_window;
int radius_das_require_event_timestamp;
@@ -324,10 +327,6 @@
int erp_send_reauth_start;
char *erp_domain;
- int ieee802_11f; /* use IEEE 802.11f (IAPP) */
- char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
- * frames */
-
enum macaddr_acl {
ACCEPT_UNLESS_DENIED = 0,
DENY_UNLESS_ACCEPTED = 1,
@@ -346,14 +345,12 @@
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
int wpa_key_mgmt;
-#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
int group_mgmt_cipher;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
unsigned int assoc_sa_query_max_timeout;
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
int assoc_sa_query_retry_timeout;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
int ocv; /* Operating Channel Validation */
#endif /* CONFIG_OCV */
@@ -414,6 +411,8 @@
unsigned int crl_reload_interval;
unsigned int tls_session_lifetime;
unsigned int tls_flags;
+ unsigned int max_auth_rounds;
+ unsigned int max_auth_rounds_short;
char *ocsp_stapling_response;
char *ocsp_stapling_response_multi;
char *dh_file;
@@ -428,7 +427,10 @@
int pac_key_refresh_time;
int eap_teap_auth;
int eap_teap_pac_no_inner;
+ int eap_teap_separate_result;
+ int eap_teap_id;
int eap_sim_aka_result_ind;
+ int eap_sim_id;
int tnc;
int fragment_size;
u16 pwd_group;
@@ -649,6 +651,8 @@
unsigned int sae_anti_clogging_threshold;
unsigned int sae_sync;
int sae_require_mfp;
+ int sae_confirm_immediate;
+ int sae_pwe;
int *sae_groups;
struct sae_password_entry *sae_passwords;
@@ -707,6 +711,8 @@
int broadcast_deauth;
#ifdef CONFIG_DPP
+ char *dpp_name;
+ char *dpp_mud_url;
char *dpp_connector;
struct wpabuf *dpp_netaccesskey;
unsigned int dpp_netaccesskey_expiry;
@@ -869,7 +875,10 @@
u16 beacon_int;
int rts_threshold;
int fragm_threshold;
+ u8 op_class;
u8 channel;
+ int enable_edmg;
+ u8 edmg_channel;
u8 acs;
struct wpa_freq_range_list acs_ch_list;
int acs_exclude_dfs;
@@ -1074,6 +1083,7 @@
int hostapd_mac_comp(const void *a, const void *b);
struct hostapd_config * hostapd_config_defaults(void);
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
+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);
@@ -1092,9 +1102,11 @@
int vlan_id);
struct hostapd_radius_attr *
hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
+struct hostapd_radius_attr * hostapd_parse_radius_attr(const char *value);
int hostapd_config_check(struct hostapd_config *conf, int full_config);
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config);
int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf);
+int hostapd_setup_sae_pt(struct hostapd_bss_config *conf);
#endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index c0ededa..204274f 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -107,6 +107,10 @@
goto fail;
#endif /* CONFIG_FILS */
+ pos = hostapd_eid_rsnxe(hapd, buf, sizeof(buf));
+ if (add_buf_data(&assocresp, buf, pos - buf) < 0)
+ goto fail;
+
if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 ||
add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0)
goto fail;
@@ -305,9 +309,7 @@
params.wpa_pairwise = hapd->conf->wpa_pairwise;
params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
params.rsn_preauth = hapd->conf->rsn_preauth;
-#ifdef CONFIG_IEEE80211W
params.ieee80211w = hapd->conf->ieee80211w;
-#endif /* CONFIG_IEEE80211W */
}
return hostapd_set_ieee8021x(hapd, ¶ms);
}
@@ -348,7 +350,7 @@
u16 auth_alg)
{
if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL)
- return 0;
+ return -EOPNOTSUPP;
return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
}
@@ -540,7 +542,8 @@
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled, int vht_enabled,
+ 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 center_segment0, int center_segment1)
@@ -548,7 +551,8 @@
struct hostapd_freq_params data;
struct hostapd_hw_modes *cmode = hapd->iface->current_mode;
- if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
+ if (hostapd_set_freq_params(&data, mode, freq, channel, edmg,
+ edmg_channel, ht_enabled,
vht_enabled, he_enabled, sec_channel_offset,
oper_chwidth,
center_segment0, center_segment1,
@@ -810,7 +814,8 @@
return -1;
}
- if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
+ if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0,
+ ht_enabled,
vht_enabled, he_enabled, sec_channel_offset,
oper_chwidth, center_segment0,
center_segment1,
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index ca7f7ab..79b1302 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -62,7 +62,8 @@
const u8 *addr, int idx, 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 ht_enabled, int vht_enabled,
+ 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 center_segment0, int center_segment1);
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index b3d9107..8e12daf 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -110,27 +110,10 @@
srv.auth_port = conf->radius_server_auth_port;
srv.acct_port = conf->radius_server_acct_port;
srv.conf_ctx = hapd;
- srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
- srv.ssl_ctx = hapd->ssl_ctx;
- srv.msg_ctx = hapd->msg_ctx;
- srv.pac_opaque_encr_key = conf->pac_opaque_encr_key;
- srv.eap_fast_a_id = conf->eap_fast_a_id;
- srv.eap_fast_a_id_len = conf->eap_fast_a_id_len;
- srv.eap_fast_a_id_info = conf->eap_fast_a_id_info;
- srv.eap_fast_prov = conf->eap_fast_prov;
- srv.pac_key_lifetime = conf->pac_key_lifetime;
- srv.pac_key_refresh_time = conf->pac_key_refresh_time;
- srv.eap_teap_auth = conf->eap_teap_auth;
- srv.eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner;
- srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
- srv.tnc = conf->tnc;
- srv.wps = hapd->wps;
srv.ipv6 = conf->radius_server_ipv6;
srv.get_eap_user = hostapd_radius_get_eap_user;
srv.eap_req_id_text = conf->eap_req_id_text;
srv.eap_req_id_text_len = conf->eap_req_id_text_len;
- srv.pwd_group = conf->pwd_group;
- srv.server_id = conf->server_id ? conf->server_id : "hostapd";
srv.sqlite_file = conf->eap_user_sqlite;
#ifdef CONFIG_RADIUS_TEST
srv.dump_msk_file = conf->dump_msk_file;
@@ -141,10 +124,8 @@
srv.hs20_sim_provisioning_url = conf->hs20_sim_provisioning_url;
srv.t_c_server_url = conf->t_c_server_url;
#endif /* CONFIG_HS20 */
- srv.erp = conf->eap_server_erp;
srv.erp_domain = conf->erp_domain;
- srv.tls_session_lifetime = conf->tls_session_lifetime;
- srv.tls_flags = conf->tls_flags;
+ srv.eap_cfg = hapd->eap_cfg;
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {
@@ -192,6 +173,60 @@
#endif /* EAP_TLS_FUNCS */
+static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd)
+{
+ struct eap_config *cfg;
+
+ cfg = os_zalloc(sizeof(*cfg));
+ if (!cfg)
+ return NULL;
+
+ cfg->eap_server = hapd->conf->eap_server;
+ cfg->ssl_ctx = hapd->ssl_ctx;
+ cfg->msg_ctx = hapd->msg_ctx;
+ cfg->eap_sim_db_priv = hapd->eap_sim_db_priv;
+ cfg->tls_session_lifetime = hapd->conf->tls_session_lifetime;
+ cfg->tls_flags = hapd->conf->tls_flags;
+ cfg->max_auth_rounds = hapd->conf->max_auth_rounds;
+ cfg->max_auth_rounds_short = hapd->conf->max_auth_rounds_short;
+ if (hapd->conf->pac_opaque_encr_key)
+ cfg->pac_opaque_encr_key =
+ os_memdup(hapd->conf->pac_opaque_encr_key, 16);
+ if (hapd->conf->eap_fast_a_id) {
+ cfg->eap_fast_a_id = os_memdup(hapd->conf->eap_fast_a_id,
+ hapd->conf->eap_fast_a_id_len);
+ cfg->eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
+ }
+ if (hapd->conf->eap_fast_a_id_info)
+ cfg->eap_fast_a_id_info =
+ os_strdup(hapd->conf->eap_fast_a_id_info);
+ cfg->eap_fast_prov = hapd->conf->eap_fast_prov;
+ cfg->pac_key_lifetime = hapd->conf->pac_key_lifetime;
+ cfg->pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
+ cfg->eap_teap_auth = hapd->conf->eap_teap_auth;
+ 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_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
+ cfg->eap_sim_id = hapd->conf->eap_sim_id;
+ cfg->tnc = hapd->conf->tnc;
+ cfg->wps = hapd->wps;
+ cfg->fragment_size = hapd->conf->fragment_size;
+ cfg->pwd_group = hapd->conf->pwd_group;
+ cfg->pbc_in_m1 = hapd->conf->pbc_in_m1;
+ if (hapd->conf->server_id) {
+ cfg->server_id = (u8 *) os_strdup(hapd->conf->server_id);
+ cfg->server_id_len = os_strlen(hapd->conf->server_id);
+ } else {
+ cfg->server_id = (u8 *) os_strdup("hostapd");
+ cfg->server_id_len = 7;
+ }
+ cfg->erp = hapd->conf->eap_server_erp;
+
+ return cfg;
+}
+
+
int authsrv_init(struct hostapd_data *hapd)
{
#ifdef EAP_TLS_FUNCS
@@ -272,6 +307,14 @@
}
#endif /* EAP_SIM_DB */
+ hapd->eap_cfg = authsrv_eap_config(hapd);
+ if (!hapd->eap_cfg) {
+ wpa_printf(MSG_ERROR,
+ "Failed to build EAP server configuration");
+ authsrv_deinit(hapd);
+ return -1;
+ }
+
#ifdef RADIUS_SERVER
if (hapd->conf->radius_server_clients &&
hostapd_setup_radius_srv(hapd))
@@ -302,4 +345,7 @@
hapd->eap_sim_db_priv = NULL;
}
#endif /* EAP_SIM_DB */
+
+ eap_server_config_free(hapd->eap_cfg);
+ hapd->eap_cfg = NULL;
}
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index a51b949..331c09b 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -456,7 +456,8 @@
pos = hostapd_eid_ext_supp_rates(hapd, pos);
/* RSN, MDIE */
- if (hapd->conf->wpa != WPA_PROTO_WPA)
+ if (!(hapd->conf->wpa == WPA_PROTO_WPA ||
+ (hapd->conf->osen && !hapd->conf->wpa)))
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
@@ -498,7 +499,8 @@
#endif /* CONFIG_FST */
#ifdef CONFIG_IEEE80211AC
- if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
+ !is_6ghz_op_class(hapd->iconf->op_class)) {
pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
pos = hostapd_eid_txpower_envelope(hapd, pos);
@@ -523,7 +525,8 @@
#endif /* CONFIG_IEEE80211AC */
/* WPA */
- if (hapd->conf->wpa == WPA_PROTO_WPA)
+ if (hapd->conf->wpa == WPA_PROTO_WPA ||
+ (hapd->conf->osen && !hapd->conf->wpa))
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
/* Wi-Fi Alliance WMM */
@@ -553,7 +556,6 @@
#ifdef CONFIG_HS20
pos = hostapd_eid_hs20_indication(hapd, pos);
- pos = hostapd_eid_osen(hapd, pos);
#endif /* CONFIG_HS20 */
pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
@@ -1164,7 +1166,8 @@
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
/* RSN, MDIE */
- if (hapd->conf->wpa != WPA_PROTO_WPA)
+ if (!(hapd->conf->wpa == WPA_PROTO_WPA ||
+ (hapd->conf->osen && !hapd->conf->wpa)))
tailpos = hostapd_eid_wpa(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE -
tailpos);
@@ -1240,7 +1243,8 @@
#endif /* CONFIG_IEEE80211AC */
/* WPA */
- if (hapd->conf->wpa == WPA_PROTO_WPA)
+ if (hapd->conf->wpa == WPA_PROTO_WPA ||
+ (hapd->conf->osen && !hapd->conf->wpa))
tailpos = hostapd_eid_wpa(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE -
tailpos);
@@ -1271,7 +1275,6 @@
#ifdef CONFIG_HS20
tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
- tailpos = hostapd_eid_osen(hapd, tailpos);
#endif /* CONFIG_HS20 */
tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
@@ -1421,11 +1424,19 @@
params.proberesp_ies = proberesp;
params.assocresp_ies = assocresp;
params.reenable = hapd->reenable_beacon;
+#ifdef CONFIG_IEEE80211AX
+ params.he_spr = !!hapd->iface->conf->spr.sr_control;
+ params.he_spr_srg_obss_pd_min_offset =
+ hapd->iface->conf->spr.srg_obss_pd_min_offset;
+ params.he_spr_srg_obss_pd_max_offset =
+ hapd->iface->conf->spr.srg_obss_pd_max_offset;
+#endif /* CONFIG_IEEE80211AX */
hapd->reenable_beacon = 0;
if (cmode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
- iconf->channel, iconf->ieee80211n,
+ iconf->channel, iconf->enable_edmg,
+ iconf->edmg_channel, iconf->ieee80211n,
iconf->ieee80211ac, iconf->ieee80211ax,
iconf->secondary_channel,
hostapd_get_oper_chwidth(iconf),
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 2c4953d..bde61ee 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -709,6 +709,8 @@
ret = os_snprintf(buf + len, buflen - len,
"channel=%u\n"
+ "edmg_enable=%d\n"
+ "edmg_channel=%d\n"
"secondary_channel=%d\n"
"ieee80211n=%d\n"
"ieee80211ac=%d\n"
@@ -716,6 +718,8 @@
"beacon_int=%u\n"
"dtim_period=%d\n",
iface->conf->channel,
+ iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
iface->conf->ieee80211n && !hapd->conf->disable_11n ?
iface->conf->secondary_channel : 0,
iface->conf->ieee80211n && !hapd->conf->disable_11n,
@@ -727,6 +731,22 @@
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
+
+#ifdef CONFIG_IEEE80211AX
+ if (iface->conf->ieee80211ax) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "he_oper_chwidth=%d\n"
+ "he_oper_centr_freq_seg0_idx=%d\n"
+ "he_oper_centr_freq_seg1_idx=%d\n",
+ iface->conf->he_oper_chwidth,
+ iface->conf->he_oper_centr_freq_seg0_idx,
+ iface->conf->he_oper_centr_freq_seg1_idx);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+#endif /* CONFIG_IEEE80211AX */
+
if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
ret = os_snprintf(buf + len, buflen - len,
"vht_oper_chwidth=%d\n"
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index ac23c2b..c4c00fc 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -960,6 +960,8 @@
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,
@@ -1093,11 +1095,18 @@
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);
+ /* 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",
- freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60);
+ freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
+ iface->dfs_cac_ms / 1000);
iface->cac_started = 1;
+ os_get_reltime(&iface->dfs_cac_start);
return 0;
}
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 697c3ba..085d423 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -607,47 +607,48 @@
static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_AKM "%s",
- dpp_akm_str(auth->akm));
- if (auth->ssid_len)
+ dpp_akm_str(conf->akm));
+ if (conf->ssid_len)
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
- wpa_ssid_txt(auth->ssid, auth->ssid_len));
- if (auth->connector) {
+ wpa_ssid_txt(conf->ssid, conf->ssid_len));
+ if (conf->connector) {
/* TODO: Save the Connector and consider using a command
* to fetch the value instead of sending an event with
* it. The Connector could end up being larger than what
* most clients are ready to receive as an event
* message. */
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
- auth->connector);
- } else if (auth->passphrase[0]) {
+ conf->connector);
+ } else if (conf->passphrase[0]) {
char hex[64 * 2 + 1];
wpa_snprintf_hex(hex, sizeof(hex),
- (const u8 *) auth->passphrase,
- os_strlen(auth->passphrase));
+ (const u8 *) conf->passphrase,
+ os_strlen(conf->passphrase));
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PASS "%s",
hex);
- } else if (auth->psk_set) {
+ } else if (conf->psk_set) {
char hex[PMK_LEN * 2 + 1];
- wpa_snprintf_hex(hex, sizeof(hex), auth->psk, PMK_LEN);
+ wpa_snprintf_hex(hex, sizeof(hex), conf->psk, PMK_LEN);
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s",
hex);
}
- if (auth->c_sign_key) {
+ if (conf->c_sign_key) {
char *hex;
size_t hexlen;
- hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
+ hexlen = 2 * wpabuf_len(conf->c_sign_key) + 1;
hex = os_malloc(hexlen);
if (hex) {
wpa_snprintf_hex(hex, hexlen,
- wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
+ wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
wpa_msg(hapd->msg_ctx, MSG_INFO,
DPP_EVENT_C_SIGN_KEY "%s", hex);
os_free(hex);
@@ -720,7 +721,7 @@
goto fail;
}
- hostapd_dpp_handle_config_obj(hapd, auth);
+ hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
status = DPP_STATUS_OK;
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_REJECT_CONFIG) {
@@ -765,18 +766,10 @@
{
struct dpp_authentication *auth = hapd->dpp_auth;
struct wpabuf *buf;
- char json[100];
int res;
- int netrole_ap = 1;
- os_snprintf(json, sizeof(json),
- "{\"name\":\"Test\","
- "\"wi-fi_tech\":\"infra\","
- "\"netRole\":\"%s\"}",
- netrole_ap ? "ap" : "sta");
- wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
-
- buf = dpp_build_conf_req(auth, json);
+ buf = dpp_build_conf_req_helper(auth, hapd->conf->dpp_name, 1,
+ hapd->conf->dpp_mud_url, NULL);
if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
@@ -922,6 +915,24 @@
}
+static void hostapd_dpp_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth || !auth->waiting_conf_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Connection Status Result");
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONN_STATUS_RESULT "timeout");
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+}
+
+
static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len)
{
@@ -945,6 +956,20 @@
status = dpp_conf_result_rx(auth, hdr, buf, len);
+ if (status == DPP_STATUS_OK && auth->send_conn_status) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
+ eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout,
+ hapd, NULL);
+ eloop_cancel_timeout(
+ hostapd_dpp_conn_status_result_wait_timeout,
+ hapd, NULL);
+ eloop_register_timeout(
+ 16, 0, hostapd_dpp_conn_status_result_wait_timeout,
+ hapd, NULL);
+ return;
+ }
hostapd_drv_send_action_cancel_wait(hapd);
hostapd_dpp_listen_stop(hapd);
if (status == DPP_STATUS_OK)
@@ -957,6 +982,41 @@
NULL);
}
+
+static void hostapd_dpp_rx_conn_status_result(struct hostapd_data *hapd,
+ const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ enum dpp_status_error status;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len = 0;
+ char *channel_list = NULL;
+
+ wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
+
+ if (!auth || !auth->waiting_conn_status_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for connection status result - drop");
+ return;
+ }
+
+ status = dpp_conn_status_result_rx(auth, hdr, buf, len,
+ ssid, &ssid_len, &channel_list);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT
+ "result=%d ssid=%s channel_list=%s",
+ status, wpa_ssid_txt(ssid, ssid_len),
+ channel_list ? channel_list : "N/A");
+ os_free(channel_list);
+ hostapd_drv_send_action_cancel_wait(hapd);
+ hostapd_dpp_listen_stop(hapd);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+ eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout,
+ hapd, NULL);
+}
+
+
#endif /* CONFIG_DPP2 */
@@ -1403,6 +1463,9 @@
case DPP_PA_CONFIGURATION_RESULT:
hostapd_dpp_rx_conf_result(hapd, src, hdr, buf, len);
break;
+ case DPP_PA_CONNECTION_STATUS_RESULT:
+ hostapd_dpp_rx_conn_status_result(hapd, src, hdr, buf, len);
+ break;
#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
@@ -1506,7 +1569,7 @@
if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
auth, cmd) == 0 &&
dpp_configurator_own_config(auth, curve, 1) == 0) {
- hostapd_dpp_handle_config_obj(hapd, auth);
+ hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
ret = 0;
}
@@ -1715,6 +1778,8 @@
#ifdef CONFIG_DPP2
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
NULL);
+ eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd,
+ NULL);
#endif /* CONFIG_DPP2 */
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 3158768..3198bd5 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -16,6 +16,7 @@
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "common/dpp.h"
+#include "common/sae.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
@@ -111,10 +112,8 @@
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
-#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
u8 *p = buf;
-#endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS || CONFIG_OWE */
u16 reason = WLAN_REASON_UNSPECIFIED;
u16 status = WLAN_STATUS_SUCCESS;
const u8 *p2p_dev_addr = NULL;
@@ -131,6 +130,19 @@
"hostapd_notif_assoc: Skip event with no address");
return -1;
}
+
+ if (is_multicast_ether_addr(addr) ||
+ is_zero_ether_addr(addr) ||
+ os_memcmp(addr, hapd->own_addr, ETH_ALEN) == 0) {
+ /* Do not process any frames with unexpected/invalid SA so that
+ * we do not add any state for unexpected STA addresses or end
+ * up sending out frames to unexpected destination. */
+ wpa_printf(MSG_DEBUG, "%s: Invalid SA=" MACSTR
+ " in received indication - ignore this indication silently",
+ __func__, MAC2STR(addr));
+ return 0;
+ }
+
random_add_randomness(addr, ETH_ALEN);
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
@@ -308,6 +320,8 @@
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
ie, ielen,
+ elems.rsnxe ? elems.rsnxe - 2 : NULL,
+ elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len,
elems.owe_dh, elems.owe_dh_len);
if (res != WPA_IE_OK) {
@@ -324,23 +338,19 @@
} else if (res == WPA_INVALID_AKMP) {
reason = WLAN_REASON_AKMP_NOT_VALID;
status = WLAN_STATUS_AKMP_NOT_VALID;
- }
-#ifdef CONFIG_IEEE80211W
- else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
+ } else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
reason = WLAN_REASON_INVALID_IE;
status = WLAN_STATUS_INVALID_IE;
} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
- }
-#endif /* CONFIG_IEEE80211W */
- else {
+ } else {
reason = WLAN_REASON_INVALID_IE;
status = WLAN_STATUS_INVALID_IE;
}
goto fail;
}
-#ifdef CONFIG_IEEE80211W
+
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
(WLAN_STA_ASSOC | WLAN_STA_MFP) &&
!sta->sa_query_timed_out &&
@@ -373,7 +383,6 @@
sta->flags |= WLAN_STA_MFP;
else
sta->flags &= ~WLAN_STA_MFP;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
@@ -390,6 +399,20 @@
}
}
#endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_SAE
+ if (hapd->conf->sae_pwe == 2 &&
+ sta->auth_alg == WLAN_AUTH_SAE &&
+ sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
+ elems.rsnxe && elems.rsnxe_len >= 1 &&
+ (elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
+ wpa_printf(MSG_INFO, "SAE: " MACSTR
+ " indicates support for SAE H2E, but did not use it",
+ MAC2STR(sta->addr));
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ reason = WLAN_REASON_UNSPECIFIED;
+ goto fail;
+ }
+#endif /* CONFIG_SAE */
} else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS
struct wpabuf *wps;
@@ -1164,12 +1187,10 @@
return;
}
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) {
ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len);
return;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM_AP
if (mgmt->u.action.category == WLAN_ACTION_WNM) {
ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index cc75a77..3686438 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -7,6 +7,9 @@
*/
#include "utils/includes.h"
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
#include "utils/common.h"
#include "utils/eloop.h"
@@ -25,7 +28,6 @@
#include "accounting.h"
#include "ap_list.h"
#include "beacon.h"
-#include "iapp.h"
#include "ieee802_1x.h"
#include "ieee802_11_auth.h"
#include "vlan_init.h"
@@ -296,7 +298,6 @@
ifname, i);
}
}
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w) {
for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
@@ -308,7 +309,6 @@
}
}
}
-#endif /* CONFIG_IEEE80211W */
}
@@ -360,8 +360,6 @@
hapd->beacon_set_done = 0;
wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
- iapp_deinit(hapd->iapp);
- hapd->iapp = NULL;
accounting_deinit(hapd);
hostapd_deinit_wpa(hapd);
vlan_deinit(hapd);
@@ -1025,6 +1023,43 @@
#define hostapd_das_coa NULL
#endif /* CONFIG_HS20 */
+
+#ifdef CONFIG_SQLITE
+
+static int db_table_exists(sqlite3 *db, const char *name)
+{
+ char cmd[128];
+
+ os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
+ return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
+}
+
+
+static int db_table_create_radius_attributes(sqlite3 *db)
+{
+ char *err = NULL;
+ const char *sql =
+ "CREATE TABLE radius_attributes("
+ " id INTEGER PRIMARY KEY,"
+ " sta TEXT,"
+ " reqtype TEXT,"
+ " attr TEXT"
+ ");"
+ "CREATE INDEX idx_sta_reqtype ON radius_attributes(sta,reqtype);";
+
+ wpa_printf(MSG_DEBUG,
+ "Adding database table for RADIUS attribute information");
+ if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+ wpa_printf(MSG_ERROR, "SQLite error: %s", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_SQLITE */
+
#endif /* CONFIG_NO_RADIUS */
@@ -1178,6 +1213,24 @@
if (wpa_debug_level <= MSG_MSGDUMP)
conf->radius->msg_dumps = 1;
#ifndef CONFIG_NO_RADIUS
+
+#ifdef CONFIG_SQLITE
+ if (conf->radius_req_attr_sqlite) {
+ if (sqlite3_open(conf->radius_req_attr_sqlite,
+ &hapd->rad_attr_db)) {
+ wpa_printf(MSG_ERROR, "Could not open SQLite file '%s'",
+ conf->radius_req_attr_sqlite);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "Opening RADIUS attribute database: %s",
+ conf->radius_req_attr_sqlite);
+ if (!db_table_exists(hapd->rad_attr_db, "radius_attributes") &&
+ db_table_create_radius_attributes(hapd->rad_attr_db) < 0)
+ return -1;
+ }
+#endif /* CONFIG_SQLITE */
+
hapd->radius = radius_client_init(hapd, conf->radius);
if (hapd->radius == NULL) {
wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
@@ -1240,13 +1293,6 @@
return -1;
}
- if (conf->ieee802_11f &&
- (hapd->iapp = iapp_init(hapd, conf->iapp_iface)) == NULL) {
- wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
- "failed.");
- return -1;
- }
-
#ifdef CONFIG_INTERWORKING
if (gas_serv_init(hapd)) {
wpa_printf(MSG_ERROR, "GAS server initialization failed");
@@ -1544,6 +1590,9 @@
wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)");
return 0;
}
+ ret = hostapd_check_edmg_capab(iface);
+ if (ret < 0)
+ goto fail;
ret = hostapd_check_ht_capab(iface);
if (ret < 0)
goto fail;
@@ -1868,6 +1917,8 @@
if (!delay_apply_cfg &&
hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
hapd->iconf->channel,
+ hapd->iconf->enable_edmg,
+ hapd->iconf->edmg_channel,
hapd->iconf->ieee80211n,
hapd->iconf->ieee80211ac,
hapd->iconf->ieee80211ax,
@@ -2194,6 +2245,12 @@
hapd->conf ? hapd->conf->iface : "N/A");
hostapd_bss_deinit_no_free(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
+#ifdef CONFIG_SQLITE
+ if (hapd->rad_attr_db) {
+ sqlite3_close(hapd->rad_attr_db);
+ hapd->rad_attr_db = NULL;
+ }
+#endif /* CONFIG_SQLITE */
hostapd_cleanup(hapd);
}
@@ -2994,10 +3051,6 @@
hostapd_prune_associations(hapd, sta->addr);
ap_sta_clear_disconnect_timeouts(hapd, sta);
- /* IEEE 802.11F (IAPP) */
- if (hapd->conf->ieee802_11f)
- iapp_new_station(hapd->iapp, sta);
-
#ifdef CONFIG_P2P
if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
sta->no_p2p_set = 1;
@@ -3234,7 +3287,8 @@
if (old_params &&
hostapd_set_freq_params(old_params, conf->hw_mode,
hostapd_hw_get_freq(hapd, conf->channel),
- conf->channel, conf->ieee80211n,
+ conf->channel, conf->enable_edmg,
+ conf->edmg_channel, conf->ieee80211n,
conf->ieee80211ac, conf->ieee80211ax,
conf->secondary_channel,
hostapd_get_oper_chwidth(conf),
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 44ef753..016fe3b 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -9,6 +9,10 @@
#ifndef HOSTAPD_H
#define HOSTAPD_H
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
+
#include "common/defs.h"
#include "utils/list.h"
#include "ap_config.h"
@@ -175,13 +179,12 @@
u64 acct_session_id;
struct radius_das_data *radius_das;
- struct iapp_data *iapp;
-
struct hostapd_cached_radius_acl *acl_cache;
struct hostapd_acl_query_data *acl_queries;
struct wpa_authenticator *wpa_auth;
struct eapol_authenticator *eapol_auth;
+ struct eap_config *eap_cfg;
struct rsn_preauth_interface *preauth_iface;
struct os_reltime michael_mic_failure;
@@ -333,12 +336,10 @@
u8 last_gtk[WPA_GTK_MAX_LEN];
size_t last_gtk_len;
-#ifdef CONFIG_IEEE80211W
enum wpa_alg last_igtk_alg;
int last_igtk_key_idx;
u8 last_igtk[WPA_IGTK_MAX_LEN];
size_t last_igtk_len;
-#endif /* CONFIG_IEEE80211W */
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_MBO
@@ -390,6 +391,10 @@
#endif /* CONFIG_AIRTIME_POLICY */
u8 last_1x_eapol_key_replay_counter[8];
+
+#ifdef CONFIG_SQLITE
+ sqlite3 *rad_attr_db;
+#endif /* CONFIG_SQLITE */
};
diff --git a/src/ap/hs20.c b/src/ap/hs20.c
index 532580e..543fa33 100644
--- a/src/ap/hs20.c
+++ b/src/ap/hs20.c
@@ -80,13 +80,11 @@
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
if (hapd->conf->ocv)
capab |= WPA_CAPABILITY_OCVC;
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index c1f19e2..2fefaf8 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -704,6 +704,32 @@
}
+int hostapd_check_edmg_capab(struct hostapd_iface *iface)
+{
+ struct hostapd_hw_modes *mode = iface->hw_features;
+ struct ieee80211_edmg_config edmg;
+
+ if (!iface->conf->enable_edmg)
+ return 0;
+
+ hostapd_encode_edmg_chan(iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
+ iface->conf->channel,
+ &edmg);
+
+ if (mode->edmg.channels && ieee802_edmg_is_allowed(mode->edmg, edmg))
+ return 0;
+
+ wpa_printf(MSG_WARNING, "Requested EDMG configuration is not valid");
+ wpa_printf(MSG_INFO, "EDMG capab: channels 0x%x, bw_config %d",
+ mode->edmg.channels, mode->edmg.bw_config);
+ wpa_printf(MSG_INFO,
+ "Requested EDMG configuration: channels 0x%x, bw_config %d",
+ edmg.channels, edmg.bw_config);
+ return -1;
+}
+
+
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
int channel, int primary)
{
@@ -730,6 +756,67 @@
}
+static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
+{
+ int i, contiguous = 0;
+ int num_of_enabled = 0;
+ int max_contiguous = 0;
+ struct ieee80211_edmg_config edmg;
+
+ if (!iface->conf->enable_edmg)
+ return 1;
+
+ hostapd_encode_edmg_chan(iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
+ iface->conf->channel,
+ &edmg);
+ if (!(edmg.channels & BIT(iface->conf->channel - 1)))
+ return 0;
+
+ /* 60 GHz channels 1..6 */
+ for (i = 0; i < 6; i++) {
+ if (edmg.channels & BIT(i)) {
+ contiguous++;
+ num_of_enabled++;
+ } else {
+ contiguous = 0;
+ continue;
+ }
+
+ /* P802.11ay defines that the total number of subfields
+ * set to one does not exceed 4.
+ */
+ if (num_of_enabled > 4)
+ return 0;
+
+ if (!hostapd_is_usable_chan(iface, i + 1, 1))
+ return 0;
+
+ if (contiguous > max_contiguous)
+ max_contiguous = contiguous;
+ }
+
+ /* Check if the EDMG configuration is valid under the limitations
+ * of P802.11ay.
+ */
+ /* check bw_config against contiguous EDMG channels */
+ switch (edmg.bw_config) {
+ case EDMG_BW_CONFIG_4:
+ if (!max_contiguous)
+ return 0;
+ break;
+ case EDMG_BW_CONFIG_5:
+ if (max_contiguous < 2)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
{
int secondary_chan;
@@ -743,6 +830,9 @@
if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
return 0;
+ if (!hostapd_is_usable_edmg(iface))
+ return 0;
+
if (!iface->conf->secondary_channel)
return 1;
@@ -871,6 +961,7 @@
int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
int i;
+ int freq = -1;
if (iface->num_hw_features < 1)
return -1;
@@ -887,9 +978,14 @@
}
iface->current_mode = NULL;
+ if (iface->conf->channel && iface->conf->op_class)
+ freq = ieee80211_chan_to_freq(NULL, iface->conf->op_class,
+ iface->conf->channel);
for (i = 0; i < iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode = &iface->hw_features[i];
if (mode->mode == iface->conf->hw_mode) {
+ if (freq > 0 && !hw_get_chan(mode, freq))
+ continue;
iface->current_mode = mode;
break;
}
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index ca7f22b..902a19f 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -21,6 +21,7 @@
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
+int hostapd_check_edmg_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
void hostapd_stop_setup_timers(struct hostapd_iface *iface);
@@ -61,6 +62,11 @@
return 0;
}
+static inline int hostapd_check_edmg_capab(struct hostapd_iface *iface)
+{
+ return 0;
+}
+
static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode)
{
diff --git a/src/ap/iapp.c b/src/ap/iapp.c
deleted file mode 100644
index 2556da3..0000000
--- a/src/ap/iapp.c
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- *
- * Note: IEEE 802.11F-2003 was a experimental use specification. It has expired
- * and IEEE has withdrawn it. In other words, it is likely better to look at
- * using some other mechanism for AP-to-AP communication than extending the
- * implementation here.
- */
-
-/* TODO:
- * Level 1: no administrative or security support
- * (e.g., static BSSID to IP address mapping in each AP)
- * Level 2: support for dynamic mapping of BSSID to IP address
- * Level 3: support for encryption and authentication of IAPP messages
- * - add support for MOVE-notify and MOVE-response (this requires support for
- * finding out IP address for previous AP using RADIUS)
- * - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during
- * reassociation to another AP
- * - implement counters etc. for IAPP MIB
- * - verify endianness of fields in IAPP messages; are they big-endian as
- * used here?
- * - RADIUS connection for AP registration and BSSID to IP address mapping
- * - TCP connection for IAPP MOVE, CACHE
- * - broadcast ESP for IAPP ADD-notify
- * - ESP for IAPP MOVE messages
- * - security block sending/processing
- * - IEEE 802.11 context transfer
- */
-
-#include "utils/includes.h"
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <netpacket/packet.h>
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "hostapd.h"
-#include "ap_config.h"
-#include "ieee802_11.h"
-#include "sta_info.h"
-#include "iapp.h"
-
-
-#define IAPP_MULTICAST "224.0.1.178"
-#define IAPP_UDP_PORT 3517
-#define IAPP_TCP_PORT 3517
-
-struct iapp_hdr {
- u8 version;
- u8 command;
- be16 identifier;
- be16 length;
- /* followed by length-6 octets of data */
-} __attribute__ ((packed));
-
-#define IAPP_VERSION 0
-
-enum IAPP_COMMAND {
- IAPP_CMD_ADD_notify = 0,
- IAPP_CMD_MOVE_notify = 1,
- IAPP_CMD_MOVE_response = 2,
- IAPP_CMD_Send_Security_Block = 3,
- IAPP_CMD_ACK_Security_Block = 4,
- IAPP_CMD_CACHE_notify = 5,
- IAPP_CMD_CACHE_response = 6,
-};
-
-
-/* ADD-notify - multicast UDP on the local LAN */
-struct iapp_add_notify {
- u8 addr_len; /* ETH_ALEN */
- u8 reserved;
- u8 mac_addr[ETH_ALEN];
- be16 seq_num;
-} __attribute__ ((packed));
-
-
-/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
-struct iapp_layer2_update {
- u8 da[ETH_ALEN]; /* broadcast */
- u8 sa[ETH_ALEN]; /* STA addr */
- be16 len; /* 6 */
- u8 dsap; /* null DSAP address */
- u8 ssap; /* null SSAP address, CR=Response */
- u8 control;
- u8 xid_info[3];
-} __attribute__ ((packed));
-
-
-/* MOVE-notify - unicast TCP */
-struct iapp_move_notify {
- u8 addr_len; /* ETH_ALEN */
- u8 reserved;
- u8 mac_addr[ETH_ALEN];
- u16 seq_num;
- u16 ctx_block_len;
- /* followed by ctx_block_len bytes */
-} __attribute__ ((packed));
-
-
-/* MOVE-response - unicast TCP */
-struct iapp_move_response {
- u8 addr_len; /* ETH_ALEN */
- u8 status;
- u8 mac_addr[ETH_ALEN];
- u16 seq_num;
- u16 ctx_block_len;
- /* followed by ctx_block_len bytes */
-} __attribute__ ((packed));
-
-enum {
- IAPP_MOVE_SUCCESSFUL = 0,
- IAPP_MOVE_DENIED = 1,
- IAPP_MOVE_STALE_MOVE = 2,
-};
-
-
-/* CACHE-notify */
-struct iapp_cache_notify {
- u8 addr_len; /* ETH_ALEN */
- u8 reserved;
- u8 mac_addr[ETH_ALEN];
- u16 seq_num;
- u8 current_ap[ETH_ALEN];
- u16 ctx_block_len;
- /* ctx_block_len bytes of context block followed by 16-bit context
- * timeout */
-} __attribute__ ((packed));
-
-
-/* CACHE-response - unicast TCP */
-struct iapp_cache_response {
- u8 addr_len; /* ETH_ALEN */
- u8 status;
- u8 mac_addr[ETH_ALEN];
- u16 seq_num;
-} __attribute__ ((packed));
-
-enum {
- IAPP_CACHE_SUCCESSFUL = 0,
- IAPP_CACHE_STALE_CACHE = 1,
-};
-
-
-/* Send-Security-Block - unicast TCP */
-struct iapp_send_security_block {
- u8 iv[8];
- u16 sec_block_len;
- /* followed by sec_block_len bytes of security block */
-} __attribute__ ((packed));
-
-
-/* ACK-Security-Block - unicast TCP */
-struct iapp_ack_security_block {
- u8 iv[8];
- u8 new_ap_ack_authenticator[48];
-} __attribute__ ((packed));
-
-
-struct iapp_data {
- struct hostapd_data *hapd;
- u16 identifier; /* next IAPP identifier */
- struct in_addr own, multicast;
- int udp_sock;
- int packet_sock;
-};
-
-
-static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
-{
- char buf[128];
- struct iapp_hdr *hdr;
- struct iapp_add_notify *add;
- struct sockaddr_in addr;
-
- /* Send IAPP ADD-notify to remove possible association from other APs
- */
-
- hdr = (struct iapp_hdr *) buf;
- hdr->version = IAPP_VERSION;
- hdr->command = IAPP_CMD_ADD_notify;
- hdr->identifier = host_to_be16(iapp->identifier++);
- hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
-
- add = (struct iapp_add_notify *) (hdr + 1);
- add->addr_len = ETH_ALEN;
- add->reserved = 0;
- os_memcpy(add->mac_addr, mac_addr, ETH_ALEN);
-
- add->seq_num = host_to_be16(seq_num);
-
- os_memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = iapp->multicast.s_addr;
- addr.sin_port = htons(IAPP_UDP_PORT);
- if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
- (struct sockaddr *) &addr, sizeof(addr)) < 0)
- wpa_printf(MSG_INFO, "sendto[IAPP-ADD]: %s", strerror(errno));
-}
-
-
-static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
-{
- struct iapp_layer2_update msg;
-
- /* Send Level 2 Update Frame to update forwarding tables in layer 2
- * bridge devices */
-
- /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
- * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
-
- os_memset(msg.da, 0xff, ETH_ALEN);
- os_memcpy(msg.sa, addr, ETH_ALEN);
- msg.len = host_to_be16(6);
- msg.dsap = 0; /* NULL DSAP address */
- msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */
- msg.control = 0xaf; /* XID response lsb.1111F101.
- * F=0 (no poll command; unsolicited frame) */
- msg.xid_info[0] = 0x81; /* XID format identifier */
- msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
- msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW)
- * FIX: what is correct RW with 802.11? */
-
- if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
- wpa_printf(MSG_INFO, "send[L2 Update]: %s", strerror(errno));
-}
-
-
-/**
- * iapp_new_station - IAPP processing for a new STA
- * @iapp: IAPP data
- * @sta: The associated station
- */
-void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
-{
- u16 seq = 0; /* TODO */
-
- if (iapp == NULL)
- return;
-
- /* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
- hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
- iapp_send_layer2_update(iapp, sta->addr);
- iapp_send_add(iapp, sta->addr, seq);
-
- /* TODO: If this was reassociation:
- * IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
- * Context Block, Timeout)
- * TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
- * IP address */
-}
-
-
-static void iapp_process_add_notify(struct iapp_data *iapp,
- struct sockaddr_in *from,
- struct iapp_hdr *hdr, int len)
-{
- struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
- struct sta_info *sta;
-
- if (len != sizeof(*add)) {
- wpa_printf(MSG_INFO, "Invalid IAPP-ADD packet length %d (expected %lu)",
- len, (unsigned long) sizeof(*add));
- return;
- }
-
- sta = ap_get_sta(iapp->hapd, add->mac_addr);
-
- /* IAPP-ADD.indication(MAC Address, Sequence Number) */
- hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_INFO,
- "Received IAPP ADD-notify (seq# %d) from %s:%d%s",
- be_to_host16(add->seq_num),
- inet_ntoa(from->sin_addr), ntohs(from->sin_port),
- sta ? "" : " (STA not found)");
-
- if (!sta)
- return;
-
- /* TODO: could use seq_num to try to determine whether last association
- * to this AP is newer than the one advertised in IAPP-ADD. Although,
- * this is not really a reliable verification. */
-
- hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_DEBUG,
- "Removing STA due to IAPP ADD-notify");
- ap_sta_disconnect(iapp->hapd, sta, NULL, 0);
-}
-
-
-/**
- * iapp_receive_udp - Process IAPP UDP frames
- * @sock: File descriptor for the socket
- * @eloop_ctx: IAPP data (struct iapp_data *)
- * @sock_ctx: Not used
- */
-static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
-{
- struct iapp_data *iapp = eloop_ctx;
- int len, hlen;
- unsigned char buf[128];
- struct sockaddr_in from;
- socklen_t fromlen;
- struct iapp_hdr *hdr;
-
- /* Handle incoming IAPP frames (over UDP/IP) */
-
- fromlen = sizeof(from);
- len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
- (struct sockaddr *) &from, &fromlen);
- if (len < 0) {
- wpa_printf(MSG_INFO, "iapp_receive_udp - recvfrom: %s",
- strerror(errno));
- return;
- }
-
- if (from.sin_addr.s_addr == iapp->own.s_addr)
- return; /* ignore own IAPP messages */
-
- hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_DEBUG,
- "Received %d byte IAPP frame from %s%s\n",
- len, inet_ntoa(from.sin_addr),
- len < (int) sizeof(*hdr) ? " (too short)" : "");
-
- if (len < (int) sizeof(*hdr))
- return;
-
- hdr = (struct iapp_hdr *) buf;
- hlen = be_to_host16(hdr->length);
- hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_DEBUG,
- "RX: version=%d command=%d id=%d len=%d\n",
- hdr->version, hdr->command,
- be_to_host16(hdr->identifier), hlen);
- if (hdr->version != IAPP_VERSION) {
- wpa_printf(MSG_INFO, "Dropping IAPP frame with unknown version %d",
- hdr->version);
- return;
- }
- if (hlen > len) {
- wpa_printf(MSG_INFO, "Underflow IAPP frame (hlen=%d len=%d)",
- hlen, len);
- return;
- }
- if (hlen < len) {
- wpa_printf(MSG_INFO, "Ignoring %d extra bytes from IAPP frame",
- len - hlen);
- len = hlen;
- }
-
- switch (hdr->command) {
- case IAPP_CMD_ADD_notify:
- iapp_process_add_notify(iapp, &from, hdr, len - sizeof(*hdr));
- break;
- case IAPP_CMD_MOVE_notify:
- /* TODO: MOVE is using TCP; so move this to TCP handler once it
- * is implemented.. */
- /* IAPP-MOVE.indication(MAC Address, New BSSID,
- * Sequence Number, AP Address, Context Block) */
- /* TODO: process */
- break;
- default:
- wpa_printf(MSG_INFO, "Unknown IAPP command %d", hdr->command);
- break;
- }
-}
-
-
-struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
-{
- struct ifreq ifr;
- struct sockaddr_ll addr;
- int ifindex;
- struct sockaddr_in *paddr, uaddr;
- struct iapp_data *iapp;
- struct ip_mreqn mreq;
- int reuseaddr = 1;
-
- iapp = os_zalloc(sizeof(*iapp));
- if (iapp == NULL)
- return NULL;
- iapp->hapd = hapd;
- iapp->udp_sock = iapp->packet_sock = -1;
-
- /* TODO:
- * open socket for sending and receiving IAPP frames over TCP
- */
-
- iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
- if (iapp->udp_sock < 0) {
- wpa_printf(MSG_INFO, "iapp_init - socket[PF_INET,SOCK_DGRAM]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
- if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
- wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFINDEX): %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
- ifindex = ifr.ifr_ifindex;
-
- if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
- wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFADDR): %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
- paddr = (struct sockaddr_in *) &ifr.ifr_addr;
- if (paddr->sin_family != AF_INET) {
- wpa_printf(MSG_INFO, "IAPP: Invalid address family %i (SIOCGIFADDR)",
- paddr->sin_family);
- iapp_deinit(iapp);
- return NULL;
- }
- iapp->own.s_addr = paddr->sin_addr.s_addr;
-
- if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
- wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFBRDADDR): %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
- paddr = (struct sockaddr_in *) &ifr.ifr_addr;
- if (paddr->sin_family != AF_INET) {
- wpa_printf(MSG_INFO, "Invalid address family %i (SIOCGIFBRDADDR)",
- paddr->sin_family);
- iapp_deinit(iapp);
- return NULL;
- }
- inet_aton(IAPP_MULTICAST, &iapp->multicast);
-
- os_memset(&uaddr, 0, sizeof(uaddr));
- uaddr.sin_family = AF_INET;
- uaddr.sin_port = htons(IAPP_UDP_PORT);
-
- if (setsockopt(iapp->udp_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
- sizeof(reuseaddr)) < 0) {
- wpa_printf(MSG_INFO,
- "iapp_init - setsockopt[UDP,SO_REUSEADDR]: %s",
- strerror(errno));
- /*
- * Ignore this and try to continue. This is fine for single
- * BSS cases, but may fail if multiple BSSes enable IAPP.
- */
- }
-
- if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
- sizeof(uaddr)) < 0) {
- wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- os_memset(&mreq, 0, sizeof(mreq));
- mreq.imr_multiaddr = iapp->multicast;
- mreq.imr_address.s_addr = INADDR_ANY;
- mreq.imr_ifindex = 0;
- if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
- sizeof(mreq)) < 0) {
- wpa_printf(MSG_INFO, "iapp_init - setsockopt[UDP,IP_ADD_MEMBERSHIP]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
- if (iapp->packet_sock < 0) {
- wpa_printf(MSG_INFO, "iapp_init - socket[PF_PACKET,SOCK_RAW]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- os_memset(&addr, 0, sizeof(addr));
- addr.sll_family = AF_PACKET;
- addr.sll_ifindex = ifindex;
- if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
- sizeof(addr)) < 0) {
- wpa_printf(MSG_INFO, "iapp_init - bind[PACKET]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
- iapp, NULL)) {
- wpa_printf(MSG_INFO, "Could not register read socket for IAPP");
- iapp_deinit(iapp);
- return NULL;
- }
-
- wpa_printf(MSG_INFO, "IEEE 802.11F (IAPP) using interface %s", iface);
-
- /* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
- * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
- * be openned only after receiving Initiate-Accept. If Initiate-Reject
- * is received, IAPP is not started. */
-
- return iapp;
-}
-
-
-void iapp_deinit(struct iapp_data *iapp)
-{
- struct ip_mreqn mreq;
-
- if (iapp == NULL)
- return;
-
- if (iapp->udp_sock >= 0) {
- os_memset(&mreq, 0, sizeof(mreq));
- mreq.imr_multiaddr = iapp->multicast;
- mreq.imr_address.s_addr = INADDR_ANY;
- mreq.imr_ifindex = 0;
- if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
- &mreq, sizeof(mreq)) < 0) {
- wpa_printf(MSG_INFO, "iapp_deinit - setsockopt[UDP,IP_DEL_MEMBERSHIP]: %s",
- strerror(errno));
- }
-
- eloop_unregister_read_sock(iapp->udp_sock);
- close(iapp->udp_sock);
- }
- if (iapp->packet_sock >= 0) {
- eloop_unregister_read_sock(iapp->packet_sock);
- close(iapp->packet_sock);
- }
- os_free(iapp);
-}
diff --git a/src/ap/iapp.h b/src/ap/iapp.h
deleted file mode 100644
index c221183..0000000
--- a/src/ap/iapp.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
- * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef IAPP_H
-#define IAPP_H
-
-struct iapp_data;
-
-#ifdef CONFIG_IAPP
-
-void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta);
-struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface);
-void iapp_deinit(struct iapp_data *iapp);
-
-#else /* CONFIG_IAPP */
-
-static inline void iapp_new_station(struct iapp_data *iapp,
- struct sta_info *sta)
-{
-}
-
-static inline struct iapp_data * iapp_init(struct hostapd_data *hapd,
- const char *iface)
-{
- return NULL;
-}
-
-static inline void iapp_deinit(struct iapp_data *iapp)
-{
-}
-
-#endif /* CONFIG_IAPP */
-
-#endif /* IAPP_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index fff35b7..4d30bae 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -98,6 +98,8 @@
num++;
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
num++;
+ if (hapd->conf->sae_pwe == 1)
+ num++;
if (num > 8) {
/* rest of the rates are encoded in Extended supported
* rates element */
@@ -124,6 +126,11 @@
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
}
+ if (hapd->conf->sae_pwe == 1 && count < 8) {
+ count++;
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
+ }
+
return pos;
}
@@ -141,6 +148,8 @@
num++;
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
num++;
+ if (hapd->conf->sae_pwe == 1)
+ num++;
if (num <= 8)
return eid;
num -= 8;
@@ -170,6 +179,12 @@
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
}
+ if (hapd->conf->sae_pwe == 1) {
+ count++;
+ if (count > 8)
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
+ }
+
return pos;
}
@@ -388,15 +403,25 @@
static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
- struct sta_info *sta, int update)
+ struct sta_info *sta, int update,
+ int status_code)
{
struct wpabuf *buf;
const char *password = NULL;
struct sae_password_entry *pw;
const char *rx_id = NULL;
+ int use_pt = 0;
+ struct sae_pt *pt = NULL;
- if (sta->sae->tmp)
+ if (sta->sae->tmp) {
rx_id = sta->sae->tmp->pw_id;
+ use_pt = sta->sae->tmp->h2e;
+ }
+
+ if (status_code == WLAN_STATUS_SUCCESS)
+ use_pt = 0;
+ else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+ use_pt = 1;
for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
if (!is_broadcast_ether_addr(pw->peer_addr) &&
@@ -408,16 +433,24 @@
os_strcmp(rx_id, pw->identifier) != 0)
continue;
password = pw->password;
+ pt = pw->pt;
break;
}
- if (!password)
- password = hapd->conf->ssid.wpa_passphrase;
if (!password) {
+ password = hapd->conf->ssid.wpa_passphrase;
+ pt = hapd->conf->ssid.pt;
+ }
+ if (!password || (use_pt && !pt)) {
wpa_printf(MSG_DEBUG, "SAE: No password available");
return NULL;
}
- if (update &&
+ if (update && use_pt &&
+ sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
+ NULL) < 0)
+ return NULL;
+
+ if (update && !use_pt &&
sae_prepare_commit(hapd->own_addr, sta->addr,
(u8 *) password, os_strlen(password), rx_id,
sta->sae) < 0) {
@@ -462,19 +495,22 @@
static int auth_sae_send_commit(struct hostapd_data *hapd,
struct sta_info *sta,
- const u8 *bssid, int update)
+ const u8 *bssid, int update, int status_code)
{
struct wpabuf *data;
int reply_res;
+ u16 status;
- data = auth_build_sae_commit(hapd, sta, update);
+ data = auth_build_sae_commit(hapd, sta, update, status_code);
if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ status = (sta->sae->tmp && sta->sae->tmp->h2e) ?
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS;
reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
- WLAN_STATUS_SUCCESS, wpabuf_head(data),
+ status, wpabuf_head(data),
wpabuf_len(data), "sae-send-commit");
wpabuf_free(data);
@@ -663,7 +699,7 @@
switch (sta->sae->state) {
case SAE_COMMITTED:
- ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
eloop_register_timeout(0,
hapd->dot11RSNASAERetransPeriod * 1000,
auth_sae_retransmit_timer, hapd, sta);
@@ -761,8 +797,8 @@
static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *bssid, u8 auth_transaction, int allow_reuse,
- int *sta_removed)
+ const u8 *bssid, u16 auth_transaction, u16 status_code,
+ int allow_reuse, int *sta_removed)
{
int ret;
@@ -777,8 +813,11 @@
switch (sta->sae->state) {
case SAE_NOTHING:
if (auth_transaction == 1) {
+ if (sta->sae->tmp)
+ sta->sae->tmp->h2e = status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT;
ret = auth_sae_send_commit(hapd, sta, bssid,
- !allow_reuse);
+ !allow_reuse, status_code);
if (ret)
return ret;
sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -787,14 +826,17 @@
return WLAN_STATUS_UNSPECIFIED_FAILURE;
/*
- * In mesh case, both Commit and Confirm can be sent
- * immediately. In infrastructure BSS, only a single
- * Authentication frame (Commit) is expected from the AP
- * here and the second one (Confirm) will be sent once
- * the STA has sent its second Authentication frame
- * (Confirm).
+ * In mesh case, both Commit and Confirm are sent
+ * immediately. In infrastructure BSS, by default, only
+ * a single Authentication frame (Commit) is expected
+ * from the AP here and the second one (Confirm) will
+ * be sent once the STA has sent its second
+ * Authentication frame (Confirm). This behavior can be
+ * overridden with explicit configuration so that the
+ * infrastructure BSS case sends both frames together.
*/
- if (hapd->conf->mesh & MESH_ENABLED) {
+ if ((hapd->conf->mesh & MESH_ENABLED) ||
+ hapd->conf->sae_confirm_immediate) {
/*
* Send both Commit and Confirm immediately
* based on SAE finite state machine
@@ -845,7 +887,8 @@
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
- ret = auth_sae_send_commit(hapd, sta, bssid, 0);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 0,
+ status_code);
if (ret)
return ret;
@@ -868,7 +911,7 @@
* additional events.
*/
return sae_sm_step(hapd, sta, bssid, auth_transaction,
- 0, sta_removed);
+ WLAN_STATUS_SUCCESS, 0, sta_removed);
}
break;
case SAE_CONFIRMED:
@@ -878,7 +921,8 @@
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
- ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1,
+ status_code);
if (ret)
return ret;
@@ -906,7 +950,8 @@
*sta_removed = 1;
} else if (auth_transaction == 1) {
wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
- ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1,
+ status_code);
if (ret)
return ret;
sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -976,6 +1021,64 @@
}
+static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
+{
+ return (hapd->conf->sae_pwe == 0 &&
+ status_code == WLAN_STATUS_SUCCESS) ||
+ (hapd->conf->sae_pwe == 1 &&
+ status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) ||
+ (hapd->conf->sae_pwe == 2 &&
+ (status_code == WLAN_STATUS_SUCCESS ||
+ status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT));
+}
+
+
+static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
+{
+ int *groups = hapd->conf->sae_groups;
+ int default_groups[] = { 19, 0 };
+ int i;
+
+ if (!groups)
+ groups = default_groups;
+
+ for (i = 0; groups[i] > 0; i++) {
+ if (groups[i] == group)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int check_sae_rejected_groups(struct hostapd_data *hapd,
+ const struct wpabuf *groups)
+{
+ size_t i, count;
+ const u8 *pos;
+
+ if (!groups)
+ return 0;
+
+ pos = wpabuf_head(groups);
+ count = wpabuf_len(groups) / 2;
+ for (i = 0; i < count; i++) {
+ int enabled;
+ u16 group;
+
+ group = WPA_GET_LE16(pos);
+ pos += 2;
+ enabled = sae_is_group_enabled(hapd, group);
+ wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
+ group, enabled ? "enabled" : "disabled");
+ if (enabled)
+ return 1;
+ }
+
+ return 0;
+}
+
+
static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
const struct ieee80211_mgmt *mgmt, size_t len,
u16 auth_transaction, u16 status_code)
@@ -1013,7 +1116,7 @@
#endif /* CONFIG_TESTING_OPTIONS */
if (!sta->sae) {
if (auth_transaction != 1 ||
- status_code != WLAN_STATUS_SUCCESS) {
+ !sae_status_success(hapd, status_code)) {
resp = -1;
goto remove_sta;
}
@@ -1080,7 +1183,8 @@
* Authentication frame, and the commit-scalar and
* COMMIT-ELEMENT previously sent.
*/
- resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0);
+ resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
+ status_code);
if (resp != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_ERROR,
"SAE: Failed to send commit message");
@@ -1103,7 +1207,7 @@
goto remove_sta;
}
- if (status_code != WLAN_STATUS_SUCCESS)
+ if (!sae_status_success(hapd, status_code))
goto remove_sta;
if (!(hapd->conf->mesh & MESH_ENABLED) &&
@@ -1136,7 +1240,8 @@
resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
- &token_len, groups);
+ &token_len, groups, status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT);
if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack",
@@ -1166,6 +1271,13 @@
if (resp != WLAN_STATUS_SUCCESS)
goto reply;
+ if (sta->sae->tmp &&
+ check_sae_rejected_groups(
+ hapd, sta->sae->tmp->peer_rejected_groups) < 0) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto remove_sta;
+ }
+
if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
wpa_printf(MSG_DEBUG,
"SAE: Request anti-clogging token from "
@@ -1180,7 +1292,7 @@
}
resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
- allow_reuse, &sta_removed);
+ status_code, allow_reuse, &sta_removed);
} else if (auth_transaction == 2) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -1221,8 +1333,8 @@
}
sta->sae->rc = peer_send_confirm;
}
- resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 0,
- &sta_removed);
+ resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
+ status_code, 0, &sta_removed);
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -1283,7 +1395,7 @@
if (sta->sae->state != SAE_NOTHING)
return -1;
- ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
if (ret)
return -1;
@@ -1406,12 +1518,10 @@
return WLAN_STATUS_AKMP_NOT_VALID;
if (res == WPA_ALLOC_FAIL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
-#ifdef CONFIG_IEEE80211W
if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
-#endif /* CONFIG_IEEE80211W */
if (res == WPA_INVALID_MDIE)
return WLAN_STATUS_INVALID_MDIE;
if (res == WPA_INVALID_PMKID)
@@ -1554,6 +1664,8 @@
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ elems.rsnxe ? elems.rsnxe - 2 : NULL,
+ elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len, NULL, 0);
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
@@ -2865,7 +2977,7 @@
rsn_ie_len += 2;
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq, rsn_ie, rsn_ie_len,
- NULL, 0, owe_dh, owe_dh_len);
+ NULL, 0, NULL, 0, owe_dh, owe_dh_len);
status = wpa_res_to_status_code(res);
if (status != WLAN_STATUS_SUCCESS)
goto end;
@@ -3073,12 +3185,13 @@
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
wpa_ie, wpa_ie_len,
+ elems.rsnxe ? elems.rsnxe - 2 : NULL,
+ elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len,
elems.owe_dh, elems.owe_dh_len);
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
-#ifdef CONFIG_IEEE80211W
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
(WLAN_STA_ASSOC | WLAN_STA_MFP) &&
!sta->sa_query_timed_out &&
@@ -3105,7 +3218,6 @@
sta->flags |= WLAN_STA_MFP;
else
sta->flags &= ~WLAN_STA_MFP;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
@@ -3150,6 +3262,17 @@
MAC2STR(sta->addr), sta->auth_alg);
return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
}
+
+ if (hapd->conf->sae_pwe == 2 &&
+ sta->auth_alg == WLAN_AUTH_SAE &&
+ sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
+ elems.rsnxe && elems.rsnxe_len >= 1 &&
+ (elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
+ wpa_printf(MSG_INFO, "SAE: " MACSTR
+ " indicates support for SAE H2E, but did not use it",
+ MAC2STR(sta->addr));
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
#endif /* CONFIG_SAE */
#ifdef CONFIG_OWE
@@ -3243,7 +3366,8 @@
sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
elems.hs20_len - 4);
release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
- if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm)) {
+ if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
+ hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
wpa_printf(MSG_DEBUG,
"HS 2.0: PMF not negotiated by release %d station "
MACSTR, release, MAC2STR(sta->addr));
@@ -3549,10 +3673,8 @@
ies, ies_len);
#endif /* CONFIG_OWE */
-#ifdef CONFIG_IEEE80211W
if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211N
p = hostapd_eid_ht_capabilities(hapd, p);
@@ -3560,7 +3682,8 @@
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
- if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
+ !is_6ghz_op_class(hapd->iconf->op_class)) {
u32 nsts = 0, sta_nsts;
if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
@@ -3604,6 +3727,8 @@
}
#endif /* CONFIG_FST */
+ p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
+
#ifdef CONFIG_OWE
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
@@ -4150,7 +4275,6 @@
*/
sta->flags |= WLAN_STA_ASSOC_REQ_OK;
-#ifdef CONFIG_IEEE80211W
if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
"SA Query procedure", reassoc ? "re" : "");
@@ -4161,7 +4285,6 @@
* trying to associate.
*/
}
-#endif /* CONFIG_IEEE80211W */
/* Make sure that the previously registered inactivity timer will not
* remove the STA immediately. */
@@ -4386,13 +4509,11 @@
}
-#ifdef CONFIG_IEEE80211W
static int robust_action_frame(u8 category)
{
return category != WLAN_ACTION_PUBLIC &&
category != WLAN_ACTION_HT;
}
-#endif /* CONFIG_IEEE80211W */
static int handle_action(struct hostapd_data *hapd,
@@ -4426,7 +4547,6 @@
return 0;
}
-#ifdef CONFIG_IEEE80211W
if (sta && (sta->flags & WLAN_STA_MFP) &&
!(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
robust_action_frame(mgmt->u.action.category)) {
@@ -4436,7 +4556,6 @@
"an MFP STA");
return 0;
}
-#endif /* CONFIG_IEEE80211W */
if (sta) {
u16 fc = le_to_host16(mgmt->frame_control);
@@ -4470,11 +4589,9 @@
case WLAN_ACTION_WMM:
hostapd_wmm_action(hapd, mgmt, len);
return 1;
-#ifdef CONFIG_IEEE80211W
case WLAN_ACTION_SA_QUERY:
ieee802_11_sa_query_action(hapd, mgmt, len);
return 1;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM_AP
case WLAN_ACTION_WNM:
ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
@@ -4626,6 +4743,18 @@
fc = le_to_host16(mgmt->frame_control);
stype = WLAN_FC_GET_STYPE(fc);
+ if (is_multicast_ether_addr(mgmt->sa) ||
+ is_zero_ether_addr(mgmt->sa) ||
+ os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
+ /* Do not process any frames with unexpected/invalid SA so that
+ * we do not add any state for unexpected STA addresses or end
+ * up sending out frames to unexpected destination. */
+ wpa_printf(MSG_DEBUG, "MGMT: Invalid SA=" MACSTR
+ " in received frame - ignore this frame silently",
+ MAC2STR(mgmt->sa));
+ return 0;
+ }
+
if (stype == WLAN_FC_STYPE_BEACON) {
handle_beacon(hapd, mgmt, len, fi);
return 1;
@@ -4862,9 +4991,7 @@
else
mlme_associate_indication(hapd, sta);
-#ifdef CONFIG_IEEE80211W
sta->sa_query_timed_out = 0;
-#endif /* CONFIG_IEEE80211W */
if (sta->eapol_sm == NULL) {
/*
@@ -5257,8 +5384,10 @@
wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
MACSTR, MAC2STR(src));
- if (is_multicast_ether_addr(src)) {
- /* Broadcast bit set in SA?! Ignore the frame silently. */
+ if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) ||
+ os_memcmp(src, hapd->own_addr, ETH_ALEN) == 0) {
+ /* Broadcast bit set in SA or unexpected SA?! Ignore the frame
+ * silently. */
return;
}
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index b8453c9..f592da5 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -192,5 +192,6 @@
int ap_seg1_idx, int *bandwidth, int *seg1_idx);
void auth_sae_process_commit(void *eloop_ctx, void *user_ctx);
+u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index a51f3fc..abd3940 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "beacon.h"
@@ -44,6 +45,41 @@
}
+static u8 ieee80211_he_mcs_set_size(const u8 *phy_cap_info)
+{
+ u8 sz = 4;
+
+ if (phy_cap_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)
+ sz += 4;
+ if (phy_cap_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
+ sz += 4;
+
+ return sz;
+}
+
+
+static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len)
+{
+ struct ieee80211_he_capabilities *cap;
+ size_t cap_len;
+
+ cap = (struct ieee80211_he_capabilities *) buf;
+ cap_len = sizeof(*cap) - sizeof(cap->optional);
+ if (len < cap_len)
+ return 1;
+
+ cap_len += ieee80211_he_mcs_set_size(cap->he_phy_capab_info);
+ if (len < cap_len)
+ return 1;
+
+ cap_len += ieee80211_he_ppet_size(buf[cap_len], cap->he_phy_capab_info);
+
+ return len != cap_len;
+}
+
+
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
enum ieee80211_op_mode opmode)
{
@@ -51,12 +87,12 @@
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
u8 he_oper_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK;
u8 *pos = eid;
- u8 ie_size = 0, mcs_nss_size = 0, ppet_size = 0;
+ u8 ie_size = 0, mcs_nss_size = 4, ppet_size = 0;
if (!mode)
return eid;
- ie_size = sizeof(struct ieee80211_he_capabilities);
+ ie_size = sizeof(*cap) - sizeof(cap->optional);
ppet_size = ieee80211_he_ppet_size(mode->he_capab[opmode].ppet[0],
mode->he_capab[opmode].phy_cap);
@@ -74,7 +110,6 @@
case CHANWIDTH_USE_HT:
he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
- mcs_nss_size += 4;
break;
}
@@ -136,6 +171,9 @@
if (!hapd->iface->current_mode)
return eid;
+ if (is_6ghz_op_class(hapd->iconf->op_class))
+ oper_size += 5;
+
*pos++ = WLAN_EID_EXTENSION;
*pos++ = 1 + oper_size;
*pos++ = WLAN_EID_EXT_HE_OPERATION;
@@ -164,9 +202,26 @@
/* TODO: conditional MaxBSSID Indicator subfield */
- oper->he_oper_params = host_to_le32(params);
+ pos += 6; /* skip the fixed part */
- pos += oper_size;
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
+
+ if (!seg0)
+ seg0 = hapd->iconf->channel;
+
+ params |= HE_OPERATION_6GHZ_OPER_INFO;
+ *pos++ = hapd->iconf->channel; /* Primary Channel */
+ *pos++ = center_idx_to_bw_6ghz(seg0); /* Control: Channel Width
+ */
+ /* Channel Center Freq Seg0/Seg0 */
+ *pos++ = seg0;
+ *pos++ = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
+ /* Minimum Rate */
+ *pos++ = 6; /* TODO: what should be set here? */
+ }
+
+ oper->he_oper_params = host_to_le32(params);
return pos;
}
@@ -325,6 +380,7 @@
{
if (!he_capab || !hapd->iconf->ieee80211ax ||
!check_valid_he_mcs(hapd, he_capab, opmode) ||
+ ieee80211_invalid_he_cap_size(he_capab, he_capab_len) ||
he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
sta->flags &= ~WLAN_STA_HE;
os_free(sta->he_capab);
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 214855d..6db9365 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -27,7 +27,7 @@
u8 *pos = eid;
if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode ||
- hapd->conf->disable_11n)
+ hapd->conf->disable_11n || is_6ghz_op_class(hapd->iconf->op_class))
return eid;
*pos++ = WLAN_EID_HT_CAP;
@@ -84,7 +84,8 @@
struct ieee80211_ht_operation *oper;
u8 *pos = eid;
- if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
+ if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n ||
+ is_6ghz_op_class(hapd->iconf->op_class))
return eid;
*pos++ = WLAN_EID_HT_OPERATION;
@@ -113,7 +114,8 @@
u8 sec_ch;
if (!hapd->cs_freq_params.channel ||
- !hapd->cs_freq_params.sec_channel_offset)
+ !hapd->cs_freq_params.sec_channel_offset ||
+ is_6ghz_op_class(hapd->iconf->op_class))
return eid;
if (hapd->cs_freq_params.sec_channel_offset == -1)
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 707381f..0b828e9 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -19,8 +19,6 @@
#include "ieee802_11.h"
-#ifdef CONFIG_IEEE80211W
-
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
struct sta_info *sta, u8 *eid)
{
@@ -304,8 +302,6 @@
ap_sta_stop_sa_query(hapd, sta);
}
-#endif /* CONFIG_IEEE80211W */
-
static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
{
@@ -404,14 +400,22 @@
u8 *pos = eid;
u8 len = 0, i;
- if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
+ if (hapd->conf->qos_map_set_len ||
+ (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)))
len = 5;
- if (len < 4 && hapd->conf->interworking)
+ if (len < 4 &&
+ (hapd->conf->time_advertisement == 2 || hapd->conf->interworking))
len = 4;
- if (len < 3 && hapd->conf->wnm_sleep_mode)
+ if (len < 3 &&
+ (hapd->conf->wnm_sleep_mode || hapd->conf->bss_transition))
len = 3;
- if (len < 1 && hapd->iconf->obss_interval)
+ if (len < 1 &&
+ (hapd->iconf->obss_interval ||
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)))
len = 1;
+ if (len < 2 &&
+ (hapd->conf->proxy_arp || hapd->conf->coloc_intf_reporting))
+ len = 2;
if (len < 7 && hapd->conf->ssid.utf8_ssid)
len = 7;
if (len < 9 &&
@@ -1000,3 +1004,22 @@
return 0;
}
#endif /* CONFIG_OCV */
+
+
+u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+ u8 *pos = eid;
+
+ if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
+ (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2) ||
+ len < 3)
+ return pos;
+
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = 1;
+ /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
+ * used for now */
+ *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+
+ return pos;
+}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 269345f..f50f142 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -26,7 +26,7 @@
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
u8 *pos = eid;
- if (!mode)
+ if (!mode || is_6ghz_op_class(hapd->iconf->op_class))
return eid;
if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
@@ -76,6 +76,9 @@
struct ieee80211_vht_operation *oper;
u8 *pos = eid;
+ if (is_6ghz_op_class(hapd->iconf->op_class))
+ return eid;
+
*pos++ = WLAN_EID_VHT_OPERATION;
*pos++ = sizeof(*oper);
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index d628641..d081031 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -7,6 +7,9 @@
*/
#include "utils/includes.h"
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
#include "utils/common.h"
#include "utils/eloop.h"
@@ -55,10 +58,9 @@
len = sizeof(*xhdr) + datalen;
buf = os_zalloc(len);
- if (buf == NULL) {
- wpa_printf(MSG_ERROR, "malloc() failed for "
- "ieee802_1x_send(len=%lu)",
- (unsigned long) len);
+ if (!buf) {
+ wpa_printf(MSG_ERROR, "malloc() failed for %s(len=%lu)",
+ __func__, (unsigned long) len);
return;
}
@@ -149,12 +151,12 @@
size_t len, ekey_len;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
len = sizeof(*key) + key_len;
buf = os_zalloc(sizeof(*hdr) + len);
- if (buf == NULL)
+ if (!buf)
return;
hdr = (struct ieee802_1x_hdr *) buf;
@@ -195,16 +197,16 @@
/* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and
* MSK[32..63] is used to sign the message. */
- if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) {
- wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting "
- "and signing EAPOL-Key");
+ if (!sm->eap_if->eapKeyData || sm->eap_if->eapKeyDataLen < 64) {
+ wpa_printf(MSG_ERROR,
+ "No eapKeyData available for encrypting and signing EAPOL-Key");
os_free(buf);
return;
}
os_memcpy((u8 *) (key + 1), key_data, key_len);
ekey_len = sizeof(key->key_iv) + 32;
ekey = os_malloc(ekey_len);
- if (ekey == NULL) {
+ if (!ekey) {
wpa_printf(MSG_ERROR, "Could not encrypt key");
os_free(buf);
return;
@@ -241,7 +243,7 @@
struct eapol_authenticator *eapol = hapd->eapol_auth;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL || !sm->eap_if->eapKeyData)
+ if (!sm || !sm->eap_if->eapKeyData)
return;
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR,
@@ -262,12 +264,13 @@
if (hapd->conf->individual_wep_key_len > 0) {
u8 *ikey;
+
ikey = os_malloc(hapd->conf->individual_wep_key_len);
- if (ikey == NULL ||
+ if (!ikey ||
random_get_bytes(ikey, hapd->conf->individual_wep_key_len))
{
- wpa_printf(MSG_ERROR, "Could not generate random "
- "individual WEP key.");
+ wpa_printf(MSG_ERROR,
+ "Could not generate random individual WEP key");
os_free(ikey);
return;
}
@@ -283,8 +286,8 @@
if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
sta->addr, 0, 1, NULL, 0, ikey,
hapd->conf->individual_wep_key_len)) {
- wpa_printf(MSG_ERROR, "Could not set individual WEP "
- "encryption.");
+ wpa_printf(MSG_ERROR,
+ "Could not set individual WEP encryption");
}
os_free(ikey);
@@ -344,13 +347,13 @@
eap_erp_update_identity(sm->eap, eap, len);
identity = eap_get_identity(sm->eap, &identity_len);
- if (identity == NULL)
+ if (!identity)
return;
/* Save station identity for future RADIUS packets */
os_free(sm->identity);
sm->identity = (u8 *) dup_binstr(identity, identity_len);
- if (sm->identity == NULL) {
+ if (!sm->identity) {
sm->identity_len = 0;
return;
}
@@ -405,7 +408,6 @@
return -1;
}
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
suite = wpa_cipher_to_suite(WPA_PROTO_RSN,
hapd->conf->group_mgmt_cipher);
@@ -418,7 +420,6 @@
return -1;
}
}
-#endif /* CONFIG_IEEE80211W */
return 0;
}
@@ -605,8 +606,7 @@
if (!radius_msg_add_attr(msg, attr->type,
wpabuf_head(attr->val),
wpabuf_len(attr->val))) {
- wpa_printf(MSG_ERROR, "Could not add RADIUS "
- "attribute");
+ wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
return -1;
}
}
@@ -615,6 +615,63 @@
}
+int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta,
+ struct radius_msg *msg, int acct)
+{
+#ifdef CONFIG_SQLITE
+ const char *attrtxt;
+ char addrtxt[3 * ETH_ALEN];
+ char *sql;
+ sqlite3_stmt *stmt = NULL;
+
+ if (!hapd->rad_attr_db)
+ return 0;
+
+ os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(sta->addr));
+
+ sql = "SELECT attr FROM radius_attributes WHERE sta=? AND (reqtype=? OR reqtype IS NULL);";
+ if (sqlite3_prepare_v2(hapd->rad_attr_db, sql, os_strlen(sql), &stmt,
+ NULL) != SQLITE_OK) {
+ wpa_printf(MSG_ERROR, "DB: Failed to prepare SQL statement: %s",
+ sqlite3_errmsg(hapd->rad_attr_db));
+ return -1;
+ }
+ sqlite3_bind_text(stmt, 1, addrtxt, os_strlen(addrtxt), SQLITE_STATIC);
+ sqlite3_bind_text(stmt, 2, acct ? "acct" : "auth", 4, SQLITE_STATIC);
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ struct hostapd_radius_attr *attr;
+ struct radius_attr_hdr *hdr;
+
+ attrtxt = (const char *) sqlite3_column_text(stmt, 0);
+ attr = hostapd_parse_radius_attr(attrtxt);
+ if (!attr) {
+ wpa_printf(MSG_ERROR,
+ "Skipping invalid attribute from SQL: %s",
+ attrtxt);
+ continue;
+ }
+ wpa_printf(MSG_DEBUG, "Adding RADIUS attribute from SQL: %s",
+ attrtxt);
+ hdr = radius_msg_add_attr(msg, attr->type,
+ wpabuf_head(attr->val),
+ wpabuf_len(attr->val));
+ hostapd_config_free_radius_attr(attr);
+ if (!hdr) {
+ wpa_printf(MSG_ERROR,
+ "Could not add RADIUS attribute from SQL");
+ continue;
+ }
+ }
+
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+#endif /* CONFIG_SQLITE */
+
+ return 0;
+}
+
+
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
struct sta_info *sta,
const u8 *eap, size_t len)
@@ -622,18 +679,17 @@
struct radius_msg *msg;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
ieee802_1x_learn_identity(hapd, sm, eap, len);
- wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
- "packet");
+ wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS packet");
sm->radius_identifier = radius_client_get_id(hapd->radius);
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
sm->radius_identifier);
- if (msg == NULL) {
+ if (!msg) {
wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
return;
}
@@ -654,6 +710,9 @@
msg) < 0)
goto fail;
+ if (sta && add_sqlite_radius_attr(hapd, sta, msg, 0) < 0)
+ goto fail;
+
/* TODO: should probably check MTU from driver config; 2304 is max for
* IEEE 802.11, but use 1400 to avoid problems with too large packets
*/
@@ -677,12 +736,12 @@
int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
RADIUS_ATTR_STATE);
if (res < 0) {
- wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge");
+ wpa_printf(MSG_INFO,
+ "Could not copy State attribute from previous Access-Challenge");
goto fail;
}
- if (res > 0) {
+ if (res > 0)
wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute");
- }
}
if (hapd->conf->radius_request_cui) {
@@ -711,8 +770,8 @@
if (!radius_msg_add_wfa(
msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION,
&ver, 1)) {
- wpa_printf(MSG_ERROR, "Could not add HS 2.0 AP "
- "version");
+ wpa_printf(MSG_ERROR,
+ "Could not add HS 2.0 AP version");
goto fail;
}
@@ -720,6 +779,7 @@
const u8 *pos;
u8 buf[3];
u16 id;
+
pos = wpabuf_head_u8(sta->hs20_ie);
buf[0] = (*pos) >> 4;
if (((*pos) & HS20_PPS_MO_ID_PRESENT) &&
@@ -732,8 +792,8 @@
msg,
RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION,
buf, sizeof(buf))) {
- wpa_printf(MSG_ERROR, "Could not add HS 2.0 "
- "STA version");
+ wpa_printf(MSG_ERROR,
+ "Could not add HS 2.0 STA version");
goto fail;
}
}
@@ -792,13 +852,14 @@
{
u8 type, *data;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+
+ if (!sm)
return;
data = (u8 *) (eap + 1);
if (len < sizeof(*eap) + 1) {
- wpa_printf(MSG_INFO, "handle_eap_response: too short response data");
+ wpa_printf(MSG_INFO, "%s: too short response data", __func__);
return;
}
@@ -826,12 +887,11 @@
u8 type, *data;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
if (len < sizeof(*eap) + 1) {
- wpa_printf(MSG_INFO,
- "handle_eap_initiate: too short response data");
+ wpa_printf(MSG_INFO, "%s: too short response data", __func__);
return;
}
@@ -839,8 +899,8 @@
type = data[0];
hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
- "id=%d len=%d) from STA: EAP Initiate type %u",
+ HOSTAPD_LEVEL_DEBUG,
+ "received EAP packet (code=%d id=%d len=%d) from STA: EAP Initiate type %u",
eap->code, eap->identifier, be_to_host16(eap->length),
type);
@@ -851,6 +911,29 @@
}
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char * eap_code_str(u8 code)
+{
+ switch (code) {
+ case EAP_CODE_REQUEST:
+ return "request";
+ case EAP_CODE_RESPONSE:
+ return "response";
+ case EAP_CODE_SUCCESS:
+ return "success";
+ case EAP_CODE_FAILURE:
+ return "failure";
+ case EAP_CODE_INITIATE:
+ return "initiate";
+ case EAP_CODE_FINISH:
+ return "finish";
+ default:
+ return "unknown";
+ }
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
/* Process incoming EAP packet from Supplicant */
static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
u8 *buf, size_t len)
@@ -866,44 +949,29 @@
eap = (struct eap_hdr *) buf;
eap_len = be_to_host16(eap->length);
- wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d",
- eap->code, eap->identifier, eap_len);
+ wpa_printf(MSG_DEBUG, "EAP: code=%d (%s) identifier=%d length=%d",
+ eap->code, eap_code_str(eap->code), eap->identifier,
+ eap_len);
if (eap_len < sizeof(*eap)) {
wpa_printf(MSG_DEBUG, " Invalid EAP length");
return;
} else if (eap_len > len) {
- wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP "
- "packet");
+ wpa_printf(MSG_DEBUG,
+ " Too short frame to contain this EAP packet");
return;
} else if (eap_len < len) {
- wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP "
- "packet", (unsigned long) len - eap_len);
+ wpa_printf(MSG_DEBUG,
+ " Ignoring %lu extra bytes after EAP packet",
+ (unsigned long) len - eap_len);
}
switch (eap->code) {
- case EAP_CODE_REQUEST:
- wpa_printf(MSG_DEBUG, " (request)");
- return;
case EAP_CODE_RESPONSE:
- wpa_printf(MSG_DEBUG, " (response)");
handle_eap_response(hapd, sta, eap, eap_len);
break;
- case EAP_CODE_SUCCESS:
- wpa_printf(MSG_DEBUG, " (success)");
- return;
- case EAP_CODE_FAILURE:
- wpa_printf(MSG_DEBUG, " (failure)");
- return;
case EAP_CODE_INITIATE:
- wpa_printf(MSG_DEBUG, " (initiate)");
handle_eap_initiate(hapd, sta, eap, eap_len);
break;
- case EAP_CODE_FINISH:
- wpa_printf(MSG_DEBUG, " (finish)");
- break;
- default:
- wpa_printf(MSG_DEBUG, " (unknown code)");
- return;
}
}
@@ -912,6 +980,7 @@
ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
{
int flags = 0;
+
if (sta->flags & WLAN_STA_PREAUTH)
flags |= EAPOL_SM_PREAUTH;
if (sta->wpa_sm) {
@@ -976,8 +1045,8 @@
sta = ap_get_sta(hapd, sa);
if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
- "associated/Pre-authenticating STA");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X data frame from not associated/Pre-authenticating STA");
if (sta && (sta->flags & WLAN_STA_AUTH)) {
wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
@@ -999,14 +1068,15 @@
hdr->version, hdr->type, datalen);
if (len - sizeof(*hdr) < datalen) {
- wpa_printf(MSG_INFO, " frame too short for this IEEE 802.1X packet");
+ wpa_printf(MSG_INFO,
+ " frame too short for this IEEE 802.1X packet");
if (sta->eapol_sm)
sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
return;
}
if (len - sizeof(*hdr) > datalen) {
- wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after "
- "IEEE 802.1X packet",
+ wpa_printf(MSG_DEBUG,
+ " ignoring %lu extra octets after IEEE 802.1X packet",
(unsigned long) len - sizeof(*hdr) - datalen);
}
@@ -1027,8 +1097,8 @@
if (!hapd->conf->ieee802_1x && !hapd->conf->osen &&
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
- "802.1X not enabled and WPS not used");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Ignore EAPOL message - 802.1X not enabled and WPS not used");
return;
}
@@ -1036,8 +1106,8 @@
if (key_mgmt != -1 &&
(wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE ||
key_mgmt == WPA_KEY_MGMT_DPP)) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
- "STA is using PSK");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Ignore EAPOL message - STA is using PSK");
return;
}
@@ -1060,9 +1130,8 @@
* skipped if the STA is known to support WPS
* 2.0.
*/
- wpa_printf(MSG_DEBUG, "WPS: Do not start "
- "EAPOL until EAPOL-Start is "
- "received");
+ wpa_printf(MSG_DEBUG,
+ "WPS: Do not start EAPOL until EAPOL-Start is received");
sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
}
}
@@ -1085,15 +1154,14 @@
case IEEE802_1X_TYPE_EAPOL_START:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start "
- "from STA");
+ HOSTAPD_LEVEL_DEBUG,
+ "received EAPOL-Start from STA");
sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
if (pmksa) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
- HOSTAPD_LEVEL_DEBUG, "cached PMKSA "
- "available - ignore it since "
- "STA sent EAPOL-Start");
+ HOSTAPD_LEVEL_DEBUG,
+ "cached PMKSA available - ignore it since STA sent EAPOL-Start");
wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
}
sta->eapol_sm->eapolStart = TRUE;
@@ -1104,8 +1172,8 @@
case IEEE802_1X_TYPE_EAPOL_LOGOFF:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff "
- "from STA");
+ HOSTAPD_LEVEL_DEBUG,
+ "received EAPOL-Logoff from STA");
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
accounting_sta_stop(hapd, sta);
@@ -1117,8 +1185,8 @@
case IEEE802_1X_TYPE_EAPOL_KEY:
wpa_printf(MSG_DEBUG, " EAPOL-Key");
if (!ap_sta_is_authorized(sta)) {
- wpa_printf(MSG_DEBUG, " Dropped key data from "
- "unauthorized Supplicant");
+ wpa_printf(MSG_DEBUG,
+ " Dropped key data from unauthorized Supplicant");
break;
}
break;
@@ -1174,8 +1242,8 @@
#endif /* CONFIG_WPS */
if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
- "802.1X not enabled or forced for WPS");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Ignore STA - 802.1X not enabled or forced for WPS");
/*
* Clear any possible EAPOL authenticator state to support
* reassociation change from WPS to PSK.
@@ -1197,11 +1265,11 @@
return;
}
- if (sta->eapol_sm == NULL) {
+ if (!sta->eapol_sm) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "start authentication");
sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
- if (sta->eapol_sm == NULL) {
+ if (!sta->eapol_sm) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_INFO,
@@ -1220,8 +1288,8 @@
* initiates the handshake with EAPOL-Start. Only allow the
* wait to be skipped if the STA is known to support WPS 2.0.
*/
- wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until "
- "EAPOL-Start is received");
+ wpa_printf(MSG_DEBUG,
+ "WPS: Do not start EAPOL until EAPOL-Start is received");
sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
}
#endif /* CONFIG_WPS */
@@ -1317,7 +1385,7 @@
sta->pending_eapol_rx = NULL;
}
- if (sm == NULL)
+ if (!sm)
return;
sta->eapol_sm = NULL;
@@ -1342,7 +1410,7 @@
struct radius_msg *msg;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL || sm->last_recv_radius == NULL) {
+ if (!sm || !sm->last_recv_radius) {
if (sm)
sm->eap_if->aaaEapNoReq = TRUE;
return;
@@ -1351,21 +1419,21 @@
msg = sm->last_recv_radius;
eap = radius_msg_get_eap(msg);
- if (eap == NULL) {
+ if (!eap) {
/* RFC 3579, Chap. 2.6.3:
* RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
* attribute */
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "could not extract "
- "EAP-Message from RADIUS message");
+ HOSTAPD_LEVEL_WARNING,
+ "could not extract EAP-Message from RADIUS message");
sm->eap_if->aaaEapNoReq = TRUE;
return;
}
if (wpabuf_len(eap) < sizeof(*hdr)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "too short EAP packet "
- "received from authentication server");
+ HOSTAPD_LEVEL_WARNING,
+ "too short EAP packet received from authentication server");
wpabuf_free(eap);
sm->eap_if->aaaEapNoReq = TRUE;
return;
@@ -1398,8 +1466,8 @@
}
buf[sizeof(buf) - 1] = '\0';
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d "
- "id=%d len=%d) from RADIUS server: %s",
+ HOSTAPD_LEVEL_DEBUG,
+ "decapsulated EAP packet (code=%d id=%d len=%d) from RADIUS server: %s",
hdr->code, hdr->identifier, be_to_host16(hdr->length),
buf);
sm->eap_if->aaaEapReq = TRUE;
@@ -1419,7 +1487,8 @@
u8 *buf;
size_t len;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+
+ if (!sm)
return;
keys = radius_msg_get_ms_keys(msg, req, shared_secret,
@@ -1482,8 +1551,7 @@
struct radius_attr_data *nclass;
size_t nclass_count;
- if (!hapd->conf->radius->acct_server || hapd->radius == NULL ||
- sm == NULL)
+ if (!hapd->conf->radius->acct_server || !hapd->radius || !sm)
return;
radius_free_class(&sm->radius_class);
@@ -1492,7 +1560,7 @@
return;
nclass = os_calloc(count, sizeof(struct radius_attr_data));
- if (nclass == NULL)
+ if (!nclass)
return;
nclass_count = 0;
@@ -1509,7 +1577,7 @@
} while (class_len < 1);
nclass[nclass_count].data = os_memdup(attr_class, class_len);
- if (nclass[nclass_count].data == NULL)
+ if (!nclass[nclass_count].data)
break;
nclass[nclass_count].len = class_len;
@@ -1518,8 +1586,9 @@
sm->radius_class.attr = nclass;
sm->radius_class.count = nclass_count;
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class "
- "attributes for " MACSTR,
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Stored %lu RADIUS Class attributes for "
+ MACSTR,
(unsigned long) sm->radius_class.count,
MAC2STR(sta->addr));
}
@@ -1534,7 +1603,7 @@
size_t len;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len,
@@ -1542,12 +1611,12 @@
return;
identity = (u8 *) dup_binstr(buf, len);
- if (identity == NULL)
+ if (!identity)
return;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
- "User-Name from Access-Accept '%s'",
+ HOSTAPD_LEVEL_DEBUG,
+ "old identity '%s' updated with User-Name from Access-Accept '%s'",
sm->identity ? (char *) sm->identity : "N/A",
(char *) identity);
@@ -1567,7 +1636,7 @@
u8 *buf;
size_t len;
- if (sm == NULL)
+ if (!sm)
return;
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
@@ -1575,7 +1644,7 @@
return;
cui = wpabuf_alloc_copy(buf, len);
- if (cui == NULL)
+ if (!cui)
return;
wpabuf_free(sm->radius_cui);
@@ -1596,14 +1665,16 @@
sta->remediation_method = pos[0];
os_memcpy(sta->remediation_url, pos + 1, len - 1);
sta->remediation_url[len - 1] = '\0';
- wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed "
- "for " MACSTR " - server method %u URL %s",
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Subscription remediation needed for "
+ MACSTR " - server method %u URL %s",
MAC2STR(sta->addr), sta->remediation_method,
sta->remediation_url);
} else {
sta->remediation_url = NULL;
- wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed "
- "for " MACSTR, MAC2STR(sta->addr));
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Subscription remediation needed for "
+ MACSTR, MAC2STR(sta->addr));
}
/* TODO: assign the STA into remediation VLAN or add filtering */
}
@@ -1616,8 +1687,8 @@
if (len < 3)
return; /* Malformed information */
sta->hs20_deauth_requested = 1;
- wpa_printf(MSG_DEBUG, "HS 2.0: Deauthentication request - Code %u "
- "Re-auth Delay %u",
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Deauthentication request - Code %u Re-auth Delay %u",
*pos, WPA_GET_LE16(pos + 1));
wpabuf_free(sta->hs20_deauth_req);
sta->hs20_deauth_req = wpabuf_alloc(len + 1);
@@ -1641,16 +1712,17 @@
return; /* Malformed information */
os_free(sta->hs20_session_info_url);
sta->hs20_session_info_url = os_malloc(len);
- if (sta->hs20_session_info_url == NULL)
+ if (!sta->hs20_session_info_url)
return;
swt = pos[0];
os_memcpy(sta->hs20_session_info_url, pos + 1, len - 1);
sta->hs20_session_info_url[len - 1] = '\0';
- wpa_printf(MSG_DEBUG, "HS 2.0: Session Information URL='%s' SWT=%u "
- "(session_timeout=%d)",
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Session Information URL='%s' SWT=%u (session_timeout=%d)",
sta->hs20_session_info_url, swt, session_timeout);
if (session_timeout < 0) {
- wpa_printf(MSG_DEBUG, "HS 2.0: No Session-Timeout set - ignore session info URL");
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: No Session-Timeout set - ignore session info URL");
return;
}
if (swt == 255)
@@ -1783,6 +1855,7 @@
ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier)
{
struct sta_id_search id_search;
+
id_search.identifier = identifier;
id_search.sm = NULL;
ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search);
@@ -1853,9 +1926,9 @@
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
- if (sm == NULL) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching "
- "station for this RADIUS message");
+ if (!sm) {
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Could not find matching station for this RADIUS message");
return RADIUS_RX_UNKNOWN;
}
sta = sm->sta;
@@ -1866,12 +1939,12 @@
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");
+ 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)) {
- wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
+ wpa_printf(MSG_INFO,
+ "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
@@ -1904,8 +1977,7 @@
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_INFO,
- "ignored too small "
- "Acct-Interim-Interval %d",
+ "ignored too small Acct-Interim-Interval %d",
acct_interim_interval);
} else
sta->acct_interim_interval = acct_interim_interval;
@@ -1974,8 +2046,7 @@
hostapd_logger(hapd, sm->addr,
HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG,
- "using EAP timeout of %d seconds (from "
- "RADIUS)",
+ "using EAP timeout of %d seconds (from RADIUS)",
sm->eap_if->aaaMethodTimeout);
} else {
/*
@@ -2014,7 +2085,8 @@
void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
{
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+
+ if (!sm)
return;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
@@ -2050,7 +2122,7 @@
os_free(eapol->default_wep_key);
eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
- if (eapol->default_wep_key == NULL ||
+ if (!eapol->default_wep_key ||
random_get_bytes(eapol->default_wep_key,
hapd->conf->default_wep_key_len)) {
wpa_printf(MSG_INFO, "Could not generate random WEP key");
@@ -2094,8 +2166,8 @@
if (ieee802_1x_rekey_broadcast(hapd)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "failed to generate a "
- "new broadcast key");
+ HOSTAPD_LEVEL_WARNING,
+ "failed to generate a new broadcast key");
os_free(eapol->default_wep_key);
eapol->default_wep_key = NULL;
return;
@@ -2109,8 +2181,8 @@
eapol->default_wep_key,
hapd->conf->default_wep_key_len)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "failed to configure a "
- "new broadcast key");
+ HOSTAPD_LEVEL_WARNING,
+ "failed to configure a new broadcast key");
os_free(eapol->default_wep_key);
eapol->default_wep_key = NULL;
return;
@@ -2145,8 +2217,8 @@
(identity_len == WSC_ID_REGISTRAR_LEN &&
os_memcmp(identity, WSC_ID_REGISTRAR,
WSC_ID_REGISTRAR_LEN) == 0))) {
- wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> "
- "WLAN_STA_WPS");
+ wpa_printf(MSG_DEBUG,
+ "WPS: WLAN_STA_MAYBE_WPS -> WLAN_STA_WPS");
sta->flags |= WLAN_STA_WPS;
}
}
@@ -2173,6 +2245,7 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
if (preauth)
rsn_preauth_finished(hapd, sta, success);
else
@@ -2190,7 +2263,7 @@
int rv = -1;
eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
- if (eap_user == NULL)
+ if (!eap_user)
goto out;
os_memset(user, 0, sizeof(*user));
@@ -2203,7 +2276,7 @@
if (eap_user->password) {
user->password = os_memdup(eap_user->password,
eap_user->password_len);
- if (user->password == NULL)
+ if (!user->password)
goto out;
user->password_len = eap_user->password_len;
user->password_hash = eap_user->password_hash;
@@ -2233,8 +2306,9 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+
sta = ap_get_sta(hapd, addr);
- if (sta == NULL || sta->eapol_sm == NULL)
+ if (!sta || !sta->eapol_sm)
return 0;
return 1;
}
@@ -2271,6 +2345,7 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
ieee802_1x_set_sta_authorized(hapd, sta, authorized);
}
@@ -2279,6 +2354,7 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
ieee802_1x_abort_auth(hapd, sta);
}
@@ -2289,6 +2365,7 @@
#ifndef CONFIG_NO_RC4
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
ieee802_1x_tx_key(hapd, sta);
#endif /* CONFIG_NO_RC4 */
#endif /* CONFIG_FIPS */
@@ -2300,6 +2377,7 @@
{
/* struct hostapd_data *hapd = ctx; */
struct sta_info *sta = sta_ctx;
+
switch (type) {
case EAPOL_AUTH_SM_CHANGE:
wpa_auth_sm_notify(sta->wpa_sm);
@@ -2349,43 +2427,15 @@
dl_list_init(&hapd->erp_keys);
os_memset(&conf, 0, sizeof(conf));
+ conf.eap_cfg = hapd->eap_cfg;
conf.ctx = hapd;
conf.eap_reauth_period = hapd->conf->eap_reauth_period;
conf.wpa = hapd->conf->wpa;
conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
- conf.eap_server = hapd->conf->eap_server;
- conf.ssl_ctx = hapd->ssl_ctx;
- conf.msg_ctx = hapd->msg_ctx;
- conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
conf.eap_req_id_text = hapd->conf->eap_req_id_text;
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;
- conf.erp = hapd->conf->eap_server_erp;
- conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
- conf.tls_flags = hapd->conf->tls_flags;
- conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
- conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
- conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
- conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info;
- conf.eap_fast_prov = hapd->conf->eap_fast_prov;
- conf.pac_key_lifetime = hapd->conf->pac_key_lifetime;
- conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
- conf.eap_teap_auth = hapd->conf->eap_teap_auth;
- conf.eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner;
- conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
- conf.tnc = hapd->conf->tnc;
- conf.wps = hapd->wps;
- conf.fragment_size = hapd->conf->fragment_size;
- conf.pwd_group = hapd->conf->pwd_group;
- conf.pbc_in_m1 = hapd->conf->pbc_in_m1;
- if (hapd->conf->server_id) {
- conf.server_id = (const u8 *) hapd->conf->server_id;
- conf.server_id_len = os_strlen(hapd->conf->server_id);
- } else {
- conf.server_id = (const u8 *) "hostapd";
- conf.server_id_len = 7;
- }
os_memset(&cb, 0, sizeof(cb));
cb.eapol_send = ieee802_1x_eapol_send;
@@ -2404,7 +2454,7 @@
#endif /* CONFIG_ERP */
hapd->eapol_auth = eapol_auth_init(&conf, &cb);
- if (hapd->eapol_auth == NULL)
+ if (!hapd->eapol_auth)
return -1;
if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
@@ -2425,7 +2475,7 @@
ieee802_1x_rekey(hapd, NULL);
- if (hapd->eapol_auth->default_wep_key == NULL)
+ if (!hapd->eapol_auth->default_wep_key)
return -1;
}
@@ -2468,7 +2518,7 @@
const unsigned char rfc1042_hdr[ETH_ALEN] =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
- if (sta == NULL)
+ if (!sta)
return -1;
if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2)
return 0;
@@ -2497,8 +2547,8 @@
if (len < (int) sizeof(*xhdr))
return 0;
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
- "type=%d length=%d - ack=%d",
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
+ " TX status - version=%d type=%d length=%d - ack=%d",
MAC2STR(sta->addr), xhdr->version, xhdr->type,
be_to_host16(xhdr->length), ack);
@@ -2517,6 +2567,7 @@
if (pos + sizeof(struct wpa_eapol_key) <= buf + len) {
const struct wpa_eapol_key *wpa;
+
wpa = (const struct wpa_eapol_key *) pos;
if (wpa->type == EAPOL_KEY_TYPE_RSN ||
wpa->type == EAPOL_KEY_TYPE_WPA)
@@ -2532,8 +2583,8 @@
if (!ack && pos + sizeof(*key) <= buf + len) {
key = (struct ieee802_1x_eapol_key *) pos;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
- "frame (%scast index=%d)",
+ HOSTAPD_LEVEL_DEBUG,
+ "did not Ack EAPOL-Key frame (%scast index=%d)",
key->key_index & BIT(7) ? "uni" : "broad",
key->key_index & ~BIT(7));
/* TODO: re-send EAPOL-Key couple of times (with short delay
@@ -2553,7 +2604,7 @@
u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
{
- if (sm == NULL || sm->identity == NULL)
+ if (!sm || !sm->identity)
return NULL;
*len = sm->identity_len;
@@ -2564,7 +2615,7 @@
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
int idx)
{
- if (sm == NULL || sm->radius_class.attr == NULL ||
+ if (!sm || !sm->radius_class.attr ||
idx >= (int) sm->radius_class.count)
return NULL;
@@ -2575,7 +2626,7 @@
struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return NULL;
return sm->radius_cui;
}
@@ -2584,7 +2635,7 @@
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
{
*len = 0;
- if (sm == NULL)
+ if (!sm)
return NULL;
*len = sm->eap_if->eapKeyDataLen;
@@ -2609,7 +2660,7 @@
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
int enabled)
{
- if (sm == NULL)
+ if (!sm)
return;
sm->eap_if->portEnabled = enabled ? TRUE : FALSE;
eapol_auth_step(sm);
@@ -2619,7 +2670,7 @@
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
int valid)
{
- if (sm == NULL)
+ if (!sm)
return;
sm->portValid = valid ? TRUE : FALSE;
eapol_auth_step(sm);
@@ -2628,7 +2679,7 @@
void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
{
- if (sm == NULL)
+ if (!sm)
return;
if (pre_auth)
sm->flags |= EAPOL_SM_PREAUTH;
@@ -2660,7 +2711,7 @@
const char *name2;
char *identity_buf = NULL;
- if (sm == NULL)
+ if (!sm)
return 0;
ret = os_snprintf(buf + len, buflen - len,
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index d771ba5..bb85b93 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -59,6 +59,8 @@
struct hostapd_radius_attr *req_attr,
struct sta_info *sta,
struct radius_msg *msg);
+int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta,
+ struct radius_msg *msg, int acct);
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
struct sta_info *sta,
const u8 *eap, size_t len);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 51d7884..cbb8752 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -46,9 +46,7 @@
static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
-#ifdef CONFIG_IEEE80211W
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
-#endif /* CONFIG_IEEE80211W */
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx);
@@ -301,10 +299,8 @@
os_free(sta->challenge);
-#ifdef CONFIG_IEEE80211W
os_free(sta->sa_query_trans_id);
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_P2P
p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
@@ -1095,8 +1091,6 @@
}
-#ifdef CONFIG_IEEE80211W
-
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
{
u32 tu;
@@ -1186,8 +1180,6 @@
sta->sa_query_count = 0;
}
-#endif /* CONFIG_IEEE80211W */
-
const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
struct sta_info *sta)
@@ -1414,7 +1406,7 @@
int res;
buf[0] = '\0';
- res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ res = os_snprintf(buf, buflen, "%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]" : ""),
@@ -1433,6 +1425,7 @@
(flags & WLAN_STA_GAS ? "[GAS]" : ""),
(flags & WLAN_STA_HT ? "[HT]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
+ (flags & WLAN_STA_HE ? "[HE]" : ""),
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
"[WNM_SLEEP_MODE]" : ""));
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 5456a63..de806b4 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -171,7 +171,6 @@
struct ieee80211_he_capabilities *he_capab;
size_t he_capab_len;
-#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
* 0 = no SA Query in progress */
int sa_query_timed_out;
@@ -179,7 +178,6 @@
* sa_query_count octets of pending SA Query
* transaction identifiers */
struct os_reltime sa_query_start;
-#endif /* CONFIG_IEEE80211W */
#if defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 27c69d3..e4dcfe9 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -150,7 +150,6 @@
pos += gtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4, gtk_len = %d",
(int) gtk_elem_len);
-#ifdef CONFIG_IEEE80211W
res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
if (res < 0)
goto fail;
@@ -158,7 +157,6 @@
pos += igtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
(int) igtk_elem_len);
-#endif /* CONFIG_IEEE80211W */
WPA_PUT_LE16((u8 *)
&mgmt->u.action.u.wnm_sleep_resp.keydata_len,
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index e1c0c2c..7b690d7 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -708,6 +708,7 @@
#endif /* CONFIG_IEEE80211R_AP */
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
+ os_free(sm->rsnxe);
wpa_group_put(sm->wpa_auth, sm->group);
#ifdef CONFIG_DPP2
wpabuf_clear_free(sm->dpp_z);
@@ -1818,10 +1819,8 @@
sm->ft_completed = 0;
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
if (sm->mgmt_frame_prot && event == WPA_AUTH)
remove_ptk = 0;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_FILS
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
(event == WPA_AUTH || event == WPA_ASSOC))
@@ -2938,6 +2937,22 @@
WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
}
+ if ((!sm->rsnxe && kde.rsnxe) ||
+ (sm->rsnxe && !kde.rsnxe) ||
+ (sm->rsnxe && kde.rsnxe &&
+ (sm->rsnxe_len != kde.rsnxe_len ||
+ os_memcmp(sm->rsnxe, kde.rsnxe, sm->rsnxe_len) != 0))) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "RSNXE from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4");
+ wpa_hexdump(MSG_DEBUG, "RSNXE in AssocReq",
+ sm->rsnxe, sm->rsnxe_len);
+ wpa_hexdump(MSG_DEBUG, "RSNXE in EAPOL-Key msg 2/4",
+ kde.rsnxe, kde.rsnxe_len);
+ /* MLME-DEAUTHENTICATE.request */
+ wpa_sta_disconnect(wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
@@ -3045,8 +3060,6 @@
}
-#ifdef CONFIG_IEEE80211W
-
static int ieee80211w_kde_len(struct wpa_state_machine *sm)
{
if (sm->mgmt_frame_prot) {
@@ -3093,21 +3106,6 @@
return pos;
}
-#else /* CONFIG_IEEE80211W */
-
-static int ieee80211w_kde_len(struct wpa_state_machine *sm)
-{
- return 0;
-}
-
-
-static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
-{
- return pos;
-}
-
-#endif /* CONFIG_IEEE80211W */
-
static int ocv_oci_len(struct wpa_state_machine *sm)
{
@@ -3145,7 +3143,7 @@
size_t gtk_len, kde_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
- int wpa_ie_len, secure, keyidx, encr = 0;
+ int wpa_ie_len, secure, gtkidx, encr = 0;
SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
sm->TimeoutEvt = FALSE;
@@ -3196,7 +3194,7 @@
return;
gtk = dummy_gtk;
}
- keyidx = gsm->GN;
+ gtkidx = gsm->GN;
_rsc = rsc;
encr = 1;
} else {
@@ -3204,7 +3202,6 @@
secure = 0;
gtk = NULL;
gtk_len = 0;
- keyidx = 0;
_rsc = NULL;
if (sm->rx_eapol_key_secure) {
/*
@@ -3261,7 +3258,7 @@
#endif /* CONFIG_IEEE80211R_AP */
if (gtk) {
u8 hdr[2];
- hdr[0] = keyidx & 0x03;
+ hdr[0] = gtkidx & 0x03;
hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gtk_len);
@@ -3333,7 +3330,7 @@
WPA_KEY_INFO_MIC : 0) |
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
WPA_KEY_INFO_KEY_TYPE,
- _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+ _rsc, sm->ANonce, kde, pos - kde, 0, encr);
os_free(kde);
}
@@ -3746,7 +3743,6 @@
wpa_hexdump_key(MSG_DEBUG, "GTK",
group->GTK[group->GN - 1], group->GTK_len);
-#ifdef CONFIG_IEEE80211W
if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
size_t len;
len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
@@ -3759,7 +3755,6 @@
wpa_hexdump_key(MSG_DEBUG, "IGTK",
group->IGTK[group->GN_igtk - 4], len);
}
-#endif /* CONFIG_IEEE80211W */
return ret;
}
@@ -3777,10 +3772,8 @@
os_memset(group->GTK, 0, sizeof(group->GTK));
group->GN = 1;
group->GM = 2;
-#ifdef CONFIG_IEEE80211W
group->GN_igtk = 4;
group->GM_igtk = 5;
-#endif /* CONFIG_IEEE80211W */
/* GTK[GN] = CalcGTK() */
wpa_gtk_update(wpa_auth, group);
}
@@ -3869,7 +3862,6 @@
}
-#ifdef CONFIG_IEEE80211W
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
struct wpa_group *gsm = sm->group;
@@ -3898,7 +3890,7 @@
return pos - start;
}
-#endif /* CONFIG_IEEE80211W */
+
#endif /* CONFIG_WNM_AP */
@@ -3915,11 +3907,9 @@
tmp = group->GM;
group->GM = group->GN;
group->GN = tmp;
-#ifdef CONFIG_IEEE80211W
tmp = group->GM_igtk;
group->GM_igtk = group->GN_igtk;
group->GN_igtk = tmp;
-#endif /* CONFIG_IEEE80211W */
/* "GKeyDoneStations = GNoStations" is done in more robust way by
* counting the STAs that are marked with GUpdateStationKeys instead of
* including all STAs that could be in not-yet-completed state. */
@@ -3948,7 +3938,6 @@
group->GTK[group->GN - 1], group->GTK_len) < 0)
ret = -1;
-#ifdef CONFIG_IEEE80211W
if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
enum wpa_alg alg;
size_t len;
@@ -3962,7 +3951,6 @@
group->IGTK[group->GN_igtk - 4], len) < 0)
ret = -1;
}
-#endif /* CONFIG_IEEE80211W */
return ret;
}
@@ -4100,11 +4088,9 @@
tmp = group->GM;
group->GM = group->GN;
group->GN = tmp;
-#ifdef CONFIG_IEEE80211W
tmp = group->GM_igtk;
group->GM_igtk = group->GN_igtk;
group->GN_igtk = tmp;
-#endif /* CONFIG_IEEE80211W */
wpa_gtk_update(wpa_auth, group);
wpa_group_config_group_keys(wpa_auth, group);
}
@@ -4250,8 +4236,12 @@
/* Private MIB */
ret = os_snprintf(buf + len, buflen - len,
+ "wpa=%d\n"
+ "AKMSuiteSelector=" RSN_SUITE "\n"
"hostapdWPAPTKState=%d\n"
"hostapdWPAPTKGroupState=%d\n",
+ sm->wpa,
+ RSN_SUITE_ARG(wpa_akm_to_suite(sm->wpa_key_mgmt)),
sm->wpa_ptk_state,
sm->wpa_ptk_group_state);
if (os_snprintf_error(buflen - len, ret))
@@ -4975,13 +4965,11 @@
void *ctx1, void *ctx2)
{
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
-#ifdef CONFIG_IEEE80211W
u8 *opos;
-#endif /* CONFIG_IEEE80211W */
size_t gtk_len, kde_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
- int wpa_ie_len, secure, keyidx, encr = 0;
+ int wpa_ie_len, secure, gtkidx, encr = 0;
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
GTK[GN], IGTK, [FTIE], [TIE * 2])
@@ -5008,7 +4996,7 @@
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- keyidx = gsm->GN;
+ gtkidx = gsm->GN;
_rsc = rsc;
encr = 1;
} else {
@@ -5016,7 +5004,6 @@
secure = 0;
gtk = NULL;
gtk_len = 0;
- keyidx = 0;
_rsc = NULL;
if (sm->rx_eapol_key_secure) {
/*
@@ -5069,12 +5056,11 @@
#endif /* CONFIG_IEEE80211R_AP */
if (gtk) {
u8 hdr[2];
- hdr[0] = keyidx & 0x03;
+ hdr[0] = gtkidx & 0x03;
hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gtk_len);
}
-#ifdef CONFIG_IEEE80211W
opos = pos;
pos = ieee80211w_kde_add(sm, pos);
if (pos - opos >= 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
@@ -5082,7 +5068,6 @@
opos += 2 + RSN_SELECTOR_LEN + 2;
os_memset(opos, 0, 6); /* clear PN */
}
-#endif /* CONFIG_IEEE80211W */
if (ocv_oci_add(sm, &pos) < 0) {
os_free(kde);
return -1;
@@ -5139,7 +5124,7 @@
WPA_KEY_INFO_MIC : 0) |
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
WPA_KEY_INFO_KEY_TYPE,
- _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+ _rsc, sm->ANonce, kde, pos - kde, 0, encr);
os_free(kde);
return 0;
}
@@ -5153,9 +5138,7 @@
struct wpa_group *gsm = sm->group;
const u8 *kde;
u8 *kde_buf = NULL, *pos, hdr[2];
-#ifdef CONFIG_IEEE80211W
u8 *opos;
-#endif /* CONFIG_IEEE80211W */
size_t kde_len;
u8 *gtk;
@@ -5178,7 +5161,6 @@
hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gsm->GTK_len);
-#ifdef CONFIG_IEEE80211W
opos = pos;
pos = ieee80211w_kde_add(sm, pos);
if (pos - opos >=
@@ -5187,7 +5169,6 @@
opos += 2 + RSN_SELECTOR_LEN + 2;
os_memset(opos, 0, 6); /* clear PN */
}
-#endif /* CONFIG_IEEE80211W */
if (ocv_oci_add(sm, &pos) < 0) {
os_free(kde_buf);
return -1;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index a348bc2..f627838 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -187,11 +187,9 @@
int disable_pmksa_caching;
int okc;
int tx_status;
-#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
int group_mgmt_cipher;
int sae_require_mfp;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
int ocv; /* Operating Channel Validation */
#endif /* CONFIG_OCV */
@@ -232,6 +230,7 @@
unsigned int fils_cache_id_set:1;
u8 fils_cache_id[FILS_CACHE_ID_LEN];
#endif /* CONFIG_FILS */
+ int sae_pwe;
};
typedef enum {
@@ -320,6 +319,7 @@
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int freq,
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);
int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 696f8d5..a599be2 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2232,7 +2232,6 @@
}
-#ifdef CONFIG_IEEE80211W
static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
{
u8 *subelem, *pos;
@@ -2279,7 +2278,6 @@
*len = subelem_len;
return subelem;
}
-#endif /* CONFIG_IEEE80211W */
static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
@@ -2420,6 +2418,8 @@
u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
u8 *fte_mic, *elem_count;
size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0;
+ u8 rsnxe[10];
+ size_t rsnxe_len;
int res;
struct wpa_auth_config *conf;
struct wpa_ft_ies parse;
@@ -2487,7 +2487,6 @@
r0kh_id_len = sm->r0kh_id_len;
anonce = sm->ANonce;
snonce = sm->SNonce;
-#ifdef CONFIG_IEEE80211W
if (sm->mgmt_frame_prot) {
u8 *igtk;
size_t igtk_len;
@@ -2510,7 +2509,6 @@
subelem_len += igtk_len;
os_free(igtk);
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
@@ -2584,6 +2582,13 @@
if (ric_start == pos)
ric_start = NULL;
+ res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe, sizeof(rsnxe));
+ if (res < 0)
+ return NULL;
+ rsnxe_len = res;
+ if (auth_alg == WLAN_AUTH_FT && rsnxe_len)
+ *elem_count += 1;
+
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
kck = sm->PTK.kck2;
kck_len = sm->PTK.kck2_len;
@@ -2596,6 +2601,7 @@
mdie, mdie_len, ftie, ftie_len,
rsnie, rsnie_len,
ric_start, ric_start ? pos - ric_start : 0,
+ rsnxe_len ? rsnxe : NULL, rsnxe_len,
fte_mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
return NULL;
@@ -3253,6 +3259,8 @@
count = 3;
if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len);
+ if (parse.rsnxe)
+ count++;
if (fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
@@ -3272,6 +3280,8 @@
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
parse.ric, parse.ric_len,
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0,
mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -3290,6 +3300,9 @@
parse.ftie - 2, parse.ftie_len + 2);
wpa_hexdump(MSG_MSGDUMP, "FT: RSN",
parse.rsn - 2, parse.rsn_len + 2);
+ wpa_hexdump(MSG_MSGDUMP, "FT: RSNXE",
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0);
return WLAN_STATUS_INVALID_FTIE;
}
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 0800a87..ddab950 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -64,11 +64,9 @@
wconf->ocv = conf->ocv;
#endif /* CONFIG_OCV */
wconf->okc = conf->okc;
-#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = conf->ieee80211w;
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
wconf->sae_require_mfp = conf->sae_require_mfp;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
wconf->ssid_len = conf->ssid.ssid_len;
if (wconf->ssid_len > SSID_MAX_LEN)
@@ -107,9 +105,7 @@
wconf->rsn_pairwise = WPA_CIPHER_CCMP;
wconf->rsn_preauth = 0;
wconf->disable_pmksa_caching = 1;
-#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = 1;
-#endif /* CONFIG_IEEE80211W */
}
#endif /* CONFIG_HS20 */
#ifdef CONFIG_TESTING_OPTIONS
@@ -134,6 +130,7 @@
os_memcpy(wconf->fils_cache_id, conf->fils_cache_id,
FILS_CACHE_ID_LEN);
#endif /* CONFIG_FILS */
+ wconf->sae_pwe = conf->sae_pwe;
}
@@ -380,7 +377,6 @@
os_memcpy(sta->last_tk, key, key_len);
sta->last_tk_len = key_len;
}
-#ifdef CONFIG_IEEE80211W
} else if (alg == WPA_ALG_IGTK ||
alg == WPA_ALG_BIP_GMAC_128 ||
alg == WPA_ALG_BIP_GMAC_256 ||
@@ -390,7 +386,6 @@
if (key)
os_memcpy(hapd->last_igtk, key, key_len);
hapd->last_igtk_len = key_len;
-#endif /* CONFIG_IEEE80211W */
} else {
hapd->last_gtk_alg = alg;
hapd->last_gtk_key_idx = idx;
@@ -896,18 +891,28 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ int ret;
wpa_printf(MSG_DEBUG, "Add station entry for " MACSTR
" based on WPA authenticator callback",
MAC2STR(sta_addr));
- if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0)
+ ret = hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT);
+
+ /*
+ * The expected return values from hostapd_add_sta_node() are
+ * 0: successfully added STA entry
+ * -EOPNOTSUPP: driver or driver wrapper does not support/need this
+ * operations
+ * any other negative value: error in adding the STA entry */
+ if (ret < 0 && ret != -EOPNOTSUPP)
return NULL;
sta = ap_sta_add(hapd, sta_addr);
if (sta == NULL)
return NULL;
- if (hapd->driver && hapd->driver->add_sta_node)
+ if (ret == 0)
sta->added_unassoc = 1;
+
sta->ft_over_ds = 1;
if (sta->wpa_sm) {
sta->auth_alg = WLAN_AUTH_FT;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 4babd0c..a993f50 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -102,6 +102,8 @@
u8 *wpa_ie;
size_t wpa_ie_len;
+ u8 *rsnxe;
+ size_t rsnxe_len;
enum {
WPA_VERSION_NO_WPA = 0 /* WPA not used */,
@@ -190,10 +192,8 @@
Boolean changed;
Boolean first_sta_seen;
Boolean reject_4way_hs_for_entropy;
-#ifdef CONFIG_IEEE80211W
u8 IGTK[2][WPA_IGTK_MAX_LEN];
int GN_igtk, GM_igtk;
-#endif /* CONFIG_IEEE80211W */
/* Number of references except those in struct wpa_group->next */
unsigned int references;
unsigned int num_setup_iface;
@@ -269,6 +269,7 @@
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid);
+int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len);
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt);
void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 2e5c916..2e6d059 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -183,7 +183,6 @@
num_suites++;
}
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
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;
@@ -194,7 +193,6 @@
pos += RSN_SELECTOR_LEN;
num_suites++;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
@@ -286,13 +284,11 @@
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
-#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
if (conf->ocv)
capab |= WPA_CAPABILITY_OCVC;
@@ -314,7 +310,6 @@
pos += PMKID_LEN;
}
-#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
if (2 + 4 > buf + len - pos)
@@ -347,7 +342,6 @@
}
pos += RSN_SELECTOR_LEN;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -378,6 +372,26 @@
}
+int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
+{
+ u8 *pos = buf;
+
+ if (conf->sae_pwe != 1 && conf->sae_pwe != 2)
+ return 0; /* no supported extended RSN capabilities */
+
+ if (len < 3)
+ return -1;
+
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = 1;
+ /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
+ * used for now */
+ *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+
+ return pos - buf;
+}
+
+
static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
{
u8 *len;
@@ -411,13 +425,11 @@
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
-#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
if (conf->ocv)
capab |= WPA_CAPABILITY_OCVC;
@@ -464,6 +476,11 @@
if (res < 0)
return res;
pos += res;
+ res = wpa_write_rsnxe(&wpa_auth->conf, pos,
+ buf + sizeof(buf) - pos);
+ if (res < 0)
+ return res;
+ pos += res;
}
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
@@ -532,6 +549,7 @@
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int freq,
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)
{
@@ -607,12 +625,10 @@
else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
selector = RSN_AUTH_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
selector = RSN_AUTH_KEY_MGMT_SAE;
@@ -717,12 +733,10 @@
else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
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)
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (key_mgmt & WPA_KEY_MGMT_SAE)
sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
@@ -758,7 +772,6 @@
return WPA_INVALID_PAIRWISE;
}
-#ifdef CONFIG_IEEE80211W
if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
wpa_printf(MSG_DEBUG, "Management frame protection "
@@ -807,7 +820,6 @@
"Management frame protection cannot use TKIP");
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -941,6 +953,21 @@
os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
sm->wpa_ie_len = wpa_ie_len;
+ if (rsnxe && rsnxe_len) {
+ if (!sm->rsnxe || sm->rsnxe_len < rsnxe_len) {
+ os_free(sm->rsnxe);
+ sm->rsnxe = os_malloc(rsnxe_len);
+ if (!sm->rsnxe)
+ return WPA_ALLOC_FAIL;
+ }
+ os_memcpy(sm->rsnxe, rsnxe, rsnxe_len);
+ sm->rsnxe_len = rsnxe_len;
+ } else {
+ os_free(sm->rsnxe);
+ sm->rsnxe = NULL;
+ sm->rsnxe_len = 0;
+ }
+
return WPA_IE_OK;
}
@@ -975,153 +1002,6 @@
#endif /* CONFIG_HS20 */
-/**
- * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
- * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, 1 if end mark is found, -1 on failure
- */
-static int wpa_parse_generic(const u8 *pos, const u8 *end,
- struct wpa_eapol_ie_parse *ie)
-{
- if (pos[1] == 0)
- return 1;
-
- if (pos[1] >= 6 &&
- RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
- pos[2 + WPA_SELECTOR_LEN] == 1 &&
- pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
- ie->wpa_ie = pos;
- ie->wpa_ie_len = pos[1] + 2;
- return 0;
- }
-
- if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
- ie->osen = pos;
- ie->osen_len = pos[1] + 2;
- return 0;
- }
-
- if (1 + RSN_SELECTOR_LEN < end - pos &&
- pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
- ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
- ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
- ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
- ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-
-#ifdef CONFIG_IEEE80211W
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
- ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-#endif /* CONFIG_IEEE80211W */
-
-#ifdef CONFIG_P2P
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
- ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
- ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-
- if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
- ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG,
- "WPA: IP Address Allocation in EAPOL-Key",
- ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-#endif /* CONFIG_P2P */
-
-#ifdef CONFIG_OCV
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
- ie->oci = pos + 2 + RSN_SELECTOR_LEN;
- ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-#endif /* CONFIG_OCV */
-
- return 0;
-}
-
-
-/**
- * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
- * @buf: Pointer to the Key Data buffer
- * @len: Key Data Length
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, -1 on failure
- */
-int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
-{
- const u8 *pos, *end;
- int ret = 0;
-
- os_memset(ie, 0, sizeof(*ie));
- for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
- if (pos[0] == 0xdd &&
- ((pos == buf + len - 1) || pos[1] == 0)) {
- /* Ignore padding */
- break;
- }
- if (2 + pos[1] > end - pos) {
- wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
- "underflow (ie=%d len=%d pos=%d)",
- pos[0], pos[1], (int) (pos - buf));
- wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
- buf, len);
- ret = -1;
- break;
- }
- if (*pos == WLAN_EID_RSN) {
- ie->rsn_ie = pos;
- ie->rsn_ie_len = pos[1] + 2;
-#ifdef CONFIG_IEEE80211R_AP
- } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
- ie->mdie = pos;
- ie->mdie_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
- ie->ftie = pos;
- ie->ftie_len = pos[1] + 2;
-#endif /* CONFIG_IEEE80211R_AP */
- } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
- ret = wpa_parse_generic(pos, end, ie);
- if (ret < 0)
- break;
- if (ret > 0) {
- ret = 0;
- break;
- }
- } else {
- wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
- "Key Data IE", pos, 2 + pos[1]);
- }
- }
-
- return ret;
-}
-
-
int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
{
return sm ? sm->mgmt_frame_prot : 0;
diff --git a/src/ap/wpa_auth_ie.h b/src/ap/wpa_auth_ie.h
index a38b206..dd44b9e 100644
--- a/src/ap/wpa_auth_ie.h
+++ b/src/ap/wpa_auth_ie.h
@@ -9,41 +9,6 @@
#ifndef WPA_AUTH_IE_H
#define WPA_AUTH_IE_H
-struct wpa_eapol_ie_parse {
- const u8 *wpa_ie;
- size_t wpa_ie_len;
- const u8 *rsn_ie;
- size_t rsn_ie_len;
- const u8 *pmkid;
- const u8 *gtk;
- size_t gtk_len;
- const u8 *mac_addr;
- size_t mac_addr_len;
-#ifdef CONFIG_IEEE80211W
- const u8 *igtk;
- size_t igtk_len;
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R_AP
- const u8 *mdie;
- size_t mdie_len;
- const u8 *ftie;
- size_t ftie_len;
-#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_P2P
- const u8 *ip_addr_req;
- const u8 *ip_addr_alloc;
-#endif /* CONFIG_P2P */
-#ifdef CONFIG_OCV
- const u8 *oci;
- size_t oci_len;
-#endif /* CONFIG_OCV */
-
- const u8 *osen;
- size_t osen_len;
-};
-
-int wpa_parse_kde_ies(const u8 *buf, size_t len,
- struct wpa_eapol_ie_parse *ie);
u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
const u8 *data2, size_t data2_len);
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth);
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 6161cdb..33caeaf 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -358,12 +358,10 @@
(cred->auth_type & WPS_AUTH_WPA2PSK) &&
cred->key_len != 2 * PMK_LEN) {
bss->wpa_key_mgmt |= WPA_KEY_MGMT_SAE;
-#ifdef CONFIG_IEEE80211W
if (bss->ieee80211w == NO_MGMT_FRAME_PROTECTION)
bss->ieee80211w =
MGMT_FRAME_PROTECTION_OPTIONAL;
bss->sae_require_mfp = 1;
-#endif /* CONFIG_IEEE80211W */
}
if (cred->key_len >= 8 && cred->key_len < 64) {
@@ -533,9 +531,7 @@
if (wpa) {
char *prefix;
-#ifdef CONFIG_IEEE80211W
int sae = 0;
-#endif /* CONFIG_IEEE80211W */
fprintf(nconf, "wpa=%d\n", wpa);
@@ -553,13 +549,10 @@
(cred->auth_type & WPS_AUTH_WPA2PSK) &&
cred->key_len != 2 * PMK_LEN) {
fprintf(nconf, "%sSAE", prefix);
-#ifdef CONFIG_IEEE80211W
sae = 1;
-#endif /* CONFIG_IEEE80211W */
}
fprintf(nconf, "\n");
-#ifdef CONFIG_IEEE80211W
if (sae && hapd->conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
fprintf(nconf, "ieee80211w=%d\n",
MGMT_FRAME_PROTECTION_OPTIONAL);
@@ -567,7 +560,6 @@
}
if (sae)
fprintf(nconf, "sae_require_mfp=1\n");
-#endif /* CONFIG_IEEE80211W */
fprintf(nconf, "wpa_pairwise=");
prefix = "";
diff --git a/src/common/Makefile b/src/common/Makefile
index e703630..ccb280e 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -9,7 +9,6 @@
include ../lib.rules
CFLAGS += -DCONFIG_IEEE80211R
-CFLAGS += -DCONFIG_IEEE80211W
CFLAGS += -DCONFIG_HS20
CFLAGS += -DCONFIG_SAE
CFLAGS += -DCONFIG_SUITE
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 30c5247..fb0cf43 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "utils/module_tests.h"
#include "crypto/crypto.h"
+#include "crypto/dh_groups.h"
#include "ieee802_11_common.h"
#include "ieee802_11_defs.h"
#include "gas.h"
@@ -258,6 +259,7 @@
/* IEEE P802.11-REVmd/D2.1, Annex J.10 */
const u8 addr1[ETH_ALEN] = { 0x82, 0x7b, 0x91, 0x9d, 0xd4, 0xb9 };
const u8 addr2[ETH_ALEN] = { 0x1e, 0xec, 0x49, 0xea, 0x64, 0x88 };
+ const char *ssid = "byteme";
const char *pw = "mekmitasdigoat";
const char *pwid = "psk4internet";
const u8 local_rand[] = {
@@ -338,6 +340,72 @@
};
struct wpabuf *buf = NULL;
struct crypto_bignum *mask = NULL;
+ const u8 pwe_19_x[32] = {
+ 0x19, 0xd3, 0x37, 0xc9, 0x30, 0x79, 0x2b, 0x47,
+ 0x2b, 0x14, 0x5f, 0xc1, 0x5b, 0x98, 0x64, 0x0a,
+ 0x0e, 0x7d, 0x3b, 0xb0, 0x7d, 0xc0, 0xad, 0xee,
+ 0x6f, 0xc9, 0xdf, 0x75, 0xde, 0xc2, 0xd6, 0x94
+ };
+ const u8 pwe_19_y[32] = {
+ 0xb7, 0x8a, 0x02, 0x39, 0x20, 0x29, 0xe7, 0xf4,
+ 0x52, 0x41, 0x3d, 0x35, 0x8c, 0x88, 0xd9, 0x16,
+ 0xc8, 0x90, 0xba, 0x40, 0xd9, 0x93, 0xe3, 0x2d,
+ 0xd0, 0x0f, 0xfb, 0x58, 0xee, 0x62, 0x74, 0x98
+ };
+ const u8 pwe_15[384] = {
+ 0x59, 0x00, 0x9a, 0x32, 0xbb, 0x37, 0x84, 0x60,
+ 0x27, 0xeb, 0x70, 0x20, 0x57, 0x34, 0xf1, 0xb4,
+ 0xde, 0x1b, 0x48, 0xfc, 0x0e, 0xa5, 0xb8, 0x65,
+ 0xb1, 0xa0, 0xd4, 0xb9, 0x42, 0x1d, 0x6d, 0xdf,
+ 0x8b, 0x86, 0xeb, 0x4a, 0x2c, 0x2e, 0x38, 0x06,
+ 0x52, 0xae, 0x67, 0x39, 0xed, 0x7d, 0x0c, 0xd0,
+ 0xea, 0x30, 0x6e, 0x50, 0xe7, 0xb1, 0x8d, 0x91,
+ 0xf0, 0x05, 0x1f, 0x16, 0xf5, 0x45, 0xa7, 0x37,
+ 0x21, 0x0d, 0x8a, 0x69, 0x9a, 0xd1, 0xf1, 0x8c,
+ 0x2b, 0xbb, 0xd8, 0x21, 0xa2, 0x8f, 0xcc, 0xd1,
+ 0x35, 0x98, 0x66, 0xf3, 0x3c, 0x03, 0xba, 0x70,
+ 0x72, 0x4e, 0xe4, 0x23, 0xb5, 0x2e, 0x96, 0x5f,
+ 0xdd, 0xd1, 0xae, 0x71, 0xb1, 0xc1, 0x4b, 0x69,
+ 0x4e, 0x60, 0x0a, 0x08, 0x02, 0xa1, 0x6e, 0x80,
+ 0x68, 0x0a, 0xe7, 0x97, 0x9f, 0x5b, 0xbf, 0xa8,
+ 0x77, 0xda, 0x5b, 0x26, 0x13, 0x0a, 0xab, 0x92,
+ 0x79, 0x87, 0xa3, 0x85, 0x78, 0x74, 0xae, 0xae,
+ 0x01, 0xf0, 0x31, 0x8a, 0xc3, 0x96, 0xce, 0xaa,
+ 0x57, 0xbf, 0xb3, 0x57, 0xce, 0x2d, 0x2d, 0x36,
+ 0xda, 0x02, 0x5b, 0x12, 0xeb, 0xff, 0x13, 0x00,
+ 0x9e, 0xf7, 0xae, 0xe0, 0x47, 0xa4, 0x5d, 0x0a,
+ 0x88, 0x65, 0xbc, 0x66, 0x23, 0x3e, 0xf2, 0xf1,
+ 0xa0, 0x64, 0x5c, 0x6b, 0xdc, 0x81, 0xe9, 0x3c,
+ 0x46, 0x4f, 0x83, 0xcf, 0x9f, 0x55, 0x33, 0x8f,
+ 0xaa, 0x60, 0x4b, 0xd7, 0x21, 0x73, 0x6b, 0xdb,
+ 0x26, 0xad, 0x2f, 0xb7, 0xe2, 0x42, 0x56, 0x33,
+ 0xdb, 0xd6, 0xb2, 0x3a, 0x7d, 0x75, 0x87, 0xda,
+ 0x86, 0xc4, 0xe9, 0x41, 0x8d, 0x63, 0x19, 0x8e,
+ 0x8b, 0x17, 0x95, 0xfe, 0x2b, 0x96, 0xa0, 0x38,
+ 0xf1, 0xe2, 0x1d, 0x42, 0xa9, 0xe3, 0x8a, 0xa1,
+ 0x61, 0x62, 0x10, 0xf8, 0xb3, 0xb2, 0x2c, 0x7b,
+ 0xdf, 0xba, 0x74, 0xb2, 0x5b, 0xf6, 0xa9, 0xae,
+ 0x1d, 0x21, 0x0d, 0xc0, 0x48, 0x20, 0xfc, 0x28,
+ 0xf6, 0x22, 0xd2, 0xf6, 0x9c, 0x71, 0x3f, 0x9f,
+ 0x32, 0xd6, 0xbb, 0x9b, 0xd3, 0x87, 0x25, 0xcf,
+ 0x62, 0xd1, 0x68, 0xba, 0x55, 0x3b, 0x74, 0x2b,
+ 0x1d, 0x5a, 0xe4, 0x94, 0x59, 0x3b, 0x13, 0x21,
+ 0x15, 0x87, 0x3b, 0x09, 0x0e, 0xcf, 0x35, 0x60,
+ 0x04, 0xa8, 0xde, 0xa1, 0x09, 0xca, 0xb8, 0x35,
+ 0x1e, 0x16, 0x61, 0xed, 0xa1, 0x1f, 0x8c, 0x92,
+ 0x83, 0xa5, 0x27, 0x92, 0xf2, 0x80, 0xc3, 0xcb,
+ 0xdd, 0x3c, 0x0c, 0xf5, 0x8d, 0x69, 0xb3, 0xe4,
+ 0xd5, 0x49, 0x4d, 0x62, 0xcb, 0xb8, 0xe3, 0x9f,
+ 0x89, 0xb5, 0x57, 0xff, 0xef, 0x12, 0x37, 0x05,
+ 0xb6, 0x35, 0xe5, 0xc6, 0xd9, 0x23, 0xe2, 0xeb,
+ 0xe4, 0x0d, 0x1a, 0x30, 0x8f, 0x73, 0x70, 0x3a,
+ 0xef, 0x5a, 0xd1, 0x8c, 0x18, 0x34, 0x1e, 0xf0,
+ 0xb9, 0x08, 0x57, 0xab, 0xcb, 0x5c, 0x87, 0x10
+ };
+ int pt_groups[] = { 19, 20, 21, 25, 26, 28, 29, 30, 15, 0 };
+ struct sae_pt *pt_info, *pt;
+ u8 addr1b[ETH_ALEN] = { 0x3b, 0x36, 0xc2, 0x8b, 0x83, 0x03 };
+ u8 addr2b[ETH_ALEN] = { 0x58, 0x36, 0xc0, 0x64, 0x2d, 0x31 };
os_memset(&sae, 0, sizeof(sae));
buf = wpabuf_alloc(1000);
@@ -377,7 +445,7 @@
}
if (sae_parse_commit(&sae, peer_commit, sizeof(peer_commit), NULL, NULL,
- NULL) != 0 ||
+ NULL, 0) != 0 ||
sae_process_commit(&sae) < 0)
goto fail;
@@ -411,6 +479,62 @@
if (sae_check_confirm(&sae, peer_confirm, sizeof(peer_confirm)) < 0)
goto fail;
+ pt_info = sae_derive_pt(pt_groups,
+ (const u8 *) ssid, os_strlen(ssid),
+ (const u8 *) pw, os_strlen(pw), pwid);
+ if (!pt_info)
+ goto fail;
+
+ for (pt = pt_info; pt; pt = pt->next) {
+ if (pt->group == 19) {
+ struct crypto_ec_point *pwe;
+ u8 bin[SAE_MAX_ECC_PRIME_LEN * 2];
+ size_t prime_len = sizeof(pwe_19_x);
+
+ pwe = sae_derive_pwe_from_pt_ecc(pt, addr1b, addr2b);
+ if (!pwe) {
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ if (crypto_ec_point_to_bin(pt->ec, pwe, bin,
+ bin + prime_len) < 0 ||
+ os_memcmp(pwe_19_x, bin, prime_len) != 0 ||
+ os_memcmp(pwe_19_y, bin + prime_len,
+ prime_len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE: PT/PWE test vector mismatch");
+ crypto_ec_point_deinit(pwe, 1);
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ crypto_ec_point_deinit(pwe, 1);
+ }
+
+ if (pt->group == 15) {
+ struct crypto_bignum *pwe;
+ u8 bin[SAE_MAX_PRIME_LEN];
+ size_t prime_len = sizeof(pwe_15);
+
+ pwe = sae_derive_pwe_from_pt_ffc(pt, addr1b, addr2b);
+ if (!pwe) {
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ if (crypto_bignum_to_bin(pwe, bin, sizeof(bin),
+ prime_len) < 0 ||
+ os_memcmp(pwe_15, bin, prime_len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE: PT/PWE test vector mismatch");
+ crypto_bignum_deinit(pwe, 1);
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ crypto_bignum_deinit(pwe, 1);
+ }
+ }
+
+ sae_deinit_pt(pt_info);
+
ret = 0;
fail:
sae_clear_data(&sae);
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 3eb86c5..ab7072c 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -610,6 +610,91 @@
}
+static int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer,
+ u8 *secret, size_t *secret_len)
+{
+ EVP_PKEY_CTX *ctx;
+ int ret = -1;
+
+ ERR_clear_error();
+ *secret_len = 0;
+
+ ctx = EVP_PKEY_CTX_new(own, NULL);
+ if (!ctx) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ if (EVP_PKEY_derive_init(ctx) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive_init failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (EVP_PKEY_derive_set_peer(ctx, peer) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: EVP_PKEY_derive_set_peet failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive(NULL) failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
+ u8 buf[200];
+ int level = *secret_len > 200 ? MSG_ERROR : MSG_DEBUG;
+
+ /* It looks like OpenSSL can return unexpectedly large buffer
+ * need for shared secret from EVP_PKEY_derive(NULL) in some
+ * cases. For example, group 19 has shown cases where secret_len
+ * is set to 72 even though the actual length ends up being
+ * updated to 32 when EVP_PKEY_derive() is called with a buffer
+ * for the value. Work around this by trying to fetch the value
+ * and continue if it is within supported range even when the
+ * initial buffer need is claimed to be larger. */
+ wpa_printf(level,
+ "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
+ (int) *secret_len);
+ if (*secret_len > 200)
+ goto fail;
+ if (EVP_PKEY_derive(ctx, buf, secret_len) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
+ (int) *secret_len);
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: Unexpected secret_len change",
+ buf, *secret_len);
+ os_memcpy(secret, buf, *secret_len);
+ forced_memzero(buf, sizeof(buf));
+ goto done;
+ }
+
+ if (EVP_PKEY_derive(ctx, secret, secret_len) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+done:
+ ret = 0;
+
+fail:
+ EVP_PKEY_CTX_free(ctx);
+ return ret;
+}
+
+
static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
{
wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
@@ -657,6 +742,34 @@
}
+static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len,
+ u16 req_id, u16 *ret_len)
+{
+ u16 id, alen;
+ const u8 *pos, *end = buf + len;
+
+ if (!prev)
+ pos = buf;
+ else
+ pos = prev + WPA_GET_LE16(prev - 2);
+ while (end - pos >= 4) {
+ id = WPA_GET_LE16(pos);
+ pos += 2;
+ alen = WPA_GET_LE16(pos);
+ pos += 2;
+ if (alen > end - pos)
+ return NULL;
+ if (id == req_id) {
+ *ret_len = alen;
+ return pos;
+ }
+ pos += alen;
+ }
+
+ return NULL;
+}
+
+
int dpp_check_attrs(const u8 *buf, size_t len)
{
const u8 *pos, *end;
@@ -2142,7 +2255,6 @@
{
struct dpp_authentication *auth;
size_t nonce_len;
- EVP_PKEY_CTX *ctx = NULL;
size_t secret_len;
struct wpabuf *pi = NULL;
const u8 *r_pubkey_hash, *i_pubkey_hash;
@@ -2211,21 +2323,10 @@
goto fail;
/* ECDH: M = pI * BR */
- ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, auth->peer_bi->pubkey) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
- secret_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(auth->own_protocol_key, auth->peer_bi->pubkey,
+ auth->Mx, &secret_len) < 0)
goto fail;
- }
auth->secret_len = secret_len;
- EVP_PKEY_CTX_free(ctx);
- ctx = NULL;
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
auth->Mx, auth->secret_len);
@@ -2277,7 +2378,6 @@
out:
wpabuf_free(pi);
- EVP_PKEY_CTX_free(ctx);
return auth;
fail:
dpp_auth_deinit(auth);
@@ -2304,7 +2404,7 @@
}
wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
json_len = os_strlen(json);
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: configAttr JSON", json, json_len);
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len);
/* { E-nonce, configAttrib }ke */
clear_len = 4 + nonce_len + 4 + json_len;
@@ -2440,6 +2540,67 @@
}
+struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
+ const char *name, int netrole_ap,
+ const char *mud_url, int *opclasses)
+{
+ size_t len, nlen;
+ const char *tech = "infra";
+ const char *dpp_name;
+ char *nbuf;
+ struct wpabuf *buf, *json;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
+ static const char *bogus_tech = "knfra";
+
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
+ tech = bogus_tech;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ dpp_name = name ? name : "Test";
+ len = os_strlen(dpp_name);
+ nlen = len * 6 + 1;
+ nbuf = os_malloc(nlen);
+ if (!nbuf)
+ return NULL;
+ json_escape_string(nbuf, nlen, dpp_name, len);
+
+ len = 100 + os_strlen(nbuf) + int_array_len(opclasses) * 4;
+ if (mud_url && mud_url[0])
+ len += 10 + os_strlen(mud_url);
+ json = wpabuf_alloc(len);
+ if (!json) {
+ os_free(nbuf);
+ return NULL;
+ }
+
+ wpabuf_printf(json,
+ "{\"name\":\"%s\","
+ "\"wi-fi_tech\":\"%s\","
+ "\"netRole\":\"%s\"",
+ nbuf, tech, netrole_ap ? "ap" : "sta");
+ if (mud_url && mud_url[0])
+ wpabuf_printf(json, ",\"mudurl\":\"%s\"", mud_url);
+ if (opclasses) {
+ int i;
+
+ wpabuf_put_str(json, ",\"bandSupport\":[");
+ for (i = 0; opclasses[i]; i++)
+ wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
+ wpabuf_put_str(json, "]");
+ }
+ wpabuf_put_str(json, "}");
+ os_free(nbuf);
+
+ buf = dpp_build_conf_req(auth, wpabuf_head(json));
+ wpabuf_free(json);
+
+ return buf;
+}
+
+
static void dpp_auth_success(struct dpp_authentication *auth)
{
wpa_printf(MSG_DEBUG,
@@ -2750,7 +2911,6 @@
static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
{
size_t nonce_len;
- EVP_PKEY_CTX *ctx = NULL;
size_t secret_len;
struct wpabuf *msg, *pr = NULL;
u8 r_auth[4 + DPP_MAX_HASH_LEN];
@@ -2813,20 +2973,9 @@
goto fail;
/* ECDH: N = pR * PI */
- ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, auth->peer_protocol_key) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
- secret_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
+ auth->Nx, &secret_len) < 0)
goto fail;
- }
- EVP_PKEY_CTX_free(ctx);
- ctx = NULL;
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
auth->Nx, auth->secret_len);
@@ -3122,22 +3271,9 @@
}
dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
- ctx = EVP_PKEY_CTX_new(own_bi->pubkey, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pi) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
- secret_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
- dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
+ if (dpp_ecdh(own_bi->pubkey, pi, auth->Mx, &secret_len) < 0)
goto fail;
- }
auth->secret_len = secret_len;
- EVP_PKEY_CTX_free(ctx);
- ctx = NULL;
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
auth->Mx, auth->secret_len);
@@ -3591,7 +3727,6 @@
const u8 *attr_start, size_t attr_len)
{
EVP_PKEY *pr;
- EVP_PKEY_CTX *ctx = NULL;
size_t secret_len;
const u8 *addr[2];
size_t len[2];
@@ -3741,21 +3876,10 @@
}
dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
- ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pr) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
- secret_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(auth->own_protocol_key, pr, auth->Nx, &secret_len) < 0) {
dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
goto fail;
}
- EVP_PKEY_CTX_free(ctx);
- ctx = NULL;
EVP_PKEY_free(auth->peer_protocol_key);
auth->peer_protocol_key = pr;
pr = NULL;
@@ -3927,7 +4051,6 @@
bin_clear_free(unwrapped, unwrapped_len);
bin_clear_free(unwrapped2, unwrapped2_len);
EVP_PKEY_free(pr);
- EVP_PKEY_CTX_free(ctx);
return NULL;
}
@@ -4265,8 +4388,8 @@
}
-static int dpp_configuration_parse(struct dpp_authentication *auth,
- const char *cmd)
+static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
+ const char *cmd, int idx)
{
const char *pos, *end;
struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
@@ -4277,6 +4400,7 @@
conf_sta = dpp_configuration_alloc(pos + 10);
if (!conf_sta)
goto fail;
+ conf_sta->netrole = DPP_NETROLE_STA;
conf = conf_sta;
}
@@ -4285,6 +4409,7 @@
conf_ap = dpp_configuration_alloc(pos + 9);
if (!conf_ap)
goto fail;
+ conf_ap->netrole = DPP_NETROLE_AP;
conf = conf_ap;
}
@@ -4362,8 +4487,15 @@
if (!dpp_configuration_valid(conf))
goto fail;
- auth->conf_sta = conf_sta;
- auth->conf_ap = conf_ap;
+ if (idx == 0) {
+ auth->conf_sta = conf_sta;
+ auth->conf_ap = conf_ap;
+ } else if (idx == 1) {
+ auth->conf2_sta = conf_sta;
+ auth->conf2_ap = conf_ap;
+ } else {
+ goto fail;
+ }
return 0;
fail:
@@ -4373,6 +4505,41 @@
}
+static int dpp_configuration_parse(struct dpp_authentication *auth,
+ const char *cmd)
+{
+ const char *pos;
+ char *tmp;
+ size_t len;
+ int res;
+
+ pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
+ if (!pos)
+ return dpp_configuration_parse_helper(auth, cmd, 0);
+
+ len = pos - cmd;
+ tmp = os_malloc(len + 1);
+ if (!tmp)
+ goto fail;
+ os_memcpy(tmp, cmd, len);
+ tmp[len] = '\0';
+ res = dpp_configuration_parse_helper(auth, cmd, 0);
+ str_clear_free(tmp);
+ if (res)
+ goto fail;
+ res = dpp_configuration_parse_helper(auth, cmd + len, 1);
+ if (res)
+ goto fail;
+ return 0;
+fail:
+ dpp_configuration_free(auth->conf_sta);
+ dpp_configuration_free(auth->conf2_sta);
+ dpp_configuration_free(auth->conf_ap);
+ dpp_configuration_free(auth->conf2_ap);
+ return -1;
+}
+
+
static struct dpp_configurator *
dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
{
@@ -4412,6 +4579,18 @@
}
}
+ pos = os_strstr(cmd, " conn_status=");
+ if (pos) {
+ pos += 13;
+ auth->send_conn_status = atoi(pos);
+ }
+
+ pos = os_strstr(cmd, " akm_use_selector=");
+ if (pos) {
+ pos += 18;
+ auth->akm_use_selector = atoi(pos);
+ }
+
if (dpp_configuration_parse(auth, cmd) < 0) {
wpa_msg(msg_ctx, MSG_INFO,
"DPP: Failed to set configurator parameters");
@@ -4423,18 +4602,26 @@
void dpp_auth_deinit(struct dpp_authentication *auth)
{
+ unsigned int i;
+
if (!auth)
return;
dpp_configuration_free(auth->conf_ap);
+ dpp_configuration_free(auth->conf2_ap);
dpp_configuration_free(auth->conf_sta);
+ dpp_configuration_free(auth->conf2_sta);
EVP_PKEY_free(auth->own_protocol_key);
EVP_PKEY_free(auth->peer_protocol_key);
wpabuf_free(auth->req_msg);
wpabuf_free(auth->resp_msg);
wpabuf_free(auth->conf_req);
- os_free(auth->connector);
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ struct dpp_config_obj *conf = &auth->conf_obj[i];
+
+ os_free(conf->connector);
+ wpabuf_free(conf->c_sign_key);
+ }
wpabuf_free(auth->net_access_key);
- wpabuf_free(auth->c_sign_key);
dpp_bootstrap_info_free(auth->tmp_own_bi);
#ifdef CONFIG_TESTING_OPTIONS
os_free(auth->config_obj_override);
@@ -4545,8 +4732,21 @@
}
+static const char * dpp_netrole_str(enum dpp_netrole netrole)
+{
+ switch (netrole) {
+ case DPP_NETROLE_STA:
+ return "sta";
+ case DPP_NETROLE_AP:
+ return "ap";
+ default:
+ return "??";
+ }
+}
+
+
static struct wpabuf *
-dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
+dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
struct dpp_configuration *conf)
{
struct wpabuf *buf = NULL;
@@ -4567,6 +4767,7 @@
size_t extra_len = 1000;
int incl_legacy;
enum dpp_akm akm;
+ const char *akm_str;
if (!auth->conf) {
wpa_printf(MSG_INFO,
@@ -4620,7 +4821,8 @@
#endif /* CONFIG_TESTING_OPTIONS */
wpabuf_printf(dppcon, "{\"groups\":[{\"groupId\":\"%s\",",
conf->group_id ? conf->group_id : "*");
- wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
+ wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],",
+ dpp_netrole_str(conf->netrole));
#ifdef CONFIG_TESTING_OPTIONS
skip_groups:
#endif /* CONFIG_TESTING_OPTIONS */
@@ -4719,7 +4921,11 @@
if (!buf)
goto fail;
- wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm));
+ if (auth->akm_use_selector && dpp_akm_ver2(akm))
+ akm_str = dpp_akm_selector_str(akm);
+ else
+ akm_str = dpp_akm_str(akm);
+ wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", akm_str);
if (incl_legacy) {
dpp_build_legacy_cred_params(buf, conf);
wpabuf_put_str(buf, ",");
@@ -4760,16 +4966,21 @@
static struct wpabuf *
-dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
+dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
struct dpp_configuration *conf)
{
struct wpabuf *buf;
+ const char *akm_str;
buf = dpp_build_conf_start(auth, conf, 1000);
if (!buf)
return NULL;
- wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm));
+ if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
+ akm_str = dpp_akm_selector_str(conf->akm);
+ else
+ akm_str = dpp_akm_str(conf->akm);
+ wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", akm_str);
dpp_build_legacy_cred_params(buf, conf);
wpabuf_put_str(buf, "}}");
@@ -4781,29 +4992,37 @@
static struct wpabuf *
-dpp_build_conf_obj(struct dpp_authentication *auth, int ap)
+dpp_build_conf_obj(struct dpp_authentication *auth, int ap, int idx)
{
struct dpp_configuration *conf;
#ifdef CONFIG_TESTING_OPTIONS
if (auth->config_obj_override) {
+ if (idx != 0)
+ return NULL;
wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
return wpabuf_alloc_copy(auth->config_obj_override,
os_strlen(auth->config_obj_override));
}
#endif /* CONFIG_TESTING_OPTIONS */
- conf = ap ? auth->conf_ap : auth->conf_sta;
+ if (idx == 0)
+ conf = ap ? auth->conf_ap : auth->conf_sta;
+ else if (idx == 1)
+ conf = ap ? auth->conf2_ap : auth->conf2_sta;
+ else
+ conf = NULL;
if (!conf) {
- wpa_printf(MSG_DEBUG,
- "DPP: No configuration available for Enrollee(%s) - reject configuration request",
- ap ? "ap" : "sta");
+ if (idx == 0)
+ wpa_printf(MSG_DEBUG,
+ "DPP: No configuration available for Enrollee(%s) - reject configuration request",
+ ap ? "ap" : "sta");
return NULL;
}
if (dpp_akm_dpp(conf->akm))
- return dpp_build_conf_obj_dpp(auth, ap, conf);
- return dpp_build_conf_obj_legacy(auth, ap, conf);
+ return dpp_build_conf_obj_dpp(auth, conf);
+ return dpp_build_conf_obj_legacy(auth, conf);
}
@@ -4811,7 +5030,7 @@
dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
u16 e_nonce_len, int ap)
{
- struct wpabuf *conf;
+ struct wpabuf *conf, *conf2 = NULL;
size_t clear_len, attr_len;
struct wpabuf *clear = NULL, *msg = NULL;
u8 *wrapped;
@@ -4819,18 +5038,23 @@
size_t len[1];
enum dpp_status_error status;
- conf = dpp_build_conf_obj(auth, ap);
+ conf = dpp_build_conf_obj(auth, ap, 0);
if (conf) {
wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
wpabuf_head(conf), wpabuf_len(conf));
+ conf2 = dpp_build_conf_obj(auth, ap, 1);
}
status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
auth->conf_resp_status = status;
- /* { E-nonce, configurationObject}ke */
+ /* { E-nonce, configurationObject[, sendConnStatus]}ke */
clear_len = 4 + e_nonce_len;
if (conf)
clear_len += 4 + wpabuf_len(conf);
+ if (conf2)
+ clear_len += 4 + wpabuf_len(conf2);
+ if (auth->peer_version >= 2 && auth->send_conn_status && !ap)
+ clear_len += 4;
clear = wpabuf_alloc(clear_len);
attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
#ifdef CONFIG_TESTING_OPTIONS
@@ -4878,6 +5102,20 @@
wpabuf_put_le16(clear, wpabuf_len(conf));
wpabuf_put_buf(clear, conf);
}
+ if (auth->peer_version >= 2 && conf2) {
+ wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
+ wpabuf_put_le16(clear, wpabuf_len(conf2));
+ wpabuf_put_buf(clear, conf2);
+ } else if (conf2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Second Config Object available, but peer does not support more than one");
+ }
+
+ if (auth->peer_version >= 2 && auth->send_conn_status && !ap) {
+ wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
+ wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
+ wpabuf_put_le16(clear, 0);
+ }
#ifdef CONFIG_TESTING_OPTIONS
skip_config_obj:
@@ -4926,6 +5164,7 @@
"DPP: Configuration Response attributes", msg);
out:
wpabuf_free(conf);
+ wpabuf_free(conf2);
wpabuf_free(clear);
return msg;
@@ -5054,6 +5293,26 @@
goto fail;
}
+ token = json_get_member(root, "mudurl");
+ if (token && token->type == JSON_STRING)
+ wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
+
+ token = json_get_member(root, "bandSupport");
+ if (token && token->type == JSON_ARRAY) {
+ wpa_printf(MSG_DEBUG, "DPP: bandSupport");
+ token = token->child;
+ while (token) {
+ if (token->type != JSON_NUMBER)
+ wpa_printf(MSG_DEBUG,
+ "DPP: Invalid bandSupport array member type");
+ else
+ wpa_printf(MSG_DEBUG,
+ "DPP: Supported global operating class: %d",
+ token->number);
+ token = token->sibling;
+ }
+ }
+
resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
fail:
@@ -5143,7 +5402,7 @@
}
-static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
+static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
struct json_token *cred)
{
struct json_token *pass, *psk_hex;
@@ -5160,28 +5419,28 @@
pass->string, len);
if (len < 8 || len > 63)
return -1;
- os_strlcpy(auth->passphrase, pass->string,
- sizeof(auth->passphrase));
+ os_strlcpy(conf->passphrase, pass->string,
+ sizeof(conf->passphrase));
} else if (psk_hex && psk_hex->type == JSON_STRING) {
- if (dpp_akm_sae(auth->akm) && !dpp_akm_psk(auth->akm)) {
+ if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
wpa_printf(MSG_DEBUG,
"DPP: Unexpected psk_hex with akm=sae");
return -1;
}
if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
- hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) {
+ hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
- auth->psk, PMK_LEN);
- auth->psk_set = 1;
+ conf->psk, PMK_LEN);
+ conf->psk_set = 1;
} else {
wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
return -1;
}
- if (dpp_akm_sae(auth->akm) && !auth->passphrase[0]) {
+ if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
return -1;
}
@@ -5349,6 +5608,7 @@
static int dpp_parse_connector(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf,
const unsigned char *payload,
u16 payload_len)
{
@@ -5476,7 +5736,7 @@
}
-static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
+static void dpp_copy_csign(struct dpp_config_obj *conf, EVP_PKEY *csign)
{
unsigned char *der = NULL;
int der_len;
@@ -5484,13 +5744,14 @@
der_len = i2d_PUBKEY(csign, &der);
if (der_len <= 0)
return;
- wpabuf_free(auth->c_sign_key);
- auth->c_sign_key = wpabuf_alloc_copy(der, der_len);
+ wpabuf_free(conf->c_sign_key);
+ conf->c_sign_key = wpabuf_alloc_copy(der, der_len);
OPENSSL_free(der);
}
-static void dpp_copy_netaccesskey(struct dpp_authentication *auth)
+static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
unsigned char *der = NULL;
int der_len;
@@ -5684,6 +5945,7 @@
static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf,
struct json_token *cred)
{
struct dpp_signed_connector_info info;
@@ -5695,10 +5957,10 @@
os_memset(&info, 0, sizeof(info));
- if (dpp_akm_psk(auth->akm) || dpp_akm_sae(auth->akm)) {
+ if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
wpa_printf(MSG_DEBUG,
"DPP: Legacy credential included in Connector credential");
- if (dpp_parse_cred_legacy(auth, cred) < 0)
+ if (dpp_parse_cred_legacy(conf, cred) < 0)
return -1;
}
@@ -5737,16 +5999,17 @@
signed_connector) != DPP_STATUS_OK)
goto fail;
- if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
+ if (dpp_parse_connector(auth, conf,
+ info.payload, info.payload_len) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
goto fail;
}
- os_free(auth->connector);
- auth->connector = os_strdup(signed_connector);
+ os_free(conf->connector);
+ conf->connector = os_strdup(signed_connector);
- dpp_copy_csign(auth, csign_pub);
- dpp_copy_netaccesskey(auth);
+ dpp_copy_csign(conf, csign_pub);
+ dpp_copy_netaccesskey(auth, conf);
ret = 0;
fail:
@@ -5777,8 +6040,32 @@
}
+const char * dpp_akm_selector_str(enum dpp_akm akm)
+{
+ switch (akm) {
+ case DPP_AKM_DPP:
+ return "506F9A02";
+ case DPP_AKM_PSK:
+ return "000FAC02+000FAC06";
+ case DPP_AKM_SAE:
+ return "000FAC08";
+ case DPP_AKM_PSK_SAE:
+ return "000FAC02+000FAC06+000FAC08";
+ case DPP_AKM_SAE_DPP:
+ return "506F9A02+000FAC08";
+ case DPP_AKM_PSK_SAE_DPP:
+ return "506F9A02+000FAC08+000FAC02+000FAC06";
+ default:
+ return "??";
+ }
+}
+
+
static enum dpp_akm dpp_akm_from_str(const char *akm)
{
+ const char *pos;
+ int dpp = 0, psk = 0, sae = 0;
+
if (os_strcmp(akm, "psk") == 0)
return DPP_AKM_PSK;
if (os_strcmp(akm, "sae") == 0)
@@ -5791,6 +6078,38 @@
return DPP_AKM_SAE_DPP;
if (os_strcmp(akm, "dpp+psk+sae") == 0)
return DPP_AKM_PSK_SAE_DPP;
+
+ pos = akm;
+ while (*pos) {
+ if (os_strlen(pos) < 8)
+ break;
+ if (os_strncasecmp(pos, "506F9A02", 8) == 0)
+ dpp = 1;
+ else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
+ psk = 1;
+ else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
+ psk = 1;
+ else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
+ sae = 1;
+ pos += 8;
+ if (*pos != '+')
+ break;
+ pos++;
+ }
+
+ if (dpp && psk && sae)
+ return DPP_AKM_PSK_SAE_DPP;
+ if (dpp && sae)
+ return DPP_AKM_SAE_DPP;
+ if (dpp)
+ return DPP_AKM_DPP;
+ if (psk && sae)
+ return DPP_AKM_PSK_SAE;
+ if (sae)
+ return DPP_AKM_SAE;
+ if (psk)
+ return DPP_AKM_PSK;
+
return DPP_AKM_UNKNOWN;
}
@@ -5800,6 +6119,7 @@
{
int ret = -1;
struct json_token *root, *token, *discovery, *cred;
+ struct dpp_config_obj *conf;
root = json_parse((const char *) conf_obj, conf_obj_len);
if (!root)
@@ -5838,8 +6158,17 @@
dpp_auth_fail(auth, "Too long discovery::ssid string value");
goto fail;
}
- auth->ssid_len = os_strlen(token->string);
- os_memcpy(auth->ssid, token->string, auth->ssid_len);
+
+ if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No room for this many Config Objects - ignore this one");
+ json_free(root);
+ return 0;
+ }
+ conf = &auth->conf_obj[auth->num_conf_obj++];
+
+ conf->ssid_len = os_strlen(token->string);
+ os_memcpy(conf->ssid, token->string, conf->ssid_len);
cred = json_get_member(root, "cred");
if (!cred || cred->type != JSON_OBJECT) {
@@ -5852,13 +6181,13 @@
dpp_auth_fail(auth, "No cred::akm string value found");
goto fail;
}
- auth->akm = dpp_akm_from_str(token->string);
+ conf->akm = dpp_akm_from_str(token->string);
- if (dpp_akm_legacy(auth->akm)) {
- if (dpp_parse_cred_legacy(auth, cred) < 0)
+ if (dpp_akm_legacy(conf->akm)) {
+ if (dpp_parse_cred_legacy(conf, cred) < 0)
goto fail;
- } else if (dpp_akm_dpp(auth->akm)) {
- if (dpp_parse_cred_dpp(auth, cred) < 0)
+ } else if (dpp_akm_dpp(conf->akm)) {
+ if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
goto fail;
} else {
wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
@@ -5955,17 +6284,32 @@
goto fail;
}
- conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
- DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
+ conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
+ &conf_obj_len);
if (!conf_obj) {
dpp_auth_fail(auth,
"Missing required Configuration Object attribute");
goto fail;
}
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
- conf_obj, conf_obj_len);
- if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
- goto fail;
+ while (conf_obj) {
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
+ conf_obj, conf_obj_len);
+ if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
+ goto fail;
+ conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
+ DPP_ATTR_CONFIG_OBJ,
+ &conf_obj_len);
+ }
+
+#ifdef CONFIG_DPP2
+ status = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_SEND_CONN_STATUS, &status_len);
+ if (status) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configurator requested connection status result");
+ auth->conn_status_requested = 1;
+ }
+#endif /* CONFIG_DPP2 */
ret = 0;
@@ -5976,6 +6320,7 @@
#ifdef CONFIG_DPP2
+
enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
const u8 *hdr,
const u8 *attr_start, size_t attr_len)
@@ -6056,7 +6401,6 @@
bin_clear_free(unwrapped, unwrapped_len);
return ret;
}
-#endif /* CONFIG_DPP2 */
struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
@@ -6074,7 +6418,7 @@
clear = wpabuf_alloc(clear_len);
msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
if (!clear || !msg)
- return NULL;
+ goto fail;
/* DPP Status */
dpp_build_attr_status(clear, status);
@@ -6115,6 +6459,219 @@
}
+static int valid_channel_list(const char *val)
+{
+ while (*val) {
+ if (!((*val >= '0' && *val <= '9') ||
+ *val == '/' || *val == ','))
+ return 0;
+ val++;
+ }
+
+ return 1;
+}
+
+
+enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start,
+ size_t attr_len,
+ u8 *ssid, size_t *ssid_len,
+ char **channel_list)
+{
+ const u8 *wrapped_data, *status, *e_nonce;
+ u16 wrapped_data_len, status_len, e_nonce_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ enum dpp_status_error ret = 256;
+ struct json_token *root = NULL, *token;
+
+ *ssid_len = 0;
+ *channel_list = NULL;
+
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
+ wrapped_data, wrapped_data_len);
+
+ attr_len = wrapped_data - 4 - attr_start;
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+ if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_ENROLLEE_NONCE,
+ &e_nonce_len);
+ if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Enrollee Nonce attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
+ if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Enrollee Nonce mismatch");
+ wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
+ auth->e_nonce, e_nonce_len);
+ goto fail;
+ }
+
+ status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
+ &status_len);
+ if (!status) {
+ dpp_auth_fail(auth,
+ "Missing required DPP Connection Status attribute");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
+ status, status_len);
+
+ root = json_parse((const char *) status, status_len);
+ if (!root) {
+ dpp_auth_fail(auth, "Could not parse connStatus");
+ goto fail;
+ }
+
+ token = json_get_member(root, "ssid");
+ if (token && token->type == JSON_STRING &&
+ os_strlen(token->string) <= SSID_MAX_LEN) {
+ *ssid_len = os_strlen(token->string);
+ os_memcpy(ssid, token->string, *ssid_len);
+ }
+
+ token = json_get_member(root, "channelList");
+ if (token && token->type == JSON_STRING &&
+ valid_channel_list(token->string))
+ *channel_list = os_strdup(token->string);
+
+ token = json_get_member(root, "result");
+ if (!token || token->type != JSON_NUMBER) {
+ dpp_auth_fail(auth, "No connStatus - result");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
+ ret = token->number;
+
+fail:
+ json_free(root);
+ bin_clear_free(unwrapped, unwrapped_len);
+ return ret;
+}
+
+
+struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
+ enum dpp_status_error result,
+ const u8 *ssid, size_t ssid_len,
+ const char *channel_list)
+{
+ struct wpabuf *msg, *clear, *json;
+ size_t nonce_len, clear_len, attr_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *wrapped;
+
+ json = wpabuf_alloc(1000);
+ if (!json)
+ return NULL;
+ wpabuf_printf(json, "{\"result\":%d", result);
+ if (ssid) {
+ char ssid_str[6 * SSID_MAX_LEN + 1];
+
+ wpabuf_put_str(json, ",\"ssid\":\"");
+ json_escape_string(ssid_str, sizeof(ssid_str),
+ (const char *) ssid, ssid_len);
+ wpabuf_put_str(json, ssid_str);
+ wpabuf_put_str(json, "\"");
+ }
+ if (channel_list)
+ wpabuf_printf(json, ",\"channelList\":\"%s\"", channel_list);
+ wpabuf_put_str(json, "}");
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
+ wpabuf_head(json), wpabuf_len(json));
+
+ nonce_len = auth->curve->nonce_len;
+ clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+ clear = wpabuf_alloc(clear_len);
+ msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
+ if (!clear || !msg)
+ goto fail;
+
+ /* E-nonce */
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(clear, nonce_len);
+ wpabuf_put_data(clear, auth->e_nonce, nonce_len);
+
+ /* DPP Connection Status */
+ wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
+ wpabuf_put_le16(clear, wpabuf_len(json));
+ wpabuf_put_buf(clear, json);
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data (none) */
+ addr[1] = wpabuf_put(msg, 0);
+ len[1] = 0;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ /* Wrapped Data */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+ wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 2, addr, len, wrapped) < 0)
+ goto fail;
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
+ msg);
+ wpabuf_free(json);
+ wpabuf_free(clear);
+ return msg;
+fail:
+ wpabuf_free(json);
+ wpabuf_free(clear);
+ wpabuf_free(msg);
+ return NULL;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
void dpp_configurator_free(struct dpp_configurator *conf)
{
if (!conf)
@@ -6240,11 +6797,11 @@
auth->own_protocol_key = dpp_gen_keypair(auth->curve);
if (!auth->own_protocol_key)
return -1;
- dpp_copy_netaccesskey(auth);
+ dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
auth->peer_protocol_key = auth->own_protocol_key;
- dpp_copy_csign(auth, auth->conf->csign);
+ dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
- conf_obj = dpp_build_conf_obj(auth, ap);
+ conf_obj = dpp_build_conf_obj(auth, ap, 0);
if (!conf_obj)
goto fail;
ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
@@ -6427,7 +6984,6 @@
const char *pos, *end;
unsigned char *own_conn = NULL;
size_t own_conn_len;
- EVP_PKEY_CTX *ctx = NULL;
size_t Nx_len;
u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
@@ -6541,18 +7097,8 @@
}
/* ECDH: N = nk * PK */
- ctx = EVP_PKEY_CTX_new(own_key, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, peer_key) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Nx_len) != 1 ||
- Nx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Nx, &Nx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
Nx, Nx_len);
@@ -6575,7 +7121,6 @@
if (ret != DPP_STATUS_OK)
os_memset(intro, 0, sizeof(*intro));
os_memset(Nx, 0, sizeof(Nx));
- EVP_PKEY_CTX_free(ctx);
os_free(own_conn);
os_free(signed_connector);
os_free(info.payload);
@@ -7250,7 +7795,6 @@
u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
size_t Kx_len;
int res;
- EVP_PKEY_CTX *ctx = NULL;
if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
@@ -7417,18 +7961,8 @@
goto fail;
/* K = y * X' */
- ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
- Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
Kx, Kx_len);
@@ -7446,7 +7980,6 @@
pkex->exchange_done = 1;
out:
- EVP_PKEY_CTX_free(ctx);
BN_CTX_free(bnctx);
EC_POINT_free(Qi);
EC_POINT_free(Qr);
@@ -7594,7 +8127,6 @@
const struct dpp_curve_params *curve = pkex->own_bi->curve;
EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
BIGNUM *Nx = NULL, *Ny = NULL;
- EVP_PKEY_CTX *ctx = NULL;
EC_KEY *Y_ec = NULL;
size_t Jx_len, Kx_len;
u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
@@ -7706,18 +8238,8 @@
if (!pkex->y ||
EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
goto fail;
- ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
- Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
Jx, Jx_len);
@@ -7741,19 +8263,8 @@
wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
/* K = x * Y’ */
- EVP_PKEY_CTX_free(ctx);
- ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
- Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
Kx, Kx_len);
@@ -7783,7 +8294,6 @@
BN_free(Nx);
BN_free(Ny);
EC_KEY_free(Y_ec);
- EVP_PKEY_CTX_free(ctx);
BN_CTX_free(bnctx);
EC_GROUP_free(group);
return msg;
@@ -7911,7 +8421,6 @@
const u8 *buf, size_t buflen)
{
const struct dpp_curve_params *curve = pkex->own_bi->curve;
- EVP_PKEY_CTX *ctx = NULL;
size_t Jx_len, Lx_len;
u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
@@ -7995,18 +8504,8 @@
pkex->peer_bootstrap_key);
/* ECDH: J' = y * A' */
- ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
- Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
Jx, Jx_len);
@@ -8042,19 +8541,8 @@
wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
/* ECDH: L = b * X' */
- EVP_PKEY_CTX_free(ctx);
- ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
- Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
Lx, Lx_len);
@@ -8080,7 +8568,6 @@
goto fail;
out:
- EVP_PKEY_CTX_free(ctx);
os_free(unwrapped);
wpabuf_free(A_pub);
wpabuf_free(B_pub);
@@ -8109,7 +8596,6 @@
u8 v[DPP_MAX_HASH_LEN];
size_t Lx_len;
u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
- EVP_PKEY_CTX *ctx = NULL;
struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
#ifdef CONFIG_TESTING_OPTIONS
@@ -8180,18 +8666,8 @@
pkex->peer_bootstrap_key);
/* ECDH: L' = x * B' */
- ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
- Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
Lx, Lx_len);
@@ -8231,7 +8707,6 @@
wpabuf_free(B_pub);
wpabuf_free(X_pub);
wpabuf_free(Y_pub);
- EVP_PKEY_CTX_free(ctx);
os_free(unwrapped);
return ret;
fail:
@@ -8767,6 +9242,10 @@
#ifdef CONFIG_DPP2
+static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+
+
static void dpp_connection_free(struct dpp_connection *conn)
{
if (conn->sock >= 0) {
@@ -8776,6 +9255,8 @@
eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
close(conn->sock);
}
+ eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout,
+ conn, NULL);
wpabuf_free(conn->msg);
wpabuf_free(conn->msg_out);
dpp_auth_deinit(conn->auth);
@@ -8999,23 +9480,9 @@
{
struct dpp_authentication *auth = conn->auth;
struct wpabuf *buf;
- char json[100];
int netrole_ap = 0; /* TODO: make this configurable */
- os_snprintf(json, sizeof(json),
- "{\"name\":\"Test\","
- "\"wi-fi_tech\":\"infra\","
- "\"netRole\":\"%s\"}",
- netrole_ap ? "ap" : "sta");
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
- json[29] = 'k'; /* replace "infra" with "knfra" */
- }
-#endif /* CONFIG_TESTING_OPTIONS */
- wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
-
- buf = dpp_build_conf_req(auth, json);
+ buf = dpp_build_conf_req_helper(auth, "Test", netrole_ap, NULL, NULL);
if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
@@ -9030,7 +9497,7 @@
return;
}
wpabuf_put_be32(conn->msg_out, wpabuf_len(buf) - 1);
- wpabuf_put_data(conn->msg_out, wpabuf_head(buf) + 1,
+ wpabuf_put_data(conn->msg_out, wpabuf_head_u8(buf) + 1,
wpabuf_len(buf) - 1);
wpabuf_free(buf);
@@ -9410,7 +9877,7 @@
if (!conn->msg_out)
return -1;
wpabuf_put_be32(conn->msg_out, wpabuf_len(conn->auth->resp_msg) - 1);
- wpabuf_put_data(conn->msg_out, wpabuf_head(conn->auth->resp_msg) + 1,
+ wpabuf_put_data(conn->msg_out, wpabuf_head_u8(conn->auth->resp_msg) + 1,
wpabuf_len(conn->auth->resp_msg) - 1);
if (dpp_tcp_send(conn) == 1) {
@@ -9458,7 +9925,7 @@
return -1;
}
wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
- wpabuf_put_data(conn->msg_out, wpabuf_head(msg) + 1,
+ wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
wpabuf_len(msg) - 1);
wpabuf_free(msg);
@@ -9500,6 +9967,22 @@
}
+static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+
+ if (!conn->auth->waiting_conf_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Connection Status Result");
+ wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONN_STATUS_RESULT "timeout");
+ dpp_connection_remove(conn);
+}
+
+
static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
const u8 *hdr, const u8 *buf,
size_t len)
@@ -9519,6 +10002,18 @@
}
status = dpp_conf_result_rx(auth, hdr, buf, len);
+ if (status == DPP_STATUS_OK && auth->send_conn_status) {
+ wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
+ eloop_cancel_timeout(
+ dpp_controller_conn_status_result_wait_timeout,
+ conn, NULL);
+ eloop_register_timeout(
+ 16, 0, dpp_controller_conn_status_result_wait_timeout,
+ conn, NULL);
+ return 0;
+ }
if (status == DPP_STATUS_OK)
wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
DPP_EVENT_CONF_SENT);
@@ -9529,6 +10024,39 @@
}
+static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf,
+ size_t len)
+{
+ struct dpp_authentication *auth = conn->auth;
+ enum dpp_status_error status;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len = 0;
+ char *channel_list = NULL;
+
+ if (!conn->ctrl)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
+
+ if (!auth || !auth->waiting_conn_status_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for connection status result - drop");
+ return -1;
+ }
+
+ status = dpp_conn_status_result_rx(auth, hdr, buf, len,
+ ssid, &ssid_len, &channel_list);
+ wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONN_STATUS_RESULT
+ "result=%d ssid=%s channel_list=%s",
+ status, wpa_ssid_txt(ssid, ssid_len),
+ channel_list ? channel_list : "N/A");
+ os_free(channel_list);
+ return -1; /* to remove the completed connection */
+}
+
+
static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
size_t len)
{
@@ -9576,6 +10104,9 @@
return dpp_controller_rx_auth_conf(conn, msg, pos, end - pos);
case DPP_PA_CONFIGURATION_RESULT:
return dpp_controller_rx_conf_result(conn, msg, pos, end - pos);
+ case DPP_PA_CONNECTION_STATUS_RESULT:
+ return dpp_controller_rx_conn_status_result(conn, msg, pos,
+ end - pos);
default:
/* TODO: missing messages types */
wpa_printf(MSG_DEBUG,
@@ -9692,6 +10223,7 @@
if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK)
return -1;
+#ifdef CONFIG_DPP2
wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK;
msg = dpp_build_conf_result(auth, status);
@@ -9704,7 +10236,7 @@
return -1;
}
wpabuf_put_be32(encaps, wpabuf_len(msg) - 1);
- wpabuf_put_data(encaps, wpabuf_head(msg) + 1, wpabuf_len(msg) - 1);
+ wpabuf_put_data(encaps, wpabuf_head_u8(msg) + 1, wpabuf_len(msg) - 1);
wpabuf_free(msg);
wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", encaps);
@@ -9717,6 +10249,9 @@
/* This exchange will be terminated in the TX status handler */
return 0;
+#else /* CONFIG_DPP2 */
+ return -1;
+#endif /* CONFIG_DPP2 */
}
diff --git a/src/common/dpp.h b/src/common/dpp.h
index db640ef..0be26d7 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -35,6 +35,7 @@
DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9,
DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
DPP_PA_CONFIGURATION_RESULT = 11,
+ DPP_PA_CONNECTION_STATUS_RESULT = 12,
};
enum dpp_attribute_id {
@@ -64,6 +65,8 @@
DPP_ATTR_CHANNEL = 0x1018,
DPP_ATTR_PROTOCOL_VERSION = 0x1019,
DPP_ATTR_ENVELOPED_DATA = 0x101A,
+ DPP_ATTR_SEND_CONN_STATUS = 0x101B,
+ DPP_ATTR_CONN_STATUS = 0x101C,
};
enum dpp_status_error {
@@ -77,6 +80,7 @@
DPP_STATUS_INVALID_CONNECTOR = 7,
DPP_STATUS_NO_MATCH = 8,
DPP_STATUS_CONFIG_REJECTED = 9,
+ DPP_STATUS_NO_AP = 10,
};
#define DPP_CAPAB_ENROLLEE BIT(0)
@@ -157,10 +161,16 @@
DPP_AKM_PSK_SAE_DPP,
};
+enum dpp_netrole {
+ DPP_NETROLE_STA,
+ DPP_NETROLE_AP,
+};
+
struct dpp_configuration {
u8 ssid[32];
size_t ssid_len;
enum dpp_akm akm;
+ enum dpp_netrole netrole;
/* For DPP configuration (connector) */
os_time_t netaccesskey_expiry;
@@ -174,6 +184,8 @@
int psk_set;
};
+#define DPP_MAX_CONF_OBJ 10
+
struct dpp_authentication {
void *msg_ctx;
u8 peer_version;
@@ -222,22 +234,31 @@
int remove_on_tx_status;
int connect_on_tx_status;
int waiting_conf_result;
+ int waiting_conn_status_result;
int auth_success;
struct wpabuf *conf_req;
const struct wpabuf *conf_resp; /* owned by GAS server */
struct dpp_configuration *conf_ap;
+ struct dpp_configuration *conf2_ap;
struct dpp_configuration *conf_sta;
+ struct dpp_configuration *conf2_sta;
struct dpp_configurator *conf;
- char *connector; /* received signedConnector */
- u8 ssid[SSID_MAX_LEN];
- u8 ssid_len;
- char passphrase[64];
- u8 psk[PMK_LEN];
- int psk_set;
- enum dpp_akm akm;
+ struct dpp_config_obj {
+ char *connector; /* received signedConnector */
+ u8 ssid[SSID_MAX_LEN];
+ u8 ssid_len;
+ char passphrase[64];
+ u8 psk[PMK_LEN];
+ int psk_set;
+ enum dpp_akm akm;
+ struct wpabuf *c_sign_key;
+ } conf_obj[DPP_MAX_CONF_OBJ];
+ unsigned int num_conf_obj;
struct wpabuf *net_access_key;
os_time_t net_access_key_expiry;
- struct wpabuf *c_sign_key;
+ int send_conn_status;
+ int conn_status_requested;
+ int akm_use_selector;
#ifdef CONFIG_TESTING_OPTIONS
char *config_obj_override;
char *discovery_override;
@@ -413,6 +434,9 @@
const u8 *attr_start, size_t attr_len);
struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
const char *json);
+struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
+ const char *name, int netrole_ap,
+ const char *mud_url, int *opclasses);
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,
@@ -439,12 +463,23 @@
const u8 *attr_start, size_t attr_len);
struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
enum dpp_status_error status);
+enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start,
+ size_t attr_len,
+ u8 *ssid, size_t *ssid_len,
+ char **channel_list);
+struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
+ enum dpp_status_error result,
+ const u8 *ssid, size_t ssid_len,
+ const char *channel_list);
struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
size_t len);
const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len);
int dpp_check_attrs(const u8 *buf, size_t len);
int dpp_key_expired(const char *timestamp, os_time_t *expiry);
const char * dpp_akm_str(enum dpp_akm akm);
+const char * dpp_akm_selector_str(enum dpp_akm akm);
int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
size_t buflen);
void dpp_configurator_free(struct dpp_configurator *conf);
diff --git a/src/common/dragonfly.c b/src/common/dragonfly.c
index e98bce6..547be66 100644
--- a/src/common/dragonfly.c
+++ b/src/common/dragonfly.c
@@ -21,14 +21,35 @@
* purposes: FFC groups whose prime is >= 3072 bits and ECC groups
* defined over a prime field whose prime is >= 256 bits. Furthermore,
* ECC groups defined over a characteristic 2 finite field and ECC
- * groups with a co-factor greater than 1 are not suitable. */
+ * groups with a co-factor greater than 1 are not suitable. Disable
+ * groups that use Brainpool curves as well for now since they leak more
+ * timing information due to the prime not being close to a power of
+ * two. */
return group == 19 || group == 20 || group == 21 ||
- group == 28 || group == 29 || group == 30 ||
(!ecc_only &&
(group == 15 || group == 16 || group == 17 || group == 18));
}
+unsigned int dragonfly_min_pwe_loop_iter(int group)
+{
+ if (group == 22 || group == 23 || group == 24) {
+ /* FFC groups for which pwd-value is likely to be >= p
+ * frequently */
+ return 40;
+ }
+
+ if (group == 1 || group == 2 || group == 5 || group == 14 ||
+ group == 15 || group == 16 || group == 17 || group == 18) {
+ /* FFC groups that have prime that is close to a power of two */
+ return 1;
+ }
+
+ /* Default to 40 (this covers most ECC groups) */
+ return 40;
+}
+
+
int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime,
struct crypto_bignum **qr,
struct crypto_bignum **qnr)
diff --git a/src/common/dragonfly.h b/src/common/dragonfly.h
index e7627ef..ec3dd59 100644
--- a/src/common/dragonfly.h
+++ b/src/common/dragonfly.h
@@ -16,6 +16,7 @@
struct crypto_ec;
int dragonfly_suitable_group(int group, int ecc_only);
+unsigned int dragonfly_min_pwe_loop_iter(int group);
int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime,
struct crypto_bignum **qr,
struct crypto_bignum **qnr);
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 3fdbf89..1ad8d7c 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -360,7 +360,8 @@
int hostapd_set_freq_params(struct hostapd_freq_params *data,
enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled,
+ 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,
@@ -381,6 +382,74 @@
data->center_freq2 = 0;
data->bandwidth = sec_channel_offset ? 40 : 20;
+ hostapd_encode_edmg_chan(enable_edmg, edmg_channel, channel,
+ &data->edmg);
+
+ if (is_6ghz_freq(freq)) {
+ if (!data->he_enabled) {
+ wpa_printf(MSG_ERROR,
+ "Can't set 6 GHz mode - HE isn't enabled");
+ return -1;
+ }
+
+ if (center_idx_to_bw_6ghz(channel) != 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid control channel for 6 GHz band");
+ return -1;
+ }
+
+ if (!center_segment0) {
+ if (center_segment1) {
+ wpa_printf(MSG_ERROR,
+ "Segment 0 center frequency isn't set");
+ return -1;
+ }
+
+ data->center_freq1 = data->freq;
+ data->bandwidth = 20;
+ } else {
+ int freq1, freq2 = 0;
+ int bw = center_idx_to_bw_6ghz(center_segment0);
+
+ if (bw < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid center frequency index for 6 GHz");
+ return -1;
+ }
+
+ freq1 = ieee80211_chan_to_freq(NULL, 131,
+ center_segment0);
+ if (freq1 < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid segment 0 center frequency for 6 GHz");
+ return -1;
+ }
+
+ if (center_segment1) {
+ if (center_idx_to_bw_6ghz(center_segment1) != 2 ||
+ bw != 2) {
+ wpa_printf(MSG_ERROR,
+ "6 GHz 80+80 MHz configuration doesn't use valid 80 MHz channels");
+ return -1;
+ }
+
+ freq2 = ieee80211_chan_to_freq(NULL, 131,
+ center_segment1);
+ if (freq2 < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid segment 1 center frequency for UHB");
+ return -1;
+ }
+ }
+
+ data->bandwidth = (1 << (u8) bw) * 20;
+ data->center_freq1 = freq1;
+ data->center_freq2 = freq2;
+ }
+
+ return 0;
+ }
+
if (data->vht_enabled) switch (oper_chwidth) {
case CHANWIDTH_USE_HT:
if (center_segment1 ||
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 2d2a539..c86e195 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -31,7 +31,8 @@
int sec_chan);
int hostapd_set_freq_params(struct hostapd_freq_params *data,
enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled,
+ 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 center_segment0,
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 9f57828..c6e6440 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -365,6 +365,10 @@
elems->rsn_ie = pos;
elems->rsn_ie_len = elen;
break;
+ case WLAN_EID_RSNX:
+ elems->rsnxe = pos;
+ elems->rsnxe_len = elen;
+ break;
case WLAN_EID_PWR_CAPABILITY:
if (elen < 2)
break;
@@ -873,8 +877,8 @@
return HOSTAPD_MODE_IEEE80211A;
}
- /* 56.16 GHz, channel 1..4 */
- if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
+ /* 56.16 GHz, channel 1..6 */
+ if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) {
if (sec_channel || vht)
return NUM_HOSTAPD_MODES;
@@ -884,6 +888,19 @@
return HOSTAPD_MODE_IEEE80211AD;
}
+ if (freq > 5940 && freq <= 7105) {
+ int bw;
+ u8 idx = (freq - 5940) / 5;
+
+ bw = center_idx_to_bw_6ghz(idx);
+ if (bw < 0)
+ return NUM_HOSTAPD_MODES;
+
+ *channel = idx;
+ *op_class = 131 + bw;
+ return HOSTAPD_MODE_IEEE80211A;
+ }
+
return NUM_HOSTAPD_MODES;
}
@@ -993,8 +1010,8 @@
if (chan < 149 || chan > 165)
return -1;
return 5000 + 5 * chan;
- case 34: /* 60 GHz band, channels 1..3 */
- if (chan < 1 || chan > 3)
+ case 34: /* 60 GHz band, channels 1..6 */
+ if (chan < 1 || chan > 6)
return -1;
return 56160 + 2160 * chan;
}
@@ -1031,8 +1048,8 @@
if (chan < 149 || chan > 169)
return -1;
return 5000 + 5 * chan;
- case 18: /* 60 GHz band, channels 1..4 */
- if (chan < 1 || chan > 4)
+ case 18: /* 60 GHz band, channels 1..6 */
+ if (chan < 1 || chan > 6)
return -1;
return 56160 + 2160 * chan;
}
@@ -1075,8 +1092,8 @@
if (chan < 100 || chan > 140)
return -1;
return 5000 + 5 * chan;
- case 59: /* 60 GHz band, channels 1..4 */
- if (chan < 1 || chan > 3)
+ case 59: /* 60 GHz band, channels 1..6 */
+ if (chan < 1 || chan > 6)
return -1;
return 56160 + 2160 * chan;
}
@@ -1163,8 +1180,16 @@
if (chan < 36 || chan > 128)
return -1;
return 5000 + 5 * chan;
- case 180: /* 60 GHz band, channels 1..4 */
- if (chan < 1 || chan > 4)
+ case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
+ case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
+ case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
+ case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
+ case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
+ if (chan < 1 || chan > 233)
+ return -1;
+ return 5940 + chan * 5;
+ case 180: /* 60 GHz band, channels 1..6 */
+ if (chan < 1 || chan > 6)
return -1;
return 56160 + 2160 * chan;
}
@@ -1494,6 +1519,7 @@
S2S(FILS_AUTHENTICATION_FAILURE)
S2S(UNKNOWN_AUTHENTICATION_SERVER)
S2S(UNKNOWN_PASSWORD_IDENTIFIER)
+ S2S(SAE_HASH_TO_ELEMENT)
}
return "UNKNOWN";
#undef S2S
@@ -1592,6 +1618,7 @@
{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160, P2P_SUPP },
{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
};
@@ -1906,6 +1933,43 @@
}
+int center_idx_to_bw_6ghz(u8 idx)
+{
+ /* channels: 1, 5, 9, 13... */
+ if ((idx & 0x3) == 0x1)
+ return 0; /* 20 MHz */
+ /* channels 3, 11, 19... */
+ if ((idx & 0x7) == 0x3)
+ return 1; /* 40 MHz */
+ /* channels 7, 23, 39.. */
+ if ((idx & 0xf) == 0x7)
+ return 2; /* 80 MHz */
+ /* channels 15, 47, 79...*/
+ if ((idx & 0x1f) == 0xf)
+ return 3; /* 160 MHz */
+
+ return -1;
+}
+
+
+int is_6ghz_freq(int freq)
+{
+ if (freq < 5940 || freq > 7105)
+ return 0;
+
+ if (center_idx_to_bw_6ghz((freq - 5940) / 5) < 0)
+ return 0;
+
+ return 1;
+}
+
+
+int is_6ghz_op_class(u8 op_class)
+{
+ return op_class >= 131 && op_class <= 135;
+}
+
+
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len)
{
@@ -2014,3 +2078,75 @@
return 0;
return !!(ie[2 + capab / 8] & BIT(capab % 8));
}
+
+
+void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
+ int primary_channel,
+ struct ieee80211_edmg_config *edmg)
+{
+ if (!edmg_enable) {
+ edmg->channels = 0;
+ edmg->bw_config = 0;
+ return;
+ }
+
+ /* Only EDMG CB1 and EDMG CB2 contiguous channels supported for now */
+ switch (edmg_channel) {
+ case EDMG_CHANNEL_9:
+ edmg->channels = EDMG_CHANNEL_9_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_10:
+ edmg->channels = EDMG_CHANNEL_10_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_11:
+ edmg->channels = EDMG_CHANNEL_11_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_12:
+ edmg->channels = EDMG_CHANNEL_12_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_13:
+ edmg->channels = EDMG_CHANNEL_13_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ default:
+ if (primary_channel > 0 && primary_channel < 7) {
+ edmg->channels = BIT(primary_channel - 1);
+ edmg->bw_config = EDMG_BW_CONFIG_4;
+ } else {
+ edmg->channels = 0;
+ edmg->bw_config = 0;
+ }
+ break;
+ }
+}
+
+
+/* Check if the requested EDMG configuration is a subset of the allowed
+ * EDMG configuration. */
+int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
+ struct ieee80211_edmg_config requested)
+{
+ /*
+ * The validation check if the requested EDMG configuration
+ * is a subset of the allowed EDMG configuration:
+ * 1. Check that the requested channels are part (set) of the allowed
+ * channels.
+ * 2. P802.11ay defines the values of bw_config between 4 and 15.
+ * (bw config % 4) will give us 4 groups inside bw_config definition,
+ * inside each group we can check the subset just by comparing the
+ * bw_config value.
+ * Between this 4 groups, there is no subset relation - as a result of
+ * the P802.11ay definition.
+ * bw_config defined by IEEE P802.11ay/D4.0, 9.4.2.251, Table 13.
+ */
+ if (((requested.channels & allowed.channels) != requested.channels) ||
+ ((requested.bw_config % 4) > (allowed.bw_config % 4)) ||
+ requested.bw_config > allowed.bw_config)
+ return 0;
+
+ return 1;
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 9b045b4..052f333 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -40,6 +40,7 @@
const u8 *ext_supp_rates;
const u8 *wpa_ie;
const u8 *rsn_ie;
+ const u8 *rsnxe;
const u8 *wmm; /* WMM Information or Parameter Element */
const u8 *wmm_tspec;
const u8 *wps_ie;
@@ -102,6 +103,7 @@
u8 ext_supp_rates_len;
u8 wpa_ie_len;
u8 rsn_ie_len;
+ u8 rsnxe_len;
u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
u8 wmm_tspec_len;
u8 wps_ie_len;
@@ -220,6 +222,9 @@
const struct oper_class_map * get_oper_class(const char *country, u8 op_class);
int oper_class_bw_to_int(const struct oper_class_map *map);
+int center_idx_to_bw_6ghz(u8 idx);
+int is_6ghz_freq(int freq);
+int is_6ghz_op_class(u8 op_class);
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len);
@@ -273,4 +278,13 @@
return (const u8 *) element == (const u8 *) data + datalen;
}
+struct ieee80211_edmg_config;
+
+void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
+ int primary_channel,
+ struct ieee80211_edmg_config *edmg);
+
+int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
+ struct ieee80211_edmg_config requested);
+
#endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index b0aa913..fbed051 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -204,6 +204,7 @@
#define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
#define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
+#define WLAN_STATUS_SAE_HASH_TO_ELEMENT 126
/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
#define WLAN_REASON_UNSPECIFIED 1
@@ -446,6 +447,7 @@
#define WLAN_EID_FILS_INDICATION 240
#define WLAN_EID_DILS 241
#define WLAN_EID_FRAGMENT 242
+#define WLAN_EID_RSNX 244
#define WLAN_EID_EXTENSION 255
/* Element ID Extension (EID 255) values */
@@ -470,6 +472,9 @@
#define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38
#define WLAN_EID_EXT_SPATIAL_REUSE 39
#define WLAN_EID_EXT_OCV_OCI 54
+#define WLAN_EID_EXT_EDMG_CAPABILITIES 61
+#define WLAN_EID_EXT_EDMG_OPERATION 62
+#define WLAN_EID_EXT_REJECTED_GROUPS 92
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -552,6 +557,11 @@
#define WLAN_EXT_CAPAB_SAE_PW_ID 81
#define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82
+/* Extended RSN Capabilities */
+/* bits 0-3: Field length (n-1) */
+#define WLAN_RSNX_CAPAB_PROTECTED_TWT 4
+#define WLAN_RSNX_CAPAB_SAE_H2E 5
+
/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
#define WLAN_ACTION_QOS 1
@@ -1217,6 +1227,7 @@
#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
+#define BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY 123
/* VHT Defines */
#define VHT_CAP_MAX_MPDU_LENGTH_7991 ((u32) BIT(0))
@@ -2109,7 +2120,7 @@
u8 he_phy_capab_info[11];
/* Followed by 4, 8, or 12 octets of Supported HE-MCS And NSS Set field
* and optional variable length PPE Thresholds field. */
- u8 optional[];
+ u8 optional[37];
} STRUCT_PACKED;
struct ieee80211_he_operation {
@@ -2174,6 +2185,10 @@
BIT(10) | BIT(11) | \
BIT(12) | BIT(13)))
#define HE_OPERATION_RTS_THRESHOLD_OFFSET 4
+#define HE_OPERATION_VHT_OPER_INFO ((u32) BIT(14))
+#define HE_OPERATION_COHOSTED_BSS ((u32) BIT(15))
+#define HE_OPERATION_ER_SU_DISABLE ((u32) BIT(16))
+#define HE_OPERATION_6GHZ_OPER_INFO ((u32) BIT(17))
#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(24) | BIT(25) | \
BIT(26) | BIT(27) | \
BIT(28) | BIT(29)))
@@ -2221,6 +2236,39 @@
/* B7: Reserved if sent by an AP; More Data Ack if sent by a non-AP STA */
#define HE_QOS_INFO_MORE_DATA_ACK ((u8) (BIT(7)))
+/* IEEE P802.11ay/D4.0, 9.4.2.251 - EDMG Operation element */
+#define EDMG_BSS_OPERATING_CHANNELS_OFFSET 6
+#define EDMG_OPERATING_CHANNEL_WIDTH_OFFSET 7
+
+/* IEEE P802.11ay/D4.0, 29.3.4 - Channelization */
+enum edmg_channel {
+ EDMG_CHANNEL_9 = 9,
+ EDMG_CHANNEL_10 = 10,
+ EDMG_CHANNEL_11 = 11,
+ EDMG_CHANNEL_12 = 12,
+ EDMG_CHANNEL_13 = 13,
+};
+
+/* Represent CB2 contiguous channels */
+#define EDMG_CHANNEL_9_SUBCHANNELS (BIT(0) | BIT(1)) /* channels 1 and 2 */
+#define EDMG_CHANNEL_10_SUBCHANNELS (BIT(1) | BIT(2)) /* channels 2 and 3 */
+#define EDMG_CHANNEL_11_SUBCHANNELS (BIT(2) | BIT(3)) /* channels 3 and 4 */
+#define EDMG_CHANNEL_12_SUBCHANNELS (BIT(3) | BIT(4)) /* channels 4 and 5 */
+#define EDMG_CHANNEL_13_SUBCHANNELS (BIT(4) | BIT(5)) /* channels 5 and 6 */
+
+/**
+ * enum edmg_bw_config - Allowed channel bandwidth configurations
+ * @EDMG_BW_CONFIG_4: 2.16 GHz
+ * @EDMG_BW_CONFIG_5: 2.16 GHz and 4.32 GHz
+ *
+ * IEEE P802.11ay/D4.0, 9.4.2.251 (EDMG Operation element),
+ * Table 13 (Channel BW Configuration subfield definition)
+ */
+enum edmg_bw_config {
+ EDMG_BW_CONFIG_4 = 4,
+ EDMG_BW_CONFIG_5 = 5,
+};
+
/* DPP Public Action frame identifiers - OUI_WFA */
#define DPP_OUI_TYPE 0x1A
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 0c607b8..a0a0fb5 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -72,7 +72,7 @@
*
* @QCA_NL80211_VENDOR_SUBCMD_DO_ACS: ACS command/event which is used to
* invoke the ACS function in device and pass selected channels to
- * hostapd.
+ * hostapd. Uses enum qca_wlan_vendor_attr_acs_offload attributes.
*
* @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Command to get the features
* supported by the driver. enum qca_wlan_vendor_features defines
@@ -170,6 +170,11 @@
* to notify the connected station's status. The attributes for this
* command are defined in enum qca_wlan_vendor_attr_link_properties.
*
+ * @QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY: This command is used to configure
+ * DFS policy and channel hint for ACS operation. This command uses the
+ * attributes defined in enum qca_wlan_vendor_attr_acs_config and
+ * enum qca_acs_dfs_mode.
+ *
* @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START: Command used to
* start the P2P Listen offload function in device and pass the listen
* channel, period, interval, count, device types, and vendor specific
@@ -584,6 +589,26 @@
* by the firmware to user space for persistent storage. The attributes
* defined in enum qca_vendor_attr_interop_issues_ap are used to deliver
* the parameters.
+ * @QCA_NL80211_VENDOR_SUBCMD_OEM_DATA: This command/event is used to
+ * send/receive OEM data binary blobs to/from application/service to/from
+ * firmware. The attributes defined in enum
+ * qca_wlan_vendor_attr_oem_data_params are used to deliver the
+ * parameters.
+ * @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT: This command/event is used
+ * to send/receive avoid frequency data using
+ * enum qca_wlan_vendor_attr_avoid_frequency_ext.
+ * This new command is alternative to existing command
+ * QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY since existing command/event
+ * is using stream of bytes instead of structured data using vendor
+ * attributes.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE: This vendor subcommand is used to
+ * add the STA node details in driver/firmware. Attributes for this event
+ * are specified in enum qca_wlan_vendor_attr_add_sta_node_params.
+ * @QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE: This command is used to set BT
+ * coex chain mode from application/service.
+ * The attributes defined in enum qca_vendor_attr_btc_chain_mode are used
+ * to deliver the parameters.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -683,7 +708,8 @@
QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109,
/* 110..114 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB = 115,
- /* 116..117 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY = 116,
+ /* 117 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_SET_SAP_CONFIG = 118,
QCA_NL80211_VENDOR_SUBCMD_TSF = 119,
QCA_NL80211_VENDOR_SUBCMD_WISA = 120,
@@ -754,6 +780,10 @@
QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG = 179,
QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING = 180,
QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP = 181,
+ QCA_NL80211_VENDOR_SUBCMD_OEM_DATA = 182,
+ QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT = 183,
+ QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE = 184,
+ QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE = 185,
};
enum qca_wlan_vendor_attr {
@@ -1090,31 +1120,162 @@
QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST - 1
};
+/**
+ * enum qca_wlan_vendor_attr_acs_offload - Defines attributes to be used with
+ * vendor command/event QCA_NL80211_VENDOR_SUBCMD_DO_ACS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL: Required (u8).
+ * Used with event to notify the primary channel number selected in ACS
+ * operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY instead.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL: Required (u8).
+ * Used with event to notify the secondary channel number selected in ACS
+ * operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL is still used if either of
+ * the driver or user space application doesn't support 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE: Required (u8).
+ * (a) Used with command to configure hw_mode from
+ * enum qca_wlan_vendor_acs_hw_mode for ACS operation.
+ * (b) Also used with event to notify the hw_mode of selected primary channel
+ * in ACS operation.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for HT mode.
+ * Disable (flag attribute not present) - HT disabled and
+ * Enable (flag attribute present) - HT enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for HT40 mode.
+ * Disable (flag attribute not present) - HT40 disabled and
+ * Enable (flag attribute present) - HT40 enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for VHT mode.
+ * Disable (flag attribute not present) - VHT disabled and
+ * Enable (flag attribute present) - VHT enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH: Optional (u16) with command and
+ * mandatory with event.
+ * If specified in command path, ACS operation is configured with the given
+ * channel width (in MHz).
+ * In event path, specifies the channel width of the primary channel selected.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST: Required and type is NLA_UNSPEC.
+ * Used with command to configure channel list using an array of
+ * channel numbers (u8).
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * the driver mandates use of QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST whereas
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL: Required (u8).
+ * Used with event to notify the VHT segment 0 center channel number selected in
+ * ACS operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL is still used if either of
+ * the driver or user space application doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL: Required (u8).
+ * Used with event to notify the VHT segment 1 center channel number selected in
+ * ACS operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL is still used if either of
+ * the driver or user space application doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST: Required and type is NLA_UNSPEC.
+ * Used with command to configure the channel list using an array of channel
+ * center frequencies in MHz (u32).
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * the driver first parses the frequency list and if it fails to get a frequency
+ * list, parses the channel list specified using
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST (considers only 2 GHz and 5 GHz channels in
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY: Required (u32).
+ * Used with event to notify the primary channel center frequency (MHz) selected
+ * in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY: Required (u32).
+ * Used with event to notify the secondary channel center frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY: Required (u32).
+ * Used with event to notify the VHT segment 0 center channel frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY: Required (u32).
+ * Used with event to notify the VHT segment 1 center channel frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL.
+ */
enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
- QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
- QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL,
- QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
- QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
- QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
- QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED,
- QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
- QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
- QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
- QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
- QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
+ QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL = 1,
+ QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL = 2,
+ QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE = 3,
+ QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED = 4,
+ QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED = 5,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED = 6,
+ QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH = 7,
+ QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST = 8,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL = 9,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL = 10,
+ QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST = 11,
+ QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY = 12,
+ QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY = 13,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY = 14,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY = 15,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ACS_MAX =
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST - 1
};
+/**
+ * enum qca_wlan_vendor_acs_hw_mode - Defines HW mode to be used with the
+ * vendor command/event QCA_NL80211_VENDOR_SUBCMD_DO_ACS.
+ *
+ * @QCA_ACS_MODE_IEEE80211B: 802.11b mode
+ * @QCA_ACS_MODE_IEEE80211G: 802.11g mode
+ * @QCA_ACS_MODE_IEEE80211A: 802.11a mode
+ * @QCA_ACS_MODE_IEEE80211AD: 802.11ad mode
+ * @QCA_ACS_MODE_IEEE80211ANY: all modes
+ * @QCA_ACS_MODE_IEEE80211AX: 802.11ax mode
+ */
enum qca_wlan_vendor_acs_hw_mode {
QCA_ACS_MODE_IEEE80211B,
QCA_ACS_MODE_IEEE80211G,
QCA_ACS_MODE_IEEE80211A,
QCA_ACS_MODE_IEEE80211AD,
QCA_ACS_MODE_IEEE80211ANY,
+ QCA_ACS_MODE_IEEE80211AX,
};
/**
@@ -1146,6 +1307,8 @@
* @QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY: Device supports self
* managed regulatory.
* @QCA_WLAN_VENDOR_FEATURE_TWT: Device supports TWT (Target Wake Time).
+ * @QCA_WLAN_VENDOR_FEATURE_11AX: Device supports 802.11ax (HE)
+ * @QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT: Device supports 6 GHz band operation
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
@@ -1158,6 +1321,8 @@
QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON = 6,
QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY = 7,
QCA_WLAN_VENDOR_FEATURE_TWT = 8,
+ QCA_WLAN_VENDOR_FEATURE_11AX = 9,
+ QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT = 10,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -1850,6 +2015,30 @@
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_GTX = 57,
+ /* Attribute to configure disconnect IEs to the driver.
+ * This carries an array of unsigned 8-bit characters.
+ *
+ * If this is configured, driver shall fill the IEs in disassoc/deauth
+ * frame.
+ * These IEs are expected to be considered only for the next
+ * immediate disconnection (disassoc/deauth frame) originated by
+ * the DUT, irrespective of the entity (user space/driver/firmware)
+ * triggering the disconnection.
+ * The host drivers are not expected to use the IEs set through
+ * this interface for further disconnections after the first immediate
+ * disconnection initiated post the configuration.
+ * If the IEs are also updated through cfg80211 interface (after the
+ * enhancement to cfg80211_disconnect), host driver is expected to
+ * take the union of IEs from both of these interfaces and send in
+ * further disassoc/deauth frames.
+ */
+ QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES = 58,
+
+ /* 8-bit unsigned value for ELNA bypass.
+ * 1-Enable, 0-Disable
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS = 59,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -1858,10 +2047,23 @@
/**
* enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL: Optional (u8)
+ * Channel number on which Access Point should restart.
+ * Note: If both the driver and user space application supports the 6 GHz band,
+ * this attribute is deprecated and QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY
+ * should be used.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY: Optional (u32)
+ * Channel center frequency (MHz) on which the access point should restart.
*/
enum qca_wlan_vendor_attr_sap_config {
QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_INVALID = 0,
- /* 1 - reserved for QCA */
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL = 1,
+
/* List of frequencies on which AP is expected to operate.
* This is irrespective of ACS configuration. This list is a priority
* based one and is looked for before the AP is created to ensure the
@@ -1869,6 +2071,7 @@
* the system.
*/
QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST = 2,
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY = 3,
QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX =
@@ -1948,6 +2151,54 @@
};
/**
+ * enum qca_acs_dfs_mode - Defines different types of DFS channel
+ * configurations for ACS operation.
+ *
+ * @QCA_ACS_DFS_MODE_NONE: Refer to invalid DFS mode
+ * @QCA_ACS_DFS_MODE_ENABLE: Consider DFS channels in ACS operation
+ * @QCA_ACS_DFS_MODE_DISABLE: Do not consider DFS channels in ACS operation
+ * @QCA_ACS_DFS_MODE_DEPRIORITIZE: Deprioritize DFS channels in ACS operation
+ */
+enum qca_acs_dfs_mode {
+ QCA_ACS_DFS_MODE_NONE = 0,
+ QCA_ACS_DFS_MODE_ENABLE = 1,
+ QCA_ACS_DFS_MODE_DISABLE = 2,
+ QCA_ACS_DFS_MODE_DEPRIORITIZE = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_acs_config - Defines Configuration attributes
+ * used by the vendor command QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE: Required (u8)
+ * DFS mode for ACS operation from enum qca_acs_dfs_mode.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT: Required (u8)
+ * channel number hint for ACS operation, if valid channel is specified then
+ * ACS operation gives priority to this channel.
+ * Note: If both the driver and user space application supports the 6 GHz band,
+ * this attribute is deprecated and QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT
+ * should be used.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT: Required (u32).
+ * Channel center frequency (MHz) hint for ACS operation, if a valid center
+ * frequency is specified, ACS operation gives priority to this channel.
+ */
+enum qca_wlan_vendor_attr_acs_config {
+ QCA_WLAN_VENDOR_ATTR_ACS_MODE_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE = 1,
+ QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT = 2,
+ QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT = 3,
+
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX =
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_AFTER_LAST - 1,
+};
+
+/**
* enum qca_wlan_vendor_attr_get_hw_capability - Wi-Fi hardware capability
*/
enum qca_wlan_vendor_attr_get_hw_capability {
@@ -3330,6 +3581,345 @@
QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_AFTER_LAST - 1,
};
+/**
+ * enum qca_scan_freq_list_type: Frequency list types
+ *
+ * @QCA_PREFERRED_SCAN_FREQ_LIST: The driver shall use the scan frequency list
+ * specified with attribute QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST as
+ * a preferred frequency list for roaming.
+ *
+ * @QCA_SPECIFIC_SCAN_FREQ_LIST: The driver shall use the frequency list
+ * specified with attribute QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST as
+ * a specific frequency list for roaming.
+ */
+enum qca_scan_freq_list_type {
+ QCA_PREFERRED_SCAN_FREQ_LIST = 1,
+ QCA_SPECIFIC_SCAN_FREQ_LIST = 2,
+};
+
+/**
+ * enum qca_vendor_attr_scan_freq_list_scheme: Frequency list scheme
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST: Nested attribute of u32 values
+ * List of frequencies in MHz to be considered for a roam scan.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_TYPE: Unsigned 32-bit value.
+ * Type of frequency list scheme being configured/gotten as defined by the
+ * enum qca_scan_freq_list_type.
+ */
+enum qca_vendor_attr_scan_freq_list_scheme {
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST = 1,
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_TYPE = 2,
+
+ /* keep last */
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_AFTER_LAST,
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_MAX =
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_vendor_roam_triggers: Bitmap of roaming triggers
+ *
+ * @QCA_ROAM_TRIGGER_REASON_PER: Set if the roam has to be triggered based on
+ * a bad packet error rates (PER).
+ * @QCA_ROAM_TRIGGER_REASON_BEACON_MISS: Set if the roam has to be triggered
+ * based on beacon misses from the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_POOR_RSSI: Set if the roam has to be triggered
+ * due to poor RSSI of the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_BETTER_RSSI: Set if the roam has to be triggered
+ * upon finding a BSSID with a better RSSI than the connected BSSID.
+ * Here the RSSI of the current BSSID need not be poor.
+ * @QCA_ROAM_TRIGGER_REASON_PERIODIC: Set if the roam has to be triggered
+ * by triggering a periodic scan to find a better AP to roam.
+ * @QCA_ROAM_TRIGGER_REASON_DENSE: Set if the roam has to be triggered
+ * when the connected channel environment is too noisy/congested.
+ * @QCA_ROAM_TRIGGER_REASON_BTM: Set if the roam has to be triggered
+ * when BTM Request frame is received from the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_BSS_LOAD: Set if the roam has to be triggered
+ * when the channel utilization is goes above the configured threshold.
+ *
+ * Set the corresponding roam trigger reason bit to consider it for roam
+ * trigger.
+ * Userspace can set multiple bits and send to the driver. The driver shall
+ * consider all of them to trigger/initiate a roam scan.
+ */
+enum qca_vendor_roam_triggers {
+ QCA_ROAM_TRIGGER_REASON_PER = 1 << 0,
+ QCA_ROAM_TRIGGER_REASON_BEACON_MISS = 1 << 1,
+ QCA_ROAM_TRIGGER_REASON_POOR_RSSI = 1 << 2,
+ QCA_ROAM_TRIGGER_REASON_BETTER_RSSI = 1 << 3,
+ QCA_ROAM_TRIGGER_REASON_PERIODIC = 1 << 4,
+ QCA_ROAM_TRIGGER_REASON_DENSE = 1 << 5,
+ QCA_ROAM_TRIGGER_REASON_BTM = 1 << 6,
+ QCA_ROAM_TRIGGER_REASON_BSS_LOAD = 1 << 7,
+};
+
+/**
+ * enum qca_vendor_attr_roam_candidate_selection_criteria:
+ *
+ * Each attribute carries a weightage in percentage (%).
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_RSSI: Unsigned 8-bit value.
+ * Represents the weightage to be given for the RSSI selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE: Unsigned 8-bit value.
+ * Represents the weightage to be given for the rate selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BW: Unsigned 8-bit value.
+ * Represents the weightage to be given for the band width selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BAND: Unsigned 8-bit value.
+ * Represents the weightage to be given for the band selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_NSS: Unsigned 8-bit value.
+ * Represents the weightage to be given for the NSS selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_CHAN_CONGESTION: Unsigned 8-bit value.
+ * Represents the weightage to be given for the channel congestion
+ * selection criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BEAMFORMING: Unsigned 8-bit value.
+ * Represents the weightage to be given for the beamforming selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_OCE_WAN: Unsigned 8-bit value.
+ * Represents the weightage to be given for the OCE selection
+ * criteria among other parameters.
+ */
+enum qca_vendor_attr_roam_candidate_selection_criteria {
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_RSSI = 1,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE = 2,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BW = 3,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BAND = 4,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_NSS = 5,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_CHAN_CONGESTION = 6,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BEAMFORMING = 7,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_OCE_WAN = 8,
+
+ /* keep last */
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_AFTER_LAST,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_MAX =
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_vendor_attr_roam_control - Attributes to carry roam configuration
+ * The following attributes are used to set/get/clear the respective
+ * configurations to/from the driver.
+ * For the get, the attribute for the configuration to be queried shall
+ * carry any of its acceptable values to the driver. In return, the driver
+ * shall send the configured values within the same attribute to the user
+ * space.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_ENABLE: Unsigned 8-bit value.
+ * Signifies to enable/disable roam control in driver.
+ * 1-enable, 0-disable
+ * Enable: Mandates the driver to do the further roams using the
+ * configuration parameters set through
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET.
+ * Disable: Disables the driver/firmware roaming triggered through
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET. Further roaming is
+ * expected to continue with the default configurations.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_STATUS: Unsigned 8-bit value.
+ * This is used along with QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET.
+ * Roam control status is obtained through this attribute.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_CLEAR_ALL: Flag attribute to indicate the
+ * complete config set through QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET
+ * is to be cleared in the driver.
+ * This is used along with QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR
+ * and shall be ignored if used with other sub commands.
+ * If this attribute is specified along with subcmd
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR, the driver shall ignore
+ * all other attributes, if there are any.
+ * If this attribute is not specified when the subcmd
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR is sent, the driver shall
+ * clear the data corresponding to the attributes specified.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME: Nested attribute to carry the
+ * list of frequencies and its type, represented by
+ * enum qca_vendor_attr_scan_freq_list_scheme.
+ * Frequency list and its type are mandatory for this attribute to set
+ * the frequencies.
+ * Frequency type is mandatory for this attribute to get the frequencies
+ * and the frequency list is obtained through
+ * QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST.
+ * Frequency list type is mandatory for this attribute to clear the
+ * frequencies.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_PERIOD: Unsigned 32-bit value.
+ * Carries the value of scan period in seconds to set.
+ * The value of scan period is obtained with the same attribute for get.
+ * Clears the scan period in the driver when specified with clear command.
+ * Scan period is the idle time in seconds between each subsequent
+ * channel scans.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD: Unsigned 32-bit value.
+ * Carries the value of full scan period in seconds to set.
+ * The value of full scan period is obtained with the same attribute for
+ * get.
+ * Clears the full scan period in the driver when specified with clear
+ * command. Full scan period is the idle period in seconds between two
+ * successive full channel roam scans.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_TRIGGERS: Unsigned 32-bit value.
+ * Carries a bitmap of the roam triggers specified in
+ * enum qca_vendor_roam_triggers.
+ * The driver shall enable roaming by enabling corresponding roam triggers
+ * based on the trigger bits sent with this attribute.
+ * If this attribute is not configured, the driver shall proceed with
+ * default behavior.
+ * The bitmap configured is obtained with the same attribute for get.
+ * Clears the bitmap configured in driver when specified with clear
+ * command.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SELECTION_CRITERIA: Nested attribute signifying the
+ * weightage in percentage (%) to be given for each selection criteria.
+ * Different roam candidate selection criteria are represented by
+ * enum qca_vendor_attr_roam_candidate_selection_criteria.
+ * The driver shall select the roam candidate based on corresponding
+ * candidate selection scores sent.
+ *
+ * An empty nested attribute is used to indicate that no specific
+ * preference score/criteria is configured (i.e., to disable this mechanism
+ * in the set case and to show that the mechanism is disabled in the get
+ * case).
+ *
+ * Userspace can send multiple attributes out of this enum to the driver.
+ * Since this attribute represents the weight/percentage of preference for
+ * the respective selection criteria, it is preferred to configure 100%
+ * total weightage. The value in each attribute or cumulative weight of the
+ * values in all the nested attributes should not exceed 100%. The driver
+ * shall reject such configuration.
+ *
+ * If the weights configured through this attribute are less than 100%,
+ * the driver shall honor the weights (x%) passed for the corresponding
+ * selection criteria and choose/distribute rest of the weight (100-x)%
+ * for the other selection criteria, based on its internal logic.
+ *
+ * The selection criteria configured is obtained with the same
+ * attribute for get.
+ *
+ * Clears the selection criteria configured in the driver when specified
+ * with clear command.
+ */
+enum qca_vendor_attr_roam_control {
+ QCA_ATTR_ROAM_CONTROL_ENABLE = 1,
+ QCA_ATTR_ROAM_CONTROL_STATUS = 2,
+ QCA_ATTR_ROAM_CONTROL_CLEAR_ALL = 3,
+ QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME= 4,
+ QCA_ATTR_ROAM_CONTROL_SCAN_PERIOD = 5,
+ QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD = 6,
+ QCA_ATTR_ROAM_CONTROL_TRIGGERS = 7,
+ QCA_ATTR_ROAM_CONTROL_SELECTION_CRITERIA = 8,
+
+ /* keep last */
+ QCA_ATTR_ROAM_CONTROL_AFTER_LAST,
+ QCA_ATTR_ROAM_CONTROL_MAX =
+ QCA_ATTR_ROAM_CONTROL_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_wlan_vendor_attr_roaming_config_params: Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_ROAM sub command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD: Unsigned 32-bit value.
+ * Represents the different roam sub commands referred by
+ * enum qca_wlan_vendor_roaming_subcmd.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID: Unsigned 32-bit value.
+ * Represents the Request ID for the specific set of commands.
+ * This also helps to map specific set of commands to the respective
+ * ID / client. e.g., helps to identify the user entity configuring the
+ * Blacklist BSSID and accordingly clear the respective ones with the
+ * matching ID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS: Unsigned
+ * 32-bit value.Represents the number of whitelist SSIDs configured.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST: Nested attribute
+ * to carry the list of Whitelist SSIDs.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID: SSID (binary attribute,
+ * 0..32 octets). Represents the white list SSID. Whitelist SSIDs
+ * represent the list of SSIDs to which the firmware/driver can consider
+ * to roam to.
+ *
+ * The following PARAM_A_BAND_XX attributes are applied to 5GHz BSSIDs when
+ * comparing with a 2.4GHz BSSID. They are not applied when comparing two
+ * 5GHz BSSIDs.The following attributes are set through the Roaming SUBCMD -
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD: Signed 32-bit
+ * value, RSSI threshold above which 5GHz RSSI is favored.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD: Signed 32-bit
+ * value, RSSI threshold below which 5GHz RSSI is penalized.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR: Unsigned 32-bit
+ * value, factor by which 5GHz RSSI is boosted.
+ * boost=(RSSI_measured-5GHz_boost_threshold)*5GHz_boost_factor
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR: Unsigned 32-bit
+ * value, factor by which 5GHz RSSI is penalized.
+ * penalty=(5GHz_penalty_threshold-RSSI_measured)*5GHz_penalty_factor
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST: Unsigned 32-bit
+ * value, maximum boost that can be applied to a 5GHz RSSI.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS: Unsigned 32-bit
+ * value, boost applied to current BSSID to ensure the currently
+ * associated BSSID is favored so as to prevent ping-pong situations.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER: Signed 32-bit
+ * value, RSSI below which "Alert" roam is enabled.
+ * "Alert" mode roaming - firmware is "urgently" hunting for another BSSID
+ * because the RSSI is low, or because many successive beacons have been
+ * lost or other bad link conditions.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE: Unsigned 32-bit
+ * value. 1-Enable, 0-Disable. Represents "Lazy" mode, where
+ * firmware is hunting for a better BSSID or white listed SSID even though
+ * the RSSI of the link is good. The parameters enabling the roaming are
+ * configured through the PARAM_A_BAND_XX attrbutes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS: Nested attribute,
+ * represents the BSSIDs preferred over others while evaluating them
+ * for the roaming.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID: Unsigned
+ * 32-bit value. Represents the number of preferred BSSIDs set.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID: 6-byte MAC
+ * address representing the BSSID to be preferred.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER: Signed
+ * 32-bit value, representing the modifier to be applied to the RSSI of
+ * the BSSID for the purpose of comparing it with other roam candidate.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS: Nested attribute,
+ * represents the BSSIDs to get blacklisted for roaming.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID: Unsigned
+ * 32-bit value, represents the number of blacklisted BSSIDs.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID: 6-byte MAC
+ * address representing the Blacklisted BSSID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT: Flag attribute,
+ * indicates this BSSID blacklist as a hint to the driver. The driver can
+ * select this BSSID in the worst case (when no other BSSIDs are better).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL: Nested attribute to
+ * set/get/clear the roam control config as
+ * defined @enum qca_vendor_attr_roam_control.
+ */
enum qca_wlan_vendor_attr_roaming_config_params {
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_INVALID = 0,
@@ -3366,6 +3956,8 @@
/* Flag attribute indicates this BSSID blacklist as a hint */
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT = 21,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL = 22,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX =
@@ -3373,22 +3965,63 @@
};
/*
- * enum qca_wlan_vendor_attr_roam_subcmd: Attributes for data used by
- * QCA_NL80211_VENDOR_SUBCMD_ROAM sub command.
+ * enum qca_wlan_vendor_roaming_subcmd: Referred by
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_WHITE_LIST: Sub command to
+ * configure the white list SSIDs. These are configured through
+ * the following attributes.
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS,
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST,
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS: Sub command to
+ * configure the Roam params. These parameters are evaluated on the GScan
+ * results. Refers the attributes PARAM_A_BAND_XX above to configure the
+ * params.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_LAZY_ROAM: Sets the Lazy roam. Uses
+ * the attribute QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE
+ * to enable/disable Lazy roam.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PREFS: Sets the BSSID
+ * preference. Contains the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS to set the BSSID
+ * preference.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID: Sets the Blacklist
+ * BSSIDs. Refers QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS to
+ * set the same.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET: Command to set the
+ * roam control config to the driver with the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET: Command to obtain the
+ * roam control config from driver with the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ * For the get, the attribute for the configuration to be queried shall
+ * carry any of its acceptable value to the driver. In return, the driver
+ * shall send the configured values within the same attribute to the user
+ * space.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR: Command to clear the
+ * roam control config in the driver with the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ * The driver shall continue with its default roaming behavior when data
+ * corresponding to an attribute is cleared.
*/
-enum qca_wlan_vendor_attr_roam_subcmd {
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_INVALID = 0,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST = 1,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_GSCAN_ROAM_PARAMS = 2,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM = 3,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS = 4,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PARAMS = 5,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID = 6,
-
- /* keep last */
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX =
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST - 1,
+enum qca_wlan_vendor_roaming_subcmd {
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_INVALID = 0,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_WHITE_LIST = 1,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS = 2,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_LAZY_ROAM = 3,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PREFS = 4,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PARAMS = 5,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID = 6,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET = 7,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET = 8,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR = 9,
};
enum qca_wlan_vendor_attr_gscan_config_params {
@@ -3756,8 +4389,8 @@
/* Unsigned 32-bit value; a GSCAN Capabilities attribute.
* This is used to limit the maximum number of BSSIDs while sending
- * the vendor command QCA_NL80211_VENDOR_SUBCMD_ROAM with attributes
- * QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID and
+ * the vendor command QCA_NL80211_VENDOR_SUBCMD_ROAM with subcmd
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID and attribute
* QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID.
*/
QCA_WLAN_VENDOR_ATTR_GSCAN_MAX_NUM_BLACKLISTED_BSSID = 46,
@@ -3859,6 +4492,44 @@
QCA_WLAN_VENDOR_ACS_SELECT_REASON_DFS,
/* Represents the reason that LTE co-exist in the current band. */
QCA_WLAN_VENDOR_ACS_SELECT_REASON_LTE_COEX,
+ /* Represents the reason that generic, uncategorized interference has
+ * been found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_GENERIC_INTERFERENCE,
+ /* Represents the reason that excessive 802.11 interference has been
+ * found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_80211_INTERFERENCE,
+ /* Represents the reason that generic Continuous Wave (CW) interference
+ * has been found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_CW_INTERFERENCE,
+ /* Represents the reason that Microwave Oven (MWO) interference has been
+ * found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_MWO_INTERFERENCE,
+ /* Represents the reason that generic Frequency-Hopping Spread Spectrum
+ * (FHSS) interference has been found in the current channel. This may
+ * include 802.11 waveforms.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_FHSS_INTERFERENCE,
+ /* Represents the reason that non-802.11 generic Frequency-Hopping
+ * Spread Spectrum (FHSS) interference has been found in the current
+ * channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_NON_80211_FHSS_INTERFERENCE,
+ /* Represents the reason that generic Wideband (WB) interference has
+ * been found in the current channel. This may include 802.11 waveforms.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_WB_INTERFERENCE,
+ /* Represents the reason that non-802.11 generic Wideband (WB)
+ * interference has been found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_NON_80211_WB_INTERFERENCE,
+ /* Represents the reason that Jammer interference has been found in the
+ * current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_JAMMER_INTERFERENCE,
};
/**
@@ -4026,6 +4697,46 @@
*/
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS_2 = 11,
+ /*
+ * VHT segment 0 in MHz (u32) and the attribute is mandatory.
+ * Note: Event QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS includes
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+ * along with
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0.
+ *
+ * If both the driver and user-space application supports the 6 GHz
+ * band, QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0
+ * is deprecated and
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+ * should be used.
+ *
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0 = 12,
+
+ /*
+ * VHT segment 1 in MHz (u32) and the attribute is mandatory.
+ * Note: Event QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS includes
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+ * along with
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1.
+ *
+ * If both the driver and user-space application supports the 6 GHz
+ * band, QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1
+ * is deprecated and
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+ * should be considered.
+ *
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 = 13,
+
/* keep last */
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_LAST,
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX =
@@ -4126,9 +4837,100 @@
};
/**
- * qca_wlan_vendor_attr_external_acs_channels: Attributes to vendor subcmd
+ * enum qca_wlan_vendor_attr_external_acs_channels: Attributes to vendor subcmd
* QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS. This carries a list of channels
* in priority order as decided after ACS operation in userspace.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_REASON: Required (u8).
+ * One of reason code from enum qca_wlan_vendor_acs_select_reason.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST: Required
+ * Array of nested values for each channel with following attributes:
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY: Required (u8).
+ * Primary channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY: Required (u8).
+ * Secondary channel number, required only for 160 and 80+80 MHz bandwidths.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0: Required (u8).
+ * VHT seg0 channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0 is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1: Required (u8).
+ * VHT seg1 channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1 is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH: Required (u8).
+ * Takes one of enum nl80211_chan_width values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST: Required
+ * Array of nested values for each channel with following attributes:
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0 in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1 in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY: Required (u32)
+ * Primary channel frequency in MHz
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY: Required (u32)
+ * Secondary channel frequency in MHz used for HT 40 MHz channels.
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0: Required (u32)
+ * VHT seg0 channel frequency in MHz
+ * Note: If user-space application has no support of the 6GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1: Required (u32)
+ * VHT seg1 channel frequency in MHz
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
*/
enum qca_wlan_vendor_attr_external_acs_channels {
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_INVALID = 0,
@@ -4159,6 +4961,12 @@
/* Channel width (u8). Takes one of enum nl80211_chan_width values. */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH = 8,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST = 9,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY = 10,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY = 11,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0 = 12,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1 = 13,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LAST,
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_MAX =
@@ -4676,8 +5484,18 @@
* u8 attribute.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_DEFAULT_AGC_MAX_GAIN = 10,
- /* Flag attribute to indicate agile spectral scan capability */
+ /* Flag attribute to indicate agile spectral scan capability
+ * for 20/40/80 MHz modes.
+ */
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL = 11,
+ /* Flag attribute to indicate agile spectral scan capability
+ * for 160 MHz mode.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL_160 = 12,
+ /* Flag attribute to indicate agile spectral scan capability
+ * for 80+80 MHz mode.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL_80_80 = 13,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX =
@@ -7102,4 +7920,130 @@
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_AFTER_LAST - 1
};
+/**
+ * enum qca_vendor_oem_device_type - Represents the target device in firmware.
+ * It is used by QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO.
+ *
+ * @QCA_VENDOR_OEM_DEVICE_VIRTUAL: The command is intended for
+ * a virtual device.
+ *
+ * @QCA_VENDOR_OEM_DEVICE_PHYSICAL: The command is intended for
+ * a physical device.
+ */
+enum qca_vendor_oem_device_type {
+ QCA_VENDOR_OEM_DEVICE_VIRTUAL = 0,
+ QCA_VENDOR_OEM_DEVICE_PHYSICAL = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_oem_data_params - Used by the vendor command/event
+ * QCA_NL80211_VENDOR_SUBCMD_OEM_DATA.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA: The binary blob for the vendor
+ * command/event QCA_NL80211_VENDOR_SUBCMD_OEM_DATA are carried through this
+ * attribute.
+ * NLA_BINARY attribute, the max size is 1024 bytes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO: The binary blob will be routed
+ * based on this field. This optional attribute is included to specify whether
+ * the device type is a virtual device or a physical device for the
+ * command/event. This attribute can be omitted for a virtual device (default)
+ * command/event.
+ * This u8 attribute is used to carry information for the device type using
+ * values defined by enum qca_vendor_oem_device_type.
+ */
+enum qca_wlan_vendor_attr_oem_data_params {
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA = 1,
+ QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX =
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_avoid_frequency_ext - Defines attributes to be
+ * used with vendor command/event QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE: Required
+ * Nested attribute containing multiple ranges with following attributes:
+ * QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START and
+ * QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START: Required (u32)
+ * Starting center frequency in MHz.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END: Required (u32)
+ * Ending center frequency in MHz.
+ */
+enum qca_wlan_vendor_attr_avoid_frequency_ext {
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE = 1,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START = 2,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END = 3,
+
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX =
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_AFTER_LAST - 1
+};
+
+/*
+ * enum qca_wlan_vendor_attr_add_sta_node_params - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE.
+ */
+enum qca_wlan_vendor_attr_add_sta_node_params {
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_INVALID = 0,
+ /* 6 byte MAC address of STA */
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_MAC_ADDR = 1,
+ /* Authentication algorithm used by the station of size u16;
+ * defined in enum nl80211_auth_type.
+ */
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_MAX =
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_btc_chain_mode - Specifies BT coex chain mode.
+ * This enum defines the valid set of values of BT coex chain mode.
+ * These values are used by attribute %QCA_VENDOR_ATTR_BTC_CHAIN_MODE of
+ * %QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE.
+ *
+ * @QCA_BTC_CHAIN_SHARED: chains of BT and WLAN 2.4G are shared.
+ * @QCA_BTC_CHAIN_SEPARATED: chains of BT and WLAN 2.4G are separated.
+ */
+enum qca_btc_chain_mode {
+ QCA_BTC_CHAIN_SHARED = 0,
+ QCA_BTC_CHAIN_SEPARATED = 1,
+};
+
+/**
+ * enum qca_vendor_attr_btc_chain_mode - Specifies attributes for BT coex
+ * chain mode.
+ * Attributes for data used by QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE.
+ *
+ * @QCA_VENDOR_ATTR_COEX_BTC_CHAIN_MODE: u32 attribute.
+ * Indicates the BT coex chain mode, are 32-bit values from
+ * enum qca_btc_chain_mode. This attribute is mandatory.
+ *
+ * @QCA_VENDOR_ATTR_COEX_BTC_CHAIN_MODE_RESTART: flag attribute.
+ * If set, vdev should be restarted when BT coex chain mode is updated.
+ * This attribute is optional.
+ */
+enum qca_vendor_attr_btc_chain_mode {
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_INVALID = 0,
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE = 1,
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_RESTART = 2,
+
+ /* Keep last */
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_LAST,
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX =
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index 0da7145..2ab168b 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -12,6 +12,8 @@
#include "utils/const_time.h"
#include "crypto/crypto.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
+#include "crypto/sha512.h"
#include "crypto/random.h"
#include "crypto/dh_groups.h"
#include "ieee802_11_defs.h"
@@ -45,6 +47,7 @@
sae->group = group;
tmp->prime_len = crypto_ec_prime_len(tmp->ec);
tmp->prime = crypto_ec_get_prime(tmp->ec);
+ tmp->order_len = crypto_ec_order_len(tmp->ec);
tmp->order = crypto_ec_get_order(tmp->ec);
return 0;
}
@@ -69,6 +72,7 @@
}
tmp->prime = tmp->prime_buf;
+ tmp->order_len = tmp->dh->order_len;
tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
tmp->dh->order_len);
if (tmp->order_buf == NULL) {
@@ -105,6 +109,8 @@
crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
wpabuf_free(tmp->anti_clogging_token);
+ wpabuf_free(tmp->own_rejected_groups);
+ wpabuf_free(tmp->peer_rejected_groups);
os_free(tmp->pw_id);
bin_clear_free(tmp, sizeof(*tmp));
sae->tmp = NULL;
@@ -275,7 +281,7 @@
const u8 *addr2, const u8 *password,
size_t password_len, const char *identifier)
{
- u8 counter, k = 40;
+ u8 counter, k;
u8 addrs[2 * ETH_ALEN];
const u8 *addr[3];
size_t len[3];
@@ -346,6 +352,8 @@
* attacks that attempt to determine the number of iterations required
* in the loop.
*/
+ k = dragonfly_min_pwe_loop_iter(sae->group);
+
for (counter = 1; counter <= k || !found; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
@@ -427,13 +435,6 @@
}
-static int sae_modp_group_require_masking(int group)
-{
- /* Groups for which pwd-value is likely to be >= p frequently */
- return group == 22 || group == 23 || group == 24;
-}
-
-
static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
size_t password_len, const char *identifier)
@@ -482,7 +483,7 @@
len[num_elem] = sizeof(counter);
num_elem++;
- k = sae_modp_group_require_masking(sae->group) ? 40 : 1;
+ k = dragonfly_min_pwe_loop_iter(sae->group);
for (counter = 1; counter <= k || !found; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
@@ -528,6 +529,742 @@
}
+static int hkdf_extract(size_t hash_len, const u8 *salt, size_t salt_len,
+ size_t num_elem, const u8 *addr[], const size_t len[],
+ u8 *prk)
+{
+ if (hash_len == 32)
+ return hmac_sha256_vector(salt, salt_len, num_elem, addr, len,
+ prk);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return hmac_sha384_vector(salt, salt_len, num_elem, addr, len,
+ prk);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return hmac_sha512_vector(salt, salt_len, num_elem, addr, len,
+ prk);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
+static int hkdf_expand(size_t hash_len, const u8 *prk, size_t prk_len,
+ const char *info, u8 *okm, size_t okm_len)
+{
+ size_t info_len = os_strlen(info);
+
+ if (hash_len == 32)
+ return hmac_sha256_kdf(prk, prk_len, NULL,
+ (const u8 *) info, info_len,
+ okm, okm_len);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return hmac_sha384_kdf(prk, prk_len, NULL,
+ (const u8 *) info, info_len,
+ okm, okm_len);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return hmac_sha512_kdf(prk, prk_len, NULL,
+ (const u8 *) info, info_len,
+ okm, okm_len);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
+static int sswu_curve_param(int group, int *z)
+{
+ switch (group) {
+ case 19:
+ case 20:
+ case 21:
+ case 28:
+ *z = -2;
+ return 0;
+ case 25:
+ case 29:
+ *z = -5;
+ return 0;
+ case 26:
+ *z = -11;
+ return 0;
+ case 30:
+ *z = 2;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static void debug_print_bignum(const char *title, const struct crypto_bignum *a,
+ size_t prime_len)
+{
+ u8 *bin;
+
+ bin = os_malloc(prime_len);
+ if (bin && crypto_bignum_to_bin(a, bin, prime_len, prime_len) >= 0)
+ wpa_hexdump_key(MSG_DEBUG, title, bin, prime_len);
+ else
+ wpa_printf(MSG_DEBUG, "Could not print bignum (%s)", title);
+ bin_clear_free(bin, prime_len);
+}
+
+
+static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group,
+ const struct crypto_bignum *u)
+{
+ int z_int;
+ const struct crypto_bignum *a, *b, *prime;
+ struct crypto_bignum *u2, *t1, *t2, *z, *t, *zero, *one, *two, *three,
+ *x1a, *x1b, *y = NULL;
+ struct crypto_bignum *x1 = NULL, *x2, *gx1, *gx2, *v = NULL;
+ unsigned int m_is_zero, is_qr, is_eq;
+ size_t prime_len;
+ u8 bin[SAE_MAX_ECC_PRIME_LEN];
+ u8 bin1[SAE_MAX_ECC_PRIME_LEN];
+ u8 bin2[SAE_MAX_ECC_PRIME_LEN];
+ u8 x_y[2 * SAE_MAX_ECC_PRIME_LEN];
+ struct crypto_ec_point *p = NULL;
+
+ if (sswu_curve_param(group, &z_int) < 0)
+ return NULL;
+
+ prime = crypto_ec_get_prime(ec);
+ prime_len = crypto_ec_prime_len(ec);
+ a = crypto_ec_get_a(ec);
+ b = crypto_ec_get_b(ec);
+
+ u2 = crypto_bignum_init();
+ t1 = crypto_bignum_init();
+ t2 = crypto_bignum_init();
+ z = crypto_bignum_init_uint(abs(z_int));
+ t = crypto_bignum_init();
+ zero = crypto_bignum_init_uint(0);
+ one = crypto_bignum_init_uint(1);
+ two = crypto_bignum_init_uint(2);
+ three = crypto_bignum_init_uint(3);
+ x1a = crypto_bignum_init();
+ x1b = crypto_bignum_init();
+ x2 = crypto_bignum_init();
+ gx1 = crypto_bignum_init();
+ gx2 = crypto_bignum_init();
+ if (!u2 || !t1 || !t2 || !z || !t || !zero || !one || !two || !three ||
+ !x1a || !x1b || !x2 || !gx1 || !gx2)
+ goto fail;
+
+ if (z_int < 0 && crypto_bignum_sub(prime, z, z) < 0)
+ goto fail;
+
+ /* m = z^2 * u^4 + z * u^2 */
+ /* --> tmp = z * u^2, m = tmp^2 + tmp */
+
+ /* u2 = u^2
+ * t1 = z * u2
+ * t2 = t1^2
+ * m = t1 = t1 + t2 */
+ if (crypto_bignum_sqrmod(u, prime, u2) < 0 ||
+ crypto_bignum_mulmod(z, u2, prime, t1) < 0 ||
+ crypto_bignum_sqrmod(t1, prime, t2) < 0 ||
+ crypto_bignum_addmod(t1, t2, prime, t1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: m", t1, prime_len);
+
+ /* l = CEQ(m, 0)
+ * t = CSEL(l, 0, inverse(m); where inverse(x) is calculated as
+ * x^(p-2) modulo p which will handle m == 0 case correctly */
+ /* TODO: Make sure crypto_bignum_is_zero() is constant time */
+ m_is_zero = const_time_eq(crypto_bignum_is_zero(t1), 1);
+ /* t = m^(p-2) modulo p */
+ if (crypto_bignum_sub(prime, two, t2) < 0 ||
+ crypto_bignum_exptmod(t1, t2, prime, t) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: t", t, prime_len);
+
+ /* b / (z * a) */
+ if (crypto_bignum_mulmod(z, a, prime, t1) < 0 ||
+ crypto_bignum_inverse(t1, prime, t1) < 0 ||
+ crypto_bignum_mulmod(b, t1, prime, x1a) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: x1a = b / (z * a)", x1a, prime_len);
+
+ /* (-b/a) * (1 + t) */
+ if (crypto_bignum_sub(prime, b, t1) < 0 ||
+ crypto_bignum_inverse(a, prime, t2) < 0 ||
+ crypto_bignum_mulmod(t1, t2, prime, t1) < 0 ||
+ crypto_bignum_addmod(one, t, prime, t2) < 0 ||
+ crypto_bignum_mulmod(t1, t2, prime, x1b) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: x1b = (-b/a) * (1 + t)", x1b, prime_len);
+
+ /* x1 = CSEL(CEQ(m, 0), x1a, x1b) */
+ if (crypto_bignum_to_bin(x1a, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(x1b, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(m_is_zero, bin1, bin2, prime_len, bin);
+ x1 = crypto_bignum_init_set(bin, prime_len);
+ debug_print_bignum("SSWU: x1 = CSEL(l, x1a, x1b)", x1, prime_len);
+
+ /* gx1 = x1^3 + a * x1 + b */
+ if (crypto_bignum_exptmod(x1, three, prime, t1) < 0 ||
+ crypto_bignum_mulmod(a, x1, prime, t2) < 0 ||
+ crypto_bignum_addmod(t1, t2, prime, t1) < 0 ||
+ crypto_bignum_addmod(t1, b, prime, gx1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: gx1 = x1^3 + a * x1 + b", gx1, prime_len);
+
+ /* x2 = z * u^2 * x1 */
+ if (crypto_bignum_mulmod(z, u2, prime, t1) < 0 ||
+ crypto_bignum_mulmod(t1, x1, prime, x2) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: x2 = z * u^2 * x1", x2, prime_len);
+
+ /* gx2 = x2^3 + a * x2 + b */
+ if (crypto_bignum_exptmod(x2, three, prime, t1) < 0 ||
+ crypto_bignum_mulmod(a, x2, prime, t2) < 0 ||
+ crypto_bignum_addmod(t1, t2, prime, t1) < 0 ||
+ crypto_bignum_addmod(t1, b, prime, gx2) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: gx2 = x2^3 + a * x2 + b", gx2, prime_len);
+
+ /* l = gx1 is a quadratic residue modulo p
+ * --> gx1^((p-1)/2) modulo p is zero or one */
+ if (crypto_bignum_sub(prime, one, t1) < 0 ||
+ crypto_bignum_rshift(t1, 1, t1) < 0 ||
+ crypto_bignum_exptmod(gx1, t1, prime, t1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: gx1^((p-1)/2) modulo p", t1, prime_len);
+ is_qr = const_time_eq(crypto_bignum_is_zero(t1) |
+ crypto_bignum_is_one(t1), 1);
+
+ /* v = CSEL(l, gx1, gx2) */
+ if (crypto_bignum_to_bin(gx1, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(gx2, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(is_qr, bin1, bin2, prime_len, bin);
+ v = crypto_bignum_init_set(bin, prime_len);
+ debug_print_bignum("SSWU: v = CSEL(l, gx1, gx2)", v, prime_len);
+
+ /* x = CSEL(l, x1, x2) */
+ if (crypto_bignum_to_bin(x1, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(x2, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(is_qr, bin1, bin2, prime_len, x_y);
+ wpa_hexdump_key(MSG_DEBUG, "SSWU: x = CSEL(l, x1, x2)", x_y, prime_len);
+
+ /* y = sqrt(v)
+ * For prime p such that p = 3 mod 4 --> v^((p+1)/4) */
+ if (crypto_bignum_to_bin(prime, bin1, sizeof(bin1), prime_len) < 0)
+ goto fail;
+ if ((bin1[prime_len - 1] & 0x03) != 3) {
+ wpa_printf(MSG_DEBUG, "SSWU: prime does not have p = 3 mod 4");
+ goto fail;
+ }
+ y = crypto_bignum_init();
+ if (!y ||
+ crypto_bignum_add(prime, one, t1) < 0 ||
+ crypto_bignum_rshift(t1, 2, t1) < 0 ||
+ crypto_bignum_exptmod(v, t1, prime, y) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: y = sqrt(v)", y, prime_len);
+
+ /* l = CEQ(LSB(u), LSB(y)) */
+ if (crypto_bignum_to_bin(u, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(y, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ is_eq = const_time_eq(bin1[prime_len - 1] & 0x01,
+ bin2[prime_len - 1] & 0x01);
+
+ /* P = CSEL(l, (x,y), (x, p-y)) */
+ if (crypto_bignum_sub(prime, y, t1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: p - y", t1, prime_len);
+ if (crypto_bignum_to_bin(y, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(t1, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(is_eq, bin1, bin2, prime_len, &x_y[prime_len]);
+
+ /* output P */
+ wpa_hexdump_key(MSG_DEBUG, "SSWU: P.x", x_y, prime_len);
+ wpa_hexdump_key(MSG_DEBUG, "SSWU: P.y", &x_y[prime_len], prime_len);
+ p = crypto_ec_point_from_bin(ec, x_y);
+
+fail:
+ crypto_bignum_deinit(u2, 1);
+ crypto_bignum_deinit(t1, 1);
+ crypto_bignum_deinit(t2, 1);
+ crypto_bignum_deinit(z, 0);
+ crypto_bignum_deinit(t, 1);
+ crypto_bignum_deinit(x1a, 1);
+ crypto_bignum_deinit(x1b, 1);
+ crypto_bignum_deinit(x1, 1);
+ crypto_bignum_deinit(x2, 1);
+ crypto_bignum_deinit(gx1, 1);
+ crypto_bignum_deinit(gx2, 1);
+ crypto_bignum_deinit(y, 1);
+ crypto_bignum_deinit(v, 1);
+ crypto_bignum_deinit(zero, 0);
+ crypto_bignum_deinit(one, 0);
+ crypto_bignum_deinit(two, 0);
+ crypto_bignum_deinit(three, 0);
+ forced_memzero(bin, sizeof(bin));
+ forced_memzero(bin1, sizeof(bin1));
+ forced_memzero(bin2, sizeof(bin2));
+ forced_memzero(x_y, sizeof(x_y));
+ return p;
+}
+
+
+static int sae_pwd_seed(size_t hash_len, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier, u8 *pwd_seed)
+{
+ const u8 *addr[2];
+ size_t len[2];
+ size_t num_elem;
+
+ /* pwd-seed = HKDF-Extract(ssid, password [ || identifier ]) */
+ addr[0] = password;
+ len[0] = password_len;
+ num_elem = 1;
+ wpa_hexdump_ascii(MSG_DEBUG, "SAE: SSID", ssid, ssid_len);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+ password, password_len);
+ if (identifier) {
+ wpa_printf(MSG_DEBUG, "SAE: password identifier: %s",
+ identifier);
+ addr[num_elem] = (const u8 *) identifier;
+ len[num_elem] = os_strlen(identifier);
+ num_elem++;
+ }
+ if (hkdf_extract(hash_len, ssid, ssid_len, num_elem, addr, len,
+ pwd_seed) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, hash_len);
+ return 0;
+}
+
+
+size_t sae_ecc_prime_len_2_hash_len(size_t prime_len)
+{
+ if (prime_len <= 256 / 8)
+ return 32;
+ if (prime_len <= 384 / 8)
+ return 48;
+ return 64;
+}
+
+
+struct crypto_ec_point *
+sae_derive_pt_ecc(struct crypto_ec *ec, int group,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ u8 pwd_seed[64];
+ u8 pwd_value[SAE_MAX_ECC_PRIME_LEN * 2];
+ size_t pwd_value_len, hash_len, prime_len;
+ const struct crypto_bignum *prime;
+ struct crypto_bignum *bn = NULL;
+ struct crypto_ec_point *p1 = NULL, *p2 = NULL, *pt = NULL;
+
+ prime = crypto_ec_get_prime(ec);
+ prime_len = crypto_ec_prime_len(ec);
+ if (prime_len > SAE_MAX_ECC_PRIME_LEN)
+ goto fail;
+ hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+
+ /* len = olen(p) + ceil(olen(p)/2) */
+ pwd_value_len = prime_len + (prime_len + 1) / 2;
+
+ if (sae_pwd_seed(hash_len, ssid, ssid_len, password, password_len,
+ identifier, pwd_seed) < 0)
+ goto fail;
+
+ /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u1 P1", len)
+ */
+ if (hkdf_expand(hash_len, pwd_seed, hash_len,
+ "SAE Hash to Element u1 P1", pwd_value, pwd_value_len) <
+ 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value (u1 P1)",
+ pwd_value, pwd_value_len);
+
+ /* u1 = pwd-value modulo p */
+ bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+ if (!bn || crypto_bignum_mod(bn, prime, bn) < 0 ||
+ crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+ prime_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: u1", pwd_value, prime_len);
+
+ /* P1 = SSWU(u1) */
+ p1 = sswu(ec, group, bn);
+ if (!p1)
+ goto fail;
+
+ /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u2 P2", len)
+ */
+ if (hkdf_expand(hash_len, pwd_seed, hash_len,
+ "SAE Hash to Element u2 P2", pwd_value,
+ pwd_value_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value (u2 P2)",
+ pwd_value, pwd_value_len);
+
+ /* u2 = pwd-value modulo p */
+ crypto_bignum_deinit(bn, 1);
+ bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+ if (!bn || crypto_bignum_mod(bn, prime, bn) < 0 ||
+ crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+ prime_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: u2", pwd_value, prime_len);
+
+ /* P2 = SSWU(u2) */
+ p2 = sswu(ec, group, bn);
+ if (!p2)
+ goto fail;
+
+ /* PT = elem-op(P1, P2) */
+ pt = crypto_ec_point_init(ec);
+ if (!pt)
+ goto fail;
+ if (crypto_ec_point_add(ec, p1, p2, pt) < 0) {
+ crypto_ec_point_deinit(pt, 1);
+ pt = NULL;
+ }
+
+fail:
+ forced_memzero(pwd_seed, sizeof(pwd_seed));
+ forced_memzero(pwd_value, sizeof(pwd_value));
+ crypto_bignum_deinit(bn, 1);
+ crypto_ec_point_deinit(p1, 1);
+ crypto_ec_point_deinit(p2, 1);
+ return pt;
+}
+
+
+size_t sae_ffc_prime_len_2_hash_len(size_t prime_len)
+{
+ if (prime_len <= 2048 / 8)
+ return 32;
+ if (prime_len <= 3072 / 8)
+ return 48;
+ return 64;
+}
+
+
+static struct crypto_bignum *
+sae_derive_pt_ffc(const struct dh_group *dh, int group,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ size_t hash_len, prime_len, pwd_value_len;
+ struct crypto_bignum *prime, *order;
+ struct crypto_bignum *one = NULL, *two = NULL, *bn = NULL, *tmp = NULL,
+ *pt = NULL;
+ u8 pwd_seed[64];
+ u8 pwd_value[SAE_MAX_PRIME_LEN + SAE_MAX_PRIME_LEN / 2];
+
+ prime = crypto_bignum_init_set(dh->prime, dh->prime_len);
+ order = crypto_bignum_init_set(dh->order, dh->order_len);
+ if (!prime || !order)
+ goto fail;
+ prime_len = dh->prime_len;
+ if (prime_len > SAE_MAX_PRIME_LEN)
+ goto fail;
+ hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+
+ /* len = olen(p) + ceil(olen(p)/2) */
+ pwd_value_len = prime_len + (prime_len + 1) / 2;
+ if (pwd_value_len > sizeof(pwd_value))
+ goto fail;
+
+ if (sae_pwd_seed(hash_len, ssid, ssid_len, password, password_len,
+ identifier, pwd_seed) < 0)
+ goto fail;
+
+ /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element", len) */
+ if (hkdf_expand(hash_len, pwd_seed, hash_len,
+ "SAE Hash to Element", pwd_value, pwd_value_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
+ pwd_value, pwd_value_len);
+
+ /* pwd-value = (pwd-value modulo (p-2)) + 2 */
+ bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+ one = crypto_bignum_init_uint(1);
+ two = crypto_bignum_init_uint(2);
+ tmp = crypto_bignum_init();
+ if (!bn || !one || !two || !tmp ||
+ crypto_bignum_sub(prime, two, tmp) < 0 ||
+ crypto_bignum_mod(bn, tmp, bn) < 0 ||
+ crypto_bignum_add(bn, two, bn) < 0 ||
+ crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+ prime_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value(reduced)",
+ pwd_value, prime_len);
+
+ /* PT = pwd-value^((p-1)/q) modulo p */
+ pt = crypto_bignum_init();
+ if (!pt ||
+ crypto_bignum_sub(prime, one, tmp) < 0 ||
+ crypto_bignum_div(tmp, order, tmp) < 0 ||
+ crypto_bignum_exptmod(bn, tmp, prime, pt) < 0) {
+ crypto_bignum_deinit(pt, 1);
+ pt = NULL;
+ goto fail;
+ }
+ debug_print_bignum("SAE: PT", pt, prime_len);
+
+fail:
+ forced_memzero(pwd_seed, sizeof(pwd_seed));
+ forced_memzero(pwd_value, sizeof(pwd_value));
+ crypto_bignum_deinit(bn, 1);
+ crypto_bignum_deinit(tmp, 1);
+ crypto_bignum_deinit(one, 0);
+ crypto_bignum_deinit(two, 0);
+ crypto_bignum_deinit(prime, 0);
+ crypto_bignum_deinit(order, 0);
+ return pt;
+}
+
+
+static struct sae_pt *
+sae_derive_pt_group(int group, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ struct sae_pt *pt;
+
+ wpa_printf(MSG_DEBUG, "SAE: Derive PT - group %d", group);
+
+ pt = os_zalloc(sizeof(*pt));
+ if (!pt)
+ return NULL;
+
+ pt->group = group;
+ pt->ec = crypto_ec_init(group);
+ if (pt->ec) {
+ pt->ecc_pt = sae_derive_pt_ecc(pt->ec, group, ssid, ssid_len,
+ password, password_len,
+ identifier);
+ if (!pt->ecc_pt) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to derive PT");
+ goto fail;
+ }
+
+ return pt;
+ }
+
+ pt->dh = dh_groups_get(group);
+ if (!pt->dh) {
+ wpa_printf(MSG_DEBUG, "SAE: Unsupported group %d", group);
+ goto fail;
+ }
+
+ pt->ffc_pt = sae_derive_pt_ffc(pt->dh, group, ssid, ssid_len,
+ password, password_len, identifier);
+ if (!pt->ffc_pt) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to derive PT");
+ goto fail;
+ }
+
+ return pt;
+fail:
+ sae_deinit_pt(pt);
+ return NULL;
+}
+
+
+struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ struct sae_pt *pt = NULL, *last = NULL, *tmp;
+ int default_groups[] = { 19, 0 };
+ int i;
+
+ if (!groups)
+ groups = default_groups;
+ for (i = 0; groups[i] > 0; i++) {
+ tmp = sae_derive_pt_group(groups[i], ssid, ssid_len, password,
+ password_len, identifier);
+ if (!tmp)
+ continue;
+
+ if (last)
+ last->next = tmp;
+ else
+ pt = tmp;
+ last = tmp;
+ }
+
+ return pt;
+}
+
+
+static void sae_max_min_addr(const u8 *addr[], size_t len[],
+ const u8 *addr1, const u8 *addr2)
+{
+ len[0] = ETH_ALEN;
+ len[1] = ETH_ALEN;
+ if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
+ addr[0] = addr1;
+ addr[1] = addr2;
+ } else {
+ addr[0] = addr2;
+ addr[1] = addr1;
+ }
+}
+
+
+struct crypto_ec_point *
+sae_derive_pwe_from_pt_ecc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2)
+{
+ u8 bin[SAE_MAX_ECC_PRIME_LEN * 2];
+ size_t prime_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 salt[64], hash[64];
+ size_t hash_len;
+ const struct crypto_bignum *order;
+ struct crypto_bignum *tmp = NULL, *val = NULL, *one = NULL;
+ struct crypto_ec_point *pwe = NULL;
+
+ wpa_printf(MSG_DEBUG, "SAE: Derive PWE from PT");
+ prime_len = crypto_ec_prime_len(pt->ec);
+ if (crypto_ec_point_to_bin(pt->ec, pt->ecc_pt,
+ bin, bin + prime_len) < 0)
+ return NULL;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PT.x", bin, prime_len);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PT.y", bin + prime_len, prime_len);
+
+ sae_max_min_addr(addr, len, addr1, addr2);
+
+ /* val = H(0^n,
+ * MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC)) */
+ wpa_printf(MSG_DEBUG, "SAE: val = H(0^n, MAX(addrs) || MIN(addrs))");
+ hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+ os_memset(salt, 0, hash_len);
+ if (hkdf_extract(hash_len, salt, hash_len, 2, addr, len, hash) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "SAE: val", hash, hash_len);
+
+ /* val = val modulo (q - 1) + 1 */
+ order = crypto_ec_get_order(pt->ec);
+ tmp = crypto_bignum_init();
+ val = crypto_bignum_init_set(hash, hash_len);
+ one = crypto_bignum_init_uint(1);
+ if (!tmp || !val || !one ||
+ crypto_bignum_sub(order, one, tmp) < 0 ||
+ crypto_bignum_mod(val, tmp, val) < 0 ||
+ crypto_bignum_add(val, one, val) < 0)
+ goto fail;
+ debug_print_bignum("SAE: val(reduced to 1..q-1)", val, prime_len);
+
+ /* PWE = scalar-op(val, PT) */
+ pwe = crypto_ec_point_init(pt->ec);
+ if (!pwe ||
+ crypto_ec_point_mul(pt->ec, pt->ecc_pt, val, pwe) < 0 ||
+ crypto_ec_point_to_bin(pt->ec, pwe, bin, bin + prime_len) < 0) {
+ crypto_ec_point_deinit(pwe, 1);
+ pwe = NULL;
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PWE.x", bin, prime_len);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PWE.y", bin + prime_len, prime_len);
+
+fail:
+ crypto_bignum_deinit(tmp, 1);
+ crypto_bignum_deinit(val, 1);
+ crypto_bignum_deinit(one, 0);
+ return pwe;
+}
+
+
+struct crypto_bignum *
+sae_derive_pwe_from_pt_ffc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2)
+{
+ size_t prime_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 salt[64], hash[64];
+ size_t hash_len;
+ struct crypto_bignum *tmp = NULL, *val = NULL, *one = NULL;
+ struct crypto_bignum *pwe = NULL, *order = NULL, *prime = NULL;
+
+ wpa_printf(MSG_DEBUG, "SAE: Derive PWE from PT");
+ prime = crypto_bignum_init_set(pt->dh->prime, pt->dh->prime_len);
+ order = crypto_bignum_init_set(pt->dh->order, pt->dh->order_len);
+ if (!prime || !order)
+ goto fail;
+ prime_len = pt->dh->prime_len;
+
+ sae_max_min_addr(addr, len, addr1, addr2);
+
+ /* val = H(0^n,
+ * MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC)) */
+ wpa_printf(MSG_DEBUG, "SAE: val = H(0^n, MAX(addrs) || MIN(addrs))");
+ hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+ os_memset(salt, 0, hash_len);
+ if (hkdf_extract(hash_len, salt, hash_len, 2, addr, len, hash) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "SAE: val", hash, hash_len);
+
+ /* val = val modulo (q - 1) + 1 */
+ tmp = crypto_bignum_init();
+ val = crypto_bignum_init_set(hash, hash_len);
+ one = crypto_bignum_init_uint(1);
+ if (!tmp || !val || !one ||
+ crypto_bignum_sub(order, one, tmp) < 0 ||
+ crypto_bignum_mod(val, tmp, val) < 0 ||
+ crypto_bignum_add(val, one, val) < 0)
+ goto fail;
+ debug_print_bignum("SAE: val(reduced to 1..q-1)", val, prime_len);
+
+ /* PWE = scalar-op(val, PT) */
+ pwe = crypto_bignum_init();
+ if (!pwe || crypto_bignum_exptmod(pt->ffc_pt, val, prime, pwe) < 0) {
+ crypto_bignum_deinit(pwe, 1);
+ pwe = NULL;
+ goto fail;
+ }
+ debug_print_bignum("SAE: PWE", pwe, prime_len);
+
+fail:
+ crypto_bignum_deinit(tmp, 1);
+ crypto_bignum_deinit(val, 1);
+ crypto_bignum_deinit(one, 0);
+ crypto_bignum_deinit(prime, 0);
+ crypto_bignum_deinit(order, 0);
+ return pwe;
+}
+
+
+void sae_deinit_pt(struct sae_pt *pt)
+{
+ struct sae_pt *prev;
+
+ while (pt) {
+ crypto_ec_point_deinit(pt->ecc_pt, 1);
+ crypto_bignum_deinit(pt->ffc_pt, 1);
+ crypto_ec_deinit(pt->ec);
+ prev = pt;
+ pt = pt->next;
+ os_free(prev);
+ }
+}
+
+
static int sae_derive_commit_element_ecc(struct sae_data *sae,
struct crypto_bignum *mask)
{
@@ -607,10 +1344,66 @@
identifier) < 0) ||
(sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
password_len,
- identifier) < 0) ||
- sae_derive_commit(sae) < 0)
+ identifier) < 0))
return -1;
- return 0;
+
+ sae->tmp->h2e = 0;
+ return sae_derive_commit(sae);
+}
+
+
+int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2,
+ int *rejected_groups)
+{
+ if (!sae->tmp)
+ return -1;
+
+ while (pt) {
+ if (pt->group == sae->group)
+ break;
+ pt = pt->next;
+ }
+ if (!pt) {
+ wpa_printf(MSG_INFO, "SAE: Could not find PT for group %u",
+ sae->group);
+ return -1;
+ }
+
+ sae->tmp->own_addr_higher = os_memcmp(addr1, addr2, ETH_ALEN) > 0;
+ wpabuf_free(sae->tmp->own_rejected_groups);
+ sae->tmp->own_rejected_groups = NULL;
+ if (rejected_groups) {
+ int count, i;
+ struct wpabuf *groups;
+
+ count = int_array_len(rejected_groups);
+ groups = wpabuf_alloc(count * 2);
+ if (!groups)
+ return -1;
+ for (i = 0; i < count; i++)
+ wpabuf_put_le16(groups, rejected_groups[i]);
+ sae->tmp->own_rejected_groups = groups;
+ }
+
+ if (pt->ec) {
+ crypto_ec_point_deinit(sae->tmp->pwe_ecc, 1);
+ sae->tmp->pwe_ecc = sae_derive_pwe_from_pt_ecc(pt, addr1,
+ addr2);
+ if (!sae->tmp->pwe_ecc)
+ return -1;
+ }
+
+ if (pt->dh) {
+ crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
+ sae->tmp->pwe_ffc = sae_derive_pwe_from_pt_ffc(pt, addr1,
+ addr2);
+ if (!sae->tmp->pwe_ffc)
+ return -1;
+ }
+
+ sae->tmp->h2e = 1;
+ return sae_derive_commit(sae);
}
@@ -688,47 +1481,124 @@
}
+static int sae_kdf_hash(size_t hash_len, const u8 *k, const char *label,
+ const u8 *context, size_t context_len,
+ u8 *out, size_t out_len)
+{
+ if (hash_len == 32)
+ return sha256_prf(k, hash_len, label,
+ context, context_len, out, out_len);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return sha384_prf(k, hash_len, label,
+ context, context_len, out, out_len);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return sha512_prf(k, hash_len, label,
+ context, context_len, out, out_len);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
static int sae_derive_keys(struct sae_data *sae, const u8 *k)
{
- u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN];
- u8 keyseed[SHA256_MAC_LEN];
- u8 keys[SAE_KCK_LEN + SAE_PMK_LEN];
+ u8 zero[SAE_MAX_HASH_LEN], val[SAE_MAX_PRIME_LEN];
+ const u8 *salt;
+ struct wpabuf *rejected_groups = NULL;
+ u8 keyseed[SAE_MAX_HASH_LEN];
+ u8 keys[SAE_MAX_HASH_LEN + SAE_PMK_LEN];
struct crypto_bignum *tmp;
int ret = -1;
+ size_t hash_len, salt_len, prime_len = sae->tmp->prime_len;
+ const u8 *addr[1];
+ size_t len[1];
tmp = crypto_bignum_init();
if (tmp == NULL)
goto fail;
- /* keyseed = H(<0>32, k)
- * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
+ /* keyseed = H(salt, k)
+ * KCK || PMK = KDF-Hash-Length(keyseed, "SAE KCK and PMK",
* (commit-scalar + peer-commit-scalar) modulo r)
* PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
*/
+ if (!sae->tmp->h2e)
+ hash_len = SHA256_MAC_LEN;
+ else if (sae->tmp->dh)
+ hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+ else
+ hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+ if (sae->tmp->h2e && (sae->tmp->own_rejected_groups ||
+ sae->tmp->peer_rejected_groups)) {
+ struct wpabuf *own, *peer;
- os_memset(null_key, 0, sizeof(null_key));
- hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len,
- keyseed);
- wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed));
-
- crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
- tmp);
- crypto_bignum_mod(tmp, sae->tmp->order, tmp);
- crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
- wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
- if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
- val, sae->tmp->prime_len, keys, sizeof(keys)) < 0)
+ own = sae->tmp->own_rejected_groups;
+ peer = sae->tmp->peer_rejected_groups;
+ salt_len = 0;
+ if (own)
+ salt_len += wpabuf_len(own);
+ if (peer)
+ salt_len += wpabuf_len(peer);
+ rejected_groups = wpabuf_alloc(salt_len);
+ if (!rejected_groups)
+ goto fail;
+ if (sae->tmp->own_addr_higher) {
+ if (own)
+ wpabuf_put_buf(rejected_groups, own);
+ if (peer)
+ wpabuf_put_buf(rejected_groups, peer);
+ } else {
+ if (peer)
+ wpabuf_put_buf(rejected_groups, peer);
+ if (own)
+ wpabuf_put_buf(rejected_groups, own);
+ }
+ salt = wpabuf_head(rejected_groups);
+ salt_len = wpabuf_len(rejected_groups);
+ } else {
+ os_memset(zero, 0, hash_len);
+ salt = zero;
+ salt_len = hash_len;
+ }
+ wpa_hexdump(MSG_DEBUG, "SAE: salt for keyseed derivation",
+ salt, salt_len);
+ addr[0] = k;
+ len[0] = prime_len;
+ if (hkdf_extract(hash_len, salt, salt_len, 1, addr, len, keyseed) < 0)
goto fail;
- os_memset(keyseed, 0, sizeof(keyseed));
- os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
- os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, hash_len);
+
+ if (crypto_bignum_add(sae->tmp->own_commit_scalar,
+ sae->peer_commit_scalar, tmp) < 0 ||
+ crypto_bignum_mod(tmp, sae->tmp->order, tmp) < 0)
+ goto fail;
+ /* IEEE Std 802.11-2016 is not exactly clear on the encoding of the bit
+ * string that is needed for KCK, PMK, and PMKID derivation, but it
+ * seems to make most sense to encode the
+ * (commit-scalar + peer-commit-scalar) mod r part as a bit string by
+ * zero padding it from left to the length of the order (in full
+ * octets). */
+ crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
+ if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
+ val, sae->tmp->order_len,
+ keys, hash_len + SAE_PMK_LEN) < 0)
+ goto fail;
+ forced_memzero(keyseed, sizeof(keyseed));
+ os_memcpy(sae->tmp->kck, keys, hash_len);
+ sae->tmp->kck_len = hash_len;
+ os_memcpy(sae->pmk, keys + hash_len, SAE_PMK_LEN);
os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
- os_memset(keys, 0, sizeof(keys));
- wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
+ forced_memzero(keys, sizeof(keys));
+ wpa_hexdump_key(MSG_DEBUG, "SAE: KCK",
+ sae->tmp->kck, sae->tmp->kck_len);
wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
ret = 0;
fail:
+ wpabuf_free(rejected_groups);
crypto_bignum_deinit(tmp, 0);
return ret;
}
@@ -791,6 +1661,16 @@
wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s",
identifier);
}
+
+ if (sae->tmp->h2e && sae->tmp->own_rejected_groups) {
+ wpa_hexdump_buf(MSG_DEBUG, "SAE: own Rejected Groups",
+ sae->tmp->own_rejected_groups);
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf,
+ 1 + wpabuf_len(sae->tmp->own_rejected_groups));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_REJECTED_GROUPS);
+ wpabuf_put_buf(buf, sae->tmp->own_rejected_groups);
+ }
}
@@ -846,9 +1726,19 @@
}
+static int sae_is_rejected_groups_elem(const u8 *pos, const u8 *end)
+{
+ return end - pos >= 3 &&
+ pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] >= 2 &&
+ end - pos - 2 >= pos[1] &&
+ pos[2] == WLAN_EID_EXT_REJECTED_GROUPS;
+}
+
+
static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
const u8 *end, const u8 **token,
- size_t *token_len)
+ size_t *token_len, int h2e)
{
size_t scalar_elem_len, tlen;
const u8 *elem;
@@ -869,6 +1759,8 @@
* fields, so use that length as a requirement for the received
* token and check for the presence of possible Password
* Identifier element based on the element header information.
+ * When parsing H2E case, also consider the Rejected Groupd element
+ * similarly.
*/
tlen = end - (*pos + scalar_elem_len);
@@ -886,12 +1778,27 @@
* this frame. */
return;
}
+ if (h2e && sae_is_rejected_groups_elem(elem, end)) {
+ /* Rejected Groups takes out all available extra octets, so
+ * there can be no Anti-Clogging token in this frame. */
+ return;
+ }
elem += SHA256_MAC_LEN;
if (sae_is_password_id_elem(elem, end)) {
/* Password Identifier element is included in the end, so
* remove its length from the Anti-Clogging token field. */
tlen -= 2 + elem[1];
+ elem += 2 + elem[1];
+ if (h2e && sae_is_rejected_groups_elem(elem, end)) {
+ /* Also remove Rejected Groups element from the
+ * Anti-Clogging token field length */
+ tlen -= 2 + elem[1];
+ }
+ } else if (h2e && sae_is_rejected_groups_elem(elem, end)) {
+ /* Rejected Groups element is included in the end, so
+ * remove its length from the Anti-Clogging token field. */
+ tlen -= 2 + elem[1];
}
wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
@@ -1058,11 +1965,11 @@
static int sae_parse_password_identifier(struct sae_data *sae,
- const u8 *pos, const u8 *end)
+ const u8 **pos, const u8 *end)
{
wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
- pos, end - pos);
- if (!sae_is_password_id_elem(pos, end)) {
+ *pos, end - *pos);
+ if (!sae_is_password_id_elem(*pos, end)) {
if (sae->tmp->pw_id) {
wpa_printf(MSG_DEBUG,
"SAE: No Password Identifier included, but expected one (%s)",
@@ -1075,8 +1982,8 @@
}
if (sae->tmp->pw_id &&
- (pos[1] - 1 != (int) os_strlen(sae->tmp->pw_id) ||
- os_memcmp(sae->tmp->pw_id, pos + 3, pos[1] - 1) != 0)) {
+ ((*pos)[1] - 1 != (int) os_strlen(sae->tmp->pw_id) ||
+ os_memcmp(sae->tmp->pw_id, (*pos) + 3, (*pos)[1] - 1) != 0)) {
wpa_printf(MSG_DEBUG,
"SAE: The included Password Identifier does not match the expected one (%s)",
sae->tmp->pw_id);
@@ -1084,19 +1991,39 @@
}
os_free(sae->tmp->pw_id);
- sae->tmp->pw_id = os_malloc(pos[1]);
+ sae->tmp->pw_id = os_malloc((*pos)[1]);
if (!sae->tmp->pw_id)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- os_memcpy(sae->tmp->pw_id, pos + 3, pos[1] - 1);
- sae->tmp->pw_id[pos[1] - 1] = '\0';
+ os_memcpy(sae->tmp->pw_id, (*pos) + 3, (*pos)[1] - 1);
+ sae->tmp->pw_id[(*pos)[1] - 1] = '\0';
wpa_hexdump_ascii(MSG_DEBUG, "SAE: Received Password Identifier",
- sae->tmp->pw_id, pos[1] - 1);
+ sae->tmp->pw_id, (*pos)[1] - 1);
+ *pos = *pos + 2 + (*pos)[1];
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static int sae_parse_rejected_groups(struct sae_data *sae,
+ const u8 *pos, const u8 *end)
+{
+ wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
+ pos, end - pos);
+ if (!sae_is_rejected_groups_elem(pos, end))
+ return WLAN_STATUS_SUCCESS;
+ wpabuf_free(sae->tmp->peer_rejected_groups);
+ sae->tmp->peer_rejected_groups = wpabuf_alloc(pos[1] - 1);
+ if (!sae->tmp->peer_rejected_groups)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpabuf_put_data(sae->tmp->peer_rejected_groups, pos + 3, pos[1] - 1);
+ wpa_hexdump_buf(MSG_DEBUG, "SAE: Received Rejected Groups list",
+ sae->tmp->peer_rejected_groups);
return WLAN_STATUS_SUCCESS;
}
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
- const u8 **token, size_t *token_len, int *allowed_groups)
+ const u8 **token, size_t *token_len, int *allowed_groups,
+ int h2e)
{
const u8 *pos = data, *end = data + len;
u16 res;
@@ -1110,7 +2037,7 @@
pos += 2;
/* Optional Anti-Clogging Token */
- sae_parse_commit_token(sae, &pos, end, token, token_len);
+ sae_parse_commit_token(sae, &pos, end, token, token_len, h2e);
/* commit-scalar */
res = sae_parse_commit_scalar(sae, &pos, end);
@@ -1123,10 +2050,17 @@
return res;
/* Optional Password Identifier element */
- res = sae_parse_password_identifier(sae, pos, end);
+ res = sae_parse_password_identifier(sae, &pos, end);
if (res != WLAN_STATUS_SUCCESS)
return res;
+ /* Conditional Rejected Groups element */
+ if (h2e) {
+ res = sae_parse_rejected_groups(sae, pos, end);
+ if (res != WLAN_STATUS_SUCCESS)
+ return res;
+ }
+
/*
* Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
* the values we sent which would be evidence of a reflection attack.
@@ -1154,12 +2088,12 @@
}
-static void sae_cn_confirm(struct sae_data *sae, const u8 *sc,
- const struct crypto_bignum *scalar1,
- const u8 *element1, size_t element1_len,
- const struct crypto_bignum *scalar2,
- const u8 *element2, size_t element2_len,
- u8 *confirm)
+static int sae_cn_confirm(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const u8 *element1, size_t element1_len,
+ const struct crypto_bignum *scalar2,
+ const u8 *element2, size_t element2_len,
+ u8 *confirm)
{
const u8 *addr[5];
size_t len[5];
@@ -1173,72 +2107,81 @@
* verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
* PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
*/
+ if (crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
+ sae->tmp->prime_len) < 0 ||
+ crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
+ sae->tmp->prime_len) < 0)
+ return -1;
addr[0] = sc;
len[0] = 2;
- crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
- sae->tmp->prime_len);
addr[1] = scalar_b1;
len[1] = sae->tmp->prime_len;
addr[2] = element1;
len[2] = element1_len;
- crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
- sae->tmp->prime_len);
addr[3] = scalar_b2;
len[3] = sae->tmp->prime_len;
addr[4] = element2;
len[4] = element2_len;
- hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len,
- confirm);
+ return hkdf_extract(sae->tmp->kck_len, sae->tmp->kck, sae->tmp->kck_len,
+ 5, addr, len, confirm);
}
-static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
- const struct crypto_bignum *scalar1,
- const struct crypto_ec_point *element1,
- const struct crypto_bignum *scalar2,
- const struct crypto_ec_point *element2,
- u8 *confirm)
+static int sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const struct crypto_ec_point *element1,
+ const struct crypto_bignum *scalar2,
+ const struct crypto_ec_point *element2,
+ u8 *confirm)
{
u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN];
u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN];
- crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
- element_b1 + sae->tmp->prime_len);
- crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
- element_b2 + sae->tmp->prime_len);
-
- sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
- scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
+ if (crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
+ element_b1 + sae->tmp->prime_len) < 0 ||
+ crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
+ element_b2 + sae->tmp->prime_len) < 0 ||
+ sae_cn_confirm(sae, sc, scalar1, element_b1,
+ 2 * sae->tmp->prime_len,
+ scalar2, element_b2, 2 * sae->tmp->prime_len,
+ confirm) < 0)
+ return -1;
+ return 0;
}
-static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
- const struct crypto_bignum *scalar1,
- const struct crypto_bignum *element1,
- const struct crypto_bignum *scalar2,
- const struct crypto_bignum *element2,
- u8 *confirm)
+static int sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const struct crypto_bignum *element1,
+ const struct crypto_bignum *scalar2,
+ const struct crypto_bignum *element2,
+ u8 *confirm)
{
u8 element_b1[SAE_MAX_PRIME_LEN];
u8 element_b2[SAE_MAX_PRIME_LEN];
- crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
- sae->tmp->prime_len);
- crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
- sae->tmp->prime_len);
-
- sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
- scalar2, element_b2, sae->tmp->prime_len, confirm);
+ if (crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
+ sae->tmp->prime_len) < 0 ||
+ crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
+ sae->tmp->prime_len) < 0 ||
+ sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
+ scalar2, element_b2, sae->tmp->prime_len,
+ confirm) < 0)
+ return -1;
+ return 0;
}
void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
{
const u8 *sc;
+ size_t hash_len;
if (sae->tmp == NULL)
return;
+ hash_len = sae->tmp->kck_len;
+
/* Send-Confirm */
sc = wpabuf_put(buf, 0);
wpabuf_put_le16(buf, sae->send_confirm);
@@ -1250,59 +2193,63 @@
sae->tmp->own_commit_element_ecc,
sae->peer_commit_scalar,
sae->tmp->peer_commit_element_ecc,
- wpabuf_put(buf, SHA256_MAC_LEN));
+ wpabuf_put(buf, hash_len));
else
sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
sae->tmp->own_commit_element_ffc,
sae->peer_commit_scalar,
sae->tmp->peer_commit_element_ffc,
- wpabuf_put(buf, SHA256_MAC_LEN));
+ wpabuf_put(buf, hash_len));
}
int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
{
- u8 verifier[SHA256_MAC_LEN];
+ u8 verifier[SAE_MAX_HASH_LEN];
+ size_t hash_len;
- if (len < 2 + SHA256_MAC_LEN) {
+ if (!sae->tmp)
+ return -1;
+
+ hash_len = sae->tmp->kck_len;
+ if (len < 2 + hash_len) {
wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
return -1;
}
wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
- if (!sae->tmp || !sae->peer_commit_scalar ||
- !sae->tmp->own_commit_scalar) {
+ if (!sae->peer_commit_scalar || !sae->tmp->own_commit_scalar) {
wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
return -1;
}
if (sae->tmp->ec) {
if (!sae->tmp->peer_commit_element_ecc ||
- !sae->tmp->own_commit_element_ecc)
+ !sae->tmp->own_commit_element_ecc ||
+ sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ecc,
+ sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ecc,
+ verifier) < 0)
return -1;
- sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
- sae->tmp->peer_commit_element_ecc,
- sae->tmp->own_commit_scalar,
- sae->tmp->own_commit_element_ecc,
- verifier);
} else {
if (!sae->tmp->peer_commit_element_ffc ||
- !sae->tmp->own_commit_element_ffc)
+ !sae->tmp->own_commit_element_ffc ||
+ sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ffc,
+ sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ffc,
+ verifier) < 0)
return -1;
- sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
- sae->tmp->peer_commit_element_ffc,
- sae->tmp->own_commit_scalar,
- sae->tmp->own_commit_element_ffc,
- verifier);
}
- if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) {
+ if (os_memcmp_const(verifier, data + 2, hash_len) != 0) {
wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
- data + 2, SHA256_MAC_LEN);
+ data + 2, hash_len);
wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier",
- verifier, SHA256_MAC_LEN);
+ verifier, hash_len);
return -1;
}
diff --git a/src/common/sae.h b/src/common/sae.h
index 3eb6e32..b3787e4 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -12,17 +12,18 @@
#define SAE_KCK_LEN 32
#define SAE_PMK_LEN 32
#define SAE_PMKID_LEN 16
-#define SAE_KEYSEED_KEY_LEN 32
#define SAE_MAX_PRIME_LEN 512
#define SAE_MAX_ECC_PRIME_LEN 66
-#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN)
-#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN)
+#define SAE_MAX_HASH_LEN 64
+#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN + 255)
+#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_HASH_LEN)
/* Special value returned by sae_parse_commit() */
#define SAE_SILENTLY_DISCARD 65535
struct sae_temporary_data {
- u8 kck[SAE_KCK_LEN];
+ u8 kck[SAE_MAX_HASH_LEN];
+ size_t kck_len;
struct crypto_bignum *own_commit_scalar;
struct crypto_bignum *own_commit_element_ffc;
struct crypto_ec_point *own_commit_element_ecc;
@@ -33,6 +34,7 @@
struct crypto_bignum *sae_rand;
struct crypto_ec *ec;
int prime_len;
+ int order_len;
const struct dh_group *dh;
const struct crypto_bignum *prime;
const struct crypto_bignum *order;
@@ -42,6 +44,20 @@
char *pw_id;
int vlan_id;
u8 bssid[ETH_ALEN];
+ struct wpabuf *own_rejected_groups;
+ struct wpabuf *peer_rejected_groups;
+ unsigned int h2e:1;
+ unsigned int own_addr_higher:1;
+};
+
+struct sae_pt {
+ struct sae_pt *next;
+ int group;
+ struct crypto_ec *ec;
+ struct crypto_ec_point *ecc_pt;
+
+ const struct dh_group *dh;
+ struct crypto_bignum *ffc_pt;
};
enum sae_state {
@@ -67,14 +83,28 @@
int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
const u8 *password, size_t password_len,
const char *identifier, struct sae_data *sae);
+int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2,
+ int *rejected_groups);
int sae_process_commit(struct sae_data *sae);
void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
const struct wpabuf *token, const char *identifier);
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
- const u8 **token, size_t *token_len, int *allowed_groups);
+ const u8 **token, size_t *token_len, int *allowed_groups,
+ int h2e);
void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);
u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group);
const char * sae_state_txt(enum sae_state state);
+struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier);
+struct crypto_ec_point *
+sae_derive_pwe_from_pt_ecc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2);
+struct crypto_bignum *
+sae_derive_pwe_from_pt_ffc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2);
+void sae_deinit_pt(struct sae_pt *pt);
#endif /* SAE_H */
diff --git a/src/common/version.h b/src/common/version.h
index 031d1be..0235c9b 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -9,6 +9,6 @@
#define GIT_VERSION_STR_POSTFIX ""
#endif /* GIT_VERSION_STR_POSTFIX */
-#define VERSION_STR "2.9-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
+#define VERSION_STR "2.10-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
#endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index ed2d1c2..ea9f7a2 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -212,11 +212,9 @@
return -1;
os_memcpy(mic, hash, MD5_MAC_LEN);
break;
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
case WPA_KEY_INFO_TYPE_AES_128_CMAC:
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using AES-CMAC");
return omac1_aes_128(key, buf, len, mic);
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
case WPA_KEY_INFO_TYPE_AKM_DEFINED:
switch (akmp) {
#ifdef CONFIG_SAE
@@ -410,14 +408,10 @@
return -1;
#endif /* CONFIG_SUITEB192 || CONFIG_FILS */
} else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) {
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_SAE) || defined(CONFIG_FILS)
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
if (sha256_prf(pmk, pmk_len, label, data, data_len,
tmp, ptk_len) < 0)
return -1;
-#else /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
- return -1;
-#endif /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
#ifdef CONFIG_DPP
} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
@@ -692,7 +686,7 @@
len[2] = ETH_ALEN;
addr[3] = bssid;
len[3] = ETH_ALEN;
- if (g_sta && g_ap_len && g_ap && g_ap_len) {
+ if (g_sta && g_sta_len && g_ap && g_ap_len) {
addr[4] = g_sta;
len[4] = g_sta_len;
addr[5] = g_ap;
@@ -723,7 +717,7 @@
addr[1] = snonce;
addr[2] = bssid;
addr[3] = sta_addr;
- if (g_sta && g_ap_len && g_ap && g_ap_len) {
+ if (g_sta && g_sta_len && g_ap && g_ap_len) {
addr[4] = g_ap;
len[4] = g_ap_len;
addr[5] = g_sta;
@@ -756,10 +750,12 @@
const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
- const u8 *ric, size_t ric_len, u8 *mic)
+ const u8 *ric, size_t ric_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ u8 *mic)
{
- const u8 *addr[9];
- size_t len[9];
+ const u8 *addr[10];
+ size_t len[10];
size_t i, num_elem = 0;
u8 zero_mic[24];
size_t mic_len, fte_fixed_len;
@@ -826,6 +822,12 @@
num_elem++;
}
+ if (rsnxe) {
+ addr[num_elem] = rsnxe;
+ len[num_elem] = rsnxe_len;
+ num_elem++;
+ }
+
for (i = 0; i < num_elem; i++)
wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
#ifdef CONFIG_SHA384
@@ -892,12 +894,10 @@
parse->r0kh_id = pos;
parse->r0kh_id_len = len;
break;
-#ifdef CONFIG_IEEE80211W
case FTIE_SUBELEM_IGTK:
parse->igtk = pos;
parse->igtk_len = len;
break;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
case FTIE_SUBELEM_OCI:
parse->oci = pos;
@@ -958,6 +958,7 @@
"RSN IE: %d", ret);
return -1;
}
+ parse->rsn_capab = data.capabilities;
if (data.num_pmkid == 1 && data.pmkid)
parse->rsn_pmkid = data.pmkid;
parse->key_mgmt = data.key_mgmt;
@@ -968,6 +969,13 @@
update_use_sha384 = 0;
}
break;
+ case WLAN_EID_RSNX:
+ wpa_hexdump(MSG_DEBUG, "FT: RSNXE", pos, len);
+ if (len < 1)
+ break;
+ parse->rsnxe = pos;
+ parse->rsnxe_len = len;
+ break;
case WLAN_EID_MOBILITY_DOMAIN:
wpa_hexdump(MSG_DEBUG, "FT: MDE", pos, len);
if (len < sizeof(struct rsn_mdie))
@@ -989,9 +997,11 @@
wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
ftie_sha384->mic,
sizeof(ftie_sha384->mic));
+ parse->fte_anonce = ftie_sha384->anonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
ftie_sha384->anonce,
WPA_NONCE_LEN);
+ parse->fte_snonce = ftie_sha384->snonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
ftie_sha384->snonce,
WPA_NONCE_LEN);
@@ -1008,8 +1018,10 @@
ftie->mic_control, 2);
wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
ftie->mic, sizeof(ftie->mic));
+ parse->fte_anonce = ftie->anonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
ftie->anonce, WPA_NONCE_LEN);
+ parse->fte_snonce = ftie->snonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
ftie->snonce, WPA_NONCE_LEN);
prot_ie_count = ftie->mic_control[1];
@@ -1046,6 +1058,8 @@
prot_ie_count--;
if (parse->ftie)
prot_ie_count--;
+ if (parse->rsnxe)
+ prot_ie_count--;
if (prot_ie_count < 0) {
wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
"the protected IE count");
@@ -1087,10 +1101,8 @@
return WPA_CIPHER_TKIP;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
return WPA_CIPHER_CCMP;
-#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
return WPA_CIPHER_AES_128_CMAC;
-#endif /* CONFIG_IEEE80211W */
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
return WPA_CIPHER_GCMP;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256)
@@ -1125,12 +1137,10 @@
return WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
return WPA_KEY_MGMT_IEEE8021X_SHA256;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
return WPA_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
return WPA_KEY_MGMT_SAE;
@@ -1170,7 +1180,6 @@
}
-#ifdef CONFIG_IEEE80211W
int wpa_cipher_valid_mgmt_group(int cipher)
{
return cipher == WPA_CIPHER_AES_128_CMAC ||
@@ -1178,7 +1187,6 @@
cipher == WPA_CIPHER_BIP_GMAC_256 ||
cipher == WPA_CIPHER_BIP_CMAC_256;
}
-#endif /* CONFIG_IEEE80211W */
/**
@@ -1203,11 +1211,7 @@
data->capabilities = 0;
data->pmkid = NULL;
data->num_pmkid = 0;
-#ifdef CONFIG_IEEE80211W
data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
-#else /* CONFIG_IEEE80211W */
- data->mgmt_group_cipher = 0;
-#endif /* CONFIG_IEEE80211W */
if (rsn_ie_len == 0) {
/* No RSN IE - fail silently */
@@ -1282,13 +1286,11 @@
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
-#ifdef CONFIG_IEEE80211W
if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
"pairwise cipher", __func__);
return -1;
}
-#endif /* CONFIG_IEEE80211W */
} else if (left == 1) {
wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
__func__);
@@ -1340,7 +1342,6 @@
}
}
-#ifdef CONFIG_IEEE80211W
if (left >= 4) {
data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
@@ -1353,7 +1354,6 @@
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
-#endif /* CONFIG_IEEE80211W */
if (left > 0) {
wpa_hexdump(MSG_DEBUG,
@@ -1852,11 +1852,9 @@
wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-384");
hmac_sha384_vector(pmk, pmk_len, 3, addr, len, hash);
#endif /* CONFIG_FILS || CONFIG_SHA384 */
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
} else if (wpa_key_mgmt_sha256(akmp)) {
wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-256");
hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
-#endif /* CONFIG_IEEE80211W || CONFIG_FILS */
} else {
wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-1");
hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
@@ -2007,12 +2005,10 @@
case WPA_KEY_MGMT_FT_PSK:
return "FT-PSK";
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
case WPA_KEY_MGMT_IEEE8021X_SHA256:
return "WPA2-EAP-SHA256";
case WPA_KEY_MGMT_PSK_SHA256:
return "WPA2-PSK-SHA256";
-#endif /* CONFIG_IEEE80211W */
case WPA_KEY_MGMT_WPS:
return "WPS";
case WPA_KEY_MGMT_SAE:
@@ -2075,6 +2071,16 @@
return RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
if (akm & WPA_KEY_MGMT_FT_FILS_SHA384)
return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
+ if (akm & WPA_KEY_MGMT_SAE)
+ return RSN_AUTH_KEY_MGMT_SAE;
+ if (akm & WPA_KEY_MGMT_FT_SAE)
+ return RSN_AUTH_KEY_MGMT_FT_SAE;
+ if (akm & WPA_KEY_MGMT_OWE)
+ return RSN_AUTH_KEY_MGMT_OWE;
+ if (akm & WPA_KEY_MGMT_DPP)
+ return RSN_AUTH_KEY_MGMT_DPP;
+ if (akm & WPA_KEY_MGMT_OSEN)
+ return RSN_AUTH_KEY_MGMT_OSEN;
return 0;
}
@@ -2116,7 +2122,6 @@
}
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
{
u8 *start, *end, *rpos, *rend;
@@ -2131,11 +2136,10 @@
start += 2 + start[1];
}
if (start >= end) {
- wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
- "IEs data");
+ wpa_printf(MSG_ERROR, "RSN: Could not find RSNE in IEs data");
return -1;
}
- wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
+ wpa_hexdump(MSG_DEBUG, "RSN: RSNE before modification",
start, 2 + start[1]);
/* Find start of PMKID-Count */
@@ -2161,8 +2165,8 @@
/* Skip RSN Capabilities */
rpos += 2;
if (rpos > rend) {
- wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
- "IEs data");
+ wpa_printf(MSG_ERROR,
+ "RSN: Could not parse RSNE in IEs data");
return -1;
}
}
@@ -2193,7 +2197,7 @@
* PMKID(s) first before adding the new one.
*/
wpa_printf(MSG_DEBUG,
- "FT: Remove %u old PMKID(s) from RSN IE",
+ "RSN: Remove %u old PMKID(s) from RSNE",
num_pmkid);
after = rpos + 2 + num_pmkid * PMKID_LEN;
os_memmove(rpos + 2, after, rend - after);
@@ -2208,14 +2212,13 @@
start[1] += PMKID_LEN;
}
- wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
- "(PMKID inserted)", start, 2 + start[1]);
+ wpa_hexdump(MSG_DEBUG, "RSN: RSNE after modification (PMKID inserted)",
+ start, 2 + start[1]);
*ies_len += added;
return 0;
}
-#endif /* CONFIG_IEEE80211R || CONFIG_FILS */
int wpa_cipher_key_len(int cipher)
@@ -2600,3 +2603,266 @@
return 0;
}
#endif /* CONFIG_FILS */
+
+
+/**
+ * wpa_parse_vendor_specific - Parse Vendor Specific IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
+ struct wpa_eapol_ie_parse *ie)
+{
+ unsigned int oui;
+
+ if (pos[1] < 4) {
+ wpa_printf(MSG_MSGDUMP,
+ "Too short vendor specific IE ignored (len=%u)",
+ pos[1]);
+ return 1;
+ }
+
+ oui = WPA_GET_BE24(&pos[2]);
+ if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
+ if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
+ ie->wmm = &pos[2];
+ ie->wmm_len = pos[1];
+ wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
+ ie->wmm, ie->wmm_len);
+ } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
+ ie->wmm = &pos[2];
+ ie->wmm_len = pos[1];
+ wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
+ ie->wmm, ie->wmm_len);
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_generic(const u8 *pos, const u8 *end,
+ struct wpa_eapol_ie_parse *ie)
+{
+ if (pos[1] == 0)
+ return 1;
+
+ if (pos[1] >= 6 &&
+ RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
+ pos[2 + WPA_SELECTOR_LEN] == 1 &&
+ pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
+ ie->wpa_ie = pos;
+ ie->wpa_ie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
+ ie->wpa_ie, ie->wpa_ie_len);
+ return 0;
+ }
+
+ if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
+ ie->osen = pos;
+ ie->osen_len = pos[1] + 2;
+ return 0;
+ }
+
+ if (1 + RSN_SELECTOR_LEN < end - pos &&
+ pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
+ ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
+ ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
+ ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
+ ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
+ ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
+ ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
+ ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+ ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: IP Address Allocation in EAPOL-Key",
+ ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
+ ie->oci = pos + 2 + RSN_SELECTOR_LEN;
+ ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ return 0;
+}
+
+
+/**
+ * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
+ * @buf: Pointer to the Key Data buffer
+ * @len: Key Data Length
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
+{
+ const u8 *pos, *end;
+ int ret = 0;
+
+ os_memset(ie, 0, sizeof(*ie));
+ for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
+ if (pos[0] == 0xdd &&
+ ((pos == buf + len - 1) || pos[1] == 0)) {
+ /* Ignore padding */
+ break;
+ }
+ if (2 + pos[1] > end - pos) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key Key Data underflow (ie=%d len=%d pos=%d)",
+ pos[0], pos[1], (int) (pos - buf));
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", buf, len);
+ ret = -1;
+ break;
+ }
+ if (*pos == WLAN_EID_RSN) {
+ ie->rsn_ie = pos;
+ ie->rsn_ie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
+ ie->rsn_ie, ie->rsn_ie_len);
+ } else if (*pos == WLAN_EID_RSNX) {
+ ie->rsnxe = pos;
+ ie->rsnxe_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key",
+ ie->rsnxe, ie->rsnxe_len);
+ } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
+ ie->mdie = pos;
+ ie->mdie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
+ ie->mdie, ie->mdie_len);
+ } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
+ ie->ftie = pos;
+ ie->ftie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
+ ie->ftie, ie->ftie_len);
+ } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
+ if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
+ ie->reassoc_deadline = pos;
+ wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
+ "in EAPOL-Key",
+ ie->reassoc_deadline, pos[1] + 2);
+ } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
+ ie->key_lifetime = pos;
+ wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
+ "in EAPOL-Key",
+ ie->key_lifetime, pos[1] + 2);
+ } else {
+ wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
+ "EAPOL-Key Key Data IE",
+ pos, 2 + pos[1]);
+ }
+ } else if (*pos == WLAN_EID_LINK_ID) {
+ if (pos[1] >= 18) {
+ ie->lnkid = pos;
+ ie->lnkid_len = pos[1] + 2;
+ }
+ } else if (*pos == WLAN_EID_EXT_CAPAB) {
+ ie->ext_capab = pos;
+ ie->ext_capab_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_SUPP_RATES) {
+ ie->supp_rates = pos;
+ ie->supp_rates_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
+ ie->ext_supp_rates = pos;
+ ie->ext_supp_rates_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_HT_CAP &&
+ pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
+ ie->ht_capabilities = pos + 2;
+ } else if (*pos == WLAN_EID_VHT_AID) {
+ if (pos[1] >= 2)
+ ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
+ } else if (*pos == WLAN_EID_VHT_CAP &&
+ pos[1] >= sizeof(struct ieee80211_vht_capabilities))
+ {
+ ie->vht_capabilities = pos + 2;
+ } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
+ ie->qosinfo = pos[2];
+ } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
+ ie->supp_channels = pos + 2;
+ ie->supp_channels_len = pos[1];
+ } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
+ /*
+ * The value of the Length field of the Supported
+ * Operating Classes element is between 2 and 253.
+ * Silently skip invalid elements to avoid interop
+ * issues when trying to use the value.
+ */
+ if (pos[1] >= 2 && pos[1] <= 253) {
+ ie->supp_oper_classes = pos + 2;
+ ie->supp_oper_classes_len = pos[1];
+ }
+ } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
+ ret = wpa_parse_generic(pos, end, ie);
+ if (ret < 0)
+ break;
+ if (ret > 0) {
+ ret = 0;
+ break;
+ }
+
+ ret = wpa_parse_vendor_specific(pos, end, ie);
+ if (ret < 0)
+ break;
+ if (ret > 0) {
+ ret = 0;
+ break;
+ }
+ } else {
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: Unrecognized EAPOL-Key Key Data IE",
+ pos, 2 + pos[1]);
+ }
+ }
+
+ return ret;
+}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index e83d688..beb1ecd 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -104,9 +104,7 @@
#endif
#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
-#ifdef CONFIG_IEEE80211W
#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
-#endif /* CONFIG_IEEE80211W */
#define RSN_KEY_DATA_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
@@ -130,10 +128,8 @@
#pragma pack(push, 1)
#endif /* _MSC_VER */
-#ifdef CONFIG_IEEE80211W
#define WPA_IGTK_LEN 16
#define WPA_IGTK_MAX_LEN 32
-#endif /* CONFIG_IEEE80211W */
/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
@@ -226,12 +222,10 @@
size_t gtk_len;
};
-#ifdef CONFIG_IEEE80211W
struct wpa_igtk {
u8 igtk[WPA_IGTK_MAX_LEN];
size_t igtk_len;
};
-#endif /* CONFIG_IEEE80211W */
/* WPA IE version 1
* 00-50-f2:1 (OUI:OUI type)
@@ -291,14 +285,12 @@
be16 error_type;
} STRUCT_PACKED;
-#ifdef CONFIG_IEEE80211W
#define WPA_IGTK_KDE_PREFIX_LEN (2 + 6)
struct wpa_igtk_kde {
u8 keyid[2];
u8 pn[6];
u8 igtk[WPA_IGTK_MAX_LEN];
} STRUCT_PACKED;
-#endif /* CONFIG_IEEE80211W */
struct rsn_mdie {
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
@@ -372,7 +364,9 @@
const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
- const u8 *ric, size_t ric_len, u8 *mic);
+ const u8 *ric, size_t ric_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ u8 *mic);
int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
const u8 *ssid, size_t ssid_len,
const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
@@ -451,8 +445,11 @@
size_t gtk_len;
const u8 *r0kh_id;
size_t r0kh_id_len;
+ const u8 *fte_anonce;
+ const u8 *fte_snonce;
const u8 *rsn;
size_t rsn_len;
+ u16 rsn_capab;
const u8 *rsn_pmkid;
const u8 *tie;
size_t tie_len;
@@ -466,11 +463,67 @@
size_t ric_len;
int key_mgmt;
int pairwise_cipher;
+ const u8 *rsnxe;
+ size_t rsnxe_len;
};
int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
int use_sha384);
+struct wpa_eapol_ie_parse {
+ const u8 *wpa_ie;
+ size_t wpa_ie_len;
+ const u8 *rsn_ie;
+ size_t rsn_ie_len;
+ const u8 *pmkid;
+ const u8 *gtk;
+ size_t gtk_len;
+ const u8 *mac_addr;
+ size_t mac_addr_len;
+ const u8 *igtk;
+ size_t igtk_len;
+ const u8 *mdie;
+ size_t mdie_len;
+ const u8 *ftie;
+ size_t ftie_len;
+ const u8 *ip_addr_req;
+ const u8 *ip_addr_alloc;
+ const u8 *oci;
+ size_t oci_len;
+ const u8 *osen;
+ size_t osen_len;
+ const u8 *rsnxe;
+ size_t rsnxe_len;
+ const u8 *reassoc_deadline;
+ const u8 *key_lifetime;
+ const u8 *lnkid;
+ size_t lnkid_len;
+ const u8 *ext_capab;
+ size_t ext_capab_len;
+ const u8 *supp_rates;
+ size_t supp_rates_len;
+ const u8 *ext_supp_rates;
+ size_t ext_supp_rates_len;
+ const u8 *ht_capabilities;
+ const u8 *vht_capabilities;
+ const u8 *supp_channels;
+ size_t supp_channels_len;
+ const u8 *supp_oper_classes;
+ size_t supp_oper_classes_len;
+ u8 qosinfo;
+ u16 aid;
+ const u8 *wmm;
+ size_t wmm_len;
+};
+
+int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie);
+static inline int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
+ struct wpa_eapol_ie_parse *ie)
+{
+ return wpa_parse_kde_ies(buf, len, ie);
+}
+
+
int wpa_cipher_key_len(int cipher);
int wpa_cipher_rsc_len(int cipher);
enum wpa_alg wpa_cipher_to_alg(int cipher);
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index b24ae63..70ecf5d 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -168,6 +168,7 @@
#define DPP_EVENT_CONF_RECEIVED "DPP-CONF-RECEIVED "
#define DPP_EVENT_CONF_SENT "DPP-CONF-SENT "
#define DPP_EVENT_CONF_FAILED "DPP-CONF-FAILED "
+#define DPP_EVENT_CONN_STATUS_RESULT "DPP-CONN-STATUS-RESULT "
#define DPP_EVENT_CONFOBJ_AKM "DPP-CONFOBJ-AKM "
#define DPP_EVENT_CONFOBJ_SSID "DPP-CONFOBJ-SSID "
#define DPP_EVENT_CONFOBJ_PASS "DPP-CONFOBJ-PASS "
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 15f8ad0..440da03 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -519,6 +519,13 @@
struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len);
/**
+ * crypto_bignum_init_set - Allocate memory for bignum and set the value (uint)
+ * @val: Value to set
+ * Returns: Pointer to allocated bignum or %NULL on failure
+ */
+struct crypto_bignum * crypto_bignum_init_uint(unsigned int val);
+
+/**
* crypto_bignum_deinit - Free bignum
* @n: Bignum from crypto_bignum_init() or crypto_bignum_init_set()
* @clear: Whether to clear the value from memory
@@ -613,6 +620,19 @@
struct crypto_bignum *c);
/**
+ * crypto_bignum_addmod - d = a + b (mod c)
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum
+ * @d: Bignum; used to store the result of (a + b) % c
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_addmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d);
+
+/**
* crypto_bignum_mulmod - d = a * b (mod c)
* @a: Bignum
* @b: Bignum
@@ -626,6 +646,17 @@
struct crypto_bignum *d);
/**
+ * crypto_bignum_sqrmod - c = a^2 (mod b)
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a^2 % b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_sqrmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c);
+
+/**
* crypto_bignum_rshift - r = a >> n
* @a: Bignum
* @n: Number of bits
@@ -731,6 +762,9 @@
*/
const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e);
+const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e);
+const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e);
+
/**
* struct crypto_ec_point - Elliptic curve point
*
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index fb278c2..783b293 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -1283,6 +1283,24 @@
}
+struct crypto_bignum * crypto_bignum_init_uint(unsigned int val)
+{
+ BIGNUM *bn;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ bn = BN_new();
+ if (!bn)
+ return NULL;
+ if (BN_set_word(bn, val) != 1) {
+ BN_free(bn);
+ return NULL;
+ }
+ return (struct crypto_bignum *) bn;
+}
+
+
void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
{
if (clear)
@@ -1295,13 +1313,7 @@
int crypto_bignum_to_bin(const struct crypto_bignum *a,
u8 *buf, size_t buflen, size_t padlen)
{
-#ifdef OPENSSL_IS_BORINGSSL
-#else /* OPENSSL_IS_BORINGSSL */
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-#else
int num_bytes, offset;
-#endif
-#endif /* OPENSSL_IS_BORINGSSL */
if (TEST_FAIL())
return -1;
@@ -1309,14 +1321,18 @@
if (padlen > buflen)
return -1;
+ if (padlen) {
#ifdef OPENSSL_IS_BORINGSSL
- if (BN_bn2bin_padded(buf, padlen, (const BIGNUM *) a) == 0)
- return -1;
- return padlen;
+ if (BN_bn2bin_padded(buf, padlen, (const BIGNUM *) a) == 0)
+ return -1;
+ return padlen;
#else /* OPENSSL_IS_BORINGSSL */
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
- return BN_bn2binpad((const BIGNUM *) a, buf, padlen);
-#else
+ return BN_bn2binpad((const BIGNUM *) a, buf, padlen);
+#endif
+#endif
+ }
+
num_bytes = BN_num_bytes((const BIGNUM *) a);
if ((size_t) num_bytes > buflen)
return -1;
@@ -1329,8 +1345,6 @@
BN_bn2bin((const BIGNUM *) a, buf + offset);
return num_bytes + offset;
-#endif
-#endif /* OPENSSL_IS_BORINGSSL */
}
@@ -1453,6 +1467,28 @@
}
+int crypto_bignum_addmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+{
+ int res;
+ BN_CTX *bnctx;
+
+ if (TEST_FAIL())
+ return -1;
+
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ return -1;
+ res = BN_mod_add((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
+ (const BIGNUM *) c, bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
int crypto_bignum_mulmod(const struct crypto_bignum *a,
const struct crypto_bignum *b,
const struct crypto_bignum *c,
@@ -1476,6 +1512,27 @@
}
+int crypto_bignum_sqrmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ int res;
+ BN_CTX *bnctx;
+
+ if (TEST_FAIL())
+ return -1;
+
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ return -1;
+ res = BN_mod_sqr((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b,
+ bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
struct crypto_bignum *r)
{
@@ -1686,6 +1743,18 @@
}
+const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) e->a;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) e->b;
+}
+
+
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
{
if (clear)
@@ -2063,13 +2132,17 @@
secret = wpabuf_alloc(secret_len);
if (!secret)
goto fail;
- if (EVP_PKEY_derive(ctx, wpabuf_put(secret, secret_len),
- &secret_len) != 1) {
+ if (EVP_PKEY_derive(ctx, wpabuf_put(secret, 0), &secret_len) != 1) {
wpa_printf(MSG_ERROR,
"OpenSSL: EVP_PKEY_derive(2) failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
+ if (secret->size != secret_len)
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: EVP_PKEY_derive(2) changed secret_len %d -> %d",
+ (int) secret->size, (int) secret_len);
+ wpabuf_put(secret, secret_len);
done:
BN_free(x);
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index 4cedab4..85ce565 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -1042,6 +1042,26 @@
}
+struct crypto_bignum * crypto_bignum_init_uint(unsigned int val)
+{
+ mp_int *a;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ a = (mp_int *) crypto_bignum_init();
+ if (!a)
+ return NULL;
+
+ if (mp_set_int(a, val) != MP_OKAY) {
+ os_free(a);
+ a = NULL;
+ }
+
+ return (struct crypto_bignum *) a;
+}
+
+
void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
{
if (!n)
@@ -1151,7 +1171,7 @@
if (TEST_FAIL())
return -1;
- return mp_add((mp_int *) a, (mp_int *) b,
+ return mp_sub((mp_int *) a, (mp_int *) b,
(mp_int *) r) == MP_OKAY ? 0 : -1;
}
@@ -1168,6 +1188,19 @@
}
+int crypto_bignum_addmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_addmod((mp_int *) a, (mp_int *) b, (mp_int *) c,
+ (mp_int *) d) == MP_OKAY ? 0 : -1;
+}
+
+
int crypto_bignum_mulmod(const struct crypto_bignum *a,
const struct crypto_bignum *b,
const struct crypto_bignum *m,
@@ -1181,6 +1214,18 @@
}
+int crypto_bignum_sqrmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_sqrmod((mp_int *) a, (mp_int *) b,
+ (mp_int *) c) == MP_OKAY ? 0 : -1;
+}
+
+
int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
struct crypto_bignum *r)
{
@@ -1386,6 +1431,18 @@
}
+const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) &e->a;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) &e->b;
+}
+
+
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
{
ecc_point *point = (ecc_point *) p;
diff --git a/src/crypto/sha384-tlsprf.c b/src/crypto/sha384-tlsprf.c
new file mode 100644
index 0000000..9ff96ac
--- /dev/null
+++ b/src/crypto/sha384-tlsprf.c
@@ -0,0 +1,71 @@
+/*
+ * TLS PRF P_SHA384
+ * Copyright (c) 2011-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha384.h"
+
+
+/**
+ * tls_prf_sha384 - Pseudo-Random Function for TLS v1.2 (P_SHA384, RFC 5246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in TLS. This PRF is defined in RFC 5246, Chapter 5.
+ */
+int tls_prf_sha384(const u8 *secret, size_t secret_len, const char *label,
+ const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+ size_t clen;
+ u8 A[SHA384_MAC_LEN];
+ u8 P[SHA384_MAC_LEN];
+ size_t pos;
+ const unsigned char *addr[3];
+ size_t len[3];
+
+ addr[0] = A;
+ len[0] = SHA384_MAC_LEN;
+ addr[1] = (unsigned char *) label;
+ len[1] = os_strlen(label);
+ addr[2] = seed;
+ len[2] = seed_len;
+
+ /*
+ * RFC 5246, Chapter 5
+ * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+ * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+ * PRF(secret, label, seed) = P_SHA384(secret, label + seed)
+ */
+
+ if (hmac_sha384_vector(secret, secret_len, 2, &addr[1], &len[1], A) < 0)
+ return -1;
+
+ pos = 0;
+ while (pos < outlen) {
+ if (hmac_sha384_vector(secret, secret_len, 3, addr, len, P) <
+ 0 ||
+ hmac_sha384(secret, secret_len, A, SHA384_MAC_LEN, A) < 0)
+ return -1;
+
+ clen = outlen - pos;
+ if (clen > SHA384_MAC_LEN)
+ clen = SHA384_MAC_LEN;
+ os_memcpy(out + pos, P, clen);
+ pos += clen;
+ }
+
+ return 0;
+}
diff --git a/src/crypto/sha384.h b/src/crypto/sha384.h
index 2241425..d946907 100644
--- a/src/crypto/sha384.h
+++ b/src/crypto/sha384.h
@@ -20,6 +20,9 @@
int sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf,
size_t buf_len_bits);
+int tls_prf_sha384(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen);
int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 9718ceb..f3803bd 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -2204,7 +2204,9 @@
continue;
wpa_printf(MSG_DEBUG, "OpenSSL: Certificate Policy %s", buf);
if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.1") == 0)
- tod = 1;
+ tod = 1; /* TOD-STRICT */
+ else if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.2") == 0 && !tod)
+ tod = 2; /* TOD-TOFU */
}
return tod;
@@ -2312,6 +2314,38 @@
}
+static void debug_print_cert(X509 *cert, const char *title)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ BIO *out;
+ size_t rlen;
+ char *txt;
+ int res;
+
+ if (wpa_debug_level > MSG_DEBUG)
+ return;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return;
+
+ X509_print(out, cert);
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (txt) {
+ res = BIO_read(out, txt, rlen);
+ if (res > 0) {
+ txt[res] = '\0';
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
+ }
+ os_free(txt);
+ }
+
+ BIO_free(out);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
char buf[256];
@@ -2332,6 +2366,8 @@
depth = X509_STORE_CTX_get_error_depth(x509_ctx);
ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
+ os_snprintf(buf, sizeof(buf), "Peer certificate - depth %d", depth);
+ debug_print_cert(err_cert, buf);
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
conn = SSL_get_app_data(ssl);
@@ -4674,41 +4710,6 @@
}
-static void debug_print_cert(X509 *cert, const char *title)
-{
-#ifndef CONFIG_NO_STDOUT_DEBUG
- BIO *out;
- size_t rlen;
- char *txt;
- int res;
-
- if (wpa_debug_level > MSG_DEBUG)
- return;
-
- out = BIO_new(BIO_s_mem());
- if (!out)
- return;
-
- X509_print(out, cert);
- rlen = BIO_ctrl_pending(out);
- txt = os_malloc(rlen + 1);
- if (!txt) {
- BIO_free(out);
- return;
- }
-
- res = BIO_read(out, txt, rlen);
- if (res > 0) {
- txt[res] = '\0';
- wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
- }
- os_free(txt);
-
- BIO_free(out);
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-}
-
-
static int ocsp_resp_cb(SSL *s, void *arg)
{
struct tls_connection *conn = arg;
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
index 83704ff..d222d14 100644
--- a/src/crypto/tls_wolfssl.c
+++ b/src/crypto/tls_wolfssl.c
@@ -141,7 +141,7 @@
if (get > (wpabuf_len(data->in_data) - data->consumed))
get = wpabuf_len(data->in_data) - data->consumed;
- os_memcpy(buf, wpabuf_head(data->in_data) + data->consumed, get);
+ os_memcpy(buf, wpabuf_head_u8(data->in_data) + data->consumed, get);
data->consumed += get;
if (get == 0)
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 8a5cdb8..ad68a07 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -213,6 +213,24 @@
};
/**
+ * struct ieee80211_edmg_config - EDMG configuration
+ *
+ * This structure describes most essential parameters needed
+ * for IEEE 802.11ay EDMG configuration
+ *
+ * @channels: Bitmap that indicates the 2.16 GHz channel(s)
+ * that are allowed to be used for transmissions.
+ * Bit 0 indicates channel 1, bit 1 indicates channel 2, etc.
+ * Set to 0 to indicate EDMG not supported.
+ * @bw_config: Channel BW Configuration subfield encodes
+ * the allowed channel bandwidth configurations
+ */
+struct ieee80211_edmg_config {
+ u8 channels;
+ enum edmg_bw_config bw_config;
+};
+
+/**
* struct hostapd_hw_modes - Supported hardware mode information
*/
struct hostapd_hw_modes {
@@ -272,6 +290,12 @@
* he_capab - HE (IEEE 802.11ax) capabilities
*/
struct he_capabilities he_capab[IEEE80211_MODE_NUM];
+
+ /**
+ * This structure describes the most essential parameters needed
+ * for IEEE 802.11ay EDMG configuration.
+ */
+ struct ieee80211_edmg_config edmg;
};
@@ -493,7 +517,7 @@
* mac_addr - MAC address used with randomization. The address cannot be
* a multicast one, i.e., bit 0 of byte 0 should not be set.
*/
- const u8 *mac_addr;
+ u8 *mac_addr;
/**
* mac_addr_mask - MAC address mask used with randomization.
@@ -744,6 +768,12 @@
* bandwidth - Channel bandwidth in MHz (20, 40, 80, 160)
*/
int bandwidth;
+
+ /**
+ * This structure describes the most essential parameters needed
+ * for IEEE 802.11ay EDMG configuration.
+ */
+ struct ieee80211_edmg_config edmg;
};
/**
@@ -1074,6 +1104,14 @@
int req_key_mgmt_offload;
/**
+ * req_handshake_offload - Request EAPOL handshake offload
+ *
+ * Request EAPOL handshake offload for this connection if the device
+ * supports it.
+ */
+ int req_handshake_offload;
+
+ /**
* Flag for indicating whether this association includes support for
* RRM (Radio Resource Measurements)
*/
@@ -1434,6 +1472,21 @@
* type 11 as defined in IEEE Std 802.11-2016, 9.4.2.22.13
*/
const struct wpabuf *civic;
+
+ /**
+ * he_spr - Whether Spatial Reuse is enabled
+ */
+ int he_spr;
+
+ /**
+ * he_spr_srg_obss_pd_min_offset - Minimum TX power offset
+ */
+ int he_spr_srg_obss_pd_min_offset;
+
+ /**
+ * he_spr_srg_obss_pd_max_offset - Maximum TX power offset
+ */
+ int he_spr_srg_obss_pd_max_offset;
};
struct wpa_driver_mesh_bss_params {
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 840d4ff..eac3ae8 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -59,10 +59,6 @@
#include "netlink.h"
#include "linux_ioctl.h"
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) || defined(CONFIG_WNM) || defined(CONFIG_WPS) || defined(CONFIG_FILS)
-#define ATHEROS_USE_RAW_RECEIVE
-#endif
-
struct atheros_driver_data {
struct hostapd_data *hapd; /* back pointer */
@@ -366,13 +362,11 @@
v = 0;
if (params->rsn_preauth)
v |= BIT(0);
-#ifdef CONFIG_IEEE80211W
if (params->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
v |= BIT(7);
if (params->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
v |= BIT(6);
}
-#endif /* CONFIG_IEEE80211W */
wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v);
if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
@@ -534,7 +528,6 @@
cipher = IEEE80211_CIPHER_AES_GCM_256;
break;
#endif /* ATH_GCM_SUPPORT */
-#ifdef CONFIG_IEEE80211W
case WPA_ALG_IGTK:
cipher = IEEE80211_CIPHER_AES_CMAC;
break;
@@ -549,7 +542,6 @@
cipher = IEEE80211_CIPHER_AES_GMAC_256;
break;
#endif /* ATH_GCM_SUPPORT */
-#endif /* CONFIG_IEEE80211W */
default:
wpa_printf(MSG_INFO, "%s: unknown/unsupported algorithm %d",
__func__, alg);
@@ -856,7 +848,7 @@
return 0;
}
-#ifdef ATHEROS_USE_RAW_RECEIVE
+
static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
@@ -953,7 +945,7 @@
break;
}
}
-#endif /* ATHEROS_USE_RAW_RECEIVE */
+
static int atheros_receive_pkt(struct atheros_driver_data *drv)
{
@@ -965,11 +957,9 @@
#ifdef CONFIG_WPS
filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ;
#endif /* CONFIG_WPS */
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
IEEE80211_FILTER_TYPE_AUTH |
IEEE80211_FILTER_TYPE_ACTION);
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
#ifdef CONFIG_WNM
filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
#endif /* CONFIG_WNM */
@@ -1069,7 +1059,6 @@
#define atheros_set_ap_wps_ie NULL
#endif /* CONFIG_WPS */
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
static int
atheros_sta_auth(void *priv, struct wpa_driver_sta_auth_params *params)
{
@@ -1169,7 +1158,7 @@
}
return ret;
}
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
+
static void
atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
@@ -1315,7 +1304,6 @@
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
#endif /* CONFIG_WPS */
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
} else if (os_strncmp(custom, "Manage.assoc_req ", 17) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding |
* frame */
@@ -1339,8 +1327,6 @@
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
-#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R || CONFIG_FILS */
-#ifdef ATHEROS_USE_RAW_RECEIVE
} else if (os_strncmp(custom, "Manage.action ", 14) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding | frame
*/
@@ -1353,7 +1339,6 @@
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
-#endif /* ATHEROS_USE_RAW_RECEIVE */
}
}
@@ -1973,8 +1958,6 @@
}
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
-
static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
int noack, unsigned int freq,
const u16 *csa_offs, size_t csa_offs_len)
@@ -1999,7 +1982,6 @@
return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm,
sizeof(struct ieee80211req_mgmtbuf) + data_len);
}
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
@@ -2283,11 +2265,9 @@
.set_ap_wps_ie = atheros_set_ap_wps_ie,
.set_authmode = atheros_set_authmode,
.set_ap = atheros_set_ap,
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
.sta_assoc = atheros_sta_assoc,
.sta_auth = atheros_sta_auth,
.send_mlme = atheros_send_mgmt,
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
.add_tspec = atheros_add_tspec,
.add_sta_node = atheros_add_sta_node,
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 82ca061..8667ee5 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -1661,6 +1661,17 @@
bsd_global_init(void *ctx)
{
struct bsd_driver_global *global;
+#if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER)
+ unsigned char msgfilter[] = {
+ RTM_IEEE80211,
+#ifndef HOSTAPD
+ RTM_IFINFO, RTM_IFANNOUNCE,
+#endif
+ };
+#endif
+#ifdef ROUTE_MSGFILTER
+ unsigned int i, msgfilter_mask;
+#endif
global = os_zalloc(sizeof(*global));
if (global == NULL)
@@ -1683,6 +1694,21 @@
goto fail;
}
+#if defined(RO_MSGFILTER)
+ if (setsockopt(global->route, PF_ROUTE, RO_MSGFILTER,
+ &msgfilter, sizeof(msgfilter)) < 0)
+ wpa_printf(MSG_ERROR, "socket[PF_ROUTE,RO_MSGFILTER]: %s",
+ strerror(errno));
+#elif defined(ROUTE_MSGFILTER)
+ msgfilter_mask = 0;
+ for (i = 0; i < (sizeof(msgfilter) / sizeof(msgfilter[0])); i++)
+ msgfilter_mask |= ROUTE_FILTER(msgfilter[i]);
+ if (setsockopt(global->route, PF_ROUTE, ROUTE_MSGFILTER,
+ &msgfilter_mask, sizeof(msgfilter_mask)) < 0)
+ wpa_printf(MSG_ERROR, "socket[PF_ROUTE,ROUTE_MSGFILTER]: %s",
+ strerror(errno));
+#endif
+
global->event_buf_len = rtbuf_len();
global->event_buf = os_malloc(global->event_buf_len);
if (global->event_buf == NULL) {
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 45835a2..4c8dcad 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -2240,7 +2240,6 @@
6) < 0)
ret = -1;
#endif /* CONFIG_DPP */
-#ifdef CONFIG_IEEE80211W
#ifdef CONFIG_OCV
/* SA Query Request */
if (nl80211_register_action_frame(bss, (u8 *) "\x08\x00", 2) < 0)
@@ -2249,7 +2248,6 @@
/* SA Query Response */
if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
ret = -1;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_TDLS
if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
/* TDLS Discovery Response */
@@ -2385,11 +2383,9 @@
/* FT Action frames */
if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
ret = -1;
-#ifdef CONFIG_IEEE80211W
/* SA Query */
if (nl80211_register_action_frame(bss, (u8 *) "\x08", 1) < 0)
ret = -1;
-#endif /* CONFIG_IEEE80211W */
/* Protected Dual of Public Action */
if (nl80211_register_action_frame(bss, (u8 *) "\x09", 1) < 0)
ret = -1;
@@ -3015,7 +3011,8 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex;
- struct nl_msg *msg = NULL;
+ struct nl_msg *msg;
+ struct nl_msg *key_msg;
int ret;
int tdls = 0;
@@ -3049,26 +3046,31 @@
(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
return nl80211_set_pmk(drv, key, key_len, addr);
+ key_msg = nlmsg_alloc();
+ if (!key_msg)
+ return -ENOBUFS;
+
if (alg == WPA_ALG_NONE) {
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
if (!msg)
- return -ENOBUFS;
+ goto fail2;
} else {
u32 suite;
suite = wpa_alg_to_cipher_suite(alg, key_len);
if (!suite)
- goto fail;
+ goto fail2;
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
- if (!msg ||
- nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) ||
- nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER, suite))
+ if (!msg)
+ goto fail2;
+ if (nla_put(key_msg, NL80211_KEY_DATA, key_len, key) ||
+ nla_put_u32(key_msg, NL80211_KEY_CIPHER, suite))
goto fail;
wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
}
if (seq && seq_len) {
- if (nla_put(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq))
+ if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq))
goto fail;
wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len);
}
@@ -3080,7 +3082,7 @@
if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
- if (nla_put_u32(msg, NL80211_ATTR_KEY_TYPE,
+ if (nla_put_u32(key_msg, NL80211_KEY_TYPE,
NL80211_KEYTYPE_GROUP))
goto fail;
}
@@ -3089,14 +3091,18 @@
wpa_printf(MSG_DEBUG, " broadcast key");
- types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
+ types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
if (!types ||
- nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
+ nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
goto fail;
- nla_nest_end(msg, types);
+ nla_nest_end(key_msg, types);
}
- if (nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
+ if (nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
+ nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
goto fail;
+ nl80211_nlmsg_clear(key_msg);
+ nlmsg_free(key_msg);
+ key_msg = NULL;
ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
@@ -3115,34 +3121,46 @@
!is_broadcast_ether_addr(addr))
return ret;
+ key_msg = nlmsg_alloc();
+ if (!key_msg)
+ return -ENOBUFS;
+
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
- if (!msg ||
- nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
- nla_put_flag(msg, (alg == WPA_ALG_IGTK ||
- alg == WPA_ALG_BIP_GMAC_128 ||
- alg == WPA_ALG_BIP_GMAC_256 ||
- alg == WPA_ALG_BIP_CMAC_256) ?
- NL80211_ATTR_KEY_DEFAULT_MGMT :
- NL80211_ATTR_KEY_DEFAULT))
+ if (!msg)
+ goto fail2;
+ if (!key_msg ||
+ nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
+ nla_put_flag(key_msg, (alg == WPA_ALG_IGTK ||
+ alg == WPA_ALG_BIP_GMAC_128 ||
+ alg == WPA_ALG_BIP_GMAC_256 ||
+ alg == WPA_ALG_BIP_CMAC_256) ?
+ NL80211_KEY_DEFAULT_MGMT :
+ NL80211_KEY_DEFAULT))
goto fail;
if (addr && is_broadcast_ether_addr(addr)) {
struct nlattr *types;
- types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
+ types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
if (!types ||
- nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
+ nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
goto fail;
- nla_nest_end(msg, types);
+ nla_nest_end(key_msg, types);
} else if (addr) {
struct nlattr *types;
- types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
+ types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
if (!types ||
- nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
+ nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
goto fail;
- nla_nest_end(msg, types);
+ nla_nest_end(key_msg, types);
}
+ if (nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
+ goto fail;
+ nl80211_nlmsg_clear(key_msg);
+ nlmsg_free(key_msg);
+ key_msg = NULL;
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret == -ENOENT)
ret = 0;
@@ -3154,6 +3172,9 @@
fail:
nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
+fail2:
+ nl80211_nlmsg_clear(key_msg);
+ nlmsg_free(key_msg);
return -ENOBUFS;
}
@@ -4286,6 +4307,23 @@
nla_nest_end(msg, ftm);
}
+#ifdef CONFIG_IEEE80211AX
+ if (params->he_spr) {
+ struct nlattr *spr;
+
+ spr = nla_nest_start(msg, NL80211_ATTR_HE_OBSS_PD);
+ wpa_printf(MSG_DEBUG, "nl80211: he_spr=%d", params->he_spr);
+
+ if (nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
+ params->he_spr_srg_obss_pd_min_offset) ||
+ nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
+ params->he_spr_srg_obss_pd_max_offset))
+ goto fail;
+
+ nla_nest_end(msg, spr);
+ }
+#endif /* CONFIG_IEEE80211AX */
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
@@ -4344,6 +4382,10 @@
static int nl80211_put_freq_params(struct nl_msg *msg,
const struct hostapd_freq_params *freq)
{
+ enum hostapd_hw_mode hw_mode;
+ int is_24ghz;
+ u8 channel;
+
wpa_printf(MSG_DEBUG, " * freq=%d", freq->freq);
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
return -ENOBUFS;
@@ -4352,7 +4394,11 @@
wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
- if (freq->vht_enabled || freq->he_enabled) {
+ hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
+ is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
+ hw_mode == HOSTAPD_MODE_IEEE80211B;
+
+ if (freq->vht_enabled || (freq->he_enabled && !is_24ghz)) {
enum nl80211_chan_width cw;
wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth);
@@ -4408,6 +4454,15 @@
wpa_printf(MSG_DEBUG, " * channel_type=%d", ct);
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
return -ENOBUFS;
+ } else if (freq->edmg.channels && freq->edmg.bw_config) {
+ wpa_printf(MSG_DEBUG,
+ " * EDMG configuration: channels=0x%x bw_config=%d",
+ freq->edmg.channels, freq->edmg.bw_config);
+ if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
+ freq->edmg.channels) ||
+ nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+ freq->edmg.bw_config))
+ return -1;
} else {
wpa_printf(MSG_DEBUG, " * channel_type=%d",
NL80211_CHAN_NO_HT);
@@ -4700,8 +4755,9 @@
goto fail;
#endif /* CONFIG_MESH */
- if ((!params->set || FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) &&
- (params->flags & WPA_STA_WMM)) {
+ if ((!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
+ FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) &&
+ (params->flags & WPA_STA_WMM)) {
struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
@@ -5486,6 +5542,18 @@
return -1;
}
+ if (params->freq.edmg.channels && params->freq.edmg.bw_config) {
+ wpa_printf(MSG_DEBUG,
+ " * EDMG configuration: channels=0x%x bw_config=%d",
+ params->freq.edmg.channels,
+ params->freq.edmg.bw_config);
+ if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
+ params->freq.edmg.channels) ||
+ nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+ params->freq.edmg.bw_config))
+ return -1;
+ }
+
if (params->bg_scan_period >= 0) {
wpa_printf(MSG_DEBUG, " * bg scan period=%d",
params->bg_scan_period);
@@ -5632,7 +5700,7 @@
return -1;
}
- if (params->req_key_mgmt_offload &&
+ if (params->req_handshake_offload &&
(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) {
wpa_printf(MSG_DEBUG, " * WANT_1X_4WAY_HS");
if (nla_put_flag(msg, NL80211_ATTR_WANT_1X_4WAY_HS))
@@ -5694,7 +5762,8 @@
nl80211_put_fils_connect_params(drv, params, msg) != 0)
return -1;
- if ((params->auth_alg & WPA_AUTH_ALG_SAE) &&
+ if ((params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) &&
(!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
return -1;
@@ -5849,7 +5918,8 @@
if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
return -1;
- if (params->auth_alg & WPA_AUTH_ALG_SAE) {
+ if (params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) {
nl_connect = bss->nl_connect;
bss->use_nl_connect = 1;
} else {
@@ -9453,7 +9523,7 @@
QCA_NL80211_VENDOR_SUBCMD_ROAM) ||
!(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID) ||
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID) ||
nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID,
WPA_SUPPLICANT_CLIENT_ID) ||
nla_put_u32(msg,
@@ -9488,6 +9558,40 @@
return -1;
}
+
+static int nl80211_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params;
+
+ if (!drv->add_sta_node_vendor_cmd_avail)
+ return -EOPNOTSUPP;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Add STA node");
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ (addr &&
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_MAC_ADDR, ETH_ALEN,
+ addr)) ||
+ nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO,
+ auth_alg)) {
+ nlmsg_free(msg);
+ wpa_printf(MSG_ERROR,
+ "%s: err in adding vendor_cmd and vendor_data",
+ __func__);
+ return -1;
+ }
+ nla_nest_end(msg, params);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
#endif /* CONFIG_DRIVER_NL80211_QCA */
@@ -10745,22 +10849,37 @@
{
int fd, len;
char tmp[128];
+ int ret = 0;
fd = open(name, O_RDWR);
if (fd < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to open %s: %s",
+ int level;
+ /*
+ * Flags may not exist on older kernels, or while we're tearing
+ * down a disappearing device.
+ */
+ if (errno == ENOENT) {
+ ret = 0;
+ level = MSG_DEBUG;
+ } else {
+ ret = -1;
+ level = MSG_ERROR;
+ }
+ wpa_printf(level, "nl80211: Failed to open %s: %s",
name, strerror(errno));
- return fd;
+ return ret;
}
len = os_snprintf(tmp, sizeof(tmp), "%u\n", val);
len = write(fd, tmp, len);
- if (len < 0)
+ if (len < 0) {
+ ret = -1;
wpa_printf(MSG_ERROR, "nl80211: Failed to write to %s: %s",
name, strerror(errno));
+ }
close(fd);
- return 0;
+ return ret;
}
@@ -10875,6 +10994,14 @@
int ret = -1;
enum nl80211_auth_type type;
+ /* Update Connection Params is intended for drivers that implement
+ * internal SME and expect these updated connection params from
+ * wpa_supplicant. Do not send this request for the drivers using
+ * SME from wpa_supplicant.
+ */
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
+ return 0;
+
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_CONNECT_PARAMS);
if (!msg)
goto fail;
@@ -11129,6 +11256,7 @@
.ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
#endif /* CONFIG_MBO */
.set_bssid_blacklist = nl80211_set_bssid_blacklist,
+ .add_sta_node = nl80211_add_sta_node,
#endif /* CONFIG_DRIVER_NL80211_QCA */
.configure_data_frame_filters = nl80211_configure_data_frame_filters,
.get_ext_capab = nl80211_get_ext_capab,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 7498269..716504c 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -172,6 +172,7 @@
unsigned int fetch_bss_trans_status:1;
unsigned int roam_vendor_cmd_avail:1;
unsigned int get_supported_akm_suites_avail:1;
+ unsigned int add_sta_node_vendor_cmd_avail:1;
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 8318b10..d8630bb 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -787,6 +787,9 @@
case QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS:
drv->get_supported_akm_suites_avail = 1;
break;
+ case QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE:
+ drv->add_sta_node_vendor_cmd_avail = 1;
+ break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
}
@@ -1202,10 +1205,13 @@
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B |
- WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192 |
WPA_DRIVER_CAPA_KEY_MGMT_OWE |
WPA_DRIVER_CAPA_KEY_MGMT_DPP;
+ if (drv->capa.enc & (WPA_DRIVER_CAPA_ENC_CCMP_256 |
+ WPA_DRIVER_CAPA_ENC_GCMP_256))
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
+
if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 |
WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 |
@@ -1337,6 +1343,23 @@
}
+static int phy_info_edmg_capa(struct hostapd_hw_modes *mode,
+ struct nlattr *bw_config,
+ struct nlattr *channels)
+{
+ if (!bw_config || !channels)
+ return NL_OK;
+
+ mode->edmg.bw_config = nla_get_u8(bw_config);
+ mode->edmg.channels = nla_get_u8(channels);
+
+ if (!mode->edmg.channels || !mode->edmg.bw_config)
+ return NL_STOP;
+
+ return NL_OK;
+}
+
+
static void phy_info_freq(struct hostapd_hw_modes *mode,
struct hostapd_channel_data *chan,
struct nlattr *tb_freq[])
@@ -1694,7 +1717,12 @@
tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
- ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
+ ret = phy_info_edmg_capa(mode,
+ tb_band[NL80211_BAND_ATTR_EDMG_BW_CONFIG],
+ tb_band[NL80211_BAND_ATTR_EDMG_CHANNELS]);
+ if (ret == NL_OK)
+ ret = phy_info_freqs(phy_info, mode,
+ tb_band[NL80211_BAND_ATTR_FREQS]);
if (ret == NL_OK)
ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
if (ret != NL_OK) {
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 4d4a05d..32c2971 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1767,11 +1767,9 @@
case WPA_ALG_PMK:
ext->alg = IW_ENCODE_ALG_PMK;
break;
-#ifdef CONFIG_IEEE80211W
case WPA_ALG_IGTK:
ext->alg = IW_ENCODE_ALG_AES_CMAC;
break;
-#endif /* CONFIG_IEEE80211W */
default:
wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
__FUNCTION__, alg);
@@ -2201,7 +2199,6 @@
IW_AUTH_RX_UNENCRYPTED_EAPOL,
allow_unencrypted_eapol) < 0)
ret = -1;
-#ifdef CONFIG_IEEE80211W
switch (params->mgmt_frame_protection) {
case NO_MGMT_FRAME_PROTECTION:
value = IW_AUTH_MFP_DISABLED;
@@ -2215,7 +2212,6 @@
};
if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
ret = -1;
-#endif /* CONFIG_IEEE80211W */
if (params->freq.freq &&
wpa_driver_wext_set_freq(drv, params->freq.freq) < 0)
ret = -1;
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 6f09d15..beee59c 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -52,6 +52,11 @@
#define NL80211_MULTICAST_GROUP_NAN "nan"
#define NL80211_MULTICAST_GROUP_TESTMODE "testmode"
+#define NL80211_EDMG_BW_CONFIG_MIN 4
+#define NL80211_EDMG_BW_CONFIG_MAX 15
+#define NL80211_EDMG_CHANNELS_MIN 1
+#define NL80211_EDMG_CHANNELS_MAX 0x3c /* 0b00111100 */
+
/**
* DOC: Station handling
*
@@ -235,6 +240,15 @@
*/
/**
+ * DOC: SAE authentication offload
+ *
+ * By setting @NL80211_EXT_FEATURE_SAE_OFFLOAD flag drivers can indicate they
+ * support offloading SAE authentication for WPA3-Personal networks. In
+ * %NL80211_CMD_CONNECT the password for SAE should be specified using
+ * %NL80211_ATTR_SAE_PASSWORD.
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -648,7 +662,9 @@
* is used during CSA period.
* @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
* command may be used with the corresponding cookie to cancel the wait
- * time if it is known that it is no longer necessary.
+ * time if it is known that it is no longer necessary. This command is
+ * also sent as an event whenever the driver has completed the off-channel
+ * wait time.
* @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility.
* @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame
* transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies
@@ -2341,6 +2357,22 @@
* should be picking up the lowest tx power, either tx power per-interface
* or per-station.
*
+ * @NL80211_ATTR_SAE_PASSWORD: attribute for passing SAE password material. It
+ * is used with %NL80211_CMD_CONNECT to provide password for offloading
+ * SAE authentication for WPA3-Personal networks.
+ *
+ * @NL80211_ATTR_TWT_RESPONDER: Enable target wait time responder support.
+ *
+ * @NL80211_ATTR_HE_OBSS_PD: nested attribute for OBSS Packet Detection
+ * functionality.
+ *
+ * @NL80211_ATTR_WIPHY_EDMG_CHANNELS: bitmap that indicates the 2.16 GHz
+ * channel(s) that are allowed to be used for EDMG transmissions.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251. (u8 attribute)
+ * @NL80211_ATTR_WIPHY_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes
+ * the allowed channel bandwidth configurations. (u8 attribute)
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2794,6 +2826,15 @@
NL80211_ATTR_STA_TX_POWER_SETTING,
NL80211_ATTR_STA_TX_POWER,
+ NL80211_ATTR_SAE_PASSWORD,
+
+ NL80211_ATTR_TWT_RESPONDER,
+
+ NL80211_ATTR_HE_OBSS_PD,
+
+ NL80211_ATTR_WIPHY_EDMG_CHANNELS,
+ NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -2844,7 +2885,7 @@
#define NL80211_HT_CAPABILITY_LEN 26
#define NL80211_VHT_CAPABILITY_LEN 12
#define NL80211_HE_MIN_CAPABILITY_LEN 16
-#define NL80211_HE_MAX_CAPABILITY_LEN 51
+#define NL80211_HE_MAX_CAPABILITY_LEN 54
#define NL80211_MAX_NR_CIPHER_SUITES 5
#define NL80211_MAX_NR_AKM_SUITES 2
@@ -3175,6 +3216,8 @@
* sent to the station (u64, usec)
* @NL80211_STA_INFO_AIRTIME_WEIGHT: current airtime weight for station (u16)
* @NL80211_STA_INFO_AIRTIME_LINK_METRIC: airtime link metric for mesh station
+ * @NL80211_STA_INFO_ASSOC_AT_BOOTTIME: Timestamp (CLOCK_BOOTTIME, nanoseconds)
+ * of STA's association
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -3221,6 +3264,7 @@
NL80211_STA_INFO_TX_DURATION,
NL80211_STA_INFO_AIRTIME_WEIGHT,
NL80211_STA_INFO_AIRTIME_LINK_METRIC,
+ NL80211_STA_INFO_ASSOC_AT_BOOTTIME,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -3402,6 +3446,12 @@
* @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE
* @NL80211_BAND_ATTR_IFTYPE_DATA: nested array attribute, with each entry using
* attributes from &enum nl80211_band_iftype_attr
+ * @NL80211_BAND_ATTR_EDMG_CHANNELS: bitmap that indicates the 2.16 GHz
+ * channel(s) that are allowed to be used for EDMG transmissions.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251.
+ * @NL80211_BAND_ATTR_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes
+ * the allowed channel bandwidth configurations.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
* @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
* @__NL80211_BAND_ATTR_AFTER_LAST: internal use
*/
@@ -3419,6 +3469,9 @@
NL80211_BAND_ATTR_VHT_CAPA,
NL80211_BAND_ATTR_IFTYPE_DATA,
+ NL80211_BAND_ATTR_EDMG_CHANNELS,
+ NL80211_BAND_ATTR_EDMG_BW_CONFIG,
+
/* keep last */
__NL80211_BAND_ATTR_AFTER_LAST,
NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
@@ -3817,6 +3870,8 @@
* @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan
* (on this channel or globally)
* @NL80211_SURVEY_INFO_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_SURVEY_INFO_TIME_BSS_RX: amount of time the radio spent
+ * receiving frames destined to the local BSS
* @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
* currently defined
* @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
@@ -3833,6 +3888,7 @@
NL80211_SURVEY_INFO_TIME_TX,
NL80211_SURVEY_INFO_TIME_SCAN,
NL80211_SURVEY_INFO_PAD,
+ NL80211_SURVEY_INFO_TIME_BSS_RX,
/* keep last */
__NL80211_SURVEY_INFO_AFTER_LAST,
@@ -4406,6 +4462,7 @@
enum nl80211_wpa_versions {
NL80211_WPA_VERSION_1 = 1 << 0,
NL80211_WPA_VERSION_2 = 1 << 1,
+ NL80211_WPA_VERSION_3 = 1 << 2,
};
/**
@@ -4516,6 +4573,7 @@
* @NL80211_BAND_2GHZ: 2.4 GHz ISM band
* @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
* @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz)
+ * @NL80211_BAND_6GHZ: around 6 GHz band (5.9 - 7.2 GHz)
* @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
* since newer kernel versions may support more bands
*/
@@ -4523,6 +4581,7 @@
NL80211_BAND_2GHZ,
NL80211_BAND_5GHZ,
NL80211_BAND_60GHZ,
+ NL80211_BAND_6GHZ,
NUM_NL80211_BANDS,
};
@@ -5314,7 +5373,7 @@
NL80211_FEATURE_TDLS_CHANNEL_SWITCH = 1 << 28,
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR = 1 << 29,
NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR = 1 << 30,
- NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1 << 31,
+ NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1U << 31,
};
/**
@@ -5422,6 +5481,9 @@
* @NL80211_EXT_FEATURE_STA_TX_PWR: This driver supports controlling tx power
* to a station.
*
+ * @NL80211_EXT_FEATURE_SAE_OFFLOAD: Device wants to do SAE authentication in
+ * station mode (SAE password is passed as part of the connect command).
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -5466,6 +5528,7 @@
NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD,
NL80211_EXT_FEATURE_EXT_KEY_ID,
NL80211_EXT_FEATURE_STA_TX_PWR,
+ NL80211_EXT_FEATURE_SAE_OFFLOAD,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -6464,4 +6527,26 @@
NL80211_PMSR_FTM_RESP_ATTR_MAX = NUM_NL80211_PMSR_FTM_RESP_ATTR - 1
};
+/**
+ * enum nl80211_obss_pd_attributes - OBSS packet detection attributes
+ * @__NL80211_HE_OBSS_PD_ATTR_INVALID: Invalid
+ *
+ * @NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET: the OBSS PD minimum tx power offset.
+ * @NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET: the OBSS PD maximum tx power offset.
+ *
+ * @__NL80211_HE_OBSS_PD_ATTR_LAST: Internal
+ * @NL80211_HE_OBSS_PD_ATTR_MAX: highest OBSS PD attribute.
+ */
+enum nl80211_obss_pd_attributes {
+ __NL80211_HE_OBSS_PD_ATTR_INVALID,
+
+ NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
+ NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
+
+ /* keep last */
+ __NL80211_HE_OBSS_PD_ATTR_LAST,
+ NL80211_HE_OBSS_PD_ATTR_MAX = __NL80211_HE_OBSS_PD_ATTR_LAST - 1,
+};
+
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/eap_common/eap_common.c b/src/eap_common/eap_common.c
index 51a15d7..e27b965 100644
--- a/src/eap_common/eap_common.c
+++ b/src/eap_common/eap_common.c
@@ -63,7 +63,7 @@
* the payload regardless of whether the packet used the expanded EAP header or
* not.
*/
-const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+const u8 * eap_hdr_validate(int vendor, enum eap_type eap_type,
const struct wpabuf *msg, size_t *plen)
{
const struct eap_hdr *hdr;
@@ -125,8 +125,8 @@
* function to allocate the message buffers. The returned buffer has room for
* payload_len bytes and has the EAP header and Type field already filled in.
*/
-struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
- u8 code, u8 identifier)
+struct wpabuf * eap_msg_alloc(int vendor, enum eap_type type,
+ size_t payload_len, u8 code, u8 identifier)
{
struct wpabuf *buf;
struct eap_hdr *hdr;
@@ -196,7 +196,7 @@
* @msg: Buffer starting with an EAP header
* Returns: The EAP Type after the EAP header
*/
-EapType eap_get_type(const struct wpabuf *msg)
+enum eap_type eap_get_type(const struct wpabuf *msg)
{
if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1)
return EAP_TYPE_NONE;
diff --git a/src/eap_common/eap_common.h b/src/eap_common/eap_common.h
index e62f167..e40cabe 100644
--- a/src/eap_common/eap_common.h
+++ b/src/eap_common/eap_common.h
@@ -20,13 +20,13 @@
};
int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload);
-const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+const u8 * eap_hdr_validate(int vendor, enum eap_type eap_type,
const struct wpabuf *msg, size_t *plen);
-struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
- u8 code, u8 identifier);
+struct wpabuf * eap_msg_alloc(int vendor, enum eap_type type,
+ size_t payload_len, u8 code, u8 identifier);
void eap_update_len(struct wpabuf *msg);
u8 eap_get_id(const struct wpabuf *msg);
-EapType eap_get_type(const struct wpabuf *msg);
+enum eap_type eap_get_type(const struct wpabuf *msg);
int erp_parse_tlvs(const u8 *pos, const u8 *end, struct erp_tlvs *tlvs,
int stop_at_keyname);
diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h
index bc3047c..70999c4 100644
--- a/src/eap_common/eap_defs.h
+++ b/src/eap_common/eap_defs.h
@@ -64,7 +64,7 @@
* EAP Method Types as allocated by IANA:
* http://www.iana.org/assignments/eap-numbers
*/
-typedef enum {
+enum eap_type {
EAP_TYPE_NONE = 0,
EAP_TYPE_IDENTITY = 1 /* RFC 3748 */,
EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */,
@@ -94,7 +94,7 @@
EAP_TYPE_EKE = 53 /* RFC 6124 */,
EAP_TYPE_TEAP = 55 /* RFC 7170 */,
EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
-} EapType;
+};
/* SMI Network Management Private Enterprise Code for vendor specific types */
diff --git a/src/eap_common/eap_teap_common.c b/src/eap_common/eap_teap_common.c
index fbca1b5..ffb9a62 100644
--- a/src/eap_common/eap_teap_common.c
+++ b/src/eap_common/eap_teap_common.c
@@ -17,6 +17,9 @@
#include "eap_teap_common.h"
+static int tls_cipher_suite_mac_sha384(u16 cs);
+
+
void eap_teap_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
{
struct teap_tlv_hdr hdr;
@@ -67,24 +70,27 @@
}
-static int eap_teap_tls_prf(const u8 *secret, size_t secret_len,
+static int eap_teap_tls_prf(u16 tls_cs, const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen)
{
/* TODO: TLS-PRF for TLSv1.3 */
+ if (tls_cipher_suite_mac_sha384(tls_cs))
+ return tls_prf_sha384(secret, secret_len, label, seed, seed_len,
+ out, outlen);
return tls_prf_sha256(secret, secret_len, label, seed, seed_len,
out, outlen);
}
-int eap_teap_derive_eap_msk(const u8 *simck, u8 *msk)
+int eap_teap_derive_eap_msk(u16 tls_cs, const u8 *simck, u8 *msk)
{
/*
* RFC 7170, Section 5.4: EAP Master Session Key Generation
* MSK = TLS-PRF(S-IMCK[j], "Session Key Generating Function", 64)
*/
- if (eap_teap_tls_prf(simck, EAP_TEAP_SIMCK_LEN,
+ if (eap_teap_tls_prf(tls_cs, simck, EAP_TEAP_SIMCK_LEN,
"Session Key Generating Function", (u8 *) "", 0,
msk, EAP_TEAP_KEY_LEN) < 0)
return -1;
@@ -94,7 +100,7 @@
}
-int eap_teap_derive_eap_emsk(const u8 *simck, u8 *emsk)
+int eap_teap_derive_eap_emsk(u16 tls_cs, const u8 *simck, u8 *emsk)
{
/*
* RFC 7170, Section 5.4: EAP Master Session Key Generation
@@ -102,7 +108,7 @@
* "Extended Session Key Generating Function", 64)
*/
- if (eap_teap_tls_prf(simck, EAP_TEAP_SIMCK_LEN,
+ if (eap_teap_tls_prf(tls_cs, simck, EAP_TEAP_SIMCK_LEN,
"Extended Session Key Generating Function",
(u8 *) "", 0, emsk, EAP_EMSK_LEN) < 0)
return -1;
@@ -112,7 +118,7 @@
}
-int eap_teap_derive_cmk_basic_pw_auth(const u8 *s_imck_msk, u8 *cmk)
+int eap_teap_derive_cmk_basic_pw_auth(u16 tls_cs, const u8 *s_imck_msk, u8 *cmk)
{
u8 imsk[32], imck[EAP_TEAP_IMCK_LEN];
int res;
@@ -123,7 +129,7 @@
* published. For now, derive CMK[0] based on S-IMCK[0] and
* IMSK of 32 octets of zeros. */
os_memset(imsk, 0, 32);
- res = eap_teap_tls_prf(s_imck_msk, EAP_TEAP_SIMCK_LEN,
+ res = eap_teap_tls_prf(tls_cs, s_imck_msk, EAP_TEAP_SIMCK_LEN,
"Inner Methods Compound Keys",
imsk, 32, imck, sizeof(imck));
if (res < 0)
@@ -136,7 +142,8 @@
}
-int eap_teap_derive_imck(const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
+int eap_teap_derive_imck(u16 tls_cs,
+ const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
const u8 *msk, size_t msk_len,
const u8 *emsk, size_t emsk_len,
u8 *s_imck_msk, u8 *cmk_msk,
@@ -170,14 +177,16 @@
context[0] = 0;
context[1] = 0;
context[2] = 64;
- if (eap_teap_tls_prf(emsk, emsk_len, "TEAPbindkey@ietf.org",
+ if (eap_teap_tls_prf(tls_cs, emsk, emsk_len,
+ "TEAPbindkey@ietf.org",
context, sizeof(context), imsk, 64) < 0)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: IMSK from EMSK",
imsk, 32);
- res = eap_teap_tls_prf(prev_s_imck_emsk, EAP_TEAP_SIMCK_LEN,
+ res = eap_teap_tls_prf(tls_cs,
+ prev_s_imck_emsk, EAP_TEAP_SIMCK_LEN,
"Inner Methods Compound Keys",
imsk, 32, imck, EAP_TEAP_IMCK_LEN);
forced_memzero(imsk, sizeof(imsk));
@@ -207,7 +216,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Zero IMSK", imsk, 32);
}
- res = eap_teap_tls_prf(prev_s_imck_msk, EAP_TEAP_SIMCK_LEN,
+ res = eap_teap_tls_prf(tls_cs, prev_s_imck_msk, EAP_TEAP_SIMCK_LEN,
"Inner Methods Compound Keys",
imsk, 32, imck, EAP_TEAP_IMCK_LEN);
forced_memzero(imsk, sizeof(imsk));
@@ -418,6 +427,17 @@
int tlv_type, u8 *pos, size_t len)
{
switch (tlv_type) {
+ case TEAP_TLV_IDENTITY_TYPE:
+ if (len < 2) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short Identity-Type TLV");
+ tlv->result = TEAP_STATUS_FAILURE;
+ break;
+ }
+ tlv->identity_type = WPA_GET_BE16(pos);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Identity-Type: %u",
+ tlv->identity_type);
+ break;
case TEAP_TLV_RESULT:
wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Result TLV", pos, len);
if (tlv->result) {
@@ -452,6 +472,15 @@
tlv->nak = pos;
tlv->nak_len = len;
break;
+ case TEAP_TLV_ERROR:
+ if (len < 4) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Too short Error TLV");
+ tlv->result = TEAP_STATUS_FAILURE;
+ break;
+ }
+ tlv->error_code = WPA_GET_BE32(pos);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Error: %u", tlv->error_code);
+ break;
case TEAP_TLV_REQUEST_ACTION:
wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Request-Action TLV",
pos, len);
@@ -661,12 +690,29 @@
}
-int eap_teap_allowed_anon_prov_phase2_method(u8 type)
+struct wpabuf * eap_teap_tlv_identity_type(enum teap_identity_types id)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(4 + 2);
+ if (!buf)
+ return NULL;
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Add Identity-Type TLV(Identity-Type=%d)", id);
+ wpabuf_put_be16(buf, TEAP_TLV_IDENTITY_TYPE);
+ wpabuf_put_be16(buf, 2);
+ wpabuf_put_be16(buf, id);
+ return buf;
+}
+
+
+int eap_teap_allowed_anon_prov_phase2_method(int vendor, enum eap_type type)
{
/* RFC 7170, Section 3.8.3: MUST provide mutual authentication,
* provide key generation, and be resistant to dictionary attack.
* Section 3.8 also mentions requirement for using EMSK Compound MAC. */
- return type == EAP_TYPE_PWD || type == EAP_TYPE_EKE;
+ return vendor == EAP_VENDOR_IETF &&
+ (type == EAP_TYPE_PWD || type == EAP_TYPE_EKE);
}
diff --git a/src/eap_common/eap_teap_common.h b/src/eap_common/eap_teap_common.h
index 585ec7c..3a25879 100644
--- a/src/eap_common/eap_teap_common.h
+++ b/src/eap_common/eap_teap_common.h
@@ -151,6 +151,12 @@
TEAP_STATUS_FAILURE = 2
};
+/* Identity-Type values within Identity-Type TLV */
+enum teap_identity_types {
+ TEAP_IDENTITY_TYPE_USER = 1,
+ TEAP_IDENTITY_TYPE_MACHINE = 2,
+};
+
#define TEAP_TLV_MANDATORY 0x8000
#define TEAP_TLV_TYPE_MASK 0x3fff
@@ -188,6 +194,8 @@
size_t basic_auth_req_len;
u8 *basic_auth_resp;
size_t basic_auth_resp_len;
+ u32 error_code;
+ u16 identity_type;
};
void eap_teap_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len);
@@ -195,10 +203,12 @@
void eap_teap_put_tlv_buf(struct wpabuf *buf, u16 type,
const struct wpabuf *data);
struct wpabuf * eap_teap_tlv_eap_payload(struct wpabuf *buf);
-int eap_teap_derive_eap_msk(const u8 *simck, u8 *msk);
-int eap_teap_derive_eap_emsk(const u8 *simck, u8 *emsk);
-int eap_teap_derive_cmk_basic_pw_auth(const u8 *s_imck_msk, u8 *cmk);
-int eap_teap_derive_imck(const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
+int eap_teap_derive_eap_msk(u16 tls_cs, const u8 *simck, u8 *msk);
+int eap_teap_derive_eap_emsk(u16 tls_cs, const u8 *simck, u8 *emsk);
+int eap_teap_derive_cmk_basic_pw_auth(u16 tls_cs, const u8 *s_imck_msk,
+ u8 *cmk);
+int eap_teap_derive_imck(u16 tls_cs,
+ const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
const u8 *msk, size_t msk_len,
const u8 *emsk, size_t emsk_len,
u8 *s_imck_msk, u8 *cmk_msk,
@@ -212,7 +222,9 @@
const char * eap_teap_tlv_type_str(enum teap_tlv_types type);
struct wpabuf * eap_teap_tlv_result(int status, int intermediate);
struct wpabuf * eap_teap_tlv_error(enum teap_error_codes error);
-int eap_teap_allowed_anon_prov_phase2_method(u8 type);
+struct wpabuf * eap_teap_tlv_identity_type(enum teap_identity_types id);
+enum eap_type;
+int eap_teap_allowed_anon_prov_phase2_method(int vendor, enum eap_type type);
int eap_teap_allowed_anon_prov_cipher_suite(u16 cs);
#endif /* EAP_TEAP_H */
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index ac15e0e..c78b214 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -1,6 +1,6 @@
/*
* EAP peer state machines (RFC 4137)
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -32,12 +32,13 @@
#define STATE_MACHINE_DATA struct eap_sm
#define STATE_MACHINE_DEBUG_PREFIX "EAP"
-#define EAP_MAX_AUTH_ROUNDS 50
+#define EAP_MAX_AUTH_ROUNDS 100
+#define EAP_MAX_AUTH_ROUNDS_SHORT 50
#define EAP_CLIENT_TIMEOUT_DEFAULT 60
static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
- EapType method);
+ enum eap_type method);
static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id);
static void eap_sm_processIdentity(struct eap_sm *sm,
const struct wpabuf *req);
@@ -260,10 +261,12 @@
*/
sm->ignore = 0;
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
sm->prev_failure = 0;
sm->expected_failure = 0;
sm->reauthInit = FALSE;
sm->erp_seq = (u32) -1;
+ sm->use_machine_cred = 0;
}
@@ -276,6 +279,7 @@
{
SM_ENTRY(EAP, DISABLED);
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
/*
* RFC 4137 does not describe clearing of idleWhile here, but doing so
* allows the timer tick to be stopped more quickly when EAP is not in
@@ -309,6 +313,10 @@
/* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
eap_sm_parseEapReq(sm, eapReqData);
sm->num_rounds++;
+ if (!eapReqData || wpabuf_len(eapReqData) < 20)
+ sm->num_rounds_short++;
+ else
+ sm->num_rounds_short = 0;
}
@@ -319,7 +327,7 @@
SM_STATE(EAP, GET_METHOD)
{
int reinit;
- EapType method;
+ enum eap_type method;
const struct eap_method *eap_method;
SM_ENTRY(EAP, GET_METHOD);
@@ -815,7 +823,8 @@
wpa_printf(MSG_DEBUG, "EAP: Valid ERP key found %s (SEQ=%u)",
erp->keyname_nai, erp->next_seq);
- msg = eap_msg_alloc(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
+ msg = eap_msg_alloc(EAP_VENDOR_IETF,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH,
1 + 2 + 2 + os_strlen(erp->keyname_nai) + 1 + 16,
EAP_CODE_INITIATE, eap_id);
if (msg == NULL)
@@ -949,6 +958,8 @@
SM_ENTRY(EAP, SEND_RESPONSE);
wpabuf_free(sm->lastRespData);
if (sm->eapRespData) {
+ if (wpabuf_len(sm->eapRespData) >= 20)
+ sm->num_rounds_short = 0;
if (sm->workaround)
os_memcpy(sm->last_sha1, sm->req_sha1, 20);
sm->lastId = sm->reqId;
@@ -1341,6 +1352,14 @@
sm->num_rounds++;
SM_ENTER_GLOBAL(EAP, FAILURE);
}
+ } else if (sm->num_rounds_short > EAP_MAX_AUTH_ROUNDS_SHORT) {
+ if (sm->num_rounds_short == EAP_MAX_AUTH_ROUNDS_SHORT + 1) {
+ wpa_msg(sm->msg_ctx, MSG_INFO,
+ "EAP: more than %d authentication rounds (short) - abort",
+ EAP_MAX_AUTH_ROUNDS_SHORT);
+ sm->num_rounds_short++;
+ SM_ENTER_GLOBAL(EAP, FAILURE);
+ }
} else {
/* Local transitions */
eap_peer_sm_step_local(sm);
@@ -1349,7 +1368,7 @@
static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
- EapType method)
+ enum eap_type method)
{
if (!eap_allowed_method(sm, vendor, method)) {
wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: "
@@ -1595,13 +1614,13 @@
static int eap_sm_set_scard_pin(struct eap_sm *sm,
struct eap_peer_config *conf)
{
- if (scard_set_pin(sm->scard_ctx, conf->pin)) {
+ if (scard_set_pin(sm->scard_ctx, conf->cert.pin)) {
/*
* Make sure the same PIN is not tried again in order to avoid
* blocking SIM.
*/
- os_free(conf->pin);
- conf->pin = NULL;
+ os_free(conf->cert.pin);
+ conf->cert.pin = NULL;
wpa_printf(MSG_WARNING, "PIN validation failed");
eap_sm_request_pin(sm);
@@ -1657,6 +1676,11 @@
identity_len = config->anonymous_identity_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
identity, identity_len);
+ } else if (sm->use_machine_cred) {
+ identity = config->machine_identity;
+ identity_len = config->machine_identity_len;
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: using machine identity",
+ identity, identity_len);
} else {
identity = config->identity;
identity_len = config->identity_len;
@@ -2600,6 +2624,8 @@
static int eap_allowed_phase2_type(int vendor, int type)
{
+ if (vendor == EAP_VENDOR_HOSTAP)
+ return 1;
if (vendor != EAP_VENDOR_IETF)
return 0;
return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
@@ -2662,7 +2688,7 @@
if (eap_allowed_phase2_type(vendor, method)) {
if (vendor == EAP_VENDOR_IETF &&
method == EAP_TYPE_TLS && config &&
- config->private_key2 == NULL)
+ !config->phase2_cert.private_key)
continue;
buf[*count].vendor = vendor;
buf[*count].method = method;
@@ -2721,8 +2747,15 @@
const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
{
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL)
+
+ if (!config)
return NULL;
+
+ if (sm->use_machine_cred) {
+ *len = config->machine_identity_len;
+ return config->machine_identity;
+ }
+
*len = config->identity_len;
return config->identity;
}
@@ -2732,14 +2765,24 @@
struct eap_peer_config *config)
{
char *name;
+ const u8 *password;
+ size_t password_len;
- if (config->password == NULL)
+ if (sm->use_machine_cred) {
+ password = config->machine_password;
+ password_len = config->machine_password_len;
+ } else {
+ password = config->password;
+ password_len = config->password_len;
+ }
+
+ if (!password)
return -1;
- name = os_zalloc(config->password_len + 1);
- if (name == NULL)
+ name = os_zalloc(password_len + 1);
+ if (!name)
return -1;
- os_memcpy(name, config->password, config->password_len);
+ os_memcpy(name, password, password_len);
ext_password_free(sm->ext_pw_buf);
sm->ext_pw_buf = ext_password_get(sm->ext_pw, name);
@@ -2758,16 +2801,25 @@
const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
{
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL)
+
+ if (!config)
return NULL;
- if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ if ((sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD)) ||
+ (!sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD))) {
if (eap_get_ext_password(sm, config) < 0)
return NULL;
*len = wpabuf_len(sm->ext_pw_buf);
return wpabuf_head(sm->ext_pw_buf);
}
+ if (sm->use_machine_cred) {
+ *len = config->machine_password_len;
+ return config->machine_password;
+ }
+
*len = config->password_len;
return config->password;
}
@@ -2785,10 +2837,14 @@
const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
{
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL)
+
+ if (!config)
return NULL;
- if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ if ((sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD)) ||
+ (!sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD))) {
if (eap_get_ext_password(sm, config) < 0)
return NULL;
if (hash)
@@ -2797,6 +2853,14 @@
return wpabuf_head(sm->ext_pw_buf);
}
+ if (sm->use_machine_cred) {
+ *len = config->machine_password_len;
+ if (hash)
+ *hash = !!(config->flags &
+ EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH);
+ return config->machine_password;
+ }
+
*len = config->password_len;
if (hash)
*hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 148c906..3238f74 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -1,6 +1,6 @@
/*
* EAP peer configuration data
- * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,68 +10,9 @@
#define EAP_CONFIG_H
/**
- * struct eap_peer_config - EAP peer configuration/credentials
+ * struct eap_peer_cert_config - EAP peer certificate configuration/credential
*/
-struct eap_peer_config {
- /**
- * identity - EAP Identity
- *
- * This field is used to set the real user identity or NAI (for
- * EAP-PSK/PAX/SAKE/GPSK).
- */
- u8 *identity;
-
- /**
- * identity_len - EAP Identity length
- */
- size_t identity_len;
-
- /**
- * anonymous_identity - Anonymous EAP Identity
- *
- * This field is used for unencrypted use with EAP types that support
- * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the
- * real identity (identity field) only to the authentication server.
- *
- * If not set, the identity field will be used for both unencrypted and
- * protected fields.
- *
- * This field can also be used with EAP-SIM/AKA/AKA' to store the
- * pseudonym identity.
- */
- u8 *anonymous_identity;
-
- /**
- * anonymous_identity_len - Length of anonymous_identity
- */
- size_t anonymous_identity_len;
-
- u8 *imsi_identity;
- size_t imsi_identity_len;
-
- /**
- * password - Password string for EAP
- *
- * This field can include either the plaintext password (default
- * option) or a NtPasswordHash (16-byte MD4 hash of the unicode
- * presentation of the password) if flags field has
- * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can
- * only be used with authentication mechanism that use this hash as the
- * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2,
- * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
- *
- * In addition, this field is used to configure a pre-shared key for
- * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK
- * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length
- * PSK.
- */
- u8 *password;
-
- /**
- * password_len - Length of password field
- */
- size_t password_len;
-
+struct eap_peer_cert_config {
/**
* ca_cert - File path to CA certificate file (PEM/DER)
*
@@ -231,14 +172,6 @@
char *check_cert_subject;
/**
- * check_cert_subject2 - Constraint for server certificate subject fields
- *
- * This field is like check_cert_subject, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- */
- char *check_cert_subject2;
-
- /**
* altsubject_match - Constraint for server certificate alt. subject
*
* Semicolon separated string of entries to be matched against the
@@ -299,115 +232,181 @@
char *domain_match;
/**
- * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
+ * pin - PIN for USIM, GSM SIM, and smartcards
*
- * This file can have one or more trusted CA certificates. If ca_cert2
- * and ca_path2 are not included, server certificate will not be
- * verified. This is insecure and a trusted CA certificate should
- * always be configured. Full path to the file should be used since
- * working directory may change when wpa_supplicant is run in the
- * background.
+ * This field is used to configure PIN for SIM and smartcards for
+ * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
+ * smartcard is used for private key operations.
*
- * This field is like ca_cert, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- *
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * If left out, this will be asked through control interface.
*/
- char *ca_cert2;
+ char *pin;
/**
- * ca_path2 - Directory path for CA certificate files (PEM) (Phase 2)
+ * engine - Enable OpenSSL engine (e.g., for smartcard access)
*
- * This path may contain multiple CA certificates in OpenSSL format.
- * Common use for this is to point to system trusted CA list which is
- * often installed into directory like /etc/ssl/certs. If configured,
- * these certificates are added to the list of trusted CAs. ca_cert
- * may also be included in that case, but it is not required.
- *
- * This field is like ca_path, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *ca_path2;
+ int engine;
/**
- * client_cert2 - File path to client certificate file
+ * engine_id - Engine ID for OpenSSL engine
*
- * This field is like client_cert, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
- * file should be used since working directory may change when
- * wpa_supplicant is run in the background.
+ * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
+ * engine.
*
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *client_cert2;
+ char *engine_id;
+
/**
- * private_key2 - File path to client private key file
+ * key_id - Key ID for OpenSSL engine
*
- * This field is like private_key, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
- * file should be used since working directory may change when
- * wpa_supplicant is run in the background.
- *
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *private_key2;
+ char *key_id;
/**
- * private_key2_passwd - Password for private key file
+ * cert_id - Cert ID for OpenSSL engine
*
- * This field is like private_key_passwd, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * This is used if the certificate operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *private_key2_passwd;
+ char *cert_id;
/**
- * dh_file2 - File path to DH/DSA parameters file (in PEM format)
+ * ca_cert_id - CA Cert ID for OpenSSL engine
*
- * This field is like dh_file, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
- * file should be used since working directory may change when
- * wpa_supplicant is run in the background.
- *
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * This is used if the CA certificate for EAP-TLS is on a smartcard.
*/
- char *dh_file2;
+ char *ca_cert_id;
/**
- * subject_match2 - Constraint for server certificate subject
+ * ocsp - Whether to use/require OCSP to check server certificate
*
- * This field is like subject_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * 0 = do not use OCSP stapling (TLS certificate status extension)
+ * 1 = try to use OCSP stapling, but not require response
+ * 2 = require valid OCSP stapling response
*/
- char *subject_match2;
+ int ocsp;
+};
+
+/**
+ * struct eap_peer_config - EAP peer configuration/credentials
+ */
+struct eap_peer_config {
+ /**
+ * identity - EAP Identity
+ *
+ * This field is used to set the real user identity or NAI (for
+ * EAP-PSK/PAX/SAKE/GPSK).
+ */
+ u8 *identity;
/**
- * altsubject_match2 - Constraint for server certificate alt. subject
- *
- * This field is like altsubject_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * identity_len - EAP Identity length
*/
- char *altsubject_match2;
+ size_t identity_len;
/**
- * domain_suffix_match2 - Constraint for server domain name
+ * anonymous_identity - Anonymous EAP Identity
*
- * This field is like domain_suffix_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * This field is used for unencrypted use with EAP types that support
+ * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the
+ * real identity (identity field) only to the authentication server.
+ *
+ * If not set, the identity field will be used for both unencrypted and
+ * protected fields.
+ *
+ * This field can also be used with EAP-SIM/AKA/AKA' to store the
+ * pseudonym identity.
*/
- char *domain_suffix_match2;
+ u8 *anonymous_identity;
/**
- * domain_match2 - Constraint for server domain name
- *
- * This field is like domain_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * anonymous_identity_len - Length of anonymous_identity
*/
- char *domain_match2;
+ size_t anonymous_identity_len;
+
+ u8 *imsi_identity;
+ size_t imsi_identity_len;
+
+ /**
+ * machine_identity - EAP Identity for machine credential
+ *
+ * This field is used to set the machine identity or NAI for cases where
+ * and explicit machine credential (instead of or in addition to a user
+ * credential (from %identity) is needed.
+ */
+ u8 *machine_identity;
+
+ /**
+ * machine_identity_len - EAP Identity length for machine credential
+ */
+ size_t machine_identity_len;
+
+ /**
+ * password - Password string for EAP
+ *
+ * This field can include either the plaintext password (default
+ * option) or a NtPasswordHash (16-byte MD4 hash of the unicode
+ * presentation of the password) if flags field has
+ * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can
+ * only be used with authentication mechanism that use this hash as the
+ * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2,
+ * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
+ *
+ * In addition, this field is used to configure a pre-shared key for
+ * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK
+ * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length
+ * PSK.
+ */
+ u8 *password;
+
+ /**
+ * password_len - Length of password field
+ */
+ size_t password_len;
+
+ /**
+ * machine_password - Password string for EAP machine credential
+ *
+ * This field is used when machine credential based on username/password
+ * is needed instead of a user credential (from %password). See
+ * %password for more details on the format.
+ */
+ u8 *machine_password;
+
+ /**
+ * machine_password_len - Length of machine credential password field
+ */
+ size_t machine_password_len;
+
+ /**
+ * cert - Certificate parameters for Phase 1
+ */
+ struct eap_peer_cert_config cert;
+
+ /**
+ * phase2_cert - Certificate parameters for Phase 2
+ *
+ * This is like cert, but used for Phase 2 (inside
+ * EAP-TTLS/PEAP/FAST/TEAP tunnel) authentication.
+ */
+ struct eap_peer_cert_config phase2_cert;
+
+ /**
+ * machine_cert - Certificate parameters for Phase 2 machine credential
+ *
+ * This is like cert, but used for Phase 2 (inside EAP-TEAP tunnel)
+ * authentication with machine credentials (while phase2_cert is used
+ * for user credentials).
+ */
+ struct eap_peer_cert_config machine_cert;
/**
* eap_methods - Allowed EAP methods
@@ -496,6 +495,13 @@
char *phase2;
/**
+ * machine_phase2 - Phase2 parameters for machine credentials
+ *
+ * See phase2 for more details.
+ */
+ char *machine_phase2;
+
+ /**
* pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM
*
* This field is used to configure PC/SC smartcard interface.
@@ -507,123 +513,6 @@
char *pcsc;
/**
- * pin - PIN for USIM, GSM SIM, and smartcards
- *
- * This field is used to configure PIN for SIM and smartcards for
- * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
- * smartcard is used for private key operations.
- *
- * If left out, this will be asked through control interface.
- */
- char *pin;
-
- /**
- * engine - Enable OpenSSL engine (e.g., for smartcard access)
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- int engine;
-
- /**
- * engine_id - Engine ID for OpenSSL engine
- *
- * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
- * engine.
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *engine_id;
-
- /**
- * engine2 - Enable OpenSSL engine (e.g., for smartcard) (Phase 2)
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- *
- * This field is like engine, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- */
- int engine2;
-
-
- /**
- * pin2 - PIN for USIM, GSM SIM, and smartcards (Phase 2)
- *
- * This field is used to configure PIN for SIM and smartcards for
- * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
- * smartcard is used for private key operations.
- *
- * This field is like pin2, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- *
- * If left out, this will be asked through control interface.
- */
- char *pin2;
-
- /**
- * engine2_id - Engine ID for OpenSSL engine (Phase 2)
- *
- * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
- * engine.
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- *
- * This field is like engine_id, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- */
- char *engine2_id;
-
-
- /**
- * key_id - Key ID for OpenSSL engine
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *key_id;
-
- /**
- * cert_id - Cert ID for OpenSSL engine
- *
- * This is used if the certificate operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *cert_id;
-
- /**
- * ca_cert_id - CA Cert ID for OpenSSL engine
- *
- * This is used if the CA certificate for EAP-TLS is on a smartcard.
- */
- char *ca_cert_id;
-
- /**
- * key2_id - Key ID for OpenSSL engine (phase2)
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *key2_id;
-
- /**
- * cert2_id - Cert ID for OpenSSL engine (phase2)
- *
- * This is used if the certificate operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *cert2_id;
-
- /**
- * ca_cert2_id - CA Cert ID for OpenSSL engine (phase2)
- *
- * This is used if the CA certificate for EAP-TLS is on a smartcard.
- */
- char *ca_cert2_id;
-
- /**
* otp - One-time-password
*
* This field should not be set in configuration step. It is only used
@@ -751,6 +640,8 @@
#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1)
+#define EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH BIT(2)
+#define EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD BIT(3)
/**
* flags - Network configuration flags (bitfield)
*
@@ -760,19 +651,14 @@
* instead of plaintext password
* bit 1 = password is stored in external storage; the value in the
* password field is the name of that external entry
+ * bit 2 = machine password is represented as a 16-byte NtPasswordHash
+ * value instead of plaintext password
+ * bit 3 = machine password is stored in external storage; the value in
+ * the password field is the name of that external entry
*/
u32 flags;
/**
- * ocsp - Whether to use/require OCSP to check server certificate
- *
- * 0 = do not use OCSP stapling (TLS certificate status extension)
- * 1 = try to use OCSP stapling, but not require response
- * 2 = require valid OCSP stapling response
- */
- int ocsp;
-
- /**
* external_sim_resp - Response from external SIM processing
*
* This field should not be set in configuration step. It is only used
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 94ce57d..0ed4a2b 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -162,7 +162,7 @@
if (eap_peer_select_phase2_methods(config, "auth=",
&data->phase2_types,
- &data->num_phase2_types) < 0) {
+ &data->num_phase2_types, 0) < 0) {
eap_fast_deinit(sm, data);
return NULL;
}
@@ -364,22 +364,24 @@
}
-static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type)
+static int eap_fast_select_phase2_method(struct eap_fast_data *data,
+ int vendor, enum eap_type type)
{
size_t i;
/* TODO: TNC with anonymous provisioning; need to require both
* completed MSCHAPv2 and TNC */
- if (data->anon_provisioning && type != EAP_TYPE_MSCHAPV2) {
- wpa_printf(MSG_INFO, "EAP-FAST: Only EAP-MSCHAPv2 is allowed "
- "during unauthenticated provisioning; reject phase2"
- " type %d", type);
+ if (data->anon_provisioning &&
+ (vendor != EAP_VENDOR_IETF || type != EAP_TYPE_MSCHAPV2)) {
+ wpa_printf(MSG_INFO,
+ "EAP-FAST: Only EAP-MSCHAPv2 is allowed during unauthenticated provisioning; reject phase2 type %u:%u",
+ vendor, type);
return -1;
}
#ifdef EAP_TNC
- if (type == EAP_TYPE_TNC) {
+ if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_TNC) {
data->phase2_type.vendor = EAP_VENDOR_IETF;
data->phase2_type.method = EAP_TYPE_TNC;
wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "
@@ -391,7 +393,7 @@
#endif /* EAP_TNC */
for (i = 0; i < data->num_phase2_types; i++) {
- if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||
+ if (data->phase2_types[i].vendor != vendor ||
data->phase2_types[i].method != type)
continue;
@@ -404,7 +406,9 @@
break;
}
- if (type != data->phase2_type.method || type == EAP_TYPE_NONE)
+ if (vendor != data->phase2_type.vendor ||
+ type != data->phase2_type.method ||
+ (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_NONE))
return -1;
return 0;
@@ -422,6 +426,8 @@
struct eap_method_ret iret;
struct eap_peer_config *config = eap_get_config(sm);
struct wpabuf msg;
+ int vendor = EAP_VENDOR_IETF;
+ enum eap_type method;
if (len <= sizeof(struct eap_hdr)) {
wpa_printf(MSG_INFO, "EAP-FAST: too short "
@@ -429,14 +435,27 @@
return -1;
}
pos = (u8 *) (hdr + 1);
- wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos);
- if (*pos == EAP_TYPE_IDENTITY) {
+ method = *pos;
+ if (method == EAP_TYPE_EXPANDED) {
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-FAST: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ vendor = WPA_GET_BE24(pos + 1);
+ method = WPA_GET_BE32(pos + 4);
+ }
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%u:%u",
+ vendor, method);
+ if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_IDENTITY) {
*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
return 0;
}
if (data->phase2_priv && data->phase2_method &&
- *pos != data->phase2_type.method) {
+ (vendor != data->phase2_type.vendor ||
+ method != data->phase2_type.method)) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - "
"deinitialize previous method");
data->phase2_method->deinit(sm, data->phase2_priv);
@@ -448,7 +467,7 @@
if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
data->phase2_type.method == EAP_TYPE_NONE &&
- eap_fast_select_phase2_method(data, *pos) < 0) {
+ eap_fast_select_phase2_method(data, vendor, method) < 0) {
if (eap_peer_tls_phase2_nak(data->phase2_types,
data->num_phase2_types,
hdr, resp))
@@ -459,8 +478,9 @@
if ((data->phase2_priv == NULL &&
eap_fast_init_phase2_method(sm, data) < 0) ||
data->phase2_method == NULL) {
- wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize "
- "Phase 2 EAP method %d", *pos);
+ wpa_printf(MSG_INFO,
+ "EAP-FAST: Failed to initialize Phase 2 EAP method %u:%u",
+ vendor, method);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
return -1;
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 096f0f2..8f29d4a 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -72,7 +72,7 @@
/**
* method - EAP type number (EAP_TYPE_*)
*/
- EapType method;
+ enum eap_type method;
/**
* name - Name of the method (e.g., "TLS")
@@ -312,7 +312,7 @@
EAP_FAILURE
} EAP_state;
/* Long-term local variables */
- EapType selectedMethod;
+ enum eap_type selectedMethod;
EapMethodState methodState;
int lastId;
struct wpabuf *lastRespData;
@@ -322,7 +322,7 @@
Boolean rxSuccess;
Boolean rxFailure;
int reqId;
- EapType reqMethod;
+ enum eap_type reqMethod;
int reqVendor;
u32 reqVendorMethod;
Boolean ignore;
@@ -366,6 +366,7 @@
u8 *peer_challenge, *auth_challenge;
int num_rounds;
+ int num_rounds_short;
int force_disabled;
struct wps_context *wps;
@@ -381,6 +382,7 @@
unsigned int expected_failure:1;
unsigned int ext_cert_check:1;
unsigned int waiting_ext_cert_check:1;
+ unsigned int use_machine_cred:1;
struct dl_list erp_keys; /* struct eap_erp_key */
};
diff --git a/src/eap_peer/eap_methods.c b/src/eap_peer/eap_methods.c
index 9747954..f2d2947 100644
--- a/src/eap_peer/eap_methods.c
+++ b/src/eap_peer/eap_methods.c
@@ -27,7 +27,8 @@
* @method: EAP type number
* Returns: Pointer to EAP method or %NULL if not found
*/
-const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)
+const struct eap_method * eap_peer_get_eap_method(int vendor,
+ enum eap_type method)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -47,7 +48,7 @@
* This function maps EAP type names into EAP type numbers based on the list of
* EAP methods included in the build.
*/
-EapType eap_peer_get_type(const char *name, int *vendor)
+enum eap_type eap_peer_get_type(const char *name, int *vendor)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -70,7 +71,7 @@
* This function maps EAP type numbers into EAP type names based on the list of
* EAP methods included in the build.
*/
-const char * eap_get_name(int vendor, EapType type)
+const char * eap_get_name(int vendor, enum eap_type type)
{
struct eap_method *m;
if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
@@ -169,7 +170,7 @@
for (m = eap_methods; m; m = m->next)
c++;
-
+
*count = c;
return eap_methods;
}
@@ -279,7 +280,8 @@
* is not needed anymore.
*/
struct eap_method * eap_peer_method_alloc(int version, int vendor,
- EapType method, const char *name)
+ enum eap_type method,
+ const char *name)
{
struct eap_method *eap;
eap = os_zalloc(sizeof(*eap));
diff --git a/src/eap_peer/eap_methods.h b/src/eap_peer/eap_methods.h
index 09e08d3..e94f3d7 100644
--- a/src/eap_peer/eap_methods.h
+++ b/src/eap_peer/eap_methods.h
@@ -11,31 +11,33 @@
#include "eap_common/eap_defs.h"
-const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method);
+const struct eap_method * eap_peer_get_eap_method(int vendor,
+ enum eap_type method);
const struct eap_method * eap_peer_get_methods(size_t *count);
struct eap_method * eap_peer_method_alloc(int version, int vendor,
- EapType method, const char *name);
+ enum eap_type method,
+ const char *name);
int eap_peer_method_register(struct eap_method *method);
#ifdef IEEE8021X_EAPOL
-EapType eap_peer_get_type(const char *name, int *vendor);
-const char * eap_get_name(int vendor, EapType type);
+enum eap_type eap_peer_get_type(const char *name, int *vendor);
+const char * eap_get_name(int vendor, enum eap_type type);
size_t eap_get_names(char *buf, size_t buflen);
char ** eap_get_names_as_string_array(size_t *num);
void eap_peer_unregister_methods(void);
#else /* IEEE8021X_EAPOL */
-static inline EapType eap_peer_get_type(const char *name, int *vendor)
+static inline enum eap_type eap_peer_get_type(const char *name, int *vendor)
{
*vendor = EAP_VENDOR_IETF;
return EAP_TYPE_NONE;
}
-static inline const char * eap_get_name(int vendor, EapType type)
+static inline const char * eap_get_name(int vendor, enum eap_type type)
{
return NULL;
}
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 6453afe..92b15ec 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -148,7 +148,7 @@
if (eap_peer_select_phase2_methods(config, "auth=",
&data->phase2_types,
- &data->num_phase2_types) < 0) {
+ &data->num_phase2_types, 0) < 0) {
eap_peap_deinit(sm, data);
return NULL;
}
@@ -603,6 +603,8 @@
u8 *pos;
struct eap_method_ret iret;
struct eap_peer_config *config = eap_get_config(sm);
+ int vendor;
+ enum eap_type method;
if (len <= sizeof(struct eap_hdr)) {
wpa_printf(MSG_INFO, "EAP-PEAP: too short "
@@ -666,13 +668,26 @@
#endif /* EAP_TNC */
/* fall through */
default:
+ vendor = EAP_VENDOR_IETF;
+ method = *pos;
+
+ if (method == EAP_TYPE_EXPANDED) {
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-PEAP: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ vendor = WPA_GET_BE24(pos + 1);
+ method = WPA_GET_BE32(pos + 4);
+ }
+
if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
data->phase2_type.method == EAP_TYPE_NONE) {
size_t i;
for (i = 0; i < data->num_phase2_types; i++) {
- if (data->phase2_types[i].vendor !=
- EAP_VENDOR_IETF ||
- data->phase2_types[i].method != *pos)
+ if (data->phase2_types[i].vendor != vendor ||
+ data->phase2_types[i].method != method)
continue;
data->phase2_type.vendor =
@@ -686,8 +701,9 @@
break;
}
}
- if (*pos != data->phase2_type.method ||
- *pos == EAP_TYPE_NONE) {
+ if (vendor != data->phase2_type.vendor ||
+ method != data->phase2_type.method ||
+ (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE)) {
if (eap_peer_tls_phase2_nak(data->phase2_types,
data->num_phase2_types,
hdr, resp))
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index 6cd72e0..54f102a 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -30,6 +30,7 @@
u8 *password;
size_t password_len;
int password_hash;
+ struct wpa_freq_range_list allowed_groups;
u16 group_num;
u8 prep;
u8 token[4];
@@ -54,6 +55,9 @@
};
+static void eap_pwd_deinit(struct eap_sm *sm, void *priv);
+
+
#ifndef CONFIG_NO_STDOUT_DEBUG
static const char * eap_pwd_state_txt(int state)
{
@@ -92,6 +96,7 @@
size_t identity_len, password_len;
int fragment_size;
int pwhash;
+ const char *phase1;
password = eap_get_config_password2(sm, &password_len, &pwhash);
if (password == NULL) {
@@ -129,6 +134,30 @@
data->password_len = password_len;
data->password_hash = pwhash;
+ phase1 = eap_get_config_phase1(sm);
+ if (phase1) {
+ const char *pos, *end;
+ char *copy = NULL;
+ int res;
+
+ pos = os_strstr(phase1, "eap_pwd_groups=");
+ if (pos) {
+ pos += 15;
+ end = os_strchr(pos, ' ');
+ if (end) {
+ copy = os_zalloc(end - pos + 1);
+ if (!copy)
+ goto fail;
+ os_memcpy(copy, pos, end - pos);
+ pos = copy;
+ }
+ res = freq_range_list_parse(&data->allowed_groups, pos);
+ os_free(copy);
+ if (res)
+ goto fail;
+ }
+ }
+
data->out_frag_pos = data->in_frag_pos = 0;
data->inbuf = data->outbuf = NULL;
fragment_size = eap_get_config_fragment_size(sm);
@@ -140,6 +169,9 @@
data->state = PWD_ID_Req;
return data;
+fail:
+ eap_pwd_deinit(sm, data);
+ return NULL;
}
@@ -163,6 +195,7 @@
}
wpabuf_free(data->inbuf);
wpabuf_free(data->outbuf);
+ os_free(data->allowed_groups.range);
bin_clear_free(data, sizeof(*data));
}
@@ -203,6 +236,18 @@
}
+static int eap_pwd_allowed_group(struct eap_pwd_data *data, u16 group)
+{
+ if (!data->allowed_groups.range) {
+ /* By default, allow the groups using NIST curves P-256, P-384,
+ * and P-521. */
+ return group == 19 || group == 20 || group == 21;
+ }
+
+ return freq_range_list_includes(&data->allowed_groups, group);
+}
+
+
static void
eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
struct eap_method_ret *ret,
@@ -228,9 +273,11 @@
wpa_printf(MSG_DEBUG,
"EAP-PWD: Server EAP-pwd-ID proposal: group=%u random=%u prf=%u prep=%u",
data->group_num, id->random_function, id->prf, id->prep);
- if ((id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
- (id->prf != EAP_PWD_DEFAULT_PRF)) {
- ret->ignore = TRUE;
+ if (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC ||
+ id->prf != EAP_PWD_DEFAULT_PRF ||
+ !eap_pwd_allowed_group(data, data->group_num)) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unsupported or disabled proposal");
eap_pwd_state(data, FAILURE);
return;
}
diff --git a/src/eap_peer/eap_teap.c b/src/eap_peer/eap_teap.c
index eea7d6e..f751fbe 100644
--- a/src/eap_peer/eap_teap.c
+++ b/src/eap_peer/eap_teap.c
@@ -35,7 +35,9 @@
void *phase2_priv;
int phase2_success;
int inner_method_done;
+ int iresult_verified;
int result_success_done;
+ int on_tx_completion;
struct eap_method_type phase2_type;
struct eap_method_type *phase2_types;
@@ -167,7 +169,7 @@
eap_teap_parse_phase1(data, config->phase1);
if ((data->provisioning_allowed & EAP_TEAP_PROV_AUTH) &&
- !config->ca_cert && !config->ca_path) {
+ !config->cert.ca_cert && !config->cert.ca_path) {
/* Prevent PAC provisioning without mutual authentication
* (either by validating server certificate or by suitable
* inner EAP method). */
@@ -178,7 +180,7 @@
if (eap_peer_select_phase2_methods(config, "auth=",
&data->phase2_types,
- &data->num_phase2_types) < 0) {
+ &data->num_phase2_types, 0) < 0) {
eap_teap_deinit(sm, data);
return NULL;
}
@@ -276,8 +278,10 @@
{
/* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
* is used in this derivation */
- if (eap_teap_derive_eap_msk(data->simck_msk, data->key_data) < 0 ||
- eap_teap_derive_eap_emsk(data->simck_msk, data->emsk) < 0)
+ if (eap_teap_derive_eap_msk(data->tls_cs, data->simck_msk,
+ data->key_data) < 0 ||
+ eap_teap_derive_eap_emsk(data->tls_cs, data->simck_msk,
+ data->emsk) < 0)
return -1;
data->success = 1;
return 0;
@@ -308,6 +312,7 @@
struct eap_teap_data *data)
{
data->inner_method_done = 0;
+ data->iresult_verified = 0;
data->phase2_method =
eap_peer_get_eap_method(data->phase2_type.vendor,
data->phase2_type.method);
@@ -322,7 +327,8 @@
}
-static int eap_teap_select_phase2_method(struct eap_teap_data *data, u8 type)
+static int eap_teap_select_phase2_method(struct eap_teap_data *data,
+ int vendor, enum eap_type type)
{
size_t i;
@@ -330,15 +336,15 @@
* completed inner EAP authentication (EAP-pwd or EAP-EKE) and TNC */
if (data->anon_provisioning &&
- !eap_teap_allowed_anon_prov_phase2_method(type)) {
+ !eap_teap_allowed_anon_prov_phase2_method(vendor, type)) {
wpa_printf(MSG_INFO,
- "EAP-TEAP: EAP type %u not allowed during unauthenticated provisioning",
- type);
+ "EAP-TEAP: EAP type %u:%u not allowed during unauthenticated provisioning",
+ vendor, type);
return -1;
}
#ifdef EAP_TNC
- if (type == EAP_TYPE_TNC) {
+ if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_TNC) {
data->phase2_type.vendor = EAP_VENDOR_IETF;
data->phase2_type.method = EAP_TYPE_TNC;
wpa_printf(MSG_DEBUG,
@@ -350,7 +356,7 @@
#endif /* EAP_TNC */
for (i = 0; i < data->num_phase2_types; i++) {
- if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||
+ if (data->phase2_types[i].vendor != vendor ||
data->phase2_types[i].method != type)
continue;
@@ -363,13 +369,31 @@
break;
}
- if (type != data->phase2_type.method || type == EAP_TYPE_NONE)
+ if (vendor != data->phase2_type.vendor ||
+ type != data->phase2_type.method ||
+ (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_NONE))
return -1;
return 0;
}
+static void eap_teap_deinit_inner_eap(struct eap_sm *sm,
+ struct eap_teap_data *data)
+{
+ if (!data->phase2_priv || !data->phase2_method)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Phase 2 EAP sequence - deinitialize previous method");
+ data->phase2_method->deinit(sm, data->phase2_priv);
+ data->phase2_method = NULL;
+ data->phase2_priv = NULL;
+ data->phase2_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_type.method = EAP_TYPE_NONE;
+}
+
+
static int eap_teap_phase2_request(struct eap_sm *sm,
struct eap_teap_data *data,
struct eap_method_ret *ret,
@@ -381,6 +405,8 @@
struct eap_method_ret iret;
struct eap_peer_config *config = eap_get_config(sm);
struct wpabuf msg;
+ int vendor = EAP_VENDOR_IETF;
+ enum eap_type method;
if (len <= sizeof(struct eap_hdr)) {
wpa_printf(MSG_INFO,
@@ -389,26 +415,33 @@
return -1;
}
pos = (u8 *) (hdr + 1);
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 Request: type=%d", *pos);
- if (*pos == EAP_TYPE_IDENTITY) {
+ method = *pos;
+ if (method == EAP_TYPE_EXPANDED) {
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ vendor = WPA_GET_BE24(pos + 1);
+ method = WPA_GET_BE32(pos + 4);
+ }
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 Request: type=%u:%u",
+ vendor, method);
+ if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_IDENTITY) {
+ eap_teap_deinit_inner_eap(sm, data);
*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
return 0;
}
if (data->phase2_priv && data->phase2_method &&
- *pos != data->phase2_type.method) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Phase 2 EAP sequence - deinitialize previous method");
- data->phase2_method->deinit(sm, data->phase2_priv);
- data->phase2_method = NULL;
- data->phase2_priv = NULL;
- data->phase2_type.vendor = EAP_VENDOR_IETF;
- data->phase2_type.method = EAP_TYPE_NONE;
- }
+ (vendor != data->phase2_type.vendor ||
+ method != data->phase2_type.method))
+ eap_teap_deinit_inner_eap(sm, data);
if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
data->phase2_type.method == EAP_TYPE_NONE &&
- eap_teap_select_phase2_method(data, *pos) < 0) {
+ eap_teap_select_phase2_method(data, vendor, method) < 0) {
if (eap_peer_tls_phase2_nak(data->phase2_types,
data->num_phase2_types,
hdr, resp))
@@ -419,8 +452,8 @@
if ((!data->phase2_priv && eap_teap_init_phase2_method(sm, data) < 0) ||
!data->phase2_method) {
wpa_printf(MSG_INFO,
- "EAP-TEAP: Failed to initialize Phase 2 EAP method %d",
- *pos);
+ "EAP-TEAP: Failed to initialize Phase 2 EAP method %u:%u",
+ vendor, method);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
return -1;
@@ -435,7 +468,8 @@
if (!(*resp) ||
(iret.methodState == METHOD_DONE &&
iret.decision == DECISION_FAIL)) {
- ret->methodState = METHOD_DONE;
+ /* Wait for protected indication of failure */
+ ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
} else if ((iret.methodState == METHOD_DONE ||
iret.methodState == METHOD_MAY_CONT) &&
@@ -499,10 +533,23 @@
}
+static struct wpabuf * eap_teap_add_identity_type(struct eap_sm *sm,
+ struct wpabuf *msg)
+{
+ struct wpabuf *tlv;
+
+ tlv = eap_teap_tlv_identity_type(sm->use_machine_cred ?
+ TEAP_IDENTITY_TYPE_MACHINE :
+ TEAP_IDENTITY_TYPE_USER);
+ return wpabuf_concat(msg, tlv);
+}
+
+
static struct wpabuf * eap_teap_process_eap_payload_tlv(
struct eap_sm *sm, struct eap_teap_data *data,
struct eap_method_ret *ret,
- u8 *eap_payload_tlv, size_t eap_payload_tlv_len)
+ u8 *eap_payload_tlv, size_t eap_payload_tlv_len,
+ enum teap_identity_types req_id_type)
{
struct eap_hdr *hdr;
struct wpabuf *resp = NULL;
@@ -534,13 +581,18 @@
return NULL;
}
- return eap_teap_tlv_eap_payload(resp);
+ resp = eap_teap_tlv_eap_payload(resp);
+ if (req_id_type)
+ resp = eap_teap_add_identity_type(sm, resp);
+
+ return resp;
}
static struct wpabuf * eap_teap_process_basic_auth_req(
struct eap_sm *sm, struct eap_teap_data *data,
- u8 *basic_auth_req, size_t basic_auth_req_len)
+ u8 *basic_auth_req, size_t basic_auth_req_len,
+ enum teap_identity_types req_id_type)
{
const u8 *identity, *password;
size_t identity_len, password_len, plen;
@@ -570,6 +622,8 @@
wpabuf_put_data(resp, password, password_len);
wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TEAP: Basic-Password-Auth-Resp",
resp);
+ if (req_id_type)
+ resp = eap_teap_add_identity_type(sm, resp);
/* Assume this succeeds so that Result TLV(Success) from the server can
* be used to terminate TEAP. */
@@ -679,7 +733,8 @@
data->simck_idx + 1);
if (!data->phase2_method)
- return eap_teap_derive_cmk_basic_pw_auth(data->simck_msk,
+ return eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
+ data->simck_msk,
cmk_msk);
if (!data->phase2_method || !data->phase2_priv) {
@@ -711,7 +766,8 @@
&emsk_len);
}
- res = eap_teap_derive_imck(data->simck_msk, data->simck_emsk,
+ res = eap_teap_derive_imck(data->tls_cs,
+ data->simck_msk, data->simck_emsk,
msk, msk_len, emsk, emsk_len,
data->simck_msk, cmk_msk,
data->simck_emsk, cmk_emsk);
@@ -1188,6 +1244,7 @@
struct eap_teap_tlv_parse tlv;
int failed = 0;
enum teap_error_codes error = 0;
+ int iresult_added = 0;
if (eap_teap_parse_decrypted(decrypted, &tlv, &resp) < 0) {
/* Parsing failed - no response available */
@@ -1211,14 +1268,21 @@
goto send_resp;
}
- if ((tlv.iresult == TEAP_STATUS_SUCCESS ||
- (!data->result_success_done &&
- tlv.result == TEAP_STATUS_SUCCESS)) &&
- !tlv.crypto_binding) {
- /* Result TLV or Intermediate-Result TLV indicating success,
- * but no Crypto-Binding TLV */
+ if (tlv.iresult == TEAP_STATUS_SUCCESS && !tlv.crypto_binding) {
+ /* Intermediate-Result TLV indicating success, but no
+ * Crypto-Binding TLV */
wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Result TLV or Intermediate-Result TLV indicating success, but no Crypto-Binding TLV");
+ "EAP-TEAP: Intermediate-Result TLV indicating success, but no Crypto-Binding TLV");
+ failed = 1;
+ error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR;
+ goto done;
+ }
+
+ if (!data->iresult_verified && !data->result_success_done &&
+ tlv.result == TEAP_STATUS_SUCCESS && !tlv.crypto_binding) {
+ /* Result TLV indicating success, but no Crypto-Binding TLV */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Result TLV indicating success, but no Crypto-Binding TLV");
failed = 1;
error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR;
goto done;
@@ -1234,17 +1298,45 @@
goto done;
}
+ if (tlv.identity_type == TEAP_IDENTITY_TYPE_MACHINE) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ sm->use_machine_cred = config && config->machine_identity &&
+ config->machine_identity_len;
+ } else if (tlv.identity_type) {
+ sm->use_machine_cred = 0;
+ }
+ if (tlv.identity_type) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ os_free(data->phase2_types);
+ data->phase2_types = NULL;
+ data->num_phase2_types = 0;
+ if (config &&
+ eap_peer_select_phase2_methods(config, "auth=",
+ &data->phase2_types,
+ &data->num_phase2_types,
+ sm->use_machine_cred) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Failed to update Phase 2 EAP types");
+ failed = 1;
+ goto done;
+ }
+ }
+
if (tlv.basic_auth_req) {
tmp = eap_teap_process_basic_auth_req(sm, data,
tlv.basic_auth_req,
- tlv.basic_auth_req_len);
+ tlv.basic_auth_req_len,
+ tlv.identity_type);
if (!tmp)
failed = 1;
resp = wpabuf_concat(resp, tmp);
} else if (tlv.eap_payload_tlv) {
tmp = eap_teap_process_eap_payload_tlv(sm, data, ret,
tlv.eap_payload_tlv,
- tlv.eap_payload_tlv_len);
+ tlv.eap_payload_tlv_len,
+ tlv.identity_type);
if (!tmp)
failed = 1;
resp = wpabuf_concat(resp, tmp);
@@ -1257,6 +1349,7 @@
resp = wpabuf_concat(resp, tmp);
if (tlv.iresult == TEAP_STATUS_FAILURE)
failed = 1;
+ iresult_added = 1;
}
}
@@ -1280,8 +1373,10 @@
resp = wpabuf_concat(resp, tmp);
if (tlv.result == TEAP_STATUS_SUCCESS && !failed)
data->result_success_done = 1;
- if (tlv.iresult == TEAP_STATUS_SUCCESS && !failed)
+ if (tlv.iresult == TEAP_STATUS_SUCCESS && !failed) {
data->inner_method_done = 0;
+ data->iresult_verified = 1;
+ }
}
}
@@ -1315,6 +1410,7 @@
data->phase2_method->vendor == 0 &&
eap_teap_allowed_anon_prov_cipher_suite(data->tls_cs) &&
eap_teap_allowed_anon_prov_phase2_method(
+ data->phase2_method->vendor,
data->phase2_method->method))) &&
(tlv.iresult == TEAP_STATUS_SUCCESS ||
tlv.result == TEAP_STATUS_SUCCESS)) {
@@ -1343,13 +1439,22 @@
tmp = eap_teap_tlv_result(TEAP_STATUS_SUCCESS, 0);
resp = wpabuf_concat(tmp, resp);
}
+ if ((tlv.iresult == TEAP_STATUS_SUCCESS ||
+ tlv.iresult == TEAP_STATUS_FAILURE) && !iresult_added) {
+ tmp = eap_teap_tlv_result((!failed && data->phase2_success) ?
+ TEAP_STATUS_SUCCESS :
+ TEAP_STATUS_FAILURE, 1);
+ resp = wpabuf_concat(tmp, resp);
+ }
if (resp && tlv.result == TEAP_STATUS_SUCCESS && !failed &&
- tlv.crypto_binding && data->phase2_success) {
+ (tlv.crypto_binding || data->iresult_verified) &&
+ data->phase2_success) {
/* Successfully completed Phase 2 */
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Authentication completed successfully");
- ret->methodState = data->provisioning ?
+ ret->methodState = METHOD_MAY_CONT;
+ data->on_tx_completion = data->provisioning ?
METHOD_MAY_CONT : METHOD_DONE;
ret->decision = DECISION_UNCOND_SUCC;
}
@@ -1402,9 +1507,18 @@
if (wpabuf_len(in_data) == 0) {
/* Received TLS ACK - requesting more fragments */
- return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TEAP,
- data->teap_version,
- identifier, NULL, out_data);
+ res = eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TEAP,
+ data->teap_version,
+ identifier, NULL, out_data);
+ if (res == 0 && !data->ssl.tls_out &&
+ data->on_tx_completion) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Mark authentication completed at full TX of fragments");
+ ret->methodState = data->on_tx_completion;
+ data->on_tx_completion = 0;
+ ret->decision = DECISION_UNCOND_SUCC;
+ }
+ return res;
}
res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
@@ -1904,6 +2018,8 @@
data->phase2_success = 0;
data->inner_method_done = 0;
data->result_success_done = 0;
+ data->iresult_verified = 0;
+ data->done_on_tx_completion = 0;
data->resuming = 1;
data->provisioning = 0;
data->anon_provisioning = 0;
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index 15d60d7..d9771f6 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -33,10 +33,17 @@
{
struct eap_tls_data *data;
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL ||
- ((sm->init_phase2 ? config->private_key2 : config->private_key)
- == NULL &&
- (sm->init_phase2 ? config->engine2 : config->engine) == 0)) {
+ struct eap_peer_cert_config *cert;
+
+ if (!config)
+ return NULL;
+ if (!sm->init_phase2)
+ cert = &config->cert;
+ else if (sm->use_machine_cred)
+ cert = &config->machine_cert;
+ else
+ cert = &config->phase2_cert;
+ if (!cert->private_key && cert->engine == 0) {
wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
return NULL;
}
@@ -51,13 +58,12 @@
if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
eap_tls_deinit(sm, data);
- if (config->engine) {
+ if (cert->engine) {
wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard "
"PIN");
eap_sm_request_pin(sm);
sm->ignore = TRUE;
- } else if (config->private_key && !config->private_key_passwd)
- {
+ } else if (cert->private_key && !cert->private_key_passwd) {
wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private "
"key passphrase");
eap_sm_request_passphrase(sm);
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 7e0690c..80e2d71 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -16,7 +16,7 @@
#include "eap_config.h"
-static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+static struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len,
u8 code, u8 identifier)
{
if (type == EAP_UNAUTH_TLS_TYPE)
@@ -105,8 +105,8 @@
}
-static void eap_tls_params_from_conf1(struct tls_connection_params *params,
- struct eap_peer_config *config)
+static void eap_tls_cert_params_from_conf(struct tls_connection_params *params,
+ struct eap_peer_cert_config *config)
{
params->ca_cert = config->ca_cert;
params->ca_path = config->ca_path;
@@ -125,6 +125,19 @@
params->key_id = config->key_id;
params->cert_id = config->cert_id;
params->ca_cert_id = config->ca_cert_id;
+ if (config->ocsp)
+ params->flags |= TLS_CONN_REQUEST_OCSP;
+ if (config->ocsp >= 2)
+ params->flags |= TLS_CONN_REQUIRE_OCSP;
+ if (config->ocsp == 3)
+ params->flags |= TLS_CONN_REQUIRE_OCSP_ALL;
+}
+
+
+static void eap_tls_params_from_conf1(struct tls_connection_params *params,
+ struct eap_peer_config *config)
+{
+ eap_tls_cert_params_from_conf(params, &config->cert);
eap_tls_params_flags(params, config->phase1);
}
@@ -132,27 +145,19 @@
static void eap_tls_params_from_conf2(struct tls_connection_params *params,
struct eap_peer_config *config)
{
- params->ca_cert = config->ca_cert2;
- params->ca_path = config->ca_path2;
- params->client_cert = config->client_cert2;
- params->private_key = config->private_key2;
- params->private_key_passwd = config->private_key2_passwd;
- params->dh_file = config->dh_file2;
- params->subject_match = config->subject_match2;
- params->altsubject_match = config->altsubject_match2;
- params->check_cert_subject = config->check_cert_subject2;
- params->suffix_match = config->domain_suffix_match2;
- params->domain_match = config->domain_match2;
- params->engine = config->engine2;
- params->engine_id = config->engine2_id;
- params->pin = config->pin2;
- params->key_id = config->key2_id;
- params->cert_id = config->cert2_id;
- params->ca_cert_id = config->ca_cert2_id;
+ eap_tls_cert_params_from_conf(params, &config->phase2_cert);
eap_tls_params_flags(params, config->phase2);
}
+static void eap_tls_params_from_conf2m(struct tls_connection_params *params,
+ struct eap_peer_config *config)
+{
+ eap_tls_cert_params_from_conf(params, &config->machine_cert);
+ eap_tls_params_flags(params, config->machine_phase2);
+}
+
+
static int eap_tls_params_from_conf(struct eap_sm *sm,
struct eap_ssl_data *data,
struct tls_connection_params *params,
@@ -199,7 +204,10 @@
*/
params->flags |= TLS_CONN_DISABLE_TLSv1_3;
}
- if (phase2) {
+ if (phase2 && sm->use_machine_cred) {
+ wpa_printf(MSG_DEBUG, "TLS: using machine config options");
+ eap_tls_params_from_conf2m(params, config);
+ } else if (phase2) {
wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
eap_tls_params_from_conf2(params, config);
} else {
@@ -242,12 +250,6 @@
{
int res;
- if (config->ocsp)
- params->flags |= TLS_CONN_REQUEST_OCSP;
- if (config->ocsp >= 2)
- params->flags |= TLS_CONN_REQUIRE_OCSP;
- if (config->ocsp == 3)
- params->flags |= TLS_CONN_REQUIRE_OCSP_ALL;
data->conn = tls_connection_init(data->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
@@ -264,8 +266,8 @@
*/
wpa_printf(MSG_INFO,
"TLS: Bad PIN provided, requesting a new one");
- os_free(config->pin);
- config->pin = NULL;
+ os_free(config->cert.pin);
+ config->cert.pin = NULL;
eap_sm_request_pin(sm);
sm->ignore = TRUE;
} else if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
@@ -619,7 +621,8 @@
* @out_data: Buffer for returning the allocated output buffer
* Returns: ret (0 or 1) on success, -1 on failure
*/
-static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
+static int eap_tls_process_output(struct eap_ssl_data *data,
+ enum eap_type eap_type,
int peap_version, u8 id, int ret,
struct wpabuf **out_data)
{
@@ -717,7 +720,7 @@
* the tunneled data is used.
*/
int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version,
+ enum eap_type eap_type, int peap_version,
u8 id, const struct wpabuf *in_data,
struct wpabuf **out_data)
{
@@ -809,7 +812,7 @@
* @peap_version: Version number for EAP-PEAP/TTLS
* Returns: Pointer to the allocated ACK frame or %NULL on failure
*/
-struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
+struct wpabuf * eap_peer_tls_build_ack(u8 id, enum eap_type eap_type,
int peap_version)
{
struct wpabuf *resp;
@@ -899,7 +902,7 @@
*/
const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
struct eap_ssl_data *data,
- EapType eap_type,
+ enum eap_type eap_type,
struct eap_method_ret *ret,
const struct wpabuf *reqData,
size_t *len, u8 *flags)
@@ -1056,7 +1059,7 @@
* Returns: 0 on success, -1 on failure
*/
int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version, u8 id,
+ enum eap_type eap_type, int peap_version, u8 id,
const struct wpabuf *in_data,
struct wpabuf **out_data)
{
@@ -1092,17 +1095,21 @@
int eap_peer_select_phase2_methods(struct eap_peer_config *config,
const char *prefix,
struct eap_method_type **types,
- size_t *num_types)
+ size_t *num_types, int use_machine_cred)
{
char *start, *pos, *buf;
struct eap_method_type *methods = NULL, *_methods;
u32 method;
size_t num_methods = 0, prefix_len;
+ const char *phase2;
- if (config == NULL || config->phase2 == NULL)
+ if (!config)
+ goto get_defaults;
+ phase2 = use_machine_cred ? config->machine_phase2 : config->phase2;
+ if (!phase2)
goto get_defaults;
- start = buf = os_strdup(config->phase2);
+ start = buf = os_strdup(phase2);
if (buf == NULL)
return -1;
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index d96eff1..183b7de 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -107,17 +107,17 @@
struct eap_ssl_data *data, u8 eap_type,
size_t *len);
int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version,
+ enum eap_type eap_type, int peap_version,
u8 id, const struct wpabuf *in_data,
struct wpabuf **out_data);
-struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
+struct wpabuf * eap_peer_tls_build_ack(u8 id, enum eap_type eap_type,
int peap_version);
int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data);
int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
char *buf, size_t buflen, int verbose);
const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
struct eap_ssl_data *data,
- EapType eap_type,
+ enum eap_type eap_type,
struct eap_method_ret *ret,
const struct wpabuf *reqData,
size_t *len, u8 *flags);
@@ -127,13 +127,13 @@
const struct wpabuf *in_data,
struct wpabuf **in_decrypted);
int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version, u8 id,
+ enum eap_type eap_type, int peap_version, u8 id,
const struct wpabuf *in_data,
struct wpabuf **out_data);
int eap_peer_select_phase2_methods(struct eap_peer_config *config,
const char *prefix,
struct eap_method_type **types,
- size_t *num_types);
+ size_t *num_types, int use_machine_cred);
int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
struct eap_hdr *hdr, struct wpabuf **resp);
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 1c8dbe2..662676f 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -146,8 +146,8 @@
if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
if (eap_peer_select_phase2_methods(config, "autheap=",
&data->phase2_eap_types,
- &data->num_phase2_eap_types)
- < 0) {
+ &data->num_phase2_eap_types,
+ 0) < 0) {
eap_ttls_deinit(sm, data);
return NULL;
}
@@ -311,11 +311,11 @@
static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data,
- u8 method)
+ int vendor, enum eap_type method)
{
size_t i;
for (i = 0; i < data->num_phase2_eap_types; i++) {
- if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF ||
+ if (data->phase2_eap_types[i].vendor != vendor ||
data->phase2_eap_types[i].method != method)
continue;
@@ -362,17 +362,19 @@
struct eap_ttls_data *data,
struct eap_method_ret *ret,
struct eap_hdr *hdr, size_t len,
- u8 method, struct wpabuf **resp)
+ int vendor, enum eap_type method,
+ struct wpabuf **resp)
{
#ifdef EAP_TNC
if (data->tnc_started && data->phase2_method &&
- data->phase2_priv && method == EAP_TYPE_TNC &&
+ data->phase2_priv &&
+ vendor == EAP_VENDOR_IETF && method == EAP_TYPE_TNC &&
data->phase2_eap_type.method == EAP_TYPE_TNC)
return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len,
resp);
if (data->ready_for_tnc && !data->tnc_started &&
- method == EAP_TYPE_TNC) {
+ vendor == EAP_VENDOR_IETF && method == EAP_TYPE_TNC) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
"EAP method");
data->tnc_started = 1;
@@ -386,7 +388,7 @@
return -1;
}
- data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_eap_type.vendor = vendor;
data->phase2_eap_type.method = method;
wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
"Phase 2 EAP vendor %d method %d (TNC)",
@@ -400,10 +402,11 @@
if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF &&
data->phase2_eap_type.method == EAP_TYPE_NONE)
- eap_ttls_phase2_select_eap_method(data, method);
+ eap_ttls_phase2_select_eap_method(data, vendor, method);
- if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE)
- {
+ if (vendor != data->phase2_eap_type.vendor ||
+ method != data->phase2_eap_type.method ||
+ (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE)) {
if (eap_peer_tls_phase2_nak(data->phase2_eap_types,
data->num_phase2_eap_types,
hdr, resp))
@@ -412,8 +415,7 @@
}
if (data->phase2_priv == NULL) {
- data->phase2_method = eap_peer_get_eap_method(
- EAP_VENDOR_IETF, method);
+ data->phase2_method = eap_peer_get_eap_method(vendor, method);
if (data->phase2_method) {
sm->init_phase2 = 1;
data->phase2_priv = data->phase2_method->init(sm);
@@ -421,8 +423,9 @@
}
}
if (data->phase2_priv == NULL || data->phase2_method == NULL) {
- wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize "
- "Phase 2 EAP method %d", method);
+ wpa_printf(MSG_INFO,
+ "EAP-TTLS: failed to initialize Phase 2 EAP method %u:%u",
+ vendor, method);
return -1;
}
@@ -451,9 +454,23 @@
case EAP_TYPE_IDENTITY:
*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
break;
+ case EAP_TYPE_EXPANDED:
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-TTLS: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
+ WPA_GET_BE24(pos + 1),
+ WPA_GET_BE32(pos + 4),
+ resp) < 0)
+ return -1;
+ break;
default:
if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
- *pos, resp) < 0)
+ EAP_VENDOR_IETF, *pos,
+ resp) < 0)
return -1;
break;
}
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index a32c883..540b4e7 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -108,37 +108,162 @@
};
struct eap_config {
+ /**
+ * ssl_ctx - TLS context
+ *
+ * This is passed to the EAP server implementation as a callback
+ * context for TLS operations.
+ */
void *ssl_ctx;
void *msg_ctx;
+
+ /**
+ * eap_sim_db_priv - EAP-SIM/AKA database context
+ *
+ * This is passed to the EAP-SIM/AKA server implementation as a
+ * callback context.
+ */
void *eap_sim_db_priv;
Boolean backend_auth;
int eap_server;
+
+ /**
+ * pwd_group - The D-H group assigned for EAP-pwd
+ *
+ * If EAP-pwd is not used it can be set to zero.
+ */
u16 pwd_group;
+
+ /**
+ * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
+ *
+ * This parameter is used to set a key for EAP-FAST to encrypt the
+ * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
+ * set, must point to a 16-octet key.
+ */
u8 *pac_opaque_encr_key;
+
+ /**
+ * eap_fast_a_id - EAP-FAST authority identity (A-ID)
+ *
+ * If EAP-FAST is not used, this can be set to %NULL. In theory, this
+ * is a variable length field, but due to some existing implementations
+ * requiring A-ID to be 16 octets in length, it is recommended to use
+ * that length for the field to provide interoperability with deployed
+ * peer implementations.
+ */
u8 *eap_fast_a_id;
+
+ /**
+ * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
+ */
size_t eap_fast_a_id_len;
+ /**
+ * eap_fast_a_id_info - EAP-FAST authority identifier information
+ *
+ * This A-ID-Info contains a user-friendly name for the A-ID. For
+ * example, this could be the enterprise and server names in
+ * human-readable format. This field is encoded as UTF-8. If EAP-FAST
+ * is not used, this can be set to %NULL.
+ */
char *eap_fast_a_id_info;
- int eap_fast_prov;
+
+ /**
+ * eap_fast_prov - EAP-FAST provisioning modes
+ *
+ * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
+ * 2 = only authenticated provisioning allowed, 3 = both provisioning
+ * modes allowed.
+ */
+ enum {
+ NO_PROV, ANON_PROV, AUTH_PROV, BOTH_PROV
+ } eap_fast_prov;
+
+ /**
+ * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
+ *
+ * This is the hard limit on how long a provisioned PAC-Key can be
+ * used.
+ */
int pac_key_lifetime;
+
+ /**
+ * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
+ *
+ * This is a soft limit on the PAC-Key. The server will automatically
+ * generate a new PAC-Key when this number of seconds (or fewer) of the
+ * lifetime remains.
+ */
int pac_key_refresh_time;
int eap_teap_auth;
int eap_teap_pac_no_inner;
+ int eap_teap_separate_result;
+ enum eap_teap_id {
+ EAP_TEAP_ID_ALLOW_ANY = 0,
+ EAP_TEAP_ID_REQUIRE_USER = 1,
+ EAP_TEAP_ID_REQUIRE_MACHINE = 2,
+ EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE = 3,
+ EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER = 4,
+ EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE = 5,
+ } eap_teap_id;
+
+ /**
+ * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
+ *
+ * This controls whether the protected success/failure indication
+ * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
+ */
int eap_sim_aka_result_ind;
+ int eap_sim_id;
+
+ /**
+ * tnc - Trusted Network Connect (TNC)
+ *
+ * This controls whether TNC is enabled and will be required before the
+ * peer is allowed to connect. Note: This is only used with EAP-TTLS
+ * and EAP-FAST. If any other EAP method is enabled, the peer will be
+ * allowed to connect without TNC.
+ */
int tnc;
+
+ /**
+ * wps - Wi-Fi Protected Setup context
+ *
+ * If WPS is used with an external RADIUS server (which is quite
+ * unlikely configuration), this is used to provide a pointer to WPS
+ * context data. Normally, this can be set to %NULL.
+ */
struct wps_context *wps;
- const struct wpabuf *assoc_wps_ie;
- const struct wpabuf *assoc_p2p_ie;
- const u8 *peer_addr;
int fragment_size;
int pbc_in_m1;
- const u8 *server_id;
+ /**
+ * server_id - Server identity
+ */
+ u8 *server_id;
size_t server_id_len;
+
+ /**
+ * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
+ *
+ * This controls whether the authentication server derives ERP key
+ * hierarchy (rRK and rIK) from full EAP authentication and allows
+ * these keys to be used to perform ERP to derive rMSK instead of full
+ * EAP authentication to derive MSK.
+ */
int erp;
unsigned int tls_session_lifetime;
unsigned int tls_flags;
+ unsigned int max_auth_rounds;
+ unsigned int max_auth_rounds_short;
+};
+
+struct eap_session_data {
+ const struct wpabuf *assoc_wps_ie;
+ const struct wpabuf *assoc_p2p_ie;
+ const u8 *peer_addr;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
#endif /* CONFIG_TESTING_OPTIONS */
@@ -147,7 +272,8 @@
struct eap_sm * eap_server_sm_init(void *eapol_ctx,
const struct eapol_callbacks *eapol_cb,
- struct eap_config *eap_conf);
+ const struct eap_config *conf,
+ const struct eap_session_data *sess);
void eap_server_sm_deinit(struct eap_sm *sm);
int eap_server_sm_step(struct eap_sm *sm);
void eap_sm_notify_cached(struct eap_sm *sm);
@@ -164,5 +290,6 @@
const u8 *challenge, const u8 *response);
void eap_erp_update_identity(struct eap_sm *sm, const u8 *eap, size_t len);
void eap_user_free(struct eap_user *user);
+void eap_server_config_free(struct eap_config *cfg);
#endif /* EAP_H */
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 8e6ac46..44896a6 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -23,7 +23,7 @@
*/
struct eap_method {
int vendor;
- EapType method;
+ enum eap_type method;
const char *name;
void * (*init)(struct eap_sm *sm);
@@ -128,7 +128,7 @@
/* Full authenticator state machine local variables */
/* Long-term (maintained between packets) */
- EapType currentMethod;
+ enum eap_type currentMethod;
int currentId;
enum {
METHOD_PROPOSED, METHOD_CONTINUE, METHOD_END
@@ -141,7 +141,7 @@
Boolean rxResp;
Boolean rxInitiate;
int respId;
- EapType respMethod;
+ enum eap_type respMethod;
int respVendor;
u32 respVendorMethod;
Boolean ignore;
@@ -154,7 +154,7 @@
const struct eap_method *m; /* selected EAP method */
/* not defined in RFC 4137 */
Boolean changed;
- void *eapol_ctx, *msg_ctx;
+ void *eapol_ctx;
const struct eapol_callbacks *eapol_cb;
void *eap_method_priv;
u8 *identity;
@@ -167,13 +167,12 @@
struct eap_user *user;
int user_eap_method_index;
int init_phase2;
- void *ssl_ctx;
- struct eap_sim_db_data *eap_sim_db_priv;
- Boolean backend_auth;
+ const struct eap_config *cfg;
+ struct eap_config cfg_buf;
Boolean update_user;
- int eap_server;
- int num_rounds;
+ unsigned int num_rounds;
+ unsigned int num_rounds_short;
enum {
METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT
} method_pending;
@@ -181,21 +180,6 @@
u8 *auth_challenge;
u8 *peer_challenge;
- u8 *pac_opaque_encr_key;
- u8 *eap_fast_a_id;
- size_t eap_fast_a_id_len;
- char *eap_fast_a_id_info;
- enum {
- NO_PROV, ANON_PROV, AUTH_PROV, BOTH_PROV
- } eap_fast_prov;
- int pac_key_lifetime;
- int pac_key_refresh_time;
- int eap_teap_auth;
- int eap_teap_pac_no_inner;
- int eap_sim_aka_result_ind;
- int tnc;
- u16 pwd_group;
- struct wps_context *wps;
struct wpabuf *assoc_wps_ie;
struct wpabuf *assoc_p2p_ie;
@@ -203,19 +187,8 @@
u8 peer_addr[ETH_ALEN];
- /* Fragmentation size for EAP method init() handler */
- int fragment_size;
-
- int pbc_in_m1;
-
- const u8 *server_id;
- size_t server_id_len;
-
Boolean initiate_reauth_start_sent;
Boolean try_initiate_reauth;
- int erp;
- unsigned int tls_session_lifetime;
- unsigned int tls_flags;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
diff --git a/src/eap_server/eap_methods.h b/src/eap_server/eap_methods.h
index fdbea7a..ad60700 100644
--- a/src/eap_server/eap_methods.h
+++ b/src/eap_server/eap_methods.h
@@ -12,14 +12,15 @@
#include "eap_common/eap_defs.h"
const struct eap_method * eap_server_get_eap_method(int vendor,
- EapType method);
+ enum eap_type method);
struct eap_method * eap_server_method_alloc(int version, int vendor,
- EapType method, const char *name);
+ enum eap_type method,
+ const char *name);
int eap_server_method_register(struct eap_method *method);
-EapType eap_server_get_type(const char *name, int *vendor);
+enum eap_type eap_server_get_type(const char *name, int *vendor);
void eap_server_unregister_methods(void);
-const char * eap_server_get_name(int vendor, EapType type);
+const char * eap_server_get_name(int vendor, enum eap_type type);
/* EAP server method registration calls for statically linked in methods */
int eap_server_identity_register(void);
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 724ec15..34ce239 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -23,8 +23,6 @@
#define STATE_MACHINE_DATA struct eap_sm
#define STATE_MACHINE_DEBUG_PREFIX "EAP"
-#define EAP_MAX_AUTH_ROUNDS 50
-
/* EAP state machines are described in RFC 4137 */
static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
@@ -37,9 +35,10 @@
static int eap_sm_nextId(struct eap_sm *sm, int id);
static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
size_t len);
-static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);
+static enum eap_type eap_sm_Policy_getNextMethod(struct eap_sm *sm,
+ int *vendor);
static int eap_sm_Policy_getDecision(struct eap_sm *sm);
-static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
+static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, enum eap_type method);
static int eap_get_erp_send_reauth_start(struct eap_sm *sm)
@@ -94,7 +93,7 @@
}
msg = eap_msg_alloc(EAP_VENDOR_IETF,
- (EapType) EAP_ERP_TYPE_REAUTH_START, plen,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH_START, plen,
EAP_CODE_INITIATE, id);
if (msg == NULL)
return NULL;
@@ -215,6 +214,7 @@
{
SM_ENTRY(EAP, DISABLED);
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
}
@@ -222,7 +222,7 @@
{
SM_ENTRY(EAP, INITIALIZE);
- if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) {
+ if (sm->eap_if.eapRestart && !sm->cfg->eap_server && sm->identity) {
/*
* Need to allow internal Identity method to be used instead
* of passthrough at the beginning of reauthentication.
@@ -256,7 +256,7 @@
sm->m = NULL;
sm->user_eap_method_index = 0;
- if (sm->backend_auth) {
+ if (sm->cfg->backend_auth) {
sm->currentMethod = EAP_TYPE_NONE;
/* parse rxResp, respId, respMethod */
eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
@@ -265,9 +265,10 @@
}
}
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
sm->method_pending = METHOD_PENDING_NONE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -299,7 +300,7 @@
}
}
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
"method=%u", sm->currentMethod);
}
@@ -324,7 +325,7 @@
sm->eap_if.eapReq = TRUE;
}
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -336,6 +337,10 @@
/* parse rxResp, respId, respMethod */
eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
sm->num_rounds++;
+ if (!sm->eap_if.eapRespData || wpabuf_len(sm->eap_if.eapRespData) < 20)
+ sm->num_rounds_short++;
+ else
+ sm->num_rounds_short = 0;
}
@@ -353,6 +358,8 @@
sm->retransCount = 0;
if (sm->eap_if.eapReqData) {
+ if (wpabuf_len(sm->eap_if.eapReqData) >= 20)
+ sm->num_rounds_short = 0;
if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
{
sm->eap_if.eapResp = FALSE;
@@ -529,7 +536,7 @@
sm->eap_if.eapSessionId,
sm->eap_if.eapSessionIdLen);
}
- if (sm->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
+ if (sm->cfg->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
eap_server_erp_init(sm);
sm->methodState = METHOD_END;
} else {
@@ -541,7 +548,7 @@
SM_STATE(EAP, PROPOSE_METHOD)
{
int vendor;
- EapType type;
+ enum eap_type type;
SM_ENTRY(EAP, PROPOSE_METHOD);
@@ -579,7 +586,7 @@
else
sm->methodState = METHOD_PROPOSED;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
"vendor=%u method=%u", vendor, sm->currentMethod);
eap_log_msg(sm, "Propose EAP method vendor=%u method=%u",
vendor, sm->currentMethod);
@@ -635,8 +642,8 @@
sm->eap_if.eapTimeout = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TIMEOUT_FAILURE MACSTR,
- MAC2STR(sm->peer_addr));
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO,
+ WPA_EVENT_EAP_TIMEOUT_FAILURE MACSTR, MAC2STR(sm->peer_addr));
}
@@ -650,7 +657,7 @@
sm->lastReqData = NULL;
sm->eap_if.eapFail = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -667,7 +674,7 @@
sm->eap_if.eapKeyAvailable = TRUE;
sm->eap_if.eapSuccess = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -720,7 +727,8 @@
plen = 1 + 2 + 2 + os_strlen(nai);
if (hash_len)
plen += 1 + hash_len;
- msg = eap_msg_alloc(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
+ msg = eap_msg_alloc(EAP_VENDOR_IETF,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH,
plen, EAP_CODE_FINISH, id);
if (msg == NULL)
return;
@@ -753,7 +761,7 @@
if ((flags & 0x80) || !erp) {
sm->eap_if.eapFail = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
MACSTR, MAC2STR(sm->peer_addr));
return;
}
@@ -781,7 +789,7 @@
sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
sm->eap_if.eapSuccess = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -805,7 +813,8 @@
sm->rxInitiate = FALSE;
- pos = eap_hdr_validate(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
+ pos = eap_hdr_validate(EAP_VENDOR_IETF,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH,
sm->eap_if.eapRespData, &len);
if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-Initiate: Invalid frame");
@@ -852,7 +861,7 @@
os_memcpy(nai, parse.keyname, parse.keyname_len);
nai[parse.keyname_len] = '\0';
- if (!sm->eap_server) {
+ if (!sm->cfg->eap_server) {
/*
* In passthrough case, EAP-Initiate/Re-auth replaces
* EAP Identity exchange. Use keyName-NAI as the user identity
@@ -1015,7 +1024,7 @@
sm->eap_if.eapReq = TRUE;
}
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT2 MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT2 MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -1108,8 +1117,8 @@
sm->eap_if.eapTimeout = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TIMEOUT_FAILURE2 MACSTR,
- MAC2STR(sm->peer_addr));
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO,
+ WPA_EVENT_EAP_TIMEOUT_FAILURE2 MACSTR, MAC2STR(sm->peer_addr));
}
@@ -1120,7 +1129,7 @@
eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
sm->eap_if.eapFail = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE2 MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE2 MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -1149,7 +1158,7 @@
*/
sm->start_reauth = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS2 MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS2 MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -1160,17 +1169,26 @@
SM_ENTER_GLOBAL(EAP, INITIALIZE);
else if (!sm->eap_if.portEnabled)
SM_ENTER_GLOBAL(EAP, DISABLED);
- else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
- if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
+ else if (sm->num_rounds > sm->cfg->max_auth_rounds) {
+ if (sm->num_rounds == sm->cfg->max_auth_rounds + 1) {
wpa_printf(MSG_DEBUG, "EAP: more than %d "
"authentication rounds - abort",
- EAP_MAX_AUTH_ROUNDS);
+ sm->cfg->max_auth_rounds);
sm->num_rounds++;
SM_ENTER_GLOBAL(EAP, FAILURE);
}
+ } else if (sm->num_rounds_short > sm->cfg->max_auth_rounds_short) {
+ if (sm->num_rounds_short ==
+ sm->cfg->max_auth_rounds_short + 1) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: more than %d authentication rounds (short) - abort",
+ sm->cfg->max_auth_rounds_short);
+ sm->num_rounds_short++;
+ SM_ENTER_GLOBAL(EAP, FAILURE);
+ }
} else switch (sm->EAP_state) {
case EAP_INITIALIZE:
- if (sm->backend_auth) {
+ if (sm->cfg->backend_auth) {
if (!sm->rxResp)
SM_ENTER(EAP, SELECT_ACTION);
else if (sm->rxResp &&
@@ -1333,7 +1351,7 @@
else if (sm->decision == DECISION_INITIATE_REAUTH_START)
SM_ENTER(EAP, INITIATE_REAUTH_START);
#ifdef CONFIG_ERP
- else if (sm->eap_server && sm->erp && sm->rxInitiate)
+ else if (sm->cfg->eap_server && sm->cfg->erp && sm->rxInitiate)
SM_ENTER(EAP, INITIATE_RECEIVED);
#endif /* CONFIG_ERP */
else
@@ -1343,7 +1361,7 @@
SM_ENTER(EAP, SEND_REQUEST);
break;
case EAP_INITIATE_RECEIVED:
- if (!sm->eap_server)
+ if (!sm->cfg->eap_server)
SM_ENTER(EAP, SELECT_ACTION);
break;
case EAP_TIMEOUT_FAILURE:
@@ -1669,9 +1687,9 @@
}
-static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
+static enum eap_type eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
{
- EapType next;
+ enum eap_type next;
int idx = sm->user_eap_method_index;
/* In theory, there should be no problems with starting
@@ -1703,7 +1721,7 @@
static int eap_sm_Policy_getDecision(struct eap_sm *sm)
{
- if (!sm->eap_server && sm->identity && !sm->start_reauth) {
+ if (!sm->cfg->eap_server && sm->identity && !sm->start_reauth) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH");
return DECISION_PASSTHROUGH;
}
@@ -1783,7 +1801,7 @@
}
-static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
+static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, enum eap_type method)
{
return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
}
@@ -1834,7 +1852,8 @@
*/
struct eap_sm * eap_server_sm_init(void *eapol_ctx,
const struct eapol_callbacks *eapol_cb,
- struct eap_config *conf)
+ const struct eap_config *conf,
+ const struct eap_session_data *sess)
{
struct eap_sm *sm;
@@ -1844,53 +1863,15 @@
sm->eapol_ctx = eapol_ctx;
sm->eapol_cb = eapol_cb;
sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */
- sm->ssl_ctx = conf->ssl_ctx;
- sm->msg_ctx = conf->msg_ctx;
- sm->eap_sim_db_priv = conf->eap_sim_db_priv;
- sm->backend_auth = conf->backend_auth;
- sm->eap_server = conf->eap_server;
- if (conf->pac_opaque_encr_key) {
- sm->pac_opaque_encr_key = os_malloc(16);
- if (sm->pac_opaque_encr_key) {
- os_memcpy(sm->pac_opaque_encr_key,
- conf->pac_opaque_encr_key, 16);
- }
- }
- if (conf->eap_fast_a_id) {
- sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
- if (sm->eap_fast_a_id) {
- os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id,
- conf->eap_fast_a_id_len);
- sm->eap_fast_a_id_len = conf->eap_fast_a_id_len;
- }
- }
- if (conf->eap_fast_a_id_info)
- sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
- sm->eap_fast_prov = conf->eap_fast_prov;
- sm->pac_key_lifetime = conf->pac_key_lifetime;
- sm->pac_key_refresh_time = conf->pac_key_refresh_time;
- sm->eap_teap_auth = conf->eap_teap_auth;
- sm->eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner;
- sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
- sm->tnc = conf->tnc;
- sm->wps = conf->wps;
- if (conf->assoc_wps_ie)
- sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
- if (conf->assoc_p2p_ie)
- sm->assoc_p2p_ie = wpabuf_dup(conf->assoc_p2p_ie);
- if (conf->peer_addr)
- os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN);
- sm->fragment_size = conf->fragment_size;
- sm->pwd_group = conf->pwd_group;
- sm->pbc_in_m1 = conf->pbc_in_m1;
- sm->server_id = conf->server_id;
- sm->server_id_len = conf->server_id_len;
- sm->erp = conf->erp;
- sm->tls_session_lifetime = conf->tls_session_lifetime;
- sm->tls_flags = conf->tls_flags;
-
+ sm->cfg = conf;
+ if (sess->assoc_wps_ie)
+ sm->assoc_wps_ie = wpabuf_dup(sess->assoc_wps_ie);
+ if (sess->assoc_p2p_ie)
+ sm->assoc_p2p_ie = wpabuf_dup(sess->assoc_p2p_ie);
+ if (sess->peer_addr)
+ os_memcpy(sm->peer_addr, sess->peer_addr, ETH_ALEN);
#ifdef CONFIG_TESTING_OPTIONS
- sm->tls_test_flags = conf->tls_test_flags;
+ sm->tls_test_flags = sess->tls_test_flags;
#endif /* CONFIG_TESTING_OPTIONS */
wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
@@ -1920,9 +1901,6 @@
wpabuf_free(sm->eap_if.eapRespData);
os_free(sm->identity);
os_free(sm->serial_num);
- os_free(sm->pac_opaque_encr_key);
- os_free(sm->eap_fast_a_id);
- os_free(sm->eap_fast_a_id_info);
wpabuf_free(sm->eap_if.aaaEapReqData);
wpabuf_free(sm->eap_if.aaaEapRespData);
bin_clear_free(sm->eap_if.aaaEapKeyData, sm->eap_if.aaaEapKeyDataLen);
@@ -2112,3 +2090,15 @@
source, user, hex_challenge, hex_response);
}
#endif /* CONFIG_TESTING_OPTIONS */
+
+
+void eap_server_config_free(struct eap_config *cfg)
+{
+ if (!cfg)
+ return;
+ os_free(cfg->pac_opaque_encr_key);
+ os_free(cfg->eap_fast_a_id);
+ os_free(cfg->eap_fast_a_id_info);
+ os_free(cfg->server_id);
+ os_free(cfg);
+}
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 5f6a1b3..22dd965 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -100,7 +100,7 @@
return 0;
wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username);
- data->reauth = eap_sim_db_get_reauth_entry(sm->eap_sim_db_priv,
+ data->reauth = eap_sim_db_get_reauth_entry(sm->cfg->eap_sim_db_priv,
username);
if (data->reauth == NULL) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown reauth identity - "
@@ -157,7 +157,7 @@
wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
username);
permanent = eap_sim_db_get_permanent(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
if (permanent == NULL) {
os_free(username);
wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
@@ -182,7 +182,7 @@
{
struct eap_aka_data *data;
- if (sm->eap_sim_db_priv == NULL) {
+ if (!sm->cfg->eap_sim_db_priv) {
wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
return NULL;
}
@@ -208,7 +208,7 @@
/* TODO: make ANID configurable; see 3GPP TS 24.302 */
char *network_name = "WLAN";
- if (sm->eap_sim_db_priv == NULL) {
+ if (sm->cfg->eap_sim_db_priv == NULL) {
wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
return NULL;
}
@@ -393,10 +393,13 @@
const u8 *nonce_s)
{
os_free(data->next_pseudonym);
- if (nonce_s == NULL) {
+ if (!(sm->cfg->eap_sim_id & 0x01)) {
+ /* Use of pseudonyms disabled in configuration */
+ data->next_pseudonym = NULL;
+ } else if (!nonce_s) {
data->next_pseudonym =
eap_sim_db_get_next_pseudonym(
- sm->eap_sim_db_priv,
+ sm->cfg->eap_sim_db_priv,
data->eap_method == EAP_TYPE_AKA_PRIME ?
EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
} else {
@@ -404,10 +407,13 @@
data->next_pseudonym = NULL;
}
os_free(data->next_reauth_id);
- if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
+ if (!(sm->cfg->eap_sim_id & 0x02)) {
+ /* Use of fast reauth disabled in configuration */
+ data->next_reauth_id = NULL;
+ } else if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
data->next_reauth_id =
eap_sim_db_get_next_reauth_id(
- sm->eap_sim_db_priv,
+ sm->cfg->eap_sim_db_priv,
data->eap_method == EAP_TYPE_AKA_PRIME ?
EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
} else {
@@ -499,7 +505,7 @@
eap_aka_add_checkcode(data, msg);
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
@@ -576,7 +582,7 @@
eap_aka_add_checkcode(data, msg);
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
@@ -589,7 +595,7 @@
* Session-Id calculation after receiving response from the peer and
* after all other checks pass. */
os_memcpy(data->reauth_mac,
- (wpabuf_head_u8(buf) + wpabuf_len(buf) - EAP_SIM_MAC_LEN),
+ wpabuf_head_u8(buf) + wpabuf_len(buf) - EAP_SIM_MAC_LEN,
EAP_SIM_MAC_LEN);
return buf;
@@ -761,7 +767,7 @@
wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
username);
permanent = eap_sim_db_get_permanent(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
os_free(username);
if (permanent == NULL) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
@@ -797,7 +803,7 @@
size_t identity_len;
int res;
- res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent,
+ res = eap_sim_db_get_aka_auth(sm->cfg->eap_sim_db_priv, data->permanent,
data->rand, data->autn, data->ik,
data->ck, data->res, &data->res_len, sm);
if (res == EAP_SIM_DB_PENDING) {
@@ -992,7 +998,7 @@
wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
"correct AT_MAC");
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_aka_state(data, NOTIFICATION);
@@ -1000,14 +1006,15 @@
eap_aka_state(data, SUCCESS);
if (data->next_pseudonym) {
- eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_pseudonym(sm->cfg->eap_sim_db_priv,
+ data->permanent,
data->next_pseudonym);
data->next_pseudonym = NULL;
}
if (data->next_reauth_id) {
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
#ifdef EAP_SERVER_AKA_PRIME
- eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth_prime(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1015,7 +1022,7 @@
data->k_re);
#endif /* EAP_SERVER_AKA_PRIME */
} else {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1045,7 +1052,7 @@
* maintaining a local flag stating whether this AUTS has already been
* reported. */
if (!data->auts_reported &&
- eap_sim_db_resynchronize(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_resynchronize(sm->cfg->eap_sim_db_priv, data->permanent,
attr->auts, data->rand)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
@@ -1112,7 +1119,7 @@
return;
}
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_aka_state(data, NOTIFICATION);
@@ -1122,7 +1129,7 @@
if (data->next_reauth_id) {
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
#ifdef EAP_SERVER_AKA_PRIME
- eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth_prime(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1130,7 +1137,7 @@
data->k_re);
#endif /* EAP_SERVER_AKA_PRIME */
} else {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1138,7 +1145,8 @@
}
data->next_reauth_id = NULL;
} else {
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv,
+ data->reauth);
data->reauth = NULL;
}
@@ -1147,7 +1155,7 @@
fail:
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
eap_aka_state(data, NOTIFICATION);
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv, data->reauth);
data->reauth = NULL;
os_free(decrypted);
}
diff --git a/src/eap_server/eap_server_eke.c b/src/eap_server/eap_server_eke.c
index 71580bf..71fab96 100644
--- a/src/eap_server/eap_server_eke.c
+++ b/src/eap_server/eap_server_eke.c
@@ -84,11 +84,11 @@
eap_eke_state(data, IDENTITY);
data->serverid_type = EAP_EKE_ID_OPAQUE;
- for (i = 0; i < sm->server_id_len; i++) {
- if (sm->server_id[i] == '.' &&
+ for (i = 0; i < sm->cfg->server_id_len; i++) {
+ if (sm->cfg->server_id[i] == '.' &&
data->serverid_type == EAP_EKE_ID_OPAQUE)
data->serverid_type = EAP_EKE_ID_FQDN;
- if (sm->server_id[i] == '@')
+ if (sm->cfg->server_id[i] == '@')
data->serverid_type = EAP_EKE_ID_NAI;
}
@@ -186,7 +186,7 @@
wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Identity");
- plen = 2 + 4 * 4 + 1 + sm->server_id_len;
+ plen = 2 + 4 * 4 + 1 + sm->cfg->server_id_len;
msg = eap_eke_build_msg(data, id, plen, EAP_EKE_ID);
if (msg == NULL)
return NULL;
@@ -223,7 +223,7 @@
/* Server IDType + Identity */
wpabuf_put_u8(msg, data->serverid_type);
- wpabuf_put_data(msg, sm->server_id, sm->server_id_len);
+ wpabuf_put_data(msg, sm->cfg->server_id, sm->cfg->server_id_len);
wpabuf_free(data->msgs);
data->msgs = wpabuf_dup(msg);
@@ -252,7 +252,7 @@
if (eap_eke_derive_key(&data->sess, sm->user->password,
sm->user->password_len,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len, data->key) < 0) {
wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
@@ -338,7 +338,7 @@
wpabuf_put(msg, prot_len);
if (eap_eke_derive_ka(&data->sess,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len,
data->nonce_p, data->nonce_s) < 0) {
wpabuf_free(msg);
@@ -552,7 +552,7 @@
}
if (eap_eke_derive_ke_ki(&data->sess,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len) < 0) {
wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
@@ -641,7 +641,8 @@
return;
}
- if (eap_eke_derive_msk(&data->sess, sm->server_id, sm->server_id_len,
+ if (eap_eke_derive_msk(&data->sess, sm->cfg->server_id,
+ sm->cfg->server_id_len,
data->peerid, data->peerid_len,
data->nonce_s, data->nonce_p,
data->msk, data->emsk) < 0) {
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index a63f820..0270821 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -108,8 +108,8 @@
}
-static EapType eap_fast_req_failure(struct eap_sm *sm,
- struct eap_fast_data *data)
+static enum eap_type eap_fast_req_failure(struct eap_sm *sm,
+ struct eap_fast_data *data)
{
/* TODO: send Result TLV(FAILURE) */
eap_fast_state(data, FAILURE);
@@ -278,7 +278,7 @@
* Extra key material after TLS key_block: session_key_seed[40]
*/
- sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
+ sks = eap_fast_derive_key(sm->cfg->ssl_ctx, data->ssl.conn,
EAP_FAST_SKS_LEN);
if (sks == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -304,7 +304,7 @@
{
os_free(data->key_block_p);
data->key_block_p = (struct eap_fast_key_block_provisioning *)
- eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
+ eap_fast_derive_key(sm->cfg->ssl_ctx, data->ssl.conn,
sizeof(*data->key_block_p));
if (data->key_block_p == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -440,7 +440,7 @@
return NULL;
}
- if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn,
+ if (tls_connection_set_cipher_list(sm->cfg->ssl_ctx, data->ssl.conn,
ciphers) < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to set TLS cipher "
"suites");
@@ -448,7 +448,8 @@
return NULL;
}
- if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
+ if (tls_connection_set_session_ticket_cb(sm->cfg->ssl_ctx,
+ data->ssl.conn,
eap_fast_session_ticket_cb,
data) < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "
@@ -457,47 +458,48 @@
return NULL;
}
- if (sm->pac_opaque_encr_key == NULL) {
+ if (sm->cfg->pac_opaque_encr_key == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No PAC-Opaque encryption key "
"configured");
eap_fast_reset(sm, data);
return NULL;
}
- os_memcpy(data->pac_opaque_encr, sm->pac_opaque_encr_key,
+ os_memcpy(data->pac_opaque_encr, sm->cfg->pac_opaque_encr_key,
sizeof(data->pac_opaque_encr));
- if (sm->eap_fast_a_id == NULL) {
+ if (sm->cfg->eap_fast_a_id == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No A-ID configured");
eap_fast_reset(sm, data);
return NULL;
}
- data->srv_id = os_memdup(sm->eap_fast_a_id, sm->eap_fast_a_id_len);
+ data->srv_id = os_memdup(sm->cfg->eap_fast_a_id,
+ sm->cfg->eap_fast_a_id_len);
if (data->srv_id == NULL) {
eap_fast_reset(sm, data);
return NULL;
}
- data->srv_id_len = sm->eap_fast_a_id_len;
+ data->srv_id_len = sm->cfg->eap_fast_a_id_len;
- if (sm->eap_fast_a_id_info == NULL) {
+ if (sm->cfg->eap_fast_a_id_info == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No A-ID-Info configured");
eap_fast_reset(sm, data);
return NULL;
}
- data->srv_id_info = os_strdup(sm->eap_fast_a_id_info);
+ data->srv_id_info = os_strdup(sm->cfg->eap_fast_a_id_info);
if (data->srv_id_info == NULL) {
eap_fast_reset(sm, data);
return NULL;
}
/* PAC-Key lifetime in seconds (hard limit) */
- data->pac_key_lifetime = sm->pac_key_lifetime;
+ data->pac_key_lifetime = sm->cfg->pac_key_lifetime;
/*
* PAC-Key refresh time in seconds (soft limit on remaining hard
* limit). The server will generate a new PAC-Key when this number of
* seconds (or fewer) of the lifetime remains.
*/
- data->pac_key_refresh_time = sm->pac_key_refresh_time;
+ data->pac_key_refresh_time = sm->cfg->pac_key_refresh_time;
return data;
}
@@ -552,8 +554,8 @@
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase1 done, starting Phase2");
- if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher))
- < 0) {
+ if (tls_get_cipher(sm->cfg->ssl_ctx, data->ssl.conn,
+ cipher, sizeof(cipher)) < 0) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to get cipher "
"information");
eap_fast_state(data, FAILURE);
@@ -872,7 +874,8 @@
case START:
return eap_fast_build_start(sm, data, id);
case PHASE1:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
if (eap_fast_phase1_done(sm, data) < 0)
return NULL;
if (data->state == PHASE2_START) {
@@ -943,15 +946,14 @@
static int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data,
- EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
data->phase2_method = NULL;
data->phase2_priv = NULL;
}
- data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
- eap_type);
+ data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
if (!data->phase2_method)
return -1;
@@ -973,7 +975,8 @@
struct eap_fast_data *data,
u8 *in_data, size_t in_len)
{
- u8 next_type = EAP_TYPE_NONE;
+ int next_vendor = EAP_VENDOR_IETF;
+ enum eap_type next_type = EAP_TYPE_NONE;
struct eap_hdr *hdr;
u8 *pos;
size_t left;
@@ -999,8 +1002,9 @@
m->method == EAP_TYPE_TNC) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required "
"TNC negotiation");
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
return;
}
#endif /* EAP_SERVER_TNC */
@@ -1008,14 +1012,17 @@
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
sm->user->methods[sm->user_eap_method_index].method !=
EAP_TYPE_NONE) {
+ next_vendor = sm->user->methods[
+ sm->user_eap_method_index].vendor;
next_type = sm->user->methods[
sm->user_eap_method_index++].method;
- wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d",
- next_type);
+ wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %u:%u",
+ next_vendor, next_type);
} else {
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
}
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
return;
}
@@ -1035,8 +1042,9 @@
if (!m->isSuccess(sm, priv)) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method failed");
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
return;
}
@@ -1047,6 +1055,7 @@
"Identity not found in the user "
"database",
sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
break;
}
@@ -1057,23 +1066,28 @@
* Only EAP-MSCHAPv2 is allowed for anonymous
* provisioning.
*/
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_MSCHAPV2;
sm->user_eap_method_index = 0;
} else {
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
}
- wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type);
+ wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %u:%u",
+ next_vendor, next_type);
break;
case PHASE2_METHOD:
case CRYPTO_BINDING:
eap_fast_update_icmk(sm, data);
eap_fast_state(data, CRYPTO_BINDING);
data->eap_seq++;
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
#ifdef EAP_SERVER_TNC
- if (sm->tnc && !data->tnc_started) {
+ if (sm->cfg->tnc && !data->tnc_started) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC");
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_TNC;
data->tnc_started = 1;
}
@@ -1087,7 +1101,7 @@
break;
}
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
}
@@ -1335,8 +1349,8 @@
}
if (data->anon_provisioning &&
- sm->eap_fast_prov != ANON_PROV &&
- sm->eap_fast_prov != BOTH_PROV) {
+ sm->cfg->eap_fast_prov != ANON_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to "
"use unauthenticated provisioning which is "
"disabled");
@@ -1344,8 +1358,8 @@
return;
}
- if (sm->eap_fast_prov != AUTH_PROV &&
- sm->eap_fast_prov != BOTH_PROV &&
+ if (sm->cfg->eap_fast_prov != AUTH_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV &&
tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV &&
eap_fast_pac_type(tlv.pac, tlv.pac_len,
PAC_TYPE_TUNNEL_PAC)) {
@@ -1397,7 +1411,7 @@
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (in_decrypted == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
@@ -1457,7 +1471,7 @@
return -1;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
wpabuf_len(data->ssl.tls_out) > 0)
return 1;
@@ -1474,7 +1488,8 @@
static int eap_fast_process_phase2_start(struct eap_sm *sm,
struct eap_fast_data *data)
{
- u8 next_type;
+ int next_vendor;
+ enum eap_type next_type;
if (data->identity) {
os_free(sm->identity);
@@ -1488,10 +1503,12 @@
"Phase2 Identity not found "
"in the user database",
sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
} else {
wpa_printf(MSG_DEBUG, "EAP-FAST: Identity already "
"known - skip Phase 2 Identity Request");
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
}
@@ -1499,10 +1516,11 @@
eap_fast_state(data, PHASE2_METHOD);
} else {
eap_fast_state(data, PHASE2_ID);
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_IDENTITY;
}
- return eap_fast_phase2_init(sm, data, next_type);
+ return eap_fast_phase2_init(sm, data, next_vendor, next_type);
}
diff --git a/src/eap_server/eap_server_gpsk.c b/src/eap_server/eap_server_gpsk.c
index bebb17f..a774275 100644
--- a/src/eap_server/eap_server_gpsk.c
+++ b/src/eap_server/eap_server_gpsk.c
@@ -117,7 +117,7 @@
wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server",
data->rand_server, EAP_GPSK_RAND_LEN);
- len = 1 + 2 + sm->server_id_len + EAP_GPSK_RAND_LEN + 2 +
+ len = 1 + 2 + sm->cfg->server_id_len + EAP_GPSK_RAND_LEN + 2 +
data->csuite_count * sizeof(struct eap_gpsk_csuite);
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
EAP_CODE_REQUEST, id);
@@ -129,8 +129,8 @@
}
wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1);
- wpabuf_put_be16(req, sm->server_id_len);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_be16(req, sm->cfg->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
wpabuf_put_be16(req,
data->csuite_count * sizeof(struct eap_gpsk_csuite));
@@ -152,7 +152,7 @@
wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3");
miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
- len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->server_id_len +
+ len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->cfg->server_id_len +
sizeof(struct eap_gpsk_csuite) + 2 + miclen;
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
EAP_CODE_REQUEST, id);
@@ -168,8 +168,8 @@
wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN);
wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
- wpabuf_put_be16(req, sm->server_id_len);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_be16(req, sm->cfg->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
csuite = wpabuf_put(req, sizeof(*csuite));
WPA_PUT_BE32(csuite->vendor, data->vendor);
WPA_PUT_BE16(csuite->specifier, data->specifier);
@@ -294,8 +294,8 @@
eap_gpsk_state(data, FAILURE);
return;
}
- if (alen != sm->server_id_len ||
- os_memcmp(pos, sm->server_id, alen) != 0) {
+ if (alen != sm->cfg->server_id_len ||
+ os_memcmp(pos, sm->cfg->server_id, alen) != 0) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
"GPSK-2 did not match");
eap_gpsk_state(data, FAILURE);
@@ -409,7 +409,7 @@
data->vendor, data->specifier,
data->rand_peer, data->rand_server,
data->id_peer, data->id_peer_len,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->msk, data->emsk,
data->sk, &data->sk_len,
data->pk, &data->pk_len) < 0) {
@@ -423,7 +423,8 @@
data->vendor, data->specifier,
data->rand_peer, data->rand_server,
data->id_peer, data->id_peer_len,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id,
+ sm->cfg->server_id_len,
EAP_TYPE_GPSK,
data->session_id, &data->id_len) < 0) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
diff --git a/src/eap_server/eap_server_ikev2.c b/src/eap_server/eap_server_ikev2.c
index 32e6872..897637e 100644
--- a/src/eap_server/eap_server_ikev2.c
+++ b/src/eap_server/eap_server_ikev2.c
@@ -87,8 +87,8 @@
if (data == NULL)
return NULL;
data->state = MSG;
- data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
- IKEV2_FRAGMENT_SIZE;
+ data->fragment_size = sm->cfg->fragment_size > 0 ?
+ sm->cfg->fragment_size : IKEV2_FRAGMENT_SIZE;
data->ikev2.state = SA_INIT;
data->ikev2.peer_auth = PEER_AUTH_SECRET;
data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
@@ -103,10 +103,10 @@
data->ikev2.proposal.encr = ENCR_AES_CBC;
data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP;
- data->ikev2.IDi = os_memdup(sm->server_id, sm->server_id_len);
+ data->ikev2.IDi = os_memdup(sm->cfg->server_id, sm->cfg->server_id_len);
if (data->ikev2.IDi == NULL)
goto failed;
- data->ikev2.IDi_len = sm->server_id_len;
+ data->ikev2.IDi_len = sm->cfg->server_id_len;
data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret;
data->ikev2.cb_ctx = sm;
@@ -414,7 +414,7 @@
eap_ikev2_state(data, FAIL);
return;
}
-
+
if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
if (eap_ikev2_process_fragment(data, flags, message_length,
pos, end - pos) < 0)
diff --git a/src/eap_server/eap_server_methods.c b/src/eap_server/eap_server_methods.c
index 79ed344..f37c9c3 100644
--- a/src/eap_server/eap_server_methods.c
+++ b/src/eap_server/eap_server_methods.c
@@ -22,7 +22,8 @@
* @method: EAP type number
* Returns: Pointer to EAP method or %NULL if not found
*/
-const struct eap_method * eap_server_get_eap_method(int vendor, EapType method)
+const struct eap_method * eap_server_get_eap_method(int vendor,
+ enum eap_type method)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -42,7 +43,7 @@
* This function maps EAP type names into EAP type numbers based on the list of
* EAP methods included in the build.
*/
-EapType eap_server_get_type(const char *name, int *vendor)
+enum eap_type eap_server_get_type(const char *name, int *vendor)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -69,7 +70,8 @@
* is not needed anymore.
*/
struct eap_method * eap_server_method_alloc(int version, int vendor,
- EapType method, const char *name)
+ enum eap_type method,
+ const char *name)
{
struct eap_method *eap;
eap = os_zalloc(sizeof(*eap));
@@ -163,7 +165,7 @@
* This function maps EAP type numbers into EAP type names based on the list of
* EAP methods included in the build.
*/
-const char * eap_server_get_name(int vendor, EapType type)
+const char * eap_server_get_name(int vendor, enum eap_type type)
{
struct eap_method *m;
if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index e9e03b0..8a1621a 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -109,7 +109,7 @@
return NULL;
}
- ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->server_id_len;
+ ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->cfg->server_id_len;
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
EAP_CODE_REQUEST, id);
if (req == NULL) {
@@ -131,7 +131,7 @@
wpabuf_put(req, CHALLENGE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge",
data->auth_challenge, CHALLENGE_LEN);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
return req;
}
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index 5e125ac..02d8b8e 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -105,8 +105,8 @@
{
struct wpabuf *buf;
- if (!sm->tls_session_lifetime ||
- tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ if (!sm->cfg->tls_session_lifetime ||
+ tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = wpabuf_alloc(1 + 1 + sm->identity_len);
@@ -336,7 +336,7 @@
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
- if (tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn)) {
/* Fast-connect: IPMK|CMK = TK */
os_memcpy(data->ipmk, tk, 40);
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
@@ -521,7 +521,8 @@
return eap_peap_build_start(sm, data, id);
case PHASE1:
case PHASE1_ID2:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
"starting Phase2");
eap_peap_state(data, PHASE2_START);
@@ -585,7 +586,7 @@
static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
- int vendor, EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
@@ -1020,7 +1021,7 @@
}
#ifdef EAP_SERVER_TNC
- if (data->state != PHASE2_SOH && sm->tnc &&
+ if (data->state != PHASE2_SOH && sm->cfg->tnc &&
data->peap_version == 0) {
eap_peap_state(data, PHASE2_SOH);
wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
@@ -1077,7 +1078,7 @@
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (in_decrypted == NULL) {
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
@@ -1237,8 +1238,8 @@
}
if (data->state == SUCCESS ||
- !tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
- !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ !tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = tls_connection_get_success_data(data->ssl.conn);
diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c
index 0eab893..511973c 100644
--- a/src/eap_server/eap_server_psk.c
+++ b/src/eap_server/eap_server_psk.c
@@ -68,7 +68,7 @@
data->rand_s, EAP_PSK_RAND_LEN);
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
- sizeof(*psk) + sm->server_id_len,
+ sizeof(*psk) + sm->cfg->server_id_len,
EAP_CODE_REQUEST, id);
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
@@ -80,7 +80,7 @@
psk = wpabuf_put(req, sizeof(*psk));
psk->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */
os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
return req;
}
@@ -110,13 +110,13 @@
os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
- buflen = sm->server_id_len + EAP_PSK_RAND_LEN;
+ buflen = sm->cfg->server_id_len + EAP_PSK_RAND_LEN;
buf = os_malloc(buflen);
if (buf == NULL)
goto fail;
- os_memcpy(buf, sm->server_id, sm->server_id_len);
- os_memcpy(buf + sm->server_id_len, data->rand_p, EAP_PSK_RAND_LEN);
+ os_memcpy(buf, sm->cfg->server_id, sm->cfg->server_id_len);
+ os_memcpy(buf + sm->cfg->server_id_len, data->rand_p, EAP_PSK_RAND_LEN);
if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
os_free(buf);
goto fail;
@@ -293,7 +293,7 @@
os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN);
/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
- buflen = data->id_p_len + sm->server_id_len + 2 * EAP_PSK_RAND_LEN;
+ buflen = data->id_p_len + sm->cfg->server_id_len + 2 * EAP_PSK_RAND_LEN;
buf = os_malloc(buflen);
if (buf == NULL) {
data->state = FAILURE;
@@ -301,8 +301,8 @@
}
os_memcpy(buf, data->id_p, data->id_p_len);
pos = buf + data->id_p_len;
- os_memcpy(pos, sm->server_id, sm->server_id_len);
- pos += sm->server_id_len;
+ os_memcpy(pos, sm->cfg->server_id, sm->cfg->server_id_len);
+ pos += sm->cfg->server_id_len;
os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
pos += EAP_PSK_RAND_LEN;
os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index a8087c1..6bf3a23 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -97,7 +97,7 @@
if (data == NULL)
return NULL;
- data->group_num = sm->pwd_group;
+ data->group_num = sm->cfg->pwd_group;
wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d",
data->group_num);
data->state = PWD_ID_Req;
@@ -134,7 +134,7 @@
data->in_frag_pos = data->out_frag_pos = 0;
data->inbuf = data->outbuf = NULL;
/* use default MTU from RFC 5931 if not configured otherwise */
- data->mtu = sm->fragment_size > 0 ? sm->fragment_size : 1020;
+ data->mtu = sm->cfg->fragment_size > 0 ? sm->cfg->fragment_size : 1020;
return data;
}
diff --git a/src/eap_server/eap_server_sake.c b/src/eap_server/eap_server_sake.c
index 2fc2c05..56cfbfb 100644
--- a/src/eap_server/eap_server_sake.c
+++ b/src/eap_server/eap_server_sake.c
@@ -123,7 +123,7 @@
wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
plen = 4;
- plen += 2 + sm->server_id_len;
+ plen += 2 + sm->cfg->server_id_len;
msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
if (msg == NULL) {
data->state = FAILURE;
@@ -135,7 +135,7 @@
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
- sm->server_id, sm->server_id_len);
+ sm->cfg->server_id, sm->cfg->server_id_len);
return msg;
}
@@ -158,7 +158,7 @@
wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
data->rand_s, EAP_SAKE_RAND_LEN);
- plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->server_id_len;
+ plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->cfg->server_id_len;
msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
if (msg == NULL) {
data->state = FAILURE;
@@ -171,7 +171,7 @@
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
- sm->server_id, sm->server_id_len);
+ sm->cfg->server_id, sm->cfg->server_id_len);
return msg;
}
@@ -198,7 +198,7 @@
wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len, 0,
wpabuf_head(msg), wpabuf_len(msg), mic, mic))
{
@@ -351,7 +351,7 @@
}
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len, 1,
wpabuf_head(respData), wpabuf_len(respData),
attr.mic_p, mic_p) < 0) {
@@ -392,7 +392,7 @@
}
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len, 1,
wpabuf_head(respData), wpabuf_len(respData),
attr.mic_p, mic_p) < 0) {
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index 8562c64..d7ac87c 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -76,7 +76,7 @@
{
struct eap_sim_data *data;
- if (sm->eap_sim_db_priv == NULL) {
+ if (!sm->cfg->eap_sim_db_priv) {
wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
return NULL;
}
@@ -150,18 +150,24 @@
const u8 *nonce_s)
{
os_free(data->next_pseudonym);
- if (nonce_s == NULL) {
+ if (!(sm->cfg->eap_sim_id & 0x01)) {
+ /* Use of pseudonyms disabled in configuration */
+ data->next_pseudonym = NULL;
+ } else if (!nonce_s) {
data->next_pseudonym =
- eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv,
+ eap_sim_db_get_next_pseudonym(sm->cfg->eap_sim_db_priv,
EAP_SIM_DB_SIM);
} else {
/* Do not update pseudonym during re-authentication */
data->next_pseudonym = NULL;
}
os_free(data->next_reauth_id);
- if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
+ if (!(sm->cfg->eap_sim_id & 0x02)) {
+ /* Use of fast reauth disabled in configuration */
+ data->next_reauth_id = NULL;
+ } else if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
data->next_reauth_id =
- eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv,
+ eap_sim_db_get_next_reauth_id(sm->cfg->eap_sim_db_priv,
EAP_SIM_DB_SIM);
} else {
wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
@@ -234,7 +240,7 @@
return NULL;
}
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
@@ -273,7 +279,7 @@
return NULL;
}
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
@@ -286,7 +292,7 @@
* Session-Id calculation after receiving response from the peer and
* after all other checks pass. */
os_memcpy(data->reauth_mac,
- (wpabuf_head_u8(buf) + wpabuf_len(buf) - EAP_SIM_MAC_LEN),
+ wpabuf_head_u8(buf) + wpabuf_len(buf) - EAP_SIM_MAC_LEN,
EAP_SIM_MAC_LEN);
return buf;
@@ -469,7 +475,7 @@
wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'",
username);
data->reauth = eap_sim_db_get_reauth_entry(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
os_free(username);
if (data->reauth == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth "
@@ -491,7 +497,7 @@
wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'",
username);
permanent = eap_sim_db_get_permanent(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
os_free(username);
if (permanent == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym "
@@ -532,7 +538,7 @@
data->reauth = NULL;
data->num_chal = eap_sim_db_get_gsm_triplets(
- sm->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
+ sm->cfg->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
(u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
if (data->num_chal == EAP_SIM_DB_PENDING) {
wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
@@ -593,7 +599,7 @@
wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
"correct AT_MAC");
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_sim_state(data, NOTIFICATION);
@@ -601,12 +607,13 @@
eap_sim_state(data, SUCCESS);
if (data->next_pseudonym) {
- eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_pseudonym(sm->cfg->eap_sim_db_priv,
+ data->permanent,
data->next_pseudonym);
data->next_pseudonym = NULL;
}
if (data->next_reauth_id) {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv, data->permanent,
data->next_reauth_id, data->counter + 1,
data->mk);
data->next_reauth_id = NULL;
@@ -666,7 +673,7 @@
return;
}
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_sim_state(data, NOTIFICATION);
@@ -674,12 +681,13 @@
eap_sim_state(data, SUCCESS);
if (data->next_reauth_id) {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv, data->permanent,
data->next_reauth_id,
data->counter + 1, data->mk);
data->next_reauth_id = NULL;
} else {
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv,
+ data->reauth);
data->reauth = NULL;
}
@@ -688,7 +696,7 @@
fail:
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
eap_sim_state(data, NOTIFICATION);
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv, data->reauth);
data->reauth = NULL;
os_free(decrypted);
}
diff --git a/src/eap_server/eap_server_teap.c b/src/eap_server/eap_server_teap.c
index d8e5414..a2cbf7a 100644
--- a/src/eap_server/eap_server_teap.c
+++ b/src/eap_server/eap_server_teap.c
@@ -31,7 +31,7 @@
enum {
START, PHASE1, PHASE1B, PHASE2_START, PHASE2_ID,
PHASE2_BASIC_AUTH, PHASE2_METHOD, CRYPTO_BINDING, REQUEST_PAC,
- FAILURE_SEND_RESULT, SUCCESS, FAILURE
+ FAILURE_SEND_RESULT, SUCCESS_SEND_RESULT, SUCCESS, FAILURE
} state;
u8 teap_version;
@@ -56,7 +56,10 @@
size_t srv_id_len;
char *srv_id_info;
+ unsigned int basic_auth_not_done:1;
+ unsigned int inner_eap_not_done:1;
int anon_provisioning;
+ int skipped_inner_auth;
int send_new_pac; /* server triggered re-keying of Tunnel PAC */
struct wpabuf *pending_phase2_resp;
struct wpabuf *server_outer_tlvs;
@@ -70,6 +73,7 @@
int pac_key_refresh_time;
enum teap_error_codes error_code;
+ enum teap_identity_types cur_id_type;
};
@@ -100,6 +104,8 @@
return "REQUEST_PAC";
case FAILURE_SEND_RESULT:
return "FAILURE_SEND_RESULT";
+ case SUCCESS_SEND_RESULT:
+ return "SUCCESS_SEND_RESULT";
case SUCCESS:
return "SUCCESS";
case FAILURE:
@@ -119,8 +125,8 @@
}
-static EapType eap_teap_req_failure(struct eap_teap_data *data,
- enum teap_error_codes error)
+static enum eap_type eap_teap_req_failure(struct eap_teap_data *data,
+ enum teap_error_codes error)
{
eap_teap_state(data, FAILURE_SEND_RESULT);
return EAP_TYPE_NONE;
@@ -285,7 +291,7 @@
int res;
/* RFC 7170, Section 5.1 */
- res = tls_connection_export_key(sm->ssl_ctx, data->ssl.conn,
+ res = tls_connection_export_key(sm->cfg->ssl_ctx, data->ssl.conn,
TEAP_TLS_EXPORTER_LABEL_SKS, NULL, 0,
data->simck_msk, EAP_TEAP_SIMCK_LEN);
if (res)
@@ -308,8 +314,9 @@
wpa_printf(MSG_DEBUG, "EAP-TEAP: Deriving ICMK[%d] (S-IMCK and CMK)",
data->simck_idx + 1);
- if (sm->eap_teap_auth == 1)
- return eap_teap_derive_cmk_basic_pw_auth(data->simck_msk,
+ if (sm->cfg->eap_teap_auth == 1)
+ return eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
+ data->simck_msk,
data->cmk_msk);
if (!data->phase2_method || !data->phase2_priv) {
@@ -332,7 +339,8 @@
&emsk_len);
}
- res = eap_teap_derive_imck(data->simck_msk, data->simck_emsk,
+ res = eap_teap_derive_imck(data->tls_cs,
+ data->simck_msk, data->simck_emsk,
msk, msk_len, emsk, emsk_len,
data->simck_msk, data->cmk_msk,
data->simck_emsk, data->cmk_emsk);
@@ -366,7 +374,8 @@
/* TODO: Add anon-DH TLS cipher suites (and if one is negotiated,
* enforce inner EAP with mutual authentication to be used) */
- if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
+ if (tls_connection_set_session_ticket_cb(sm->cfg->ssl_ctx,
+ data->ssl.conn,
eap_teap_session_ticket_cb,
data) < 0) {
wpa_printf(MSG_INFO,
@@ -375,48 +384,49 @@
return NULL;
}
- if (!sm->pac_opaque_encr_key) {
+ if (!sm->cfg->pac_opaque_encr_key) {
wpa_printf(MSG_INFO,
"EAP-TEAP: No PAC-Opaque encryption key configured");
eap_teap_reset(sm, data);
return NULL;
}
- os_memcpy(data->pac_opaque_encr, sm->pac_opaque_encr_key,
+ os_memcpy(data->pac_opaque_encr, sm->cfg->pac_opaque_encr_key,
sizeof(data->pac_opaque_encr));
- if (!sm->eap_fast_a_id) {
+ if (!sm->cfg->eap_fast_a_id) {
wpa_printf(MSG_INFO, "EAP-TEAP: No A-ID configured");
eap_teap_reset(sm, data);
return NULL;
}
- data->srv_id = os_malloc(sm->eap_fast_a_id_len);
+ data->srv_id = os_malloc(sm->cfg->eap_fast_a_id_len);
if (!data->srv_id) {
eap_teap_reset(sm, data);
return NULL;
}
- os_memcpy(data->srv_id, sm->eap_fast_a_id, sm->eap_fast_a_id_len);
- data->srv_id_len = sm->eap_fast_a_id_len;
+ os_memcpy(data->srv_id, sm->cfg->eap_fast_a_id,
+ sm->cfg->eap_fast_a_id_len);
+ data->srv_id_len = sm->cfg->eap_fast_a_id_len;
- if (!sm->eap_fast_a_id_info) {
+ if (!sm->cfg->eap_fast_a_id_info) {
wpa_printf(MSG_INFO, "EAP-TEAP: No A-ID-Info configured");
eap_teap_reset(sm, data);
return NULL;
}
- data->srv_id_info = os_strdup(sm->eap_fast_a_id_info);
+ data->srv_id_info = os_strdup(sm->cfg->eap_fast_a_id_info);
if (!data->srv_id_info) {
eap_teap_reset(sm, data);
return NULL;
}
/* PAC-Key lifetime in seconds (hard limit) */
- data->pac_key_lifetime = sm->pac_key_lifetime;
+ data->pac_key_lifetime = sm->cfg->pac_key_lifetime;
/*
* PAC-Key refresh time in seconds (soft limit on remaining hard
* limit). The server will generate a new PAC-Key when this number of
* seconds (or fewer) of the lifetime remains.
*/
- data->pac_key_refresh_time = sm->pac_key_refresh_time;
+ data->pac_key_refresh_time = sm->cfg->pac_key_refresh_time;
return data;
}
@@ -496,8 +506,8 @@
wpa_printf(MSG_DEBUG, "EAP-TEAP: TLS cipher suite 0x%04x",
data->tls_cs);
- if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher))
- < 0) {
+ if (tls_get_cipher(sm->cfg->ssl_ctx, data->ssl.conn,
+ cipher, sizeof(cipher)) < 0) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Failed to get cipher information");
eap_teap_state(data, FAILURE);
@@ -523,30 +533,65 @@
struct eap_teap_data *data,
u8 id)
{
- struct wpabuf *req;
+ struct wpabuf *req, *id_tlv = NULL;
- if (sm->eap_teap_auth == 1) {
+ if (sm->cfg->eap_teap_auth == 1 ||
+ (data->phase2_priv && data->phase2_method &&
+ data->phase2_method->vendor == EAP_VENDOR_IETF &&
+ data->phase2_method->method == EAP_TYPE_IDENTITY)) {
+ switch (sm->cfg->eap_teap_id) {
+ case EAP_TEAP_ID_ALLOW_ANY:
+ break;
+ case EAP_TEAP_ID_REQUIRE_USER:
+ case EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE:
+ data->cur_id_type = TEAP_IDENTITY_TYPE_USER;
+ id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
+ break;
+ case EAP_TEAP_ID_REQUIRE_MACHINE:
+ case EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER:
+ data->cur_id_type = TEAP_IDENTITY_TYPE_MACHINE;
+ id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
+ break;
+ case EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE:
+ if (data->cur_id_type == TEAP_IDENTITY_TYPE_USER)
+ data->cur_id_type = TEAP_IDENTITY_TYPE_MACHINE;
+ else
+ data->cur_id_type = TEAP_IDENTITY_TYPE_USER;
+ id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
+ break;
+ }
+ }
+
+ if (sm->cfg->eap_teap_auth == 1) {
wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate Basic-Password-Auth");
+ data->basic_auth_not_done = 1;
req = wpabuf_alloc(sizeof(struct teap_tlv_hdr));
- if (!req)
+ if (!req) {
+ wpabuf_free(id_tlv);
return NULL;
+ }
eap_teap_put_tlv_hdr(req, TEAP_TLV_BASIC_PASSWORD_AUTH_REQ, 0);
- return req;
+ return wpabuf_concat(req, id_tlv);
}
wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate inner EAP method");
+ data->inner_eap_not_done = 1;
if (!data->phase2_priv) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Phase 2 method not initialized");
+ wpabuf_free(id_tlv);
return NULL;
}
req = data->phase2_method->buildReq(sm, data->phase2_priv, id);
- if (!req)
+ if (!req) {
+ wpabuf_free(id_tlv);
return NULL;
+ }
wpa_hexdump_buf_key(MSG_MSGDUMP, "EAP-TEAP: Phase 2 EAP-Request", req);
- return eap_teap_tlv_eap_payload(req);
+
+ return wpabuf_concat(eap_teap_tlv_eap_payload(req), id_tlv);
}
@@ -563,12 +608,14 @@
return NULL;
if (data->send_new_pac || data->anon_provisioning ||
- data->phase2_method)
+ data->basic_auth_not_done || data->inner_eap_not_done ||
+ data->phase2_method || sm->cfg->eap_teap_separate_result)
data->final_result = 0;
else
data->final_result = 1;
- if (!data->final_result || data->eap_seq > 0) {
+ if (!data->final_result || data->eap_seq > 0 ||
+ sm->cfg->eap_teap_auth == 1) {
/* Intermediate-Result */
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Add Intermediate-Result TLV (status=SUCCESS)");
@@ -842,7 +889,8 @@
case START:
return eap_teap_build_start(sm, data, id);
case PHASE1B:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
if (eap_teap_phase1_done(sm, data) < 0)
return NULL;
if (data->state == PHASE2_START) {
@@ -899,6 +947,10 @@
req = wpabuf_concat(
req, eap_teap_tlv_error(data->error_code));
break;
+ case SUCCESS_SEND_RESULT:
+ req = eap_teap_tlv_result(TEAP_STATUS_SUCCESS, 0);
+ data->final_result = 1;
+ break;
default:
wpa_printf(MSG_DEBUG, "EAP-TEAP: %s - unexpected state %d",
__func__, data->state);
@@ -930,15 +982,14 @@
static int eap_teap_phase2_init(struct eap_sm *sm, struct eap_teap_data *data,
- EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
data->phase2_method = NULL;
data->phase2_priv = NULL;
}
- data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
- eap_type);
+ data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
if (!data->phase2_method)
return -1;
@@ -950,11 +1001,33 @@
}
+static int eap_teap_valid_id_type(struct eap_sm *sm, struct eap_teap_data *data,
+ enum teap_identity_types id_type)
+{
+ if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER &&
+ id_type != TEAP_IDENTITY_TYPE_USER)
+ return 0;
+ if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_MACHINE &&
+ id_type != TEAP_IDENTITY_TYPE_MACHINE)
+ return 0;
+ if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE &&
+ id_type != data->cur_id_type)
+ return 0;
+ if (sm->cfg->eap_teap_id != EAP_TEAP_ID_ALLOW_ANY &&
+ id_type != TEAP_IDENTITY_TYPE_USER &&
+ id_type != TEAP_IDENTITY_TYPE_MACHINE)
+ return 0;
+ return 1;
+}
+
+
static void eap_teap_process_phase2_response(struct eap_sm *sm,
struct eap_teap_data *data,
- u8 *in_data, size_t in_len)
+ u8 *in_data, size_t in_len,
+ enum teap_identity_types id_type)
{
- u8 next_type = EAP_TYPE_NONE;
+ int next_vendor = EAP_VENDOR_IETF;
+ enum eap_type next_type = EAP_TYPE_NONE;
struct eap_hdr *hdr;
u8 *pos;
size_t left;
@@ -982,8 +1055,9 @@
m->method == EAP_TYPE_TNC) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Peer Nak'ed required TNC negotiation");
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_teap_req_failure(data, 0);
- eap_teap_phase2_init(sm, data, next_type);
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
return;
}
#endif /* EAP_SERVER_TNC */
@@ -991,14 +1065,17 @@
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
sm->user->methods[sm->user_eap_method_index].method !=
EAP_TYPE_NONE) {
+ next_vendor = sm->user->methods[
+ sm->user_eap_method_index].vendor;
next_type = sm->user->methods[
sm->user_eap_method_index++].method;
- wpa_printf(MSG_DEBUG, "EAP-TEAP: try EAP type %d",
- next_type);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: try EAP type %u:%u",
+ next_vendor, next_type);
} else {
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_teap_req_failure(data, 0);
}
- eap_teap_phase2_init(sm, data, next_type);
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
return;
}
@@ -1018,17 +1095,26 @@
if (!m->isSuccess(sm, priv)) {
wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 method failed");
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
- eap_teap_phase2_init(sm, data, next_type);
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
return;
}
switch (data->state) {
case PHASE2_ID:
+ if (!eap_teap_valid_id_type(sm, data, id_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Provided Identity-Type %u not allowed",
+ id_type);
+ eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
+ break;
+ }
if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-TEAP: Phase 2 Identity not found in the user database",
sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_teap_req_failure(
data, TEAP_ERROR_INNER_METHOD);
break;
@@ -1039,23 +1125,33 @@
/* TODO: Allow any inner EAP method that provides
* mutual authentication and EMSK derivation (i.e.,
* EAP-pwd or EAP-EKE). */
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_PWD;
sm->user_eap_method_index = 0;
} else {
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
}
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Try EAP type %d", next_type);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Try EAP type %u:%u",
+ next_vendor, next_type);
break;
case PHASE2_METHOD:
case CRYPTO_BINDING:
eap_teap_update_icmk(sm, data);
+ if (data->state == PHASE2_METHOD &&
+ (sm->cfg->eap_teap_id !=
+ EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE ||
+ data->cur_id_type == TEAP_IDENTITY_TYPE_MACHINE))
+ data->inner_eap_not_done = 0;
eap_teap_state(data, CRYPTO_BINDING);
data->eap_seq++;
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
#ifdef EAP_SERVER_TNC
- if (sm->tnc && !data->tnc_started) {
+ if (sm->cfg->tnc && !data->tnc_started) {
wpa_printf(MSG_DEBUG, "EAP-TEAP: Initialize TNC");
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_TNC;
data->tnc_started = 1;
}
@@ -1069,13 +1165,14 @@
break;
}
- eap_teap_phase2_init(sm, data, next_type);
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
}
static void eap_teap_process_phase2_eap(struct eap_sm *sm,
struct eap_teap_data *data,
- u8 *in_data, size_t in_len)
+ u8 *in_data, size_t in_len,
+ enum teap_identity_types id_type)
{
struct eap_hdr *hdr;
size_t len;
@@ -1102,7 +1199,8 @@
(unsigned long) len);
switch (hdr->code) {
case EAP_CODE_RESPONSE:
- eap_teap_process_phase2_response(sm, data, (u8 *) hdr, len);
+ eap_teap_process_phase2_response(sm, data, (u8 *) hdr, len,
+ id_type);
break;
default:
wpa_printf(MSG_INFO,
@@ -1115,11 +1213,20 @@
static void eap_teap_process_basic_auth_resp(struct eap_sm *sm,
struct eap_teap_data *data,
- u8 *in_data, size_t in_len)
+ u8 *in_data, size_t in_len,
+ enum teap_identity_types id_type)
{
u8 *pos, *end, *username, *password, *new_id;
u8 userlen, passlen;
+ if (!eap_teap_valid_id_type(sm, data, id_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Provided Identity-Type %u not allowed",
+ id_type);
+ eap_teap_req_failure(data, 0);
+ return;
+ }
+
pos = in_data;
end = pos + in_len;
@@ -1197,6 +1304,9 @@
sm->identity = new_id;
sm->identity_len = userlen;
}
+ if (sm->cfg->eap_teap_id != EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE ||
+ data->cur_id_type == TEAP_IDENTITY_TYPE_MACHINE)
+ data->basic_auth_not_done = 0;
eap_teap_state(data, CRYPTO_BINDING);
eap_teap_update_icmk(sm, data);
}
@@ -1444,7 +1554,8 @@
return;
}
- if (!data->final_result &&
+ if (sm->cfg->eap_teap_auth != 1 &&
+ !data->skipped_inner_auth &&
tlv.iresult != TEAP_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Crypto-Binding TLV without intermediate Success Result");
@@ -1466,16 +1577,16 @@
}
if (data->anon_provisioning &&
- sm->eap_fast_prov != ANON_PROV &&
- sm->eap_fast_prov != BOTH_PROV) {
+ sm->cfg->eap_fast_prov != ANON_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Client is trying to use unauthenticated provisioning which is disabled");
eap_teap_state(data, FAILURE);
return;
}
- if (sm->eap_fast_prov != AUTH_PROV &&
- sm->eap_fast_prov != BOTH_PROV &&
+ if (sm->cfg->eap_fast_prov != AUTH_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV &&
tlv.request_action == TEAP_REQUEST_ACTION_PROCESS_TLV &&
eap_teap_pac_type(tlv.pac, tlv.pac_len,
PAC_TYPE_TUNNEL_PAC)) {
@@ -1496,30 +1607,55 @@
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Server triggered re-keying of Tunnel PAC");
eap_teap_state(data, REQUEST_PAC);
- } else if (data->final_result)
+ } else if (data->final_result) {
eap_teap_state(data, SUCCESS);
+ } else if (sm->cfg->eap_teap_separate_result) {
+ eap_teap_state(data, SUCCESS_SEND_RESULT);
+ }
}
if (tlv.basic_auth_resp) {
- if (sm->eap_teap_auth != 1) {
+ if (sm->cfg->eap_teap_auth != 1) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Unexpected Basic-Password-Auth-Resp when trying to use inner EAP");
eap_teap_state(data, FAILURE);
return;
}
eap_teap_process_basic_auth_resp(sm, data, tlv.basic_auth_resp,
- tlv.basic_auth_resp_len);
+ tlv.basic_auth_resp_len,
+ tlv.identity_type);
}
if (tlv.eap_payload_tlv) {
- if (sm->eap_teap_auth == 1) {
+ if (sm->cfg->eap_teap_auth == 1) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Unexpected EAP Payload TLV when trying to use Basic-Password-Auth");
eap_teap_state(data, FAILURE);
return;
}
eap_teap_process_phase2_eap(sm, data, tlv.eap_payload_tlv,
- tlv.eap_payload_tlv_len);
+ tlv.eap_payload_tlv_len,
+ tlv.identity_type);
+ }
+
+ if (data->state == SUCCESS_SEND_RESULT &&
+ tlv.result == TEAP_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Peer agreed with final success - authentication completed");
+ eap_teap_state(data, SUCCESS);
+ } else if (check_crypto_binding && data->state == CRYPTO_BINDING &&
+ sm->cfg->eap_teap_auth == 1 && data->basic_auth_not_done) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Continue with basic password authentication for second credential");
+ eap_teap_state(data, PHASE2_BASIC_AUTH);
+ } else if (check_crypto_binding && data->state == CRYPTO_BINDING &&
+ sm->cfg->eap_teap_auth == 0 && data->inner_eap_not_done) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Continue with inner EAP authentication for second credential");
+ eap_teap_state(data, PHASE2_ID);
+ if (eap_teap_phase2_init(sm, data, EAP_VENDOR_IETF,
+ EAP_TYPE_IDENTITY) < 0)
+ eap_teap_state(data, FAILURE);
}
}
@@ -1544,7 +1680,7 @@
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (!in_decrypted) {
wpa_printf(MSG_INFO,
@@ -1605,7 +1741,7 @@
return -1;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
wpabuf_len(data->ssl.tls_out) > 0)
return 1;
@@ -1622,7 +1758,8 @@
static int eap_teap_process_phase2_start(struct eap_sm *sm,
struct eap_teap_data *data)
{
- u8 next_type;
+ int next_vendor;
+ enum eap_type next_type;
if (data->identity) {
/* Used PAC and identity is from PAC-Opaque */
@@ -1635,38 +1772,43 @@
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-TEAP: Phase 2 Identity not found in the user database",
sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
eap_teap_state(data, PHASE2_METHOD);
- } else if (sm->eap_teap_pac_no_inner) {
+ } else if (sm->cfg->eap_teap_pac_no_inner) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Used PAC and identity already known - skip inner auth");
+ data->skipped_inner_auth = 1;
/* FIX: Need to derive CMK here. However, how is that
* supposed to be done? RFC 7170 does not tell that for
* the no-inner-auth case. */
- eap_teap_derive_cmk_basic_pw_auth(data->simck_msk,
+ eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
+ data->simck_msk,
data->cmk_msk);
eap_teap_state(data, CRYPTO_BINDING);
return 1;
- } else if (sm->eap_teap_auth == 1) {
+ } else if (sm->cfg->eap_teap_auth == 1) {
eap_teap_state(data, PHASE2_BASIC_AUTH);
return 1;
} else {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Identity already known - skip Phase 2 Identity Request");
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
eap_teap_state(data, PHASE2_METHOD);
}
- } else if (sm->eap_teap_auth == 1) {
+ } else if (sm->cfg->eap_teap_auth == 1) {
eap_teap_state(data, PHASE2_BASIC_AUTH);
return 0;
} else {
eap_teap_state(data, PHASE2_ID);
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_IDENTITY;
}
- return eap_teap_phase2_init(sm, data, next_type);
+ return eap_teap_phase2_init(sm, data, next_vendor, next_type);
}
@@ -1690,6 +1832,7 @@
case PHASE2_METHOD:
case CRYPTO_BINDING:
case REQUEST_PAC:
+ case SUCCESS_SEND_RESULT:
eap_teap_process_phase2(sm, data, data->ssl.tls_in);
break;
case FAILURE_SEND_RESULT:
@@ -1853,7 +1996,8 @@
/* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
* is used in this derivation */
- if (eap_teap_derive_eap_msk(data->simck_msk, eapKeyData) < 0) {
+ if (eap_teap_derive_eap_msk(data->tls_cs, data->simck_msk,
+ eapKeyData) < 0) {
os_free(eapKeyData);
return NULL;
}
@@ -1877,7 +2021,8 @@
/* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
* is used in this derivation */
- if (eap_teap_derive_eap_emsk(data->simck_msk, eapKeyData) < 0) {
+ if (eap_teap_derive_eap_emsk(data->tls_cs, data->simck_msk,
+ eapKeyData) < 0) {
os_free(eapKeyData);
return NULL;
}
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 0712d4c..c64cebb 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -58,7 +58,7 @@
{
struct wpabuf *buf;
- if (!sm->tls_session_lifetime)
+ if (!sm->cfg->tls_session_lifetime)
return;
buf = wpabuf_alloc(1);
@@ -187,7 +187,8 @@
case START:
return eap_tls_build_start(sm, data, id);
case CONTINUE:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn))
data->established = 1;
break;
default:
@@ -267,7 +268,7 @@
}
if (data->ssl.tls_v13 &&
- tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn)) {
struct wpabuf *plain, *encr;
wpa_printf(MSG_DEBUG,
@@ -315,8 +316,8 @@
return;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
- !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = tls_connection_get_success_data(data->ssl.conn);
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 907101c..b38f1e0 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -18,7 +18,7 @@
static void eap_server_tls_free_in_buf(struct eap_ssl_data *data);
-struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len,
u8 code, u8 identifier)
{
if (type == EAP_UNAUTH_TLS_TYPE)
@@ -47,9 +47,9 @@
int verify_peer, int eap_type)
{
u8 session_ctx[8];
- unsigned int flags = sm->tls_flags;
+ unsigned int flags = sm->cfg->tls_flags;
- if (sm->ssl_ctx == NULL) {
+ if (!sm->cfg->ssl_ctx) {
wpa_printf(MSG_ERROR, "TLS context not initialized - cannot use TLS-based EAP method");
return -1;
}
@@ -57,7 +57,7 @@
data->eap = sm;
data->phase2 = sm->init_phase2;
- data->conn = tls_connection_init(sm->ssl_ctx);
+ data->conn = tls_connection_init(sm->cfg->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
"connection");
@@ -75,17 +75,18 @@
flags |= TLS_CONN_DISABLE_SESSION_TICKET;
os_memcpy(session_ctx, "hostapd", 7);
session_ctx[7] = (u8) eap_type;
- if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer,
+ if (tls_connection_set_verify(sm->cfg->ssl_ctx, data->conn, verify_peer,
flags, session_ctx,
sizeof(session_ctx))) {
wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
"of TLS peer certificate");
- tls_connection_deinit(sm->ssl_ctx, data->conn);
+ tls_connection_deinit(sm->cfg->ssl_ctx, data->conn);
data->conn = NULL;
return -1;
}
- data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398;
+ data->tls_out_limit = sm->cfg->fragment_size > 0 ?
+ sm->cfg->fragment_size : 1398;
if (data->phase2) {
/* Limit the fragment size in the inner TLS authentication
* since the outer authentication with EAP-PEAP does not yet
@@ -99,7 +100,7 @@
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
{
- tls_connection_deinit(sm->ssl_ctx, data->conn);
+ tls_connection_deinit(sm->cfg->ssl_ctx, data->conn);
eap_server_tls_free_in_buf(data);
wpabuf_free(data->tls_out);
data->tls_out = NULL;
@@ -116,7 +117,7 @@
if (out == NULL)
return NULL;
- if (tls_connection_export_key(sm->ssl_ctx, data->conn, label,
+ if (tls_connection_export_key(sm->cfg->ssl_ctx, data->conn, label,
context, context_len, out, len)) {
os_free(out);
return NULL;
@@ -170,7 +171,7 @@
return id;
}
- if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
+ if (tls_connection_get_random(sm->cfg->ssl_ctx, data->conn, &keys))
return NULL;
if (keys.client_random == NULL || keys.server_random == NULL)
@@ -340,29 +341,30 @@
WPA_ASSERT(data->tls_out == NULL);
}
- data->tls_out = tls_connection_server_handshake(sm->ssl_ctx,
+ data->tls_out = tls_connection_server_handshake(sm->cfg->ssl_ctx,
data->conn,
data->tls_in, NULL);
if (data->tls_out == NULL) {
wpa_printf(MSG_INFO, "SSL: TLS processing failed");
return -1;
}
- if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
+ if (tls_connection_get_failed(sm->cfg->ssl_ctx, data->conn)) {
/* TLS processing has failed - return error */
wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
"report error");
return -1;
}
- if (tls_get_version(sm->ssl_ctx, data->conn, buf, sizeof(buf)) == 0) {
+ if (tls_get_version(sm->cfg->ssl_ctx, data->conn,
+ buf, sizeof(buf)) == 0) {
wpa_printf(MSG_DEBUG, "SSL: Using TLS version %s", buf);
data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0;
}
if (!sm->serial_num &&
- tls_connection_established(sm->ssl_ctx, data->conn))
- sm->serial_num = tls_connection_peer_serial_num(sm->ssl_ctx,
- data->conn);
+ tls_connection_established(sm->cfg->ssl_ctx, data->conn))
+ sm->serial_num = tls_connection_peer_serial_num(
+ sm->cfg->ssl_ctx, data->conn);
return 0;
}
@@ -451,8 +453,7 @@
{
struct wpabuf *buf;
- buf = tls_connection_encrypt(sm->ssl_ctx, data->conn,
- plain);
+ buf = tls_connection_encrypt(sm->cfg->ssl_ctx, data->conn, plain);
if (buf == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
return NULL;
@@ -506,7 +507,7 @@
if (proc_msg)
proc_msg(sm, priv, respData);
- if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) {
+ if (tls_connection_get_write_alerts(sm->cfg->ssl_ctx, data->conn) > 1) {
wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in "
"TLS processing");
res = -1;
diff --git a/src/eap_server/eap_server_tnc.c b/src/eap_server/eap_server_tnc.c
index b568558..f6cdcb1 100644
--- a/src/eap_server/eap_server_tnc.c
+++ b/src/eap_server/eap_server_tnc.c
@@ -84,8 +84,8 @@
return NULL;
}
- data->fragment_size = sm->fragment_size > 100 ?
- sm->fragment_size - 98 : 1300;
+ data->fragment_size = sm->cfg->fragment_size > 100 ?
+ sm->cfg->fragment_size - 98 : 1300;
return data;
}
@@ -508,7 +508,7 @@
eap_tnc_set_state(data, FAIL);
return;
}
-
+
if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
if (eap_tnc_process_fragment(data, flags, message_length,
pos, end - pos) < 0)
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 52bff8a..721835d 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -81,7 +81,7 @@
{
struct wpabuf *buf;
- if (!sm->tls_session_lifetime)
+ if (!sm->cfg->tls_session_lifetime)
return;
buf = wpabuf_alloc(1 + 1 + sm->identity_len);
@@ -480,7 +480,8 @@
case START:
return eap_ttls_build_start(sm, data, id);
case PHASE1:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, "
"starting Phase2");
eap_ttls_state(data, PHASE2_START);
@@ -827,15 +828,14 @@
static int eap_ttls_phase2_eap_init(struct eap_sm *sm,
struct eap_ttls_data *data,
- EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
data->phase2_method = NULL;
data->phase2_priv = NULL;
}
- data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
- eap_type);
+ data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
if (!data->phase2_method)
return -1;
@@ -850,7 +850,8 @@
struct eap_ttls_data *data,
u8 *in_data, size_t in_len)
{
- u8 next_type = EAP_TYPE_NONE;
+ int next_vendor = EAP_VENDOR_IETF;
+ enum eap_type next_type = EAP_TYPE_NONE;
struct eap_hdr *hdr;
u8 *pos;
size_t left;
@@ -875,14 +876,17 @@
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
sm->user->methods[sm->user_eap_method_index].method !=
EAP_TYPE_NONE) {
+ next_vendor = sm->user->methods[
+ sm->user_eap_method_index].vendor;
next_type = sm->user->methods[
sm->user_eap_method_index++].method;
- wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d",
- next_type);
- if (eap_ttls_phase2_eap_init(sm, data, next_type)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to "
- "initialize EAP type %d",
- next_type);
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %u:%u",
+ next_vendor, next_type);
+ if (eap_ttls_phase2_eap_init(sm, data, next_vendor,
+ next_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Failed to initialize EAP type %u:%u",
+ next_vendor, next_type);
eap_ttls_state(data, FAILURE);
return;
}
@@ -930,12 +934,16 @@
}
eap_ttls_state(data, PHASE2_METHOD);
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
- wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", next_type);
- if (eap_ttls_phase2_eap_init(sm, data, next_type)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize "
- "EAP type %d", next_type);
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %u:%u",
+ next_vendor, next_type);
+ if (eap_ttls_phase2_eap_init(sm, data, next_vendor,
+ next_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Failed to initialize EAP type %u:%u",
+ next_vendor, next_type);
eap_ttls_state(data, FAILURE);
}
break;
@@ -962,8 +970,8 @@
if (data->state == PHASE2_START) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: initializing Phase 2");
- if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_IDENTITY) < 0)
- {
+ if (eap_ttls_phase2_eap_init(sm, data, EAP_VENDOR_IETF,
+ EAP_TYPE_IDENTITY) < 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: failed to "
"initialize EAP-Identity");
return;
@@ -1022,7 +1030,7 @@
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (in_decrypted == NULL) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 "
@@ -1112,11 +1120,11 @@
static void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data)
{
#ifdef EAP_SERVER_TNC
- if (!sm->tnc || data->state != SUCCESS || data->tnc_started)
+ if (!sm->cfg->tnc || data->state != SUCCESS || data->tnc_started)
return;
wpa_printf(MSG_DEBUG, "EAP-TTLS: Initialize TNC");
- if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_TNC)) {
+ if (eap_ttls_phase2_eap_init(sm, data, EAP_VENDOR_IETF, EAP_TYPE_TNC)) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize TNC");
eap_ttls_state(data, FAILURE);
return;
@@ -1202,8 +1210,8 @@
return;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
- !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = tls_connection_get_success_data(data->ssl.conn);
diff --git a/src/eap_server/eap_server_wsc.c b/src/eap_server/eap_server_wsc.c
index 4a5cb98..364c089 100644
--- a/src/eap_server/eap_server_wsc.c
+++ b/src/eap_server/eap_server_wsc.c
@@ -103,10 +103,10 @@
data->registrar = registrar;
os_memset(&cfg, 0, sizeof(cfg));
- cfg.wps = sm->wps;
+ cfg.wps = sm->cfg->wps;
cfg.registrar = registrar;
if (registrar) {
- if (sm->wps == NULL || sm->wps->registrar == NULL) {
+ if (!sm->cfg->wps || !sm->cfg->wps->registrar) {
wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
"initialized");
os_free(data);
@@ -138,14 +138,14 @@
cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie);
}
#endif /* CONFIG_P2P */
- cfg.pbc_in_m1 = sm->pbc_in_m1;
+ cfg.pbc_in_m1 = sm->cfg->pbc_in_m1;
data->wps = wps_init(&cfg);
if (data->wps == NULL) {
os_free(data);
return NULL;
}
- data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
- WSC_FRAGMENT_SIZE;
+ data->fragment_size = sm->cfg->fragment_size > 0 ?
+ sm->cfg->fragment_size : WSC_FRAGMENT_SIZE;
return data;
}
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index 74b1c72..b0b7361 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -73,7 +73,7 @@
#define EAP_WFA_UNAUTH_TLS_TYPE 254
-struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len,
u8 code, u8 identifier);
int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
int verify_peer, int eap_type);
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index b7423d1..5a2ba26 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -775,7 +775,7 @@
const char *identity, const char *radius_cui)
{
struct eapol_state_machine *sm;
- struct eap_config eap_conf;
+ struct eap_session_data eap_sess;
if (eapol == NULL)
return NULL;
@@ -823,35 +823,12 @@
else
sm->portValid = TRUE;
- os_memset(&eap_conf, 0, sizeof(eap_conf));
- eap_conf.eap_server = eapol->conf.eap_server;
- eap_conf.ssl_ctx = eapol->conf.ssl_ctx;
- eap_conf.msg_ctx = eapol->conf.msg_ctx;
- eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv;
- eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key;
- eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id;
- eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len;
- eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info;
- eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov;
- eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime;
- eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time;
- eap_conf.eap_teap_auth = eapol->conf.eap_teap_auth;
- eap_conf.eap_teap_pac_no_inner = eapol->conf.eap_teap_pac_no_inner;
- eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
- eap_conf.tnc = eapol->conf.tnc;
- eap_conf.wps = eapol->conf.wps;
- eap_conf.assoc_wps_ie = assoc_wps_ie;
- eap_conf.assoc_p2p_ie = assoc_p2p_ie;
- eap_conf.peer_addr = addr;
- eap_conf.fragment_size = eapol->conf.fragment_size;
- eap_conf.pwd_group = eapol->conf.pwd_group;
- eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
- eap_conf.server_id = eapol->conf.server_id;
- eap_conf.server_id_len = eapol->conf.server_id_len;
- eap_conf.erp = eapol->conf.erp;
- eap_conf.tls_session_lifetime = eapol->conf.tls_session_lifetime;
- eap_conf.tls_flags = eapol->conf.tls_flags;
- sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
+ os_memset(&eap_sess, 0, sizeof(eap_sess));
+ eap_sess.assoc_wps_ie = assoc_wps_ie;
+ eap_sess.assoc_p2p_ie = assoc_p2p_ie;
+ eap_sess.peer_addr = addr;
+ sm->eap = eap_server_sm_init(sm, &eapol_cb, eapol->conf.eap_cfg,
+ &eap_sess);
if (sm->eap == NULL) {
eapol_auth_free(sm);
return NULL;
@@ -1186,19 +1163,12 @@
static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
struct eapol_auth_config *src)
{
+ dst->eap_cfg = src->eap_cfg;
dst->ctx = src->ctx;
dst->eap_reauth_period = src->eap_reauth_period;
dst->wpa = src->wpa;
dst->individual_wep_key_len = src->individual_wep_key_len;
- dst->eap_server = src->eap_server;
- dst->ssl_ctx = src->ssl_ctx;
- dst->msg_ctx = src->msg_ctx;
- dst->eap_sim_db_priv = src->eap_sim_db_priv;
os_free(dst->eap_req_id_text);
- dst->pwd_group = src->pwd_group;
- dst->pbc_in_m1 = src->pbc_in_m1;
- dst->server_id = src->server_id;
- dst->server_id_len = src->server_id_len;
if (src->eap_req_id_text) {
dst->eap_req_id_text = os_memdup(src->eap_req_id_text,
src->eap_req_id_text_len);
@@ -1209,36 +1179,6 @@
dst->eap_req_id_text = NULL;
dst->eap_req_id_text_len = 0;
}
- if (src->pac_opaque_encr_key) {
- dst->pac_opaque_encr_key = os_memdup(src->pac_opaque_encr_key,
- 16);
- if (dst->pac_opaque_encr_key == NULL)
- goto fail;
- } else
- dst->pac_opaque_encr_key = NULL;
- if (src->eap_fast_a_id) {
- dst->eap_fast_a_id = os_memdup(src->eap_fast_a_id,
- src->eap_fast_a_id_len);
- if (dst->eap_fast_a_id == NULL)
- goto fail;
- dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
- } else
- dst->eap_fast_a_id = NULL;
- if (src->eap_fast_a_id_info) {
- dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
- if (dst->eap_fast_a_id_info == NULL)
- goto fail;
- } else
- dst->eap_fast_a_id_info = NULL;
- dst->eap_fast_prov = src->eap_fast_prov;
- dst->pac_key_lifetime = src->pac_key_lifetime;
- dst->pac_key_refresh_time = src->pac_key_refresh_time;
- dst->eap_teap_auth = src->eap_teap_auth;
- dst->eap_teap_pac_no_inner = src->eap_teap_pac_no_inner;
- dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind;
- dst->tnc = src->tnc;
- dst->wps = src->wps;
- dst->fragment_size = src->fragment_size;
os_free(dst->erp_domain);
if (src->erp_domain) {
@@ -1249,9 +1189,6 @@
dst->erp_domain = NULL;
}
dst->erp_send_reauth_start = src->erp_send_reauth_start;
- dst->erp = src->erp;
- dst->tls_session_lifetime = src->tls_session_lifetime;
- dst->tls_flags = src->tls_flags;
return 0;
@@ -1265,12 +1202,6 @@
{
os_free(conf->eap_req_id_text);
conf->eap_req_id_text = NULL;
- os_free(conf->pac_opaque_encr_key);
- conf->pac_opaque_encr_key = NULL;
- os_free(conf->eap_fast_a_id);
- conf->eap_fast_a_id = NULL;
- os_free(conf->eap_fast_a_id_info);
- conf->eap_fast_a_id_info = NULL;
os_free(conf->erp_domain);
conf->erp_domain = NULL;
}
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index 41b6b1b..5fe89c6 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -15,37 +15,14 @@
#define EAPOL_SM_FROM_PMKSA_CACHE BIT(3)
struct eapol_auth_config {
+ const struct eap_config *eap_cfg;
int eap_reauth_period;
int wpa;
int individual_wep_key_len;
- int eap_server;
- void *ssl_ctx;
- void *msg_ctx;
- void *eap_sim_db_priv;
char *eap_req_id_text; /* a copy of this will be allocated */
size_t eap_req_id_text_len;
int erp_send_reauth_start;
char *erp_domain; /* a copy of this will be allocated */
- int erp; /* Whether ERP is enabled on authentication server */
- unsigned int tls_session_lifetime;
- unsigned int tls_flags;
- u8 *pac_opaque_encr_key;
- u8 *eap_fast_a_id;
- size_t eap_fast_a_id_len;
- char *eap_fast_a_id_info;
- int eap_fast_prov;
- int pac_key_lifetime;
- int pac_key_refresh_time;
- int eap_teap_auth;
- int eap_teap_pac_no_inner;
- int eap_sim_aka_result_ind;
- int tnc;
- struct wps_context *wps;
- int fragment_size;
- u16 pwd_group;
- int pbc_in_m1;
- const u8 *server_id;
- size_t server_id_len;
/* Opaque context pointer to owner data for callback functions */
void *ctx;
diff --git a/src/fst/fst.c b/src/fst/fst.c
index 32cd941..fbe1175 100644
--- a/src/fst/fst.c
+++ b/src/fst/fst.c
@@ -214,6 +214,15 @@
}
+void fst_update_mac_addr(struct fst_iface *iface, const u8 *addr)
+{
+ fst_printf_iface(iface, MSG_DEBUG, "new MAC address " MACSTR,
+ MAC2STR(addr));
+ os_memcpy(iface->own_addr, addr, sizeof(iface->own_addr));
+ fst_group_update_ie(fst_iface_get_group(iface));
+}
+
+
enum mb_band_id fst_hw_mode_to_band(enum hostapd_hw_mode mode)
{
switch (mode) {
diff --git a/src/fst/fst.h b/src/fst/fst.h
index 2967491..7ba60d5 100644
--- a/src/fst/fst.h
+++ b/src/fst/fst.h
@@ -279,6 +279,13 @@
Boolean fst_are_ifaces_aggregated(struct fst_iface *iface1,
struct fst_iface *iface2);
+/**
+ * fst_update_mac_addr - Notify FST about MAC address change
+ * @iface: FST interface object
+ * @addr: New MAC address
+ */
+void fst_update_mac_addr(struct fst_iface *iface, const u8 *addr);
+
#else /* CONFIG_FST */
static inline int fst_global_init(void)
diff --git a/src/pae/ieee802_1x_cp.c b/src/pae/ieee802_1x_cp.c
index 1c4dc3e..69e5758 100644
--- a/src/pae/ieee802_1x_cp.c
+++ b/src/pae/ieee802_1x_cp.c
@@ -141,6 +141,24 @@
ieee802_1x_kay_delete_sas(sm->kay, sm->lki);
if (sm->oki)
ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
+ /* The standard doesn't say it but we should clear out the latest
+ * and old key values. Why would we keep advertising them if
+ * they've been deleted and the key server has been changed?
+ */
+ os_free(sm->oki);
+ sm->oki = NULL;
+ sm->otx = FALSE;
+ sm->orx = FALSE;
+ sm->oan = 0;
+ ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
+ sm->otx, sm->orx);
+ os_free(sm->lki);
+ sm->lki = NULL;
+ sm->lrx = FALSE;
+ sm->ltx = FALSE;
+ sm->lan = 0;
+ ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
+ sm->ltx, sm->lrx);
}
@@ -212,18 +230,6 @@
SM_STATE(CP, RECEIVE)
{
SM_ENTRY(CP, RECEIVE);
- /* RECEIVE state machine not keep with Figure 12-2 in
- * IEEE Std 802.1X-2010 */
- if (sm->oki) {
- ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
- os_free(sm->oki);
- }
- sm->oki = sm->lki;
- sm->oan = sm->lan;
- sm->otx = sm->ltx;
- sm->orx = sm->lrx;
- ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
- sm->otx, sm->orx);
sm->lki = os_malloc(sizeof(*sm->lki));
if (!sm->lki) {
@@ -313,24 +319,29 @@
sm->lki = NULL;
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
sm->ltx, sm->lrx);
- sm->new_sak = FALSE;
}
SM_STATE(CP, RETIRE)
{
SM_ENTRY(CP, RETIRE);
- /* RETIRE state machine not keep with Figure 12-2 in
- * IEEE Std 802.1X-2010 */
if (sm->oki) {
ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
os_free(sm->oki);
sm->oki = NULL;
}
- sm->orx = FALSE;
- sm->otx = FALSE;
+ sm->oki = sm->lki;
+ sm->otx = sm->ltx;
+ sm->orx = sm->lrx;
+ sm->oan = sm->lan;
ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
sm->otx, sm->orx);
+ sm->lki = NULL;
+ sm->ltx = FALSE;
+ sm->lrx = FALSE;
+ sm->lan = 0;
+ ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
+ sm->ltx, sm->lrx);
}
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index b4455c8..3dbd3ca 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -1085,7 +1085,17 @@
wpa_printf(MSG_DEBUG,
"KaY: My MI - received MN %u, most recently transmitted MN %u",
mn, participant->mn);
- if (mn == participant->mn)
+ /* IEEE Std 802.1X-2010 is not exactly clear
+ * which values of MN should be accepted here.
+ * It uses "acceptably recent MN" language
+ * without defining what would be acceptable
+ * recent. For now, allow the last two used MN
+ * values (i.e., peer having copied my MI,MN
+ * from either of the last two MKPDUs that I
+ * have sent). */
+ if (mn == participant->mn ||
+ (participant->mn > 1 &&
+ mn == participant->mn - 1))
return TRUE;
}
}
@@ -1277,7 +1287,7 @@
struct ieee802_1x_mka_sak_use_body *body;
struct ieee802_1x_kay *kay = participant->kay;
unsigned int length;
- u32 pn = 1;
+ u32 olpn, llpn;
length = ieee802_1x_mka_get_sak_use_length(participant);
body = wpabuf_put(buf, length);
@@ -1297,18 +1307,31 @@
/* data delay protect */
body->delay_protect = kay->mka_hello_time <= MKA_BOUNDED_HELLO_TIME;
- /* lowest accept packet number */
- pn = ieee802_1x_mka_get_lpn(participant, &participant->lki);
- if (pn > kay->pn_exhaustion) {
- wpa_printf(MSG_WARNING, "KaY: My LPN exhaustion");
- if (participant->is_key_server)
- participant->new_sak = TRUE;
+ /* lowest accept packet numbers */
+ olpn = ieee802_1x_mka_get_lpn(participant, &participant->oki);
+ body->olpn = host_to_be32(olpn);
+ llpn = ieee802_1x_mka_get_lpn(participant, &participant->lki);
+ body->llpn = host_to_be32(llpn);
+ if (participant->is_key_server) {
+ /* The CP will spend most of it's time in RETIRE where only
+ * the old key is populated. Therefore we should be checking
+ * the OLPN most of the time.
+ */
+ if (participant->lrx) {
+ if (llpn > kay->pn_exhaustion) {
+ wpa_printf(MSG_WARNING,
+ "KaY: My LLPN exhaustion");
+ participant->new_sak = TRUE;
+ }
+ } else {
+ if (olpn > kay->pn_exhaustion) {
+ wpa_printf(MSG_WARNING,
+ "KaY: My OLPN exhaustion");
+ participant->new_sak = TRUE;
+ }
+ }
}
- body->llpn = host_to_be32(pn);
- pn = ieee802_1x_mka_get_lpn(participant, &participant->oki);
- body->olpn = host_to_be32(pn);
-
/* plain tx, plain rx */
body->ptx = !kay->macsec_protect;
body->prx = kay->macsec_validate != Strict;
@@ -1358,15 +1381,12 @@
struct ieee802_1x_mka_hdr *hdr;
struct ieee802_1x_mka_sak_use_body *body;
struct ieee802_1x_kay_peer *peer;
- struct receive_sc *rxsc;
- struct receive_sa *rxsa;
struct data_key *sa_key = NULL;
size_t body_len;
struct ieee802_1x_mka_ki ki;
u32 lpn;
- Boolean all_receiving;
- Boolean found;
struct ieee802_1x_kay *kay = participant->kay;
+ u32 olpn, llpn;
if (!participant->principal) {
wpa_printf(MSG_WARNING, "KaY: Participant is not principal");
@@ -1407,46 +1427,6 @@
if (body->ptx)
wpa_printf(MSG_WARNING, "KaY: peer's plain tx are TRUE");
-
- /* check latest key is valid */
- if (body->ltx || body->lrx) {
- found = FALSE;
- os_memcpy(ki.mi, body->lsrv_mi, sizeof(ki.mi));
- ki.kn = be_to_host32(body->lkn);
- dl_list_for_each(sa_key, &participant->sak_list,
- struct data_key, list) {
- if (is_ki_equal(&sa_key->key_identifier, &ki)) {
- found = TRUE;
- break;
- }
- }
- if (!found) {
- wpa_printf(MSG_INFO, "KaY: Latest key is invalid");
- return -1;
- }
- if (os_memcmp(participant->lki.mi, body->lsrv_mi,
- sizeof(participant->lki.mi)) == 0 &&
- be_to_host32(body->lkn) == participant->lki.kn &&
- body->lan == participant->lan) {
- peer->sak_used = TRUE;
- }
- if (body->ltx && peer->is_key_server) {
- ieee802_1x_cp_set_servertransmitting(kay->cp, TRUE);
- ieee802_1x_cp_sm_step(kay->cp);
- }
- }
-
- /* check old key is valid (but only if we remember our old key) */
- if (participant->oki.kn != 0 && (body->otx || body->orx)) {
- if (os_memcmp(participant->oki.mi, body->osrv_mi,
- sizeof(participant->oki.mi)) != 0 ||
- be_to_host32(body->okn) != participant->oki.kn ||
- body->oan != participant->oan) {
- wpa_printf(MSG_WARNING, "KaY: Old key is invalid");
- return -1;
- }
- }
-
/* TODO: how to set the MACsec hardware when delay_protect is true */
if (body->delay_protect &&
(!be_to_host32(body->llpn) || !be_to_host32(body->olpn))) {
@@ -1455,65 +1435,132 @@
return -1;
}
- /* check all live peer have used the sak for receiving sa */
- all_receiving = TRUE;
- dl_list_for_each(peer, &participant->live_peers,
- struct ieee802_1x_kay_peer, list) {
- if (!peer->sak_used) {
- all_receiving = FALSE;
- break;
- }
- }
- if (all_receiving) {
- participant->to_dist_sak = FALSE;
- ieee802_1x_cp_set_allreceiving(kay->cp, TRUE);
- ieee802_1x_cp_sm_step(kay->cp);
+ olpn = be_to_host32(body->olpn);
+ llpn = be_to_host32(body->llpn);
+
+ /* Our most recent distributed key should be the first in the list.
+ * If it doesn't exist then we can't really do anything.
+ * Be lenient and don't return error here as there are legitimate cases
+ * where this can happen such as when a new participant joins the CA and
+ * the first frame it receives can have a SAKuse but not distSAK.
+ */
+ sa_key = dl_list_first(&participant->sak_list, struct data_key, list);
+ if (!sa_key) {
+ wpa_printf(MSG_INFO,
+ "KaY: We don't have a latest distributed key - ignore SAK use");
+ return 0;
}
- /* if I'm key server, and detects peer member pn exhaustion, rekey. */
- lpn = be_to_host32(body->llpn);
- if (lpn > kay->pn_exhaustion) {
- if (participant->is_key_server) {
- participant->new_sak = TRUE;
- wpa_printf(MSG_WARNING, "KaY: Peer LPN exhaustion");
- }
+ /* The peer's most recent key will be the "latest key" if it is present
+ * otherwise it will be the "old key" if in the RETIRE state.
+ */
+ if (body->lrx) {
+ os_memcpy(ki.mi, body->lsrv_mi, sizeof(ki.mi));
+ ki.kn = be_to_host32(body->lkn);
+ lpn = llpn;
+ } else {
+ os_memcpy(ki.mi, body->osrv_mi, sizeof(ki.mi));
+ ki.kn = be_to_host32(body->okn);
+ lpn = olpn;
}
- if (sa_key)
- sa_key->next_pn = lpn;
- found = FALSE;
- dl_list_for_each(rxsc, &participant->rxsc_list, struct receive_sc,
- list) {
- dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa,
- list) {
- if (sa_key && rxsa->pkey == sa_key) {
- found = TRUE;
+ /* If the most recent distributed keys don't agree then someone is out
+ * of sync. Perhaps non key server hasn't processed the most recent
+ * distSAK yet and the key server is processing an old packet after it
+ * has done distSAK. Be lenient and don't return error in this
+ * particular case; otherwise, the key server will reset its MI and
+ * cause a traffic disruption which is really undesired for a simple
+ * timing issue.
+ */
+ if (!is_ki_equal(&sa_key->key_identifier, &ki)) {
+ wpa_printf(MSG_INFO,
+ "KaY: Distributed keys don't match - ignore SAK use");
+ return 0;
+ }
+ sa_key->next_pn = lpn;
+
+ /* The key server must check that all peers are using the most recent
+ * distributed key. Non key servers must check if the key server is
+ * transmitting.
+ */
+ if (participant->is_key_server) {
+ struct ieee802_1x_kay_peer *peer_iter;
+ Boolean all_receiving = TRUE;
+
+ /* Distributed keys are equal from above comparison. */
+ peer->sak_used = TRUE;
+
+ dl_list_for_each(peer_iter, &participant->live_peers,
+ struct ieee802_1x_kay_peer, list) {
+ if (!peer_iter->sak_used) {
+ all_receiving = FALSE;
break;
}
}
- if (found)
- break;
- }
- if (!found) {
- wpa_printf(MSG_WARNING, "KaY: Can't find rxsa");
- return -1;
+ if (all_receiving) {
+ participant->to_dist_sak = FALSE;
+ ieee802_1x_cp_set_allreceiving(kay->cp, TRUE);
+ ieee802_1x_cp_sm_step(kay->cp);
+ }
+ } else if (peer->is_key_server) {
+ if (body->ltx) {
+ ieee802_1x_cp_set_servertransmitting(kay->cp, TRUE);
+ ieee802_1x_cp_sm_step(kay->cp);
+ }
}
+ /* If I'm key server, and detects peer member PN exhaustion, rekey.
+ * We only need to check the PN of the most recent distributed key. This
+ * could be the peer's "latest" or "old" key depending on its current
+ * state. If both "old" and "latest" keys are present then the "old" key
+ * has already been exhausted.
+ */
+ if (participant->is_key_server && lpn > kay->pn_exhaustion) {
+ participant->new_sak = TRUE;
+ wpa_printf(MSG_WARNING, "KaY: Peer LPN exhaustion");
+ }
+
+ /* Get the associated RX SAs of the keys for delay protection since both
+ * can be in use. Delay protect window (communicated via MKA) is tighter
+ * than SecY's current replay protect window, so tell SecY the new (and
+ * higher) lpn.
+ */
if (body->delay_protect) {
- secy_get_receive_lowest_pn(participant->kay, rxsa);
- if (lpn > rxsa->lowest_pn) {
- /* Delay protect window (communicated via MKA) is
- * tighter than SecY's current replay protect window,
- * so tell SecY the new (and higher) lpn. */
- rxsa->lowest_pn = lpn;
- secy_set_receive_lowest_pn(participant->kay, rxsa);
- wpa_printf(MSG_DEBUG, "KaY: update lpn =0x%x", lpn);
+ struct receive_sc *rxsc;
+ struct receive_sa *rxsa;
+ Boolean found = FALSE;
+
+ dl_list_for_each(rxsc, &participant->rxsc_list,
+ struct receive_sc, list) {
+ dl_list_for_each(rxsa, &rxsc->sa_list,
+ struct receive_sa, list) {
+ if (sa_key && rxsa->pkey == sa_key) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found)
+ break;
}
- /* FIX: Delay protection for olpn not implemented.
- * Note that Old Key is only active for MKA_SAK_RETIRE_TIME
- * (3 seconds) and delay protection does allow PN's within
- * a 2 seconds window, so olpn would be a lot of work for
- * just 1 second's worth of protection. */
+ if (found) {
+ secy_get_receive_lowest_pn(participant->kay, rxsa);
+ if (lpn > rxsa->lowest_pn) {
+ rxsa->lowest_pn = lpn;
+ secy_set_receive_lowest_pn(participant->kay,
+ rxsa);
+ wpa_printf(MSG_DEBUG,
+ "KaY: update dist LPN=0x%x", lpn);
+ }
+ }
+
+ /* FIX: Delay protection for the SA being replaced is not
+ * implemented. Note that this key will be active for at least
+ * MKA_SAK_RETIRE_TIME (3 seconds) but could be longer depending
+ * on how long it takes to get from RECEIVE to TRANSMITTING or
+ * if going via ABANDON. Delay protection does allow PNs within
+ * a 2 second window, so getting PN would be a lot of work for
+ * just 1 second's worth of protection.
+ */
}
return 0;
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 1b605c7..c17e53b 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -161,143 +161,10 @@
*/
int num_sess;
- /**
- * eap_sim_db_priv - EAP-SIM/AKA database context
- *
- * This is passed to the EAP-SIM/AKA server implementation as a
- * callback context.
- */
- void *eap_sim_db_priv;
-
- /**
- * ssl_ctx - TLS context
- *
- * This is passed to the EAP server implementation as a callback
- * context for TLS operations.
- */
- void *ssl_ctx;
-
- /**
- * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
- *
- * This parameter is used to set a key for EAP-FAST to encrypt the
- * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
- * set, must point to a 16-octet key.
- */
- u8 *pac_opaque_encr_key;
-
- /**
- * eap_fast_a_id - EAP-FAST authority identity (A-ID)
- *
- * If EAP-FAST is not used, this can be set to %NULL. In theory, this
- * is a variable length field, but due to some existing implementations
- * requiring A-ID to be 16 octets in length, it is recommended to use
- * that length for the field to provide interoperability with deployed
- * peer implementations.
- */
- u8 *eap_fast_a_id;
-
- /**
- * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
- */
- size_t eap_fast_a_id_len;
-
- /**
- * eap_fast_a_id_info - EAP-FAST authority identifier information
- *
- * This A-ID-Info contains a user-friendly name for the A-ID. For
- * example, this could be the enterprise and server names in
- * human-readable format. This field is encoded as UTF-8. If EAP-FAST
- * is not used, this can be set to %NULL.
- */
- char *eap_fast_a_id_info;
-
- /**
- * eap_fast_prov - EAP-FAST provisioning modes
- *
- * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
- * 2 = only authenticated provisioning allowed, 3 = both provisioning
- * modes allowed.
- */
- int eap_fast_prov;
-
- /**
- * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
- *
- * This is the hard limit on how long a provisioned PAC-Key can be
- * used.
- */
- int pac_key_lifetime;
-
- /**
- * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
- *
- * This is a soft limit on the PAC-Key. The server will automatically
- * generate a new PAC-Key when this number of seconds (or fewer) of the
- * lifetime remains.
- */
- int pac_key_refresh_time;
-
- int eap_teap_auth;
- int eap_teap_pac_no_inner;
-
- /**
- * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
- *
- * This controls whether the protected success/failure indication
- * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
- */
- int eap_sim_aka_result_ind;
-
- /**
- * tnc - Trusted Network Connect (TNC)
- *
- * This controls whether TNC is enabled and will be required before the
- * peer is allowed to connect. Note: This is only used with EAP-TTLS
- * and EAP-FAST. If any other EAP method is enabled, the peer will be
- * allowed to connect without TNC.
- */
- int tnc;
-
- /**
- * pwd_group - The D-H group assigned for EAP-pwd
- *
- * If EAP-pwd is not used it can be set to zero.
- */
- u16 pwd_group;
-
- /**
- * server_id - Server identity
- */
- const char *server_id;
-
- /**
- * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
- *
- * This controls whether the authentication server derives ERP key
- * hierarchy (rRK and rIK) from full EAP authentication and allows
- * these keys to be used to perform ERP to derive rMSK instead of full
- * EAP authentication to derive MSK.
- */
- int erp;
-
const char *erp_domain;
struct dl_list erp_keys; /* struct eap_server_erp_key */
- unsigned int tls_session_lifetime;
-
- unsigned int tls_flags;
-
- /**
- * wps - Wi-Fi Protected Setup context
- *
- * If WPS is used with an external RADIUS server (which is quite
- * unlikely configuration), this is used to provide a pointer to WPS
- * context data. Normally, this can be set to %NULL.
- */
- struct wps_context *wps;
-
/**
* ipv6 - Whether to enable IPv6 support in the RADIUS server
*/
@@ -349,11 +216,6 @@
*/
size_t eap_req_id_text_len;
- /*
- * msg_ctx - Context data for wpa_msg() calls
- */
- void *msg_ctx;
-
#ifdef CONFIG_RADIUS_TEST
char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
@@ -367,6 +229,8 @@
#ifdef CONFIG_SQLITE
sqlite3 *db;
#endif /* CONFIG_SQLITE */
+
+ const struct eap_config *eap_cfg;
};
@@ -617,7 +481,7 @@
#ifdef CONFIG_TESTING_OPTIONS
static void radius_server_testing_options_tls(struct radius_session *sess,
const char *tls,
- struct eap_config *eap_conf)
+ struct eap_session_data *eap_conf)
{
int test = atoi(tls);
@@ -662,7 +526,7 @@
#endif /* CONFIG_TESTING_OPTIONS */
static void radius_server_testing_options(struct radius_session *sess,
- struct eap_config *eap_conf)
+ struct eap_session_data *eap_conf)
{
#ifdef CONFIG_TESTING_OPTIONS
const char *pos;
@@ -705,7 +569,7 @@
size_t user_len, id_len;
int res;
struct radius_session *sess;
- struct eap_config eap_conf;
+ struct eap_session_data eap_sess;
struct eap_user *tmp;
RADIUS_DEBUG("Creating a new session");
@@ -723,7 +587,7 @@
res = data->get_eap_user(data->conf_ctx, user, user_len, 0, tmp);
#ifdef CONFIG_ERP
- if (res != 0 && data->erp) {
+ if (res != 0 && data->eap_cfg->erp) {
char *username;
username = os_zalloc(user_len + 1);
@@ -782,33 +646,10 @@
srv_log(sess, "New session created");
- os_memset(&eap_conf, 0, sizeof(eap_conf));
- eap_conf.ssl_ctx = data->ssl_ctx;
- eap_conf.msg_ctx = data->msg_ctx;
- eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;
- eap_conf.backend_auth = TRUE;
- eap_conf.eap_server = 1;
- eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;
- eap_conf.eap_fast_a_id = data->eap_fast_a_id;
- eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len;
- eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info;
- eap_conf.eap_fast_prov = data->eap_fast_prov;
- eap_conf.pac_key_lifetime = data->pac_key_lifetime;
- eap_conf.pac_key_refresh_time = data->pac_key_refresh_time;
- eap_conf.eap_teap_auth = data->eap_teap_auth;
- eap_conf.eap_teap_pac_no_inner = data->eap_teap_pac_no_inner;
- eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;
- eap_conf.tnc = data->tnc;
- eap_conf.wps = data->wps;
- eap_conf.pwd_group = data->pwd_group;
- eap_conf.server_id = (const u8 *) data->server_id;
- eap_conf.server_id_len = os_strlen(data->server_id);
- eap_conf.erp = data->erp;
- eap_conf.tls_session_lifetime = data->tls_session_lifetime;
- eap_conf.tls_flags = data->tls_flags;
- radius_server_testing_options(sess, &eap_conf);
+ os_memset(&eap_sess, 0, sizeof(eap_sess));
+ radius_server_testing_options(sess, &eap_sess);
sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
- &eap_conf);
+ data->eap_cfg, &eap_sess);
if (sess->eap == NULL) {
RADIUS_DEBUG("Failed to initialize EAP state machine for the "
"new session");
@@ -2360,75 +2201,52 @@
if (data == NULL)
return NULL;
+ data->eap_cfg = conf->eap_cfg;
data->auth_sock = -1;
data->acct_sock = -1;
dl_list_init(&data->erp_keys);
os_get_reltime(&data->start_time);
data->conf_ctx = conf->conf_ctx;
- data->eap_sim_db_priv = conf->eap_sim_db_priv;
- data->ssl_ctx = conf->ssl_ctx;
- data->msg_ctx = conf->msg_ctx;
+ conf->eap_cfg->backend_auth = TRUE;
+ conf->eap_cfg->eap_server = 1;
data->ipv6 = conf->ipv6;
- if (conf->pac_opaque_encr_key) {
- data->pac_opaque_encr_key = os_malloc(16);
- if (data->pac_opaque_encr_key) {
- os_memcpy(data->pac_opaque_encr_key,
- conf->pac_opaque_encr_key, 16);
- }
- }
- if (conf->eap_fast_a_id) {
- data->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
- if (data->eap_fast_a_id) {
- os_memcpy(data->eap_fast_a_id, conf->eap_fast_a_id,
- conf->eap_fast_a_id_len);
- data->eap_fast_a_id_len = conf->eap_fast_a_id_len;
- }
- }
- if (conf->eap_fast_a_id_info)
- data->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
- data->eap_fast_prov = conf->eap_fast_prov;
- data->pac_key_lifetime = conf->pac_key_lifetime;
- data->pac_key_refresh_time = conf->pac_key_refresh_time;
- data->eap_teap_auth = conf->eap_teap_auth;
- data->eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner;
data->get_eap_user = conf->get_eap_user;
- data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
- data->tnc = conf->tnc;
- data->wps = conf->wps;
- data->pwd_group = conf->pwd_group;
- data->server_id = conf->server_id;
if (conf->eap_req_id_text) {
data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
- if (data->eap_req_id_text) {
- os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
- conf->eap_req_id_text_len);
- data->eap_req_id_text_len = conf->eap_req_id_text_len;
- }
+ if (!data->eap_req_id_text)
+ goto fail;
+ os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
+ conf->eap_req_id_text_len);
+ data->eap_req_id_text_len = conf->eap_req_id_text_len;
}
- data->erp = conf->erp;
data->erp_domain = conf->erp_domain;
- data->tls_session_lifetime = conf->tls_session_lifetime;
- data->tls_flags = conf->tls_flags;
if (conf->subscr_remediation_url) {
data->subscr_remediation_url =
os_strdup(conf->subscr_remediation_url);
+ if (!data->subscr_remediation_url)
+ goto fail;
}
data->subscr_remediation_method = conf->subscr_remediation_method;
- if (conf->hs20_sim_provisioning_url)
+ if (conf->hs20_sim_provisioning_url) {
data->hs20_sim_provisioning_url =
os_strdup(conf->hs20_sim_provisioning_url);
+ if (!data->hs20_sim_provisioning_url)
+ goto fail;
+ }
- if (conf->t_c_server_url)
+ if (conf->t_c_server_url) {
data->t_c_server_url = os_strdup(conf->t_c_server_url);
+ if (!data->t_c_server_url)
+ goto fail;
+ }
#ifdef CONFIG_SQLITE
if (conf->sqlite_file) {
if (sqlite3_open(conf->sqlite_file, &data->db)) {
RADIUS_ERROR("Could not open SQLite file '%s'",
conf->sqlite_file);
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
}
#endif /* CONFIG_SQLITE */
@@ -2442,8 +2260,7 @@
conf->ipv6);
if (data->clients == NULL) {
wpa_printf(MSG_ERROR, "No RADIUS clients configured");
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
#ifdef CONFIG_IPV6
@@ -2454,14 +2271,12 @@
data->auth_sock = radius_server_open_socket(conf->auth_port);
if (data->auth_sock < 0) {
wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS authentication server");
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
if (eloop_register_read_sock(data->auth_sock,
radius_server_receive_auth,
data, NULL)) {
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
if (conf->acct_port) {
@@ -2474,20 +2289,20 @@
data->acct_sock = radius_server_open_socket(conf->acct_port);
if (data->acct_sock < 0) {
wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS accounting server");
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
if (eloop_register_read_sock(data->acct_sock,
radius_server_receive_acct,
- data, NULL)) {
- radius_server_deinit(data);
- return NULL;
- }
+ data, NULL))
+ goto fail;
} else {
data->acct_sock = -1;
}
return data;
+fail:
+ radius_server_deinit(data);
+ return NULL;
}
@@ -2530,9 +2345,6 @@
radius_server_free_clients(data, data->clients);
- os_free(data->pac_opaque_encr_key);
- os_free(data->eap_fast_a_id);
- os_free(data->eap_fast_a_id_info);
os_free(data->eap_req_id_text);
#ifdef CONFIG_RADIUS_TEST
os_free(data->dump_msk_file);
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 88c22db..43192e5 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -51,141 +51,8 @@
*/
void *conf_ctx;
- /**
- * eap_sim_db_priv - EAP-SIM/AKA database context
- *
- * This is passed to the EAP-SIM/AKA server implementation as a
- * callback context.
- */
- void *eap_sim_db_priv;
-
- /**
- * ssl_ctx - TLS context
- *
- * This is passed to the EAP server implementation as a callback
- * context for TLS operations.
- */
- void *ssl_ctx;
-
- /**
- * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
- *
- * This parameter is used to set a key for EAP-FAST to encrypt the
- * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
- * set, must point to a 16-octet key.
- */
- u8 *pac_opaque_encr_key;
-
- /**
- * eap_fast_a_id - EAP-FAST authority identity (A-ID)
- *
- * If EAP-FAST is not used, this can be set to %NULL. In theory, this
- * is a variable length field, but due to some existing implementations
- * requiring A-ID to be 16 octets in length, it is recommended to use
- * that length for the field to provide interoperability with deployed
- * peer implementations.
- */
- u8 *eap_fast_a_id;
-
- /**
- * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
- */
- size_t eap_fast_a_id_len;
-
- /**
- * eap_fast_a_id_info - EAP-FAST authority identifier information
- *
- * This A-ID-Info contains a user-friendly name for the A-ID. For
- * example, this could be the enterprise and server names in
- * human-readable format. This field is encoded as UTF-8. If EAP-FAST
- * is not used, this can be set to %NULL.
- */
- char *eap_fast_a_id_info;
-
- /**
- * eap_fast_prov - EAP-FAST provisioning modes
- *
- * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
- * 2 = only authenticated provisioning allowed, 3 = both provisioning
- * modes allowed.
- */
- int eap_fast_prov;
-
- /**
- * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
- *
- * This is the hard limit on how long a provisioned PAC-Key can be
- * used.
- */
- int pac_key_lifetime;
-
- /**
- * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
- *
- * This is a soft limit on the PAC-Key. The server will automatically
- * generate a new PAC-Key when this number of seconds (or fewer) of the
- * lifetime remains.
- */
- int pac_key_refresh_time;
-
- int eap_teap_auth;
- int eap_teap_pac_no_inner;
-
- /**
- * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
- *
- * This controls whether the protected success/failure indication
- * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
- */
- int eap_sim_aka_result_ind;
-
- /**
- * tnc - Trusted Network Connect (TNC)
- *
- * This controls whether TNC is enabled and will be required before the
- * peer is allowed to connect. Note: This is only used with EAP-TTLS
- * and EAP-FAST. If any other EAP method is enabled, the peer will be
- * allowed to connect without TNC.
- */
- int tnc;
-
- /**
- * pwd_group - EAP-pwd D-H group
- *
- * This is used to select which D-H group to use with EAP-pwd.
- */
- u16 pwd_group;
-
- /**
- * server_id - Server identity
- */
- const char *server_id;
-
- /**
- * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
- *
- * This controls whether the authentication server derives ERP key
- * hierarchy (rRK and rIK) from full EAP authentication and allows
- * these keys to be used to perform ERP to derive rMSK instead of full
- * EAP authentication to derive MSK.
- */
- int erp;
-
const char *erp_domain;
- unsigned int tls_session_lifetime;
-
- unsigned int tls_flags;
-
- /**
- * wps - Wi-Fi Protected Setup context
- *
- * If WPS is used with an external RADIUS server (which is quite
- * unlikely configuration), this is used to provide a pointer to WPS
- * context data. Normally, this can be set to %NULL.
- */
- struct wps_context *wps;
-
/**
* ipv6 - Whether to enable IPv6 support in the RADIUS server
*/
@@ -225,11 +92,6 @@
*/
size_t eap_req_id_text_len;
- /*
- * msg_ctx - Context data for wpa_msg() calls
- */
- void *msg_ctx;
-
#ifdef CONFIG_RADIUS_TEST
const char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
@@ -239,6 +101,8 @@
char *hs20_sim_provisioning_url;
char *t_c_server_url;
+
+ struct eap_config *eap_cfg;
};
diff --git a/src/rsn_supp/Makefile b/src/rsn_supp/Makefile
index c2d81f2..eea0efb 100644
--- a/src/rsn_supp/Makefile
+++ b/src/rsn_supp/Makefile
@@ -8,7 +8,6 @@
include ../lib.rules
-CFLAGS += -DCONFIG_IEEE80211W
CFLAGS += -DCONFIG_IEEE80211R
CFLAGS += -DCONFIG_TDLS
CFLAGS += -DCONFIG_WNM
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index c6d0298..ace0b6a 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -655,51 +655,51 @@
kde = sm->assoc_wpa_ie;
kde_len = sm->assoc_wpa_ie_len;
+ kde_buf = os_malloc(kde_len +
+ 2 + RSN_SELECTOR_LEN + 3 +
+ sm->assoc_rsnxe_len +
+ 2 + RSN_SELECTOR_LEN + 1);
+ if (!kde_buf)
+ goto failed;
+ os_memcpy(kde_buf, kde, kde_len);
+ kde = kde_buf;
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm)) {
struct wpa_channel_info ci;
u8 *pos;
+ pos = kde + kde_len;
if (wpa_sm_channel_info(sm, &ci) != 0) {
wpa_printf(MSG_WARNING,
"Failed to get channel info for OCI element in EAPOL-Key 2/4");
goto failed;
}
- kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 3);
- if (!kde_buf) {
- wpa_printf(MSG_WARNING,
- "Failed to allocate memory for KDE with OCI in EAPOL-Key 2/4");
- goto failed;
- }
-
- os_memcpy(kde_buf, kde, kde_len);
- kde = kde_buf;
- pos = kde + kde_len;
if (ocv_insert_oci_kde(&ci, &pos) < 0)
goto failed;
kde_len = pos - kde;
}
#endif /* CONFIG_OCV */
+ if (sm->assoc_rsnxe && sm->assoc_rsnxe_len) {
+ os_memcpy(kde + kde_len, sm->assoc_rsnxe, sm->assoc_rsnxe_len);
+ kde_len += sm->assoc_rsnxe_len;
+ }
+
#ifdef CONFIG_P2P
if (sm->p2p) {
- kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
- if (kde_buf) {
- u8 *pos;
- wpa_printf(MSG_DEBUG, "P2P: Add IP Address Request KDE "
- "into EAPOL-Key 2/4");
- os_memcpy(kde_buf, kde, kde_len);
- kde = kde_buf;
- pos = kde + kde_len;
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = RSN_SELECTOR_LEN + 1;
- RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
- pos += RSN_SELECTOR_LEN;
- *pos++ = 0x01;
- kde_len = pos - kde;
- }
+ u8 *pos;
+
+ wpa_printf(MSG_DEBUG,
+ "P2P: Add IP Address Request KDE into EAPOL-Key 2/4");
+ pos = kde + kde_len;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + 1;
+ RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
+ pos += RSN_SELECTOR_LEN;
+ *pos++ = 0x01;
+ kde_len = pos - kde;
}
#endif /* CONFIG_P2P */
@@ -1051,7 +1051,6 @@
}
-#ifdef CONFIG_IEEE80211W
static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
const struct wpa_igtk_kde *igtk,
int wnm_sleep)
@@ -1118,13 +1117,11 @@
return 0;
}
-#endif /* CONFIG_IEEE80211W */
static int ieee80211w_set_keys(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *ie)
{
-#ifdef CONFIG_IEEE80211W
if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
return 0;
@@ -1142,9 +1139,6 @@
}
return 0;
-#else /* CONFIG_IEEE80211W */
- return 0;
-#endif /* CONFIG_IEEE80211W */
}
@@ -1371,6 +1365,16 @@
return -1;
}
+ if ((sm->ap_rsnxe && !ie->rsnxe) ||
+ (!sm->ap_rsnxe && ie->rsnxe) ||
+ (sm->ap_rsnxe && ie->rsnxe &&
+ (sm->ap_rsnxe_len != ie->rsnxe_len ||
+ os_memcmp(sm->ap_rsnxe, ie->rsnxe, sm->ap_rsnxe_len) != 0))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: RSNXE mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
+ return -1;
+ }
+
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt) &&
wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0)
@@ -1455,7 +1459,6 @@
"WPA: GTK IE in unencrypted key data");
goto failed;
}
-#ifdef CONFIG_IEEE80211W
if (ie.igtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: IGTK KDE in unencrypted key data");
@@ -1471,7 +1474,6 @@
(unsigned long) ie.igtk_len);
goto failed;
}
-#endif /* CONFIG_IEEE80211W */
if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
goto failed;
@@ -2294,9 +2296,7 @@
key_info = WPA_GET_BE16(key->key_info);
ver = key_info & WPA_KEY_INFO_TYPE_MASK;
if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
!wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -2324,7 +2324,6 @@
}
} else
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
!wpa_use_akm_defined(sm->key_mgmt)) {
@@ -2333,11 +2332,9 @@
"negotiated AES-128-CMAC");
goto out;
}
- } else
-#endif /* CONFIG_IEEE80211W */
- if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
- !wpa_use_akm_defined(sm->key_mgmt) &&
- ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+ } else if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
+ !wpa_use_akm_defined(sm->key_mgmt) &&
+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: CCMP is used, but EAPOL-Key "
"descriptor version (%d) is not 2", ver);
@@ -2480,12 +2477,10 @@
case WPA_KEY_MGMT_FT_PSK:
return RSN_AUTH_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
case WPA_KEY_MGMT_IEEE8021X_SHA256:
return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
case WPA_KEY_MGMT_PSK_SHA256:
return RSN_AUTH_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
case WPA_KEY_MGMT_CCKM:
return (sm->proto == WPA_PROTO_RSN ?
RSN_AUTH_KEY_MGMT_CCKM:
@@ -2677,8 +2672,10 @@
eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
os_free(sm->assoc_wpa_ie);
+ os_free(sm->assoc_rsnxe);
os_free(sm->ap_wpa_ie);
os_free(sm->ap_rsn_ie);
+ os_free(sm->ap_rsnxe);
wpa_sm_drop_sa(sm);
os_free(sm->ctx);
#ifdef CONFIG_IEEE80211R
@@ -2768,10 +2765,8 @@
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
os_memset(&sm->gtk, 0, sizeof(sm->gtk));
os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
-#ifdef CONFIG_IEEE80211W
os_memset(&sm->igtk, 0, sizeof(sm->igtk));
os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
-#endif /* CONFIG_IEEE80211W */
}
#ifdef CONFIG_TDLS
@@ -3043,11 +3038,9 @@
case WPA_PARAM_KEY_MGMT:
sm->key_mgmt = value;
break;
-#ifdef CONFIG_IEEE80211W
case WPA_PARAM_MGMT_GROUP:
sm->mgmt_group_cipher = value;
break;
-#endif /* CONFIG_IEEE80211W */
case WPA_PARAM_RSN_ENABLED:
sm->rsn_enabled = value;
break;
@@ -3057,6 +3050,9 @@
case WPA_PARAM_OCV:
sm->ocv = value;
break;
+ case WPA_PARAM_SAE_PWE:
+ sm->sae_pwe = value;
+ break;
default:
break;
}
@@ -3235,6 +3231,83 @@
/**
+ * wpa_sm_set_assoc_rsnxe_default - Generate own RSNXE from configuration
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @rsnxe: Pointer to buffer for RSNXE
+ * @rsnxe_len: Pointer to the length of the rsne buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_sm_set_assoc_rsnxe_default(struct wpa_sm *sm, u8 *rsnxe,
+ size_t *rsnxe_len)
+{
+ int res;
+
+ if (!sm)
+ return -1;
+
+ res = wpa_gen_rsnxe(sm, rsnxe, *rsnxe_len);
+ if (res < 0)
+ return -1;
+ *rsnxe_len = res;
+
+ wpa_hexdump(MSG_DEBUG, "RSN: Set own RSNXE default", rsnxe, *rsnxe_len);
+
+ if (sm->assoc_rsnxe) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Leave previously set RSNXE default",
+ sm->assoc_rsnxe, sm->assoc_rsnxe_len);
+ } else if (*rsnxe_len > 0) {
+ /*
+ * Make a copy of the RSNXE so that 4-Way Handshake gets the
+ * correct version of the IE even if it gets changed.
+ */
+ sm->assoc_rsnxe = os_memdup(rsnxe, *rsnxe_len);
+ if (!sm->assoc_rsnxe)
+ return -1;
+
+ sm->assoc_rsnxe_len = *rsnxe_len;
+ }
+
+ return 0;
+}
+
+
+/**
+ * wpa_sm_set_assoc_rsnxe - Set own RSNXE from (Re)AssocReq
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the RSNXE used in (Re)Association Request
+ * frame. The IE will be used to override the default value generated
+ * with wpa_sm_set_assoc_rsnxe_default().
+ */
+int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+ if (!sm)
+ return -1;
+
+ os_free(sm->assoc_rsnxe);
+ if (!ie || len == 0) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: clearing own RSNXE");
+ sm->assoc_rsnxe = NULL;
+ sm->assoc_rsnxe_len = 0;
+ } else {
+ wpa_hexdump(MSG_DEBUG, "RSN: set own RSNXE", ie, len);
+ sm->assoc_rsnxe = os_memdup(ie, len);
+ if (!sm->assoc_rsnxe)
+ return -1;
+
+ sm->assoc_rsnxe_len = len;
+ }
+
+ return 0;
+}
+
+
+/**
* wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @ie: Pointer to IE data (starting from id)
@@ -3303,6 +3376,39 @@
/**
+ * wpa_sm_set_ap_rsnxe - Set AP RSNXE from Beacon/ProbeResp
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the RSNXE used in Beacon / Probe Response
+ * frame.
+ */
+int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+ if (!sm)
+ return -1;
+
+ os_free(sm->ap_rsnxe);
+ if (!ie || len == 0) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: clearing AP RSNXE");
+ sm->ap_rsnxe = NULL;
+ sm->ap_rsnxe_len = 0;
+ } else {
+ wpa_hexdump(MSG_DEBUG, "WPA: set AP RSNXE", ie, len);
+ sm->ap_rsnxe = os_memdup(ie, len);
+ if (!sm->ap_rsnxe)
+ return -1;
+
+ sm->ap_rsnxe_len = len;
+ }
+
+ return 0;
+}
+
+
+/**
* wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @data: Pointer to data area for parsing results
@@ -3375,10 +3481,8 @@
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
os_memset(&sm->gtk, 0, sizeof(sm->gtk));
os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
-#ifdef CONFIG_IEEE80211W
os_memset(&sm->igtk, 0, sizeof(sm->igtk));
os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
sm->xxkey_len = 0;
@@ -3452,14 +3556,12 @@
return -1;
}
forced_memzero(&gd, sizeof(gd));
-#ifdef CONFIG_IEEE80211W
} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
const struct wpa_igtk_kde *igtk;
igtk = (const struct wpa_igtk_kde *) (buf + 2);
if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0)
return -1;
-#endif /* CONFIG_IEEE80211W */
} else {
wpa_printf(MSG_DEBUG, "Unknown element id");
return -1;
@@ -4019,10 +4121,10 @@
/* RSN Capabilities */
capab = 0;
-#ifdef CONFIG_IEEE80211W
- if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
+ if (sm->mfp)
capab |= WPA_CAPABILITY_MFPC;
-#endif /* CONFIG_IEEE80211W */
+ if (sm->mfp == 2)
+ capab |= WPA_CAPABILITY_MFPR;
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
wpabuf_put_le16(buf, capab);
@@ -4062,13 +4164,11 @@
WPA_PMK_NAME_LEN);
os_memcpy(pos, sm->pmk_r1_name, WPA_PMK_NAME_LEN);
-#ifdef CONFIG_IEEE80211W
if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
/* Management Group Cipher Suite */
pos = wpabuf_put(buf, RSN_SELECTOR_LEN);
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
}
-#endif /* CONFIG_IEEE80211W */
rsnie->len = ((u8 *) wpabuf_put(buf, 0) - (u8 *) rsnie) - 2;
return 0;
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index ae9cd64..f1fbb1b 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -98,7 +98,8 @@
WPA_PARAM_MGMT_GROUP,
WPA_PARAM_RSN_ENABLED,
WPA_PARAM_MFP,
- WPA_PARAM_OCV
+ WPA_PARAM_OCV,
+ WPA_PARAM_SAE_PWE,
};
struct rsn_supp_config {
@@ -134,8 +135,12 @@
int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
size_t *wpa_ie_len);
+int wpa_sm_set_assoc_rsnxe_default(struct wpa_sm *sm, u8 *rsnxe,
+ size_t *rsnxe_len);
+int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
@@ -260,6 +265,12 @@
return -1;
}
+static inline int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie,
+ size_t len)
+{
+ return -1;
+}
+
static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
{
return 0;
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 46ffdca..2b8b41f 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -18,6 +18,7 @@
#include "drivers/driver.h"
#include "wpa.h"
#include "wpa_i.h"
+#include "wpa_ie.h"
#include "pmksa_cache.h"
#ifdef CONFIG_IEEE80211R
@@ -171,6 +172,9 @@
struct rsn_ie_hdr *rsnie;
u16 capab;
int mdie_len;
+ u8 rsnxe[10];
+ size_t rsnxe_len;
+ int res;
sm->ft_completed = 0;
sm->ft_reassoc_completed = 0;
@@ -246,13 +250,10 @@
/* RSN Capabilities */
capab = 0;
-#ifdef CONFIG_IEEE80211W
- if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC ||
- sm->mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_128 ||
- sm->mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_256 ||
- sm->mgmt_group_cipher == WPA_CIPHER_BIP_CMAC_256)
+ if (sm->mfp)
capab |= WPA_CAPABILITY_MFPC;
-#endif /* CONFIG_IEEE80211W */
+ if (sm->mfp == 2)
+ capab |= WPA_CAPABILITY_MFPR;
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
WPA_PUT_LE16(pos, capab);
@@ -266,7 +267,6 @@
os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN);
pos += WPA_PMK_NAME_LEN;
-#ifdef CONFIG_IEEE80211W
/* Management Group Cipher Suite */
switch (sm->mgmt_group_cipher) {
case WPA_CIPHER_AES_128_CMAC:
@@ -286,7 +286,6 @@
pos += RSN_SELECTOR_LEN;
break;
}
-#endif /* CONFIG_IEEE80211W */
rsnie->len = (pos - (u8 *) rsnie) - 2;
@@ -364,6 +363,13 @@
pos += ric_ies_len;
}
+ res = wpa_gen_rsnxe(sm, rsnxe, sizeof(rsnxe));
+ if (res < 0) {
+ os_free(buf);
+ return NULL;
+ }
+ rsnxe_len = res;
+
if (kck) {
/*
* IEEE Std 802.11r-2008, 11A.8.4
@@ -375,14 +381,18 @@
* MDIE
* FTIE (with MIC field set to 0)
* RIC-Request (if present)
+ * RSNXE (if present)
*/
/* Information element count */
*elem_count = 3 + ieee802_11_ie_count(ric_ies, ric_ies_len);
+ if (rsnxe_len)
+ *elem_count += 1;
if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5,
((u8 *) mdie) - 2, 2 + sizeof(*mdie),
ftie_pos, 2 + *ftie_len,
(u8 *) rsnie, 2 + rsnie->len, ric_ies,
- ric_ies_len, fte_mic) < 0) {
+ ric_ies_len, rsnxe_len ? rsnxe : NULL, rsnxe_len,
+ fte_mic) < 0) {
wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
os_free(buf);
return NULL;
@@ -598,6 +608,12 @@
return -1;
}
+ if (sm->mfp == 2 && !(parse.rsn_capab & WPA_CAPABILITY_MFPC)) {
+ wpa_printf(MSG_INFO,
+ "FT: Target AP does not support PMF, but local configuration requires that");
+ return -1;
+ }
+
os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
@@ -767,7 +783,6 @@
}
-#ifdef CONFIG_IEEE80211W
static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
size_t igtk_elem_len)
{
@@ -835,7 +850,6 @@
return 0;
}
-#endif /* CONFIG_IEEE80211W */
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
@@ -962,6 +976,8 @@
count = 3;
if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len);
+ if (parse.rsnxe)
+ count++;
if (fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
@@ -982,6 +998,8 @@
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
parse.ric, parse.ric_len,
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0,
mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
return -1;
@@ -1018,10 +1036,8 @@
if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
return -1;
-#ifdef CONFIG_IEEE80211W
if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
return -1;
-#endif /* CONFIG_IEEE80211W */
if (sm->set_ptk_after_assoc) {
wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we "
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index d86734b..2a43342 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -31,10 +31,8 @@
u8 request_counter[WPA_REPLAY_COUNTER_LEN];
struct wpa_gtk gtk;
struct wpa_gtk gtk_wnm_sleep;
-#ifdef CONFIG_IEEE80211W
struct wpa_igtk igtk;
struct wpa_igtk igtk_wnm_sleep;
-#endif /* CONFIG_IEEE80211W */
struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
@@ -87,11 +85,14 @@
int rsn_enabled; /* Whether RSN is enabled in configuration */
int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
int ocv; /* Operating Channel Validation */
+ int sae_pwe; /* SAE PWE generation options */
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
size_t assoc_wpa_ie_len;
- u8 *ap_wpa_ie, *ap_rsn_ie;
- size_t ap_wpa_ie_len, ap_rsn_ie_len;
+ u8 *assoc_rsnxe; /* Own RSNXE from (Re)AssocReq */
+ size_t assoc_rsnxe_len;
+ u8 *ap_wpa_ie, *ap_rsn_ie, *ap_rsnxe;
+ size_t ap_wpa_ie_len, ap_rsn_ie_len, ap_rsnxe_len;
#ifdef CONFIG_TDLS
struct wpa_tdls_peer *tdls;
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index ae9f4ca..03c0d7e 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -168,12 +168,10 @@
} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
} else if (key_mgmt == WPA_KEY_MGMT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
@@ -217,12 +215,10 @@
/* RSN Capabilities */
capab = 0;
-#ifdef CONFIG_IEEE80211W
if (sm->mfp)
capab |= WPA_CAPABILITY_MFPC;
if (sm->mfp == 2)
capab |= WPA_CAPABILITY_MFPR;
-#endif /* CONFIG_IEEE80211W */
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
WPA_PUT_LE16(pos, capab);
@@ -237,7 +233,6 @@
pos += PMKID_LEN;
}
-#ifdef CONFIG_IEEE80211W
if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
if (!sm->cur_pmksa) {
/* PMKID Count */
@@ -250,7 +245,6 @@
mgmt_group_cipher));
pos += RSN_SELECTOR_LEN;
}
-#endif /* CONFIG_IEEE80211W */
hdr->len = (pos - rsn_ie) - 2;
@@ -348,261 +342,23 @@
}
-/**
- * wpa_parse_vendor_specific - Parse Vendor Specific IEs
- * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, 1 if end mark is found, -1 on failure
- */
-static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
- struct wpa_eapol_ie_parse *ie)
+int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
{
- unsigned int oui;
+ u8 *pos = rsnxe;
- if (pos[1] < 4) {
- wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)",
- pos[1]);
- return 1;
- }
+ if (!wpa_key_mgmt_sae(sm->key_mgmt))
+ return 0; /* SAE not in use */
+ if (sm->sae_pwe != 1 && sm->sae_pwe != 2)
+ return 0; /* no supported extended RSN capabilities */
- oui = WPA_GET_BE24(&pos[2]);
- if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
- if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
- ie->wmm = &pos[2];
- ie->wmm_len = pos[1];
- wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
- ie->wmm, ie->wmm_len);
- } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
- ie->wmm = &pos[2];
- ie->wmm_len = pos[1];
- wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
- ie->wmm, ie->wmm_len);
- }
- }
- return 0;
-}
+ if (rsnxe_len < 3)
+ return -1;
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = 1;
+ /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
+ * used for now */
+ *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
-/**
- * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
- * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, 1 if end mark is found, -1 on failure
- */
-static int wpa_parse_generic(const u8 *pos, const u8 *end,
- struct wpa_eapol_ie_parse *ie)
-{
- if (pos[1] == 0)
- return 1;
-
- if (pos[1] >= 6 &&
- RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
- pos[2 + WPA_SELECTOR_LEN] == 1 &&
- pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
- ie->wpa_ie = pos;
- ie->wpa_ie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
- ie->wpa_ie, ie->wpa_ie_len);
- return 0;
- }
-
- if (1 + RSN_SELECTOR_LEN < end - pos &&
- pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
- ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
- ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
- ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
- ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
-#ifdef CONFIG_IEEE80211W
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
- ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-#endif /* CONFIG_IEEE80211W */
-
-#ifdef CONFIG_P2P
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
- ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
- ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-
- if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
- ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG,
- "WPA: IP Address Allocation in EAPOL-Key",
- ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-#endif /* CONFIG_P2P */
-
-#ifdef CONFIG_OCV
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
- ie->oci = pos + 2 + RSN_SELECTOR_LEN;
- ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-#endif /* CONFIG_OCV */
-
- return 0;
-}
-
-
-/**
- * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
- * @buf: Pointer to the Key Data buffer
- * @len: Key Data Length
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, -1 on failure
- */
-int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
- struct wpa_eapol_ie_parse *ie)
-{
- const u8 *pos, *end;
- int ret = 0;
-
- os_memset(ie, 0, sizeof(*ie));
- for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
- if (pos[0] == 0xdd &&
- ((pos == buf + len - 1) || pos[1] == 0)) {
- /* Ignore padding */
- break;
- }
- if (2 + pos[1] > end - pos) {
- wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
- "underflow (ie=%d len=%d pos=%d)",
- pos[0], pos[1], (int) (pos - buf));
- wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
- buf, len);
- ret = -1;
- break;
- }
- if (*pos == WLAN_EID_RSN) {
- ie->rsn_ie = pos;
- ie->rsn_ie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
- ie->rsn_ie, ie->rsn_ie_len);
- } else if (*pos == WLAN_EID_MOBILITY_DOMAIN &&
- pos[1] >= sizeof(struct rsn_mdie)) {
- ie->mdie = pos;
- ie->mdie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
- ie->mdie, ie->mdie_len);
- } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION &&
- pos[1] >= sizeof(struct rsn_ftie)) {
- ie->ftie = pos;
- ie->ftie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
- ie->ftie, ie->ftie_len);
- } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
- if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
- ie->reassoc_deadline = pos;
- wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
- "in EAPOL-Key",
- ie->reassoc_deadline, pos[1] + 2);
- } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
- ie->key_lifetime = pos;
- wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
- "in EAPOL-Key",
- ie->key_lifetime, pos[1] + 2);
- } else {
- wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
- "EAPOL-Key Key Data IE",
- pos, 2 + pos[1]);
- }
- } else if (*pos == WLAN_EID_LINK_ID) {
- if (pos[1] >= 18) {
- ie->lnkid = pos;
- ie->lnkid_len = pos[1] + 2;
- }
- } else if (*pos == WLAN_EID_EXT_CAPAB) {
- ie->ext_capab = pos;
- ie->ext_capab_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_SUPP_RATES) {
- ie->supp_rates = pos;
- ie->supp_rates_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
- ie->ext_supp_rates = pos;
- ie->ext_supp_rates_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_HT_CAP &&
- pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
- ie->ht_capabilities = pos + 2;
- } else if (*pos == WLAN_EID_VHT_AID) {
- if (pos[1] >= 2)
- ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
- } else if (*pos == WLAN_EID_VHT_CAP &&
- pos[1] >= sizeof(struct ieee80211_vht_capabilities))
- {
- ie->vht_capabilities = pos + 2;
- } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
- ie->qosinfo = pos[2];
- } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
- ie->supp_channels = pos + 2;
- ie->supp_channels_len = pos[1];
- } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
- /*
- * The value of the Length field of the Supported
- * Operating Classes element is between 2 and 253.
- * Silently skip invalid elements to avoid interop
- * issues when trying to use the value.
- */
- if (pos[1] >= 2 && pos[1] <= 253) {
- ie->supp_oper_classes = pos + 2;
- ie->supp_oper_classes_len = pos[1];
- }
- } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
- ret = wpa_parse_generic(pos, end, ie);
- if (ret < 0)
- break;
- if (ret > 0) {
- ret = 0;
- break;
- }
-
- ret = wpa_parse_vendor_specific(pos, end, ie);
- if (ret < 0)
- break;
- if (ret > 0) {
- ret = 0;
- break;
- }
- } else {
- wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
- "Key Data IE", pos, 2 + pos[1]);
- }
- }
-
- return ret;
+ return pos - rsnxe;
}
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 9d53973..6dc6cf5 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -11,56 +11,7 @@
struct wpa_sm;
-struct wpa_eapol_ie_parse {
- const u8 *wpa_ie;
- size_t wpa_ie_len;
- const u8 *rsn_ie;
- size_t rsn_ie_len;
- const u8 *pmkid;
- const u8 *gtk;
- size_t gtk_len;
- const u8 *mac_addr;
- size_t mac_addr_len;
-#ifdef CONFIG_IEEE80211W
- const u8 *igtk;
- size_t igtk_len;
-#endif /* CONFIG_IEEE80211W */
- const u8 *mdie;
- size_t mdie_len;
- const u8 *ftie;
- size_t ftie_len;
- const u8 *reassoc_deadline;
- const u8 *key_lifetime;
- const u8 *lnkid;
- size_t lnkid_len;
- const u8 *ext_capab;
- size_t ext_capab_len;
- const u8 *supp_rates;
- size_t supp_rates_len;
- const u8 *ext_supp_rates;
- size_t ext_supp_rates_len;
- const u8 *ht_capabilities;
- const u8 *vht_capabilities;
- const u8 *supp_channels;
- size_t supp_channels_len;
- const u8 *supp_oper_classes;
- size_t supp_oper_classes_len;
- u8 qosinfo;
- u16 aid;
- const u8 *wmm;
- size_t wmm_len;
-#ifdef CONFIG_P2P
- const u8 *ip_addr_req;
- const u8 *ip_addr_alloc;
-#endif /* CONFIG_P2P */
-#ifdef CONFIG_OCV
- const u8 *oci;
- size_t oci_len;
-#endif /* CONFIG_OCV */
-};
-
-int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
- struct wpa_eapol_ie_parse *ie);
int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len);
+int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len);
#endif /* WPA_IE_H */
diff --git a/src/utils/common.h b/src/utils/common.h
index 1741145..833469a 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -344,6 +344,9 @@
#ifndef ETH_P_OUI
#define ETH_P_OUI 0x88B7
#endif /* ETH_P_OUI */
+#ifndef ETH_P_8021Q
+#define ETH_P_8021Q 0x8100
+#endif /* ETH_P_8021Q */
#ifdef __GNUC__
diff --git a/src/utils/json.c b/src/utils/json.c
index b644339..3e5e214 100644
--- a/src/utils/json.c
+++ b/src/utils/json.c
@@ -51,7 +51,7 @@
*txt++ = data[i];
} else {
txt += os_snprintf(txt, end - txt, "\\u%04x",
- data[i]);
+ (unsigned char) data[i]);
}
break;
}
diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c
index 474c8a3..feade6e 100644
--- a/src/utils/os_internal.c
+++ b/src/utils/os_internal.c
@@ -25,10 +25,16 @@
void os_sleep(os_time_t sec, os_time_t usec)
{
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
+ const struct timespec req = { sec, usec * 1000 };
+
+ nanosleep(&req, NULL);
+#else
if (sec)
sleep(sec);
if (usec)
usleep(usec);
+#endif
}
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index b56bab2..494bf4c 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -51,10 +51,16 @@
void os_sleep(os_time_t sec, os_time_t usec)
{
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
+ const struct timespec req = { sec, usec * 1000 };
+
+ nanosleep(&req, NULL);
+#else
if (sec)
sleep(sec);
if (usec)
usleep(usec);
+#endif
}
diff --git a/src/utils/trace.c b/src/utils/trace.c
index e0b5b0b..4084343 100644
--- a/src/utils/trace.c
+++ b/src/utils/trace.c
@@ -186,7 +186,7 @@
if (abfd == NULL)
return;
- data.pc = (bfd_hostptr_t) (pc - start_offset);
+ data.pc = (bfd_hostptr_t) ((u8 *) pc - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -227,7 +227,7 @@
if (abfd == NULL)
return NULL;
- data.pc = (bfd_hostptr_t) (pc - start_offset);
+ data.pc = (bfd_hostptr_t) ((u8 *) pc - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -299,7 +299,7 @@
for (i = 0; i < btrace_num; i++) {
struct bfd_data data;
- data.pc = (bfd_hostptr_t) (btrace_res[i] - start_offset);
+ data.pc = (bfd_hostptr_t) ((u8 *) btrace_res[i] - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index 1fe0b7d..c94c439 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -305,7 +305,6 @@
#define HOSTAPD_MODULE_RADIUS 0x00000004
#define HOSTAPD_MODULE_WPA 0x00000008
#define HOSTAPD_MODULE_DRIVER 0x00000010
-#define HOSTAPD_MODULE_IAPP 0x00000020
#define HOSTAPD_MODULE_MLME 0x00000040
enum hostapd_logger_level {
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index 4e872f3..5ec7133 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -175,7 +175,9 @@
len[0] = wpabuf_len(wps->last_msg);
addr[1] = wpabuf_head(msg);
len[1] = wpabuf_len(msg);
- hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
+ if (hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len,
+ hash) < 0)
+ return -1;
wpa_printf(MSG_DEBUG, "WPS: * Authenticator");
wpabuf_put_be16(msg, ATTR_AUTHENTICATOR);
@@ -371,8 +373,9 @@
u8 hash[SHA256_MAC_LEN];
wpa_printf(MSG_DEBUG, "WPS: * Key Wrap Authenticator");
- hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
- wpabuf_len(msg), hash);
+ if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
+ wpabuf_len(msg), hash) < 0)
+ return -1;
wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH);
wpabuf_put_be16(msg, WPS_KWA_LEN);
diff --git a/src/wps/wps_attr_process.c b/src/wps/wps_attr_process.c
index e8c4579..44436a4 100644
--- a/src/wps/wps_attr_process.c
+++ b/src/wps/wps_attr_process.c
@@ -39,9 +39,10 @@
len[0] = wpabuf_len(wps->last_msg);
addr[1] = wpabuf_head(msg);
len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN;
- hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
- if (os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
+ if (hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len,
+ hash) < 0 ||
+ os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator");
return -1;
}
@@ -70,8 +71,8 @@
return -1;
}
- hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash);
- if (os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
+ if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash) < 0 ||
+ os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Invalid KWA");
return -1;
}
diff --git a/tests/fuzzing/eap-aka-peer/Makefile b/tests/fuzzing/eap-aka-peer/Makefile
deleted file mode 100644
index d1a4cd3..0000000
--- a/tests/fuzzing/eap-aka-peer/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-all: eap-aka-peer
-include ../rules.include
-
-CFLAGS += -DIEEE8021X_EAPOL
-CFLAGS += -DCONFIG_USIM_SIMULATOR
-
-OBJS += $(SRC)/eap_peer/eap_aka.o
-OBJS += $(SRC)/eap_common/eap_sim_common.o
-OBJS += $(SRC)/eap_common/eap_common.o
-LIBS += $(SRC)/crypto/libcrypto.a
-LIBS += $(SRC)/utils/libutils.a
-
-eap-aka-peer: eap-aka-peer.o $(OBJS) $(LIBS)
- $(Q)$(LDO) $(LDFLAGS) -o $@ $^ $(LIBS) $(ELIBS)
- @$(E) " LD " $@
-
-clean:
- $(MAKE) -C $(SRC) clean
- rm -f eap-aka-peer *~ *.o *.d ../*~ ../*.o ../*.d
-
--include $(OBJS:%.o=%.d)
diff --git a/tests/fuzzing/eap-aka-peer/corpus/server.msg b/tests/fuzzing/eap-aka-peer/corpus/server.msg
deleted file mode 100644
index 6484391..0000000
--- a/tests/fuzzing/eap-aka-peer/corpus/server.msg
+++ /dev/null
Binary files differ
diff --git a/tests/fuzzing/eap-aka-peer/eap-aka-peer.c b/tests/fuzzing/eap-aka-peer/eap-aka-peer.c
deleted file mode 100644
index e36c6ca..0000000
--- a/tests/fuzzing/eap-aka-peer/eap-aka-peer.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * EAP-AKA peer fuzzer
- * Copyright (c) 2019, 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 "eap_peer/eap_methods.h"
-#include "eap_peer/eap_config.h"
-#include "eap_peer/eap_i.h"
-#include "../fuzzer-common.h"
-
-int eap_peer_sim_register(void);
-
-struct eap_method * registered_eap_method = NULL;
-
-
-struct eap_method * eap_peer_method_alloc(int version, int vendor,
- EapType method, const char *name)
-{
- struct eap_method *eap;
- eap = os_zalloc(sizeof(*eap));
- if (!eap)
- return NULL;
- eap->version = version;
- eap->vendor = vendor;
- eap->method = method;
- eap->name = name;
- return eap;
-}
-
-
-int eap_peer_method_register(struct eap_method *method)
-{
- registered_eap_method = method;
- return 0;
-}
-
-
-static struct eap_peer_config eap_aka_config = {
- .identity = (u8 *) "0232010000000000",
- .identity_len = 16,
- .password = (u8 *) "90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
- .password_len = 78,
-};
-
-struct eap_peer_config * eap_get_config(struct eap_sm *sm)
-{
- return &eap_aka_config;
-}
-
-
-const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
-{
- static const char *id = "0232010000000000";
-
- *len = os_strlen(id);
- return (const u8 *) id;
-}
-
-
-const char * eap_get_config_phase1(struct eap_sm *sm)
-{
- return NULL;
-}
-
-
-void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len)
-{
-}
-
-
-void eap_sm_request_identity(struct eap_sm *sm)
-{
-}
-
-
-void eap_sm_request_sim(struct eap_sm *sm, const char *req)
-{
-}
-
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- const u8 *pos, *end;
- struct eap_sm *sm;
- void *priv;
- struct eap_method_ret ret;
-
- wpa_fuzzer_set_debug_level();
-
- eap_peer_aka_register();
- sm = os_zalloc(sizeof(*sm));
- if (!sm)
- return 0;
- priv = registered_eap_method->init(sm);
- os_memset(&ret, 0, sizeof(ret));
-
- pos = data;
- end = pos + size;
-
- while (end - pos > 2) {
- u16 flen;
- struct wpabuf *buf, *req;
-
- flen = WPA_GET_BE16(pos);
- pos += 2;
- if (end - pos < flen)
- break;
- req = wpabuf_alloc_copy(pos, flen);
- if (!req)
- break;
- wpa_hexdump_buf(MSG_MSGDUMP, "fuzzer - request", req);
- buf = registered_eap_method->process(sm, priv, &ret, req);
- wpa_hexdump_buf(MSG_MSGDUMP, "fuzzer - local response", buf);
- wpabuf_free(req);
- wpabuf_free(buf);
- pos += flen;
- }
-
- registered_eap_method->deinit(sm, priv);
- os_free(registered_eap_method);
- os_free(sm);
-
- return 0;
-}
diff --git a/tests/fuzzing/eap-sim-peer/Makefile b/tests/fuzzing/eap-sim-peer/Makefile
deleted file mode 100644
index 302717e..0000000
--- a/tests/fuzzing/eap-sim-peer/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-all: eap-sim-peer
-include ../rules.include
-
-CFLAGS += -DIEEE8021X_EAPOL
-CFLAGS += -DCONFIG_SIM_SIMULATOR
-
-OBJS += $(SRC)/eap_peer/eap_sim.o
-OBJS += $(SRC)/eap_common/eap_sim_common.o
-OBJS += $(SRC)/eap_common/eap_common.o
-LIBS += $(SRC)/crypto/libcrypto.a
-LIBS += $(SRC)/utils/libutils.a
-
-eap-sim-peer: eap-sim-peer.o $(OBJS) $(LIBS)
- $(Q)$(LDO) $(LDFLAGS) -o $@ $^ $(LIBS) $(ELIBS)
- @$(E) " LD " $@
-
-clean:
- $(MAKE) -C $(SRC) clean
- rm -f eap-sim-peer *~ *.o *.d ../*~ ../*.o ../*.d
-
--include $(OBJS:%.o=%.d)
diff --git a/tests/fuzzing/eap-sim-peer/corpus/server.msg b/tests/fuzzing/eap-sim-peer/corpus/server.msg
deleted file mode 100644
index adb9f6c..0000000
--- a/tests/fuzzing/eap-sim-peer/corpus/server.msg
+++ /dev/null
Binary files differ
diff --git a/tests/fuzzing/eap-sim-peer/eap-sim-peer.c b/tests/fuzzing/eap-sim-peer/eap-sim-peer.c
deleted file mode 100644
index ce701f3..0000000
--- a/tests/fuzzing/eap-sim-peer/eap-sim-peer.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * EAP-SIM peer fuzzer
- * Copyright (c) 2019, 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 "eap_peer/eap_methods.h"
-#include "eap_peer/eap_config.h"
-#include "eap_peer/eap_i.h"
-#include "../fuzzer-common.h"
-
-int eap_peer_sim_register(void);
-
-struct eap_method * registered_eap_method = NULL;
-
-
-struct eap_method * eap_peer_method_alloc(int version, int vendor,
- EapType method, const char *name)
-{
- struct eap_method *eap;
- eap = os_zalloc(sizeof(*eap));
- if (!eap)
- return NULL;
- eap->version = version;
- eap->vendor = vendor;
- eap->method = method;
- eap->name = name;
- return eap;
-}
-
-
-int eap_peer_method_register(struct eap_method *method)
-{
- registered_eap_method = method;
- return 0;
-}
-
-
-static struct eap_peer_config eap_sim_config = {
- .identity = (u8 *) "1232010000000000",
- .identity_len = 16,
- .password = (u8 *) "90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
- .password_len = 65,
-};
-
-struct eap_peer_config * eap_get_config(struct eap_sm *sm)
-{
- return &eap_sim_config;
-}
-
-
-const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
-{
- static const char *id = "1232010000000000";
-
- *len = os_strlen(id);
- return (const u8 *) id;
-}
-
-
-void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len)
-{
-}
-
-
-void eap_sm_request_identity(struct eap_sm *sm)
-{
-}
-
-
-void eap_sm_request_sim(struct eap_sm *sm, const char *req)
-{
-}
-
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- const u8 *pos, *end;
- struct eap_sm *sm;
- void *priv;
- struct eap_method_ret ret;
-
- wpa_fuzzer_set_debug_level();
-
- eap_peer_sim_register();
- sm = os_zalloc(sizeof(*sm));
- if (!sm)
- return 0;
- priv = registered_eap_method->init(sm);
- os_memset(&ret, 0, sizeof(ret));
-
- pos = data;
- end = pos + size;
-
- while (end - pos > 2) {
- u16 flen;
- struct wpabuf *buf, *req;
-
- flen = WPA_GET_BE16(pos);
- pos += 2;
- if (end - pos < flen)
- break;
- req = wpabuf_alloc_copy(pos, flen);
- if (!req)
- break;
- wpa_hexdump_buf(MSG_MSGDUMP, "fuzzer - request", req);
- buf = registered_eap_method->process(sm, priv, &ret, req);
- wpa_hexdump_buf(MSG_MSGDUMP, "fuzzer - local response", buf);
- wpabuf_free(req);
- wpabuf_free(buf);
- pos += flen;
- }
-
- registered_eap_method->deinit(sm, priv);
- os_free(registered_eap_method);
- os_free(sm);
-
- return 0;
-}
diff --git a/tests/test-eapol.c b/tests/test-eapol.c
deleted file mode 100644
index 57f2118..0000000
--- a/tests/test-eapol.c
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * Testing tool for EAPOL-Key Supplicant/Authenticator routines
- * Copyright (c) 2006-2019, 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 "utils/eloop.h"
-#include "rsn_supp/wpa.h"
-#include "ap/wpa_auth.h"
-
-
-struct wpa {
- enum { AUTH, SUPP } test_peer;
- enum { READ, WRITE } test_oper;
- FILE *f;
- int wpa1;
-
- u8 auth_addr[ETH_ALEN];
- u8 supp_addr[ETH_ALEN];
- u8 psk[PMK_LEN];
-
- /* from authenticator */
- u8 *auth_eapol;
- size_t auth_eapol_len;
-
- /* from supplicant */
- u8 *supp_eapol;
- size_t supp_eapol_len;
-
- struct wpa_sm *supp;
- struct wpa_authenticator *auth_group;
- struct wpa_state_machine *auth;
-
- u8 supp_ie[80];
- size_t supp_ie_len;
-
- int key_request_done;
- int key_request_done1;
- int auth_sent;
-};
-
-
-const struct wpa_driver_ops *const wpa_drivers[] = { NULL };
-
-
-static int auth_read_msg(struct wpa *wpa);
-static void supp_eapol_key_request(void *eloop_data, void *user_ctx);
-
-
-static void usage(void) {
- wpa_printf(MSG_INFO,
- "usage: test-eapol <auth/supp> <read/write> <file>");
- exit(-1);
-}
-
-
-static void write_msg(FILE *f, const u8 *msg, size_t msg_len)
-{
- u8 len[2];
-
- wpa_printf(MSG_DEBUG, "TEST: Write message to file (msg_len=%u)",
- (unsigned int) msg_len);
- WPA_PUT_BE16(len, msg_len);
- fwrite(len, 2, 1, f);
- fwrite(msg, msg_len, 1, f);
-}
-
-
-static u8 * read_msg(FILE *f, size_t *ret_len)
-{
- u8 len[2];
- u16 msg_len;
- u8 *msg;
-
- if (fread(len, 2, 1, f) != 1) {
- wpa_printf(MSG_ERROR, "TEST-ERROR: Could not read msg len");
- eloop_terminate();
- return NULL;
- }
- msg_len = WPA_GET_BE16(len);
-
- msg = os_malloc(msg_len);
- if (!msg)
- return NULL;
- if (msg_len > 0 && fread(msg, msg_len, 1, f) != 1) {
- wpa_printf(MSG_ERROR, "TEST-ERROR: Truncated msg (msg_len=%u)",
- msg_len);
- os_free(msg);
- eloop_terminate();
- return NULL;
- }
- wpa_hexdump(MSG_DEBUG, "TEST: Read message from file", msg, msg_len);
-
- *ret_len = msg_len;
- return msg;
-}
-
-
-static int supp_get_bssid(void *ctx, u8 *bssid)
-{
- struct wpa *wpa = ctx;
- wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
- os_memcpy(bssid, wpa->auth_addr, ETH_ALEN);
- return 0;
-}
-
-
-static void supp_set_state(void *ctx, enum wpa_states state)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s(state=%d)", __func__, state);
-}
-
-
-static void auth_eapol_rx(void *eloop_data, void *user_ctx)
-{
- struct wpa *wpa = eloop_data;
-
- wpa_printf(MSG_DEBUG, "AUTH: RX EAPOL frame");
- wpa->auth_sent = 0;
- wpa_receive(wpa->auth_group, wpa->auth, wpa->supp_eapol,
- wpa->supp_eapol_len);
- if (!wpa->auth_sent && wpa->test_peer == SUPP &&
- wpa->test_oper == READ) {
- /* Speed up process by not going through retransmit timeout */
- wpa_printf(MSG_DEBUG,
- "AUTH: No response was sent - process next message");
- auth_read_msg(wpa);
- }
- if (wpa->wpa1 && wpa->key_request_done && !wpa->key_request_done1) {
- wpa->key_request_done1 = 1;
- eloop_register_timeout(0, 0, supp_eapol_key_request,
- wpa, NULL);
- }
-
-}
-
-
-static void supp_eapol_rx(void *eloop_data, void *user_ctx)
-{
- struct wpa *wpa = eloop_data;
-
- wpa_printf(MSG_DEBUG, "SUPP: RX EAPOL frame");
- wpa_sm_rx_eapol(wpa->supp, wpa->auth_addr, wpa->auth_eapol,
- wpa->auth_eapol_len);
-}
-
-
-static int supp_read_msg(struct wpa *wpa)
-{
- os_free(wpa->auth_eapol);
- wpa->auth_eapol = read_msg(wpa->f, &wpa->auth_eapol_len);
- if (!wpa->auth_eapol)
- return -1;
- eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL);
- return 0;
-}
-
-
-static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
- size_t len)
-{
- struct wpa *wpa = ctx;
-
- wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
- "len=%lu)",
- __func__, MAC2STR(dest), proto, (unsigned long) len);
-
- if (wpa->test_peer == SUPP && wpa->test_oper == WRITE)
- write_msg(wpa->f, buf, len);
-
- if (wpa->test_peer == AUTH && wpa->test_oper == READ)
- return supp_read_msg(wpa);
-
- os_free(wpa->supp_eapol);
- wpa->supp_eapol = os_malloc(len);
- if (!wpa->supp_eapol)
- return -1;
- os_memcpy(wpa->supp_eapol, buf, len);
- wpa->supp_eapol_len = len;
- eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL);
-
- return 0;
-}
-
-
-static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data,
- u16 data_len, size_t *msg_len, void **data_pos)
-{
- struct ieee802_1x_hdr *hdr;
-
- wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)",
- __func__, type, data_len);
-
- *msg_len = sizeof(*hdr) + data_len;
- hdr = os_malloc(*msg_len);
- if (hdr == NULL)
- return NULL;
-
- hdr->version = 2;
- hdr->type = type;
- hdr->length = host_to_be16(data_len);
-
- if (data)
- os_memcpy(hdr + 1, data, data_len);
- else
- os_memset(hdr + 1, 0, data_len);
-
- if (data_pos)
- *data_pos = hdr + 1;
-
- return (u8 *) hdr;
-}
-
-
-static int supp_get_beacon_ie(void *ctx)
-{
- struct wpa *wpa = ctx;
- const u8 *ie;
- size_t ielen;
-
- wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-
- ie = wpa_auth_get_wpa_ie(wpa->auth_group, &ielen);
- if (ie == NULL || ielen < 1)
- return -1;
- if (ie[0] == WLAN_EID_RSN)
- return wpa_sm_set_ap_rsn_ie(wpa->supp, ie, 2 + ie[1]);
- return wpa_sm_set_ap_wpa_ie(wpa->supp, ie, 2 + ie[1]);
-}
-
-
-static int supp_set_key(void *ctx, enum wpa_alg alg,
- const u8 *addr, int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d "
- "set_tx=%d)",
- __func__, alg, MAC2STR(addr), key_idx, set_tx);
- wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len);
- wpa_hexdump(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
- return 0;
-}
-
-
-static int supp_mlme_setprotection(void *ctx, const u8 *addr,
- int protection_type, int key_type)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d "
- "key_type=%d)",
- __func__, MAC2STR(addr), protection_type, key_type);
- return 0;
-}
-
-
-static void supp_cancel_auth_timeout(void *ctx)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-}
-
-
-static void * supp_get_network_ctx(void *ctx)
-{
- return (void *) 1;
-}
-
-
-static void supp_deauthenticate(void *ctx, u16 reason_code)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s(%d)", __func__, reason_code);
-}
-
-
-static enum wpa_states supp_get_state(void *ctx)
-{
- return WPA_COMPLETED;
-}
-
-
-static int supp_init(struct wpa *wpa)
-{
- struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
-
- if (!ctx)
- return -1;
-
- ctx->ctx = wpa;
- ctx->msg_ctx = wpa;
- ctx->set_state = supp_set_state;
- ctx->get_bssid = supp_get_bssid;
- ctx->ether_send = supp_ether_send;
- ctx->get_beacon_ie = supp_get_beacon_ie;
- ctx->alloc_eapol = supp_alloc_eapol;
- ctx->set_key = supp_set_key;
- ctx->mlme_setprotection = supp_mlme_setprotection;
- ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
- ctx->get_network_ctx = supp_get_network_ctx;
- ctx->deauthenticate = supp_deauthenticate;
- ctx->get_state = supp_get_state;
- wpa->supp = wpa_sm_init(ctx);
- if (!wpa->supp) {
- wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
- return -1;
- }
-
- wpa_sm_set_own_addr(wpa->supp, wpa->supp_addr);
- if (wpa->wpa1) {
- wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 0);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_WPA);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE,
- WPA_CIPHER_TKIP);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_TKIP);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT,
- WPA_KEY_MGMT_PSK);
- } else {
- wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 1);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE,
- WPA_CIPHER_CCMP);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT,
- WPA_KEY_MGMT_PSK);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_MFP,
- MGMT_FRAME_PROTECTION_OPTIONAL);
- }
- wpa_sm_set_pmk(wpa->supp, wpa->psk, PMK_LEN, NULL, NULL);
-
- wpa->supp_ie_len = sizeof(wpa->supp_ie);
- if (wpa_sm_set_assoc_wpa_ie_default(wpa->supp, wpa->supp_ie,
- &wpa->supp_ie_len) < 0) {
- wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()"
- " failed");
- return -1;
- }
-
- wpa_sm_notify_assoc(wpa->supp, wpa->auth_addr);
-
- return 0;
-}
-
-
-static void auth_logger(void *ctx, const u8 *addr, logger_level level,
- const char *txt)
-{
- if (addr)
- wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
- MAC2STR(addr), txt);
- else
- wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
-}
-
-
-static int auth_read_msg(struct wpa *wpa)
-{
- os_free(wpa->supp_eapol);
- wpa->supp_eapol = read_msg(wpa->f, &wpa->supp_eapol_len);
- if (!wpa->supp_eapol)
- return -1;
- eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL);
- return 0;
-}
-
-
-static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
- size_t data_len, int encrypt)
-{
- struct wpa *wpa = ctx;
-
- wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu "
- "encrypt=%d)",
- __func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
- wpa->auth_sent = 1;
-
- if (wpa->test_peer == AUTH && wpa->test_oper == WRITE)
- write_msg(wpa->f, data, data_len);
-
- if (wpa->test_peer == SUPP && wpa->test_oper == READ)
- return auth_read_msg(wpa);
-
- os_free(wpa->auth_eapol);
- wpa->auth_eapol = os_malloc(data_len);
- if (!wpa->auth_eapol)
- return -1;
- os_memcpy(wpa->auth_eapol, data, data_len);
- wpa->auth_eapol_len = data_len;
- eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL);
-
- return 0;
-}
-
-
-static const u8 * auth_get_psk(void *ctx, const u8 *addr,
- const u8 *p2p_dev_addr, const u8 *prev_psk,
- size_t *psk_len)
-{
- struct wpa *wpa = ctx;
-
- wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
- __func__, MAC2STR(addr), prev_psk);
- if (psk_len)
- *psk_len = PMK_LEN;
- if (prev_psk)
- return NULL;
- return wpa->psk;
-}
-
-
-static void supp_eapol_key_request(void *eloop_data, void *user_ctx)
-{
- struct wpa *wpa = eloop_data;
-
- wpa_printf(MSG_DEBUG, "SUPP: EAPOL-Key Request trigger");
- if (wpa->test_peer == SUPP && wpa->test_oper == READ) {
- if (!eloop_is_timeout_registered(auth_eapol_rx, wpa, NULL))
- auth_read_msg(wpa);
- } else {
- wpa_sm_key_request(wpa->supp, 0, 1);
- }
-}
-
-
-static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
- const u8 *addr, int idx, u8 *key,
- size_t key_len)
-{
- struct wpa *wpa = ctx;
-
- wpa_printf(MSG_DEBUG, "AUTH: %s (vlan_id=%d alg=%d idx=%d key_len=%d)",
- __func__, vlan_id, alg, idx, (int) key_len);
- if (addr)
- wpa_printf(MSG_DEBUG, "AUTH: addr=" MACSTR, MAC2STR(addr));
-
- if (alg != WPA_ALG_NONE && idx == 0 && key_len > 0 &&
- !wpa->key_request_done) {
- wpa_printf(MSG_DEBUG, "Test EAPOL-Key Request");
- wpa->key_request_done = 1;
- if (!wpa->wpa1)
- eloop_register_timeout(0, 0, supp_eapol_key_request,
- wpa, NULL);
- }
-
- return 0;
-}
-
-
-static int auth_init_group(struct wpa *wpa)
-{
- struct wpa_auth_config conf;
- struct wpa_auth_callbacks cb;
-
- wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
-
- os_memset(&conf, 0, sizeof(conf));
- if (wpa->wpa1) {
- conf.wpa = 1;
- conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
- conf.wpa_pairwise = WPA_CIPHER_TKIP;
- conf.wpa_group = WPA_CIPHER_TKIP;
- } else {
- conf.wpa = 2;
- conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
- conf.wpa_pairwise = WPA_CIPHER_CCMP;
- conf.rsn_pairwise = WPA_CIPHER_CCMP;
- conf.wpa_group = WPA_CIPHER_CCMP;
- conf.ieee80211w = 2;
- conf.group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
- }
- conf.eapol_version = 2;
- conf.wpa_group_update_count = 4;
- conf.wpa_pairwise_update_count = 4;
-
- os_memset(&cb, 0, sizeof(cb));
- cb.logger = auth_logger;
- cb.send_eapol = auth_send_eapol;
- cb.get_psk = auth_get_psk;
- cb.set_key = auth_set_key,
-
- wpa->auth_group = wpa_init(wpa->auth_addr, &conf, &cb, wpa);
- if (!wpa->auth_group) {
- wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
- return -1;
- }
-
- return 0;
-}
-
-
-static int auth_init(struct wpa *wpa)
-{
- if (wpa->test_peer == AUTH && wpa->test_oper == READ)
- return supp_read_msg(wpa);
-
- wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr, NULL);
- if (!wpa->auth) {
- wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
- return -1;
- }
-
- if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, wpa->supp_ie,
- wpa->supp_ie_len, NULL, 0, NULL, 0) !=
- WPA_IE_OK) {
- wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
- return -1;
- }
-
- wpa_auth_sm_event(wpa->auth, WPA_ASSOC);
-
- wpa_auth_sta_associated(wpa->auth_group, wpa->auth);
-
- return 0;
-}
-
-
-static void deinit(struct wpa *wpa)
-{
- wpa_auth_sta_deinit(wpa->auth);
- wpa_sm_deinit(wpa->supp);
- wpa_deinit(wpa->auth_group);
- os_free(wpa->auth_eapol);
- wpa->auth_eapol = NULL;
- os_free(wpa->supp_eapol);
- wpa->supp_eapol = NULL;
-}
-
-
-int main(int argc, char *argv[])
-{
- const char *file;
- int ret;
- struct wpa wpa;
-
- if (os_program_init())
- return -1;
-
- wpa_debug_level = 0;
- wpa_debug_show_keys = 1;
- os_memset(&wpa, 0, sizeof(wpa));
-
- if (argc < 4)
- usage();
-
- if (os_strcmp(argv[1], "auth") == 0) {
- wpa.test_peer = AUTH;
- } else if (os_strcmp(argv[1], "auth1") == 0) {
- wpa.test_peer = AUTH;
- wpa.wpa1 = 1;
- } else if (os_strcmp(argv[1], "supp") == 0) {
- wpa.test_peer = SUPP;
- } else if (os_strcmp(argv[1], "supp1") == 0) {
- wpa.test_peer = SUPP;
- wpa.wpa1 = 1;
- } else {
- usage();
- }
-
- if (os_strcmp(argv[2], "read") == 0)
- wpa.test_oper = READ;
- else if (os_strcmp(argv[2], "write") == 0)
- wpa.test_oper = WRITE;
- else
- usage();
-
- file = argv[3];
-
- wpa.f = fopen(file, wpa.test_oper == READ ? "r" : "w");
- if (!wpa.f)
- return -1;
-
- os_memset(wpa.auth_addr, 0x12, ETH_ALEN);
- os_memset(wpa.supp_addr, 0x32, ETH_ALEN);
- os_memset(wpa.psk, 0x44, PMK_LEN);
-
- if (eloop_init()) {
- wpa_printf(MSG_ERROR, "Failed to initialize event loop");
- goto fail;
- }
-
- if (auth_init_group(&wpa) < 0)
- goto fail;
-
- if (supp_init(&wpa) < 0)
- goto fail;
-
- if (auth_init(&wpa) < 0)
- goto fail;
-
- wpa_printf(MSG_DEBUG, "Starting eloop");
- eloop_run();
- wpa_printf(MSG_DEBUG, "eloop done");
-
- ret = 0;
-fail:
- deinit(&wpa);
- fclose(wpa.f);
-
- eloop_destroy();
-
- os_program_deinit();
-
- return ret;
-}
diff --git a/tests/test-json.c b/tests/test-json.c
deleted file mode 100644
index c7cb460..0000000
--- a/tests/test-json.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * JSON parser - test program
- * Copyright (c) 2019, 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/os.h"
-#include "utils/json.h"
-
-
-int main(int argc, char *argv[])
-{
- char *buf;
- size_t len;
- struct json_token *root;
-
- if (argc < 2)
- return -1;
-
- buf = os_readfile(argv[1], &len);
- if (!buf)
- return -1;
-
- root = json_parse(buf, len);
- os_free(buf);
- if (root) {
- size_t buflen = 10000;
-
- buf = os_zalloc(buflen);
- if (buf) {
- json_print_tree(root, buf, buflen);
- printf("%s\n", buf);
- os_free(buf);
- }
- json_free(root);
- } else {
- printf("JSON parsing failed\n");
- }
-
- return 0;
-}
diff --git a/tests/test-tls.c b/tests/test-tls.c
deleted file mode 100644
index 9941fb5..0000000
--- a/tests/test-tls.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Testing tool for TLSv1 client/server routines
- * Copyright (c) 2019, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/tls.h"
-
-
-static void usage(void) {
- wpa_printf(MSG_INFO,
- "usage: test-tls <server/client> <read/write> <file>");
- exit(-1);
-}
-
-
-static void write_msg(FILE *f, struct wpabuf *msg)
-{
- u8 len[2];
-
- wpa_printf(MSG_DEBUG, "TEST: Write message to file (msg_len=%u)",
- (unsigned int) wpabuf_len(msg));
- WPA_PUT_BE16(len, wpabuf_len(msg));
- fwrite(len, 2, 1, f);
- fwrite(wpabuf_head(msg), wpabuf_len(msg), 1, f);
-}
-
-
-static struct wpabuf * read_msg(FILE *f)
-{
- u8 len[2];
- u16 msg_len;
- struct wpabuf *msg;
-
- if (fread(len, 2, 1, f) != 1) {
- wpa_printf(MSG_ERROR, "TEST-ERROR: Could not read msg len");
- return NULL;
- }
- msg_len = WPA_GET_BE16(len);
-
- msg = wpabuf_alloc(msg_len);
- if (!msg)
- return NULL;
- if (msg_len > 0 &&
- fread(wpabuf_put(msg, msg_len), msg_len, 1, f) != 1) {
- wpa_printf(MSG_ERROR, "TEST-ERROR: Truncated msg (msg_len=%u)",
- msg_len);
- wpabuf_free(msg);
- return NULL;
- }
- wpa_hexdump_buf(MSG_DEBUG, "TEST: Read message from file", msg);
-
- return msg;
-}
-
-
-int main(int argc, char *argv[])
-{
- struct tls_config conf;
- void *tls_server, *tls_client;
- struct tls_connection_params params;
- struct tls_connection *conn_server = NULL, *conn_client = NULL;
- int ret = -1;
- struct wpabuf *in = NULL, *out = NULL, *appl;
- enum { SERVER, CLIENT } test_peer;
- enum { READ, WRITE } test_oper;
- const char *file;
- FILE *f;
-
- wpa_debug_level = 0;
- wpa_debug_show_keys = 1;
-
- if (argc < 4)
- usage();
-
- if (os_strcmp(argv[1], "server") == 0)
- test_peer = SERVER;
- else if (os_strcmp(argv[1], "client") == 0)
- test_peer = CLIENT;
- else
- usage();
-
- if (os_strcmp(argv[2], "read") == 0)
- test_oper = READ;
- else if (os_strcmp(argv[2], "write") == 0)
- test_oper = WRITE;
- else
- usage();
-
- file = argv[3];
-
- f = fopen(file, test_oper == READ ? "r" : "w");
- if (!f)
- return -1;
-
- os_memset(&conf, 0, sizeof(conf));
- tls_server = tls_init(&conf);
- tls_client = tls_init(&conf);
- if (!tls_server || !tls_client)
- goto fail;
-
- os_memset(¶ms, 0, sizeof(params));
- params.ca_cert = "hwsim/auth_serv/ca.pem";
- params.client_cert = "hwsim/auth_serv/server.pem";
- params.private_key = "hwsim/auth_serv/server.key";
- params.dh_file = "hwsim/auth_serv/dh.conf";
-
- if (tls_global_set_params(tls_server, ¶ms)) {
- wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
- goto fail;
- }
-
- conn_server = tls_connection_init(tls_server);
- conn_client = tls_connection_init(tls_client);
- if (!conn_server || !conn_client)
- goto fail;
-
- in = NULL;
- for (;;) {
- appl = NULL;
- if (test_peer == CLIENT && test_oper == READ)
- out = read_msg(f);
- else
- out = tls_connection_handshake(tls_client, conn_client,
- in, &appl);
- wpabuf_free(in);
- in = NULL;
- if (!out)
- goto fail;
- if (test_peer == CLIENT && test_oper == WRITE &&
- wpabuf_len(out) > 0)
- write_msg(f, out);
- if (!(test_peer == CLIENT && test_oper == READ) &&
- tls_connection_get_failed(tls_client, conn_client)) {
- wpa_printf(MSG_ERROR, "TLS handshake failed");
- goto fail;
- }
- if (((test_peer == CLIENT && test_oper == READ) ||
- tls_connection_established(tls_client, conn_client)) &&
- ((test_peer == SERVER && test_oper == READ) ||
- tls_connection_established(tls_server, conn_server)))
- break;
-
- appl = NULL;
- if (test_peer == SERVER && test_oper == READ)
- in = read_msg(f);
- else
- in = tls_connection_server_handshake(tls_server,
- conn_server,
- out, &appl);
- wpabuf_free(out);
- out = NULL;
- if (!in)
- goto fail;
- if (test_peer == SERVER && test_oper == WRITE)
- write_msg(f, in);
- if (!(test_peer == SERVER && test_oper == READ) &&
- tls_connection_get_failed(tls_server, conn_server)) {
- wpa_printf(MSG_ERROR, "TLS handshake failed");
- goto fail;
- }
- if (((test_peer == CLIENT && test_oper == READ) ||
- tls_connection_established(tls_client, conn_client)) &&
- ((test_peer == SERVER && test_oper == READ) ||
- tls_connection_established(tls_server, conn_server)))
- break;
- }
-
- wpabuf_free(in);
- in = wpabuf_alloc(100);
- if (!in)
- goto fail;
- wpabuf_put_str(in, "PING");
- wpabuf_free(out);
- if (test_peer == CLIENT && test_oper == READ)
- out = read_msg(f);
- else
- out = tls_connection_encrypt(tls_client, conn_client, in);
- wpabuf_free(in);
- in = NULL;
- if (!out)
- goto fail;
- if (test_peer == CLIENT && test_oper == WRITE)
- write_msg(f, out);
-
- if (!(test_peer == SERVER && test_oper == READ)) {
- in = tls_connection_decrypt(tls_server, conn_server, out);
- wpabuf_free(out);
- out = NULL;
- if (!in)
- goto fail;
- wpa_hexdump_buf(MSG_DEBUG, "Server decrypted ApplData", in);
- }
-
- wpabuf_free(in);
- in = wpabuf_alloc(100);
- if (!in)
- goto fail;
- wpabuf_put_str(in, "PONG");
- wpabuf_free(out);
- if (test_peer == SERVER && test_oper == READ)
- out = read_msg(f);
- else
- out = tls_connection_encrypt(tls_server, conn_server, in);
- wpabuf_free(in);
- in = NULL;
- if (!out)
- goto fail;
- if (test_peer == SERVER && test_oper == WRITE)
- write_msg(f, out);
-
- if (!(test_peer == CLIENT && test_oper == READ)) {
- in = tls_connection_decrypt(tls_client, conn_client, out);
- wpabuf_free(out);
- out = NULL;
- if (!in)
- goto fail;
- wpa_hexdump_buf(MSG_DEBUG, "Client decrypted ApplData", in);
- }
-
- ret = 0;
-fail:
- if (tls_server) {
- if (conn_server)
- tls_connection_deinit(tls_server, conn_server);
- tls_deinit(tls_server);
- }
- if (tls_client) {
- if (conn_client)
- tls_connection_deinit(tls_server, conn_client);
- tls_deinit(tls_client);
- }
- wpabuf_free(in);
- wpabuf_free(out);
- fclose(f);
-
- return ret;
-}
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 3298f91..8fd2710 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -123,6 +123,7 @@
OBJS += src/utils/wpa_debug.c
OBJS += src/utils/wpabuf.c
OBJS += src/utils/bitfield.c
+OBJS += src/utils/ip_addr.c
OBJS += wmm_ac.c
OBJS += op_classes.c
OBJS += rrm.c
@@ -228,8 +229,6 @@
ifdef CONFIG_SUITEB
L_CFLAGS += -DCONFIG_SUITEB
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_SUITEB192
@@ -240,25 +239,15 @@
ifdef CONFIG_OCV
L_CFLAGS += -DCONFIG_OCV
OBJS += src/common/ocv.c
-CONFIG_IEEE80211W=y
-endif
-
-ifdef CONFIG_IEEE80211W
-L_CFLAGS += -DCONFIG_IEEE80211W
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_IEEE80211R
L_CFLAGS += -DCONFIG_IEEE80211R
OBJS += src/rsn_supp/wpa_ft.c
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_MESH
NEED_80211_COMMON=y
-NEED_SHA256=y
NEED_AES_SIV=y
CONFIG_SAE=y
CONFIG_AP=y
@@ -284,9 +273,9 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_ECC=y
NEED_JSON=y
NEED_GAS_SERVER=y
NEED_BASE64=y
@@ -301,7 +290,6 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
endif
@@ -328,8 +316,6 @@
ifdef CONFIG_TDLS
L_CFLAGS += -DCONFIG_TDLS
OBJS += src/rsn_supp/tdls.c
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_TDLS_TESTING
@@ -394,7 +380,6 @@
OBJS += hs20_supplicant.c
L_CFLAGS += -DCONFIG_HS20
CONFIG_INTERWORKING=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_INTERWORKING
@@ -461,7 +446,6 @@
ifdef CONFIG_ERP
L_CFLAGS += -DCONFIG_ERP
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -616,7 +600,6 @@
endif
CONFIG_IEEE8021X_EAPOL=y
NEED_AES=y
-NEED_AES_OMAC1=y
NEED_AES_ENCBLOCK=y
NEED_AES_EAX=y
endif
@@ -649,7 +632,6 @@
else
L_CFLAGS += -DEAP_AKA_PRIME
endif
-NEED_SHA256=y
endif
ifdef CONFIG_EAP_SIM_COMMON
@@ -689,6 +671,8 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_T_PRF=y
NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
endif
ifdef CONFIG_EAP_PAX
@@ -728,15 +712,12 @@
ifdef CONFIG_EAP_GPSK_SHA256
L_CFLAGS += -DEAP_GPSK_SHA256
endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_EAP_PWD
L_CFLAGS += -DEAP_PWD
OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c
CONFIG_IEEE8021X_EAPOL=y
-NEED_SHA256=y
NEED_ECC=y
NEED_DRAGONFLY=y
endif
@@ -753,7 +734,6 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
NEED_DH_GROUPS_ALL=y
-NEED_SHA256=y
NEED_AES_CBC=y
endif
@@ -773,7 +753,6 @@
OBJS += src/wps/wps_registrar.c
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
-NEED_SHA256=y
NEED_BASE64=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -890,7 +869,6 @@
OBJS += src/ap/utils.c
OBJS += src/ap/authsrv.c
OBJS += src/ap/ap_config.c
-OBJS += src/utils/ip_addr.c
OBJS += src/ap/sta_info.c
OBJS += src/ap/tkip_countermeasures.c
OBJS += src/ap/ap_mlme.c
@@ -959,8 +937,12 @@
ifdef CONFIG_DPP
OBJS += src/ap/dpp_hostapd.c
OBJS += src/ap/gas_query_ap.c
+NEED_AP_GAS_SERV=y
endif
ifdef CONFIG_INTERWORKING
+NEED_AP_GAS_SERV=y
+endif
+ifdef NEED_AP_GAS_SERV
OBJS += src/ap/gas_serv.c
endif
ifdef CONFIG_HS20
@@ -1064,7 +1046,6 @@
ifdef CONFIG_TLSV12
L_CFLAGS += -DCONFIG_TLSV12
-NEED_SHA256=y
endif
ifeq ($(CONFIG_TLS), openssl)
@@ -1079,7 +1060,6 @@
ifdef NEED_FIPS186_2_PRF
OBJS += src/crypto/fips_prf_openssl.c
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_p += -lcrypto
@@ -1142,7 +1122,6 @@
OBJS += src/tls/pkcs1.c
OBJS += src/tls/pkcs5.c
OBJS += src/tls/pkcs8.c
-NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -1262,12 +1241,10 @@
ifdef NEED_AES_EAX
AESOBJS += src/crypto/aes-eax.c
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_SIV
AESOBJS += src/crypto/aes-siv.c
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_CTR
AESOBJS += src/crypto/aes-ctr.c
@@ -1275,14 +1252,12 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += src/crypto/aes-encblock.c
endif
-ifdef NEED_AES_OMAC1
NEED_AES_ENC=y
ifdef CONFIG_OPENSSL_CMAC
L_CFLAGS += -DCONFIG_OPENSSL_CMAC
else
AESOBJS += src/crypto/aes-omac1.c
endif
-endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
ifdef NEED_INTERNAL_AES_WRAP
@@ -1375,7 +1350,6 @@
endif
SHA256OBJS = # none by default
-ifdef NEED_SHA256
L_CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), gnutls)
@@ -1397,6 +1371,9 @@
ifdef NEED_TLS_PRF_SHA256
SHA256OBJS += src/crypto/sha256-tlsprf.c
endif
+ifdef NEED_TLS_PRF_SHA384
+SHA256OBJS += src/crypto/sha384-tlsprf.c
+endif
ifdef NEED_HMAC_SHA256_KDF
L_CFLAGS += -DCONFIG_HMAC_SHA256_KDF
SHA256OBJS += src/crypto/sha256-kdf.c
@@ -1410,7 +1387,6 @@
SHA256OBJS += src/crypto/sha512-kdf.c
endif
OBJS += $(SHA256OBJS)
-endif
ifdef NEED_SHA384
L_CFLAGS += -DCONFIG_SHA384
ifneq ($(CONFIG_TLS), openssl)
@@ -1663,9 +1639,6 @@
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.c
OBJS_t += src/radius/radius_client.c
OBJS_t += src/radius/radius.c
-ifndef CONFIG_AP
-OBJS_t += src/utils/ip_addr.c
-endif
OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.c
OBJS += $(CONFIG_MAIN).c
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index 89119e7..f82e5e0 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,5 +1,34 @@
ChangeLog for wpa_supplicant
+2019-08-07 - v2.9
+ * SAE changes
+ - disable use of groups using Brainpool curves
+ - improved protection against side channel attacks
+ [https://w1.fi/security/2019-6/]
+ * EAP-pwd changes
+ - disable use of groups using Brainpool curves
+ - allow the set of groups to be configured (eap_pwd_groups)
+ - improved protection against side channel attacks
+ [https://w1.fi/security/2019-6/]
+ * fixed FT-EAP initial mobility domain association using PMKSA caching
+ (disabled by default for backwards compatibility; can be enabled
+ with ft_eap_pmksa_caching=1)
+ * fixed a regression in OpenSSL 1.1+ engine loading
+ * added validation of RSNE in (Re)Association Response frames
+ * fixed DPP bootstrapping URI parser of channel list
+ * extended EAP-SIM/AKA fast re-authentication to allow use with FILS
+ * extended ca_cert_blob to support PEM format
+ * improved robustness of P2P Action frame scheduling
+ * added support for EAP-SIM/AKA using anonymous@realm identity
+ * fixed Hotspot 2.0 credential selection based on roaming consortium
+ to ignore credentials without a specific EAP method
+ * added experimental support for EAP-TEAP peer (RFC 7170)
+ * added experimental support for EAP-TLS peer with TLS v1.3
+ * fixed a regression in WMM parameter configuration for a TDLS peer
+ * fixed a regression in operation with drivers that offload 802.1X
+ 4-way handshake
+ * fixed an ECDH operation corner case with OpenSSL
+
2019-04-21 - v2.8
* SAE changes
- added support for SAE Password Identifier
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index f1384d5..a6329c0 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -103,6 +103,7 @@
OBJS += ../src/utils/wpa_debug.o
OBJS += ../src/utils/wpabuf.o
OBJS += ../src/utils/bitfield.o
+OBJS += ../src/utils/ip_addr.o
OBJS += op_classes.o
OBJS += rrm.o
OBJS_p = wpa_passphrase.o
@@ -230,8 +231,6 @@
ifdef CONFIG_SUITEB
CFLAGS += -DCONFIG_SUITEB
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_SUITEB192
@@ -242,25 +241,15 @@
ifdef CONFIG_OCV
CFLAGS += -DCONFIG_OCV
OBJS += ../src/common/ocv.o
-CONFIG_IEEE80211W=y
-endif
-
-ifdef CONFIG_IEEE80211W
-CFLAGS += -DCONFIG_IEEE80211W
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_IEEE80211R
CFLAGS += -DCONFIG_IEEE80211R
OBJS += ../src/rsn_supp/wpa_ft.o
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_MESH
NEED_80211_COMMON=y
-NEED_SHA256=y
NEED_AES_SIV=y
CONFIG_SAE=y
CONFIG_AP=y
@@ -286,9 +275,9 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_ECC=y
NEED_JSON=y
NEED_GAS_SERVER=y
NEED_BASE64=y
@@ -303,7 +292,6 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
endif
@@ -330,8 +318,6 @@
ifdef CONFIG_TDLS
CFLAGS += -DCONFIG_TDLS
OBJS += ../src/rsn_supp/tdls.o
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_TDLS_TESTING
@@ -404,7 +390,6 @@
OBJS += hs20_supplicant.o
CFLAGS += -DCONFIG_HS20
CONFIG_INTERWORKING=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_INTERWORKING
@@ -458,7 +443,6 @@
ifdef CONFIG_ERP
CFLAGS += -DCONFIG_ERP
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -613,7 +597,6 @@
endif
CONFIG_IEEE8021X_EAPOL=y
NEED_AES=y
-NEED_AES_OMAC1=y
NEED_AES_ENCBLOCK=y
NEED_AES_EAX=y
endif
@@ -646,7 +629,6 @@
else
CFLAGS += -DEAP_AKA_PRIME
endif
-NEED_SHA256=y
endif
ifdef CONFIG_EAP_SIM_COMMON
@@ -686,6 +668,8 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_T_PRF=y
NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
endif
ifdef CONFIG_EAP_PAX
@@ -725,8 +709,6 @@
ifdef CONFIG_EAP_GPSK_SHA256
CFLAGS += -DEAP_GPSK_SHA256
endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_EAP_PWD
@@ -736,7 +718,6 @@
endif
OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o
CONFIG_IEEE8021X_EAPOL=y
-NEED_SHA256=y
NEED_ECC=y
NEED_DRAGONFLY=y
endif
@@ -753,7 +734,6 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
NEED_DH_GROUPS_ALL=y
-NEED_SHA256=y
NEED_AES_CBC=y
endif
@@ -773,7 +753,6 @@
OBJS += ../src/wps/wps_registrar.o
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
-NEED_SHA256=y
NEED_BASE64=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -871,7 +850,6 @@
NEED_AES_ENCBLOCK=y
NEED_AES_UNWRAP=y
NEED_AES_WRAP=y
-NEED_AES_OMAC1=y
OBJS += wpas_kay.o
OBJS += ../src/pae/ieee802_1x_cp.o
OBJS += ../src/pae/ieee802_1x_kay.o
@@ -907,7 +885,6 @@
OBJS += ../src/ap/utils.o
OBJS += ../src/ap/authsrv.o
OBJS += ../src/ap/ap_config.o
-OBJS += ../src/utils/ip_addr.o
OBJS += ../src/ap/sta_info.o
OBJS += ../src/ap/tkip_countermeasures.o
OBJS += ../src/ap/ap_mlme.o
@@ -976,8 +953,12 @@
ifdef CONFIG_DPP
OBJS += ../src/ap/dpp_hostapd.o
OBJS += ../src/ap/gas_query_ap.o
+NEED_AP_GAS_SERV=y
endif
ifdef CONFIG_INTERWORKING
+NEED_AP_GAS_SERV=y
+endif
+ifdef NEED_AP_GAS_SERV
OBJS += ../src/ap/gas_serv.o
endif
ifdef CONFIG_HS20
@@ -1081,7 +1062,6 @@
ifdef CONFIG_TLSV12
CFLAGS += -DCONFIG_TLSV12
-NEED_SHA256=y
endif
ifeq ($(CONFIG_TLS), wolfssl)
@@ -1112,7 +1092,6 @@
ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_openssl.o
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_p += -lcrypto
@@ -1176,7 +1155,6 @@
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
-NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -1256,7 +1234,6 @@
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
-NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -1342,12 +1319,10 @@
ifdef NEED_AES_EAX
AESOBJS += ../src/crypto/aes-eax.o
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_SIV
AESOBJS += ../src/crypto/aes-siv.o
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_CTR
AESOBJS += ../src/crypto/aes-ctr.o
@@ -1355,7 +1330,6 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += ../src/crypto/aes-encblock.o
endif
-ifdef NEED_AES_OMAC1
NEED_AES_ENC=y
ifdef CONFIG_OPENSSL_CMAC
CFLAGS += -DCONFIG_OPENSSL_CMAC
@@ -1366,7 +1340,6 @@
endif
endif
endif
-endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
ifdef NEED_INTERNAL_AES_WRAP
@@ -1475,7 +1448,6 @@
endif
SHA256OBJS = # none by default
-ifdef NEED_SHA256
CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
@@ -1501,6 +1473,9 @@
ifdef NEED_TLS_PRF_SHA256
SHA256OBJS += ../src/crypto/sha256-tlsprf.o
endif
+ifdef NEED_TLS_PRF_SHA384
+SHA256OBJS += ../src/crypto/sha384-tlsprf.o
+endif
ifdef NEED_HMAC_SHA256_KDF
CFLAGS += -DCONFIG_HMAC_SHA256_KDF
OBJS += ../src/crypto/sha256-kdf.o
@@ -1514,7 +1489,6 @@
OBJS += ../src/crypto/sha512-kdf.o
endif
OBJS += $(SHA256OBJS)
-endif
ifdef NEED_SHA384
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
@@ -1808,9 +1782,6 @@
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o
OBJS_t += ../src/radius/radius_client.o
OBJS_t += ../src/radius/radius.o
-ifndef CONFIG_AP
-OBJS_t += ../src/utils/ip_addr.o
-endif
OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o
OBJS_nfc := $(OBJS) $(OBJS_l2) nfc_pw_token.o
diff --git a/wpa_supplicant/README-DPP b/wpa_supplicant/README-DPP
index dcc15f1..457e32e 100644
--- a/wpa_supplicant/README-DPP
+++ b/wpa_supplicant/README-DPP
@@ -28,7 +28,6 @@
Enable DPP and protected management frame in wpa_supplicant build config
file
-CONFIG_IEEE80211W=y
CONFIG_DPP=y
hostapd build config
@@ -36,7 +35,6 @@
Enable DPP and protected management frame in hostapd build config file
-CONFIG_IEEE80211W=y
CONFIG_DPP=y
Configurator build config
@@ -120,7 +118,9 @@
Send provisioning request to enrollee. (conf is ap-dpp if enrollee is an
AP. conf is sta-dpp if enrollee is a client)
-> dpp_auth_init peer=<qr-code-id> conf=<ap-dpp|sta-dpp> configurator=<configurator-id>
+> dpp_auth_init peer=<qr-code-id> conf=<ap-dpp|sta-dpp> ssid=<SSID hexdump> configurator=<configurator-id>
+or for legacy (PSK/SAE) provisioning for a station Enrollee:
+> dpp_auth_init peer=<qr-code-id> conf=sta-psk ssid=<SSID hexdump> pass=<passphrase hexdump>
The DPP values will be printed in the console. Save this values into the
config file. If the enrollee is an AP, we need to manually write these
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index b9b5d9d..ad3af40 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -270,10 +270,6 @@
# bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
-# IEEE 802.11w (management frame protection), also known as PMF
-# Driver support is also needed for IEEE 802.11w.
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 4e3c281..59ca153 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -381,7 +381,9 @@
else
bss->wpa_key_mgmt = ssid->key_mgmt;
bss->wpa_pairwise = ssid->pairwise_cipher;
- if (ssid->psk_set) {
+ if (wpa_key_mgmt_sae(bss->wpa_key_mgmt) && ssid->passphrase) {
+ bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
+ } else if (ssid->psk_set) {
bin_clear_free(bss->ssid.wpa_psk, sizeof(*bss->ssid.wpa_psk));
bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
if (bss->ssid.wpa_psk == NULL)
@@ -407,6 +409,34 @@
wep->idx = ssid->wep_tx_keyidx;
wep->keys_set = 1;
}
+#ifdef CONFIG_SAE
+ if (ssid->sae_password) {
+ struct sae_password_entry *pw;
+
+ pw = os_zalloc(sizeof(*pw));
+ if (!pw)
+ return -1;
+ os_memset(pw->peer_addr, 0xff, ETH_ALEN);
+ pw->password = os_strdup(ssid->sae_password);
+ if (!pw->password) {
+ os_free(pw);
+ return -1;
+ }
+ if (ssid->sae_password_id) {
+ pw->identifier = os_strdup(ssid->sae_password_id);
+ if (!pw->identifier) {
+ str_clear_free(pw->password);
+ os_free(pw);
+ return -1;
+ }
+ }
+
+ pw->next = bss->sae_passwords;
+ bss->sae_passwords = pw;
+ }
+
+ bss->sae_pwe = wpa_s->conf->sae_pwe;
+#endif /* CONFIG_SAE */
if (wpa_s->conf->go_interworking) {
wpa_printf(MSG_DEBUG,
@@ -500,10 +530,8 @@
bss->wpa_group_rekey = 86400;
}
-#ifdef CONFIG_IEEE80211W
if (ssid->ieee80211w != MGMT_FRAME_PROTECTION_DEFAULT)
bss->ieee80211w = ssid->ieee80211w;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
bss->ocv = ssid->ocv;
@@ -747,6 +775,20 @@
ssid->frequency = 2462; /* default channel 11 */
params.freq.freq = ssid->frequency;
+ if (ssid->mode == WPAS_MODE_AP && ssid->enable_edmg) {
+ u8 primary_channel;
+
+ if (ieee80211_freq_to_chan(ssid->frequency, &primary_channel) ==
+ NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_WARNING,
+ "EDMG: Failed to get the primary channel");
+ return -1;
+ }
+
+ hostapd_encode_edmg_chan(ssid->enable_edmg, ssid->edmg_channel,
+ primary_channel, ¶ms.freq.edmg);
+ }
+
params.wpa_proto = ssid->proto;
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
@@ -885,6 +927,8 @@
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
wpa_s->assoc_freq = ssid->frequency;
+ wpa_s->ap_iface->conf->enable_edmg = ssid->enable_edmg;
+ wpa_s->ap_iface->conf->edmg_channel = ssid->edmg_channel;
#if defined(CONFIG_P2P) && defined(CONFIG_ACS)
if (wpa_s->p2p_go_do_acs) {
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 441529c..943a340 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1038,23 +1038,30 @@
#ifdef CONFIG_P2P
/**
- * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
+ * wpa_bss_get_p2p_dev_addr - Fetch the latest BSS table entry based on P2P Device Addr
* @wpa_s: Pointer to wpa_supplicant data
* @dev_addr: P2P Device Address of the GO
* Returns: Pointer to the BSS entry or %NULL if not found
+ *
+ * This function tries to find the entry that has the most recent update. This
+ * can help in finding the correct entry in cases where the SSID of the P2P
+ * Device may have changed recently.
*/
struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
const u8 *dev_addr)
{
- struct wpa_bss *bss;
+ struct wpa_bss *bss, *found = NULL;
dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
u8 addr[ETH_ALEN];
if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
- addr) == 0 &&
- os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
- return bss;
+ addr) != 0 ||
+ os_memcmp(addr, dev_addr, ETH_ALEN) != 0)
+ continue;
+ if (!found ||
+ os_reltime_before(&found->last_update, &bss->last_update))
+ found = bss;
}
- return NULL;
+ return found;
}
#endif /* CONFIG_P2P */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 2895dc8..d100c46 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,7 @@
#include "utils/uuid.h"
#include "utils/ip_addr.h"
#include "common/ieee802_1x_defs.h"
+#include "common/sae.h"
#include "crypto/sha1.h"
#include "rsn_supp/wpa.h"
#include "eap_peer/eap.h"
@@ -740,12 +741,10 @@
val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
val |= WPA_KEY_MGMT_PSK_SHA256;
else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
else if (os_strcmp(start, "WPS") == 0)
val |= WPA_KEY_MGMT_WPS;
@@ -910,7 +909,6 @@
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
pos == buf ? "" : " ");
@@ -930,7 +928,6 @@
}
pos += ret;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
@@ -1614,7 +1611,7 @@
#ifdef CONFIG_EXT_PASSWORD
if (os_strncmp(value, "ext:", 4) == 0) {
char *name = os_strdup(value + 4);
- if (name == NULL)
+ if (!name)
return -1;
bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = (u8 *) name;
@@ -1630,9 +1627,9 @@
size_t res_len;
tmp = wpa_config_parse_string(value, &res_len);
- if (tmp == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: failed to parse "
- "password.", line);
+ if (!tmp) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: failed to parse password.", line);
return -1;
}
wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
@@ -1650,13 +1647,14 @@
/* NtPasswordHash: hash:<32 hex digits> */
if (os_strlen(value + 5) != 2 * 16) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length "
- "(expected 32 hex digits)", line);
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid password hash length (expected 32 hex digits)",
+ line);
return -1;
}
hash = os_malloc(16);
- if (hash == NULL)
+ if (!hash)
return -1;
if (hexstr2bin(value + 5, hash, 16)) {
@@ -1683,19 +1681,118 @@
}
+static int wpa_config_parse_machine_password(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ u8 *hash;
+
+ if (os_strcmp(value, "NULL") == 0) {
+ if (!ssid->eap.machine_password)
+ return 1; /* Already unset */
+ wpa_printf(MSG_DEBUG,
+ "Unset configuration string 'machine_password'");
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = NULL;
+ ssid->eap.machine_password_len = 0;
+ return 0;
+ }
+
+#ifdef CONFIG_EXT_PASSWORD
+ if (os_strncmp(value, "ext:", 4) == 0) {
+ char *name = os_strdup(value + 4);
+
+ if (!name)
+ return -1;
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = (u8 *) name;
+ ssid->eap.machine_password_len = os_strlen(name);
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+ ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+ return 0;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
+ if (os_strncmp(value, "hash:", 5) != 0) {
+ char *tmp;
+ size_t res_len;
+
+ tmp = wpa_config_parse_string(value, &res_len);
+ if (!tmp) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: failed to parse machine_password.",
+ line);
+ return -1;
+ }
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
+ (u8 *) tmp, res_len);
+
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = (u8 *) tmp;
+ ssid->eap.machine_password_len = res_len;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+
+ return 0;
+ }
+
+
+ /* NtPasswordHash: hash:<32 hex digits> */
+ if (os_strlen(value + 5) != 2 * 16) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid machine_password hash length (expected 32 hex digits)",
+ line);
+ return -1;
+ }
+
+ hash = os_malloc(16);
+ if (!hash)
+ return -1;
+
+ if (hexstr2bin(value + 5, hash, 16)) {
+ os_free(hash);
+ wpa_printf(MSG_ERROR, "Line %d: Invalid machine_password hash",
+ line);
+ return -1;
+ }
+
+ wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
+
+ if (ssid->eap.machine_password &&
+ ssid->eap.machine_password_len == 16 &&
+ os_memcmp(ssid->eap.machine_password, hash, 16) == 0 &&
+ (ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
+ bin_clear_free(hash, 16);
+ return 1;
+ }
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = hash;
+ ssid->eap.machine_password_len = 16;
+ ssid->eap.flags |= EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+
+ return 0;
+}
+
+
#ifndef NO_CONFIG_WRITE
+
static char * wpa_config_write_password(const struct parse_data *data,
struct wpa_ssid *ssid)
{
char *buf;
- if (ssid->eap.password == NULL)
+ if (!ssid->eap.password)
return NULL;
#ifdef CONFIG_EXT_PASSWORD
if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
buf = os_zalloc(4 + ssid->eap.password_len + 1);
- if (buf == NULL)
+ if (!buf)
return NULL;
os_memcpy(buf, "ext:", 4);
os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
@@ -1709,7 +1806,7 @@
}
buf = os_malloc(5 + 32 + 1);
- if (buf == NULL)
+ if (!buf)
return NULL;
os_memcpy(buf, "hash:", 5);
@@ -1717,6 +1814,44 @@
return buf;
}
+
+
+static char * wpa_config_write_machine_password(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *buf;
+
+ if (!ssid->eap.machine_password)
+ return NULL;
+
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD) {
+ buf = os_zalloc(4 + ssid->eap.machine_password_len + 1);
+ if (!buf)
+ return NULL;
+ os_memcpy(buf, "ext:", 4);
+ os_memcpy(buf + 4, ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ return buf;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
+ if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
+ return wpa_config_write_string(
+ ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ }
+
+ buf = os_malloc(5 + 32 + 1);
+ if (!buf)
+ return NULL;
+
+ os_memcpy(buf, "hash:", 5);
+ wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.machine_password, 16);
+
+ return buf;
+}
+
#endif /* NO_CONFIG_WRITE */
#endif /* IEEE8021X_EAPOL */
@@ -2141,23 +2276,24 @@
/* STR: Define a string variable for an ASCII string; f = field name */
#ifdef NO_CONFIG_WRITE
#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
-#define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f)
+#define _STRe(f, m) #f, wpa_config_parse_str, OFFSET(eap.m)
#else /* NO_CONFIG_WRITE */
#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f)
-#define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f)
+#define _STRe(f, m) #f, wpa_config_parse_str, wpa_config_write_str, \
+ OFFSET(eap.m)
#endif /* NO_CONFIG_WRITE */
#define STR(f) _STR(f), NULL, NULL, NULL, 0
-#define STRe(f) _STRe(f), NULL, NULL, NULL, 0
+#define STRe(f, m) _STRe(f, m), NULL, NULL, NULL, 0
#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1
-#define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1
+#define STR_KEYe(f, m) _STRe(f, m), NULL, NULL, NULL, 1
/* STR_LEN: Define a string variable with a separate variable for storing the
* data length. Unlike STR(), this can be used to store arbitrary binary data
* (i.e., even nul termination character). */
#define _STR_LEN(f) _STR(f), OFFSET(f ## _len)
-#define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len)
+#define _STR_LENe(f, m) _STRe(f, m), OFFSET(eap.m ## _len)
#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0
-#define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0
+#define STR_LENe(f, m) _STR_LENe(f, m), NULL, NULL, 0
#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1
/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length
@@ -2168,17 +2304,17 @@
#ifdef NO_CONFIG_WRITE
#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0
-#define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0
+#define _INTe(f, m) #f, wpa_config_parse_int, OFFSET(eap.m), (void *) 0
#else /* NO_CONFIG_WRITE */
#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \
OFFSET(f), (void *) 0
-#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \
- OFFSET(eap.f), (void *) 0
+#define _INTe(f, m) #f, wpa_config_parse_int, wpa_config_write_int, \
+ OFFSET(eap.m), (void *) 0
#endif /* NO_CONFIG_WRITE */
/* INT: Define an integer variable */
#define INT(f) _INT(f), NULL, NULL, 0
-#define INTe(f) _INTe(f), NULL, NULL, 0
+#define INTe(f, m) _INTe(f, m), NULL, NULL, 0
/* INT_RANGE: Define an integer variable with allowed value range */
#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0
@@ -2246,51 +2382,74 @@
{ INT(vht_center_freq2) },
#ifdef IEEE8021X_EAPOL
{ FUNC(eap) },
- { STR_LENe(identity) },
- { STR_LENe(anonymous_identity) },
- { STR_LENe(imsi_identity) },
+ { STR_LENe(identity, identity) },
+ { STR_LENe(anonymous_identity, anonymous_identity) },
+ { STR_LENe(imsi_identity, imsi_identity) },
+ { STR_LENe(machine_identity, machine_identity) },
{ FUNC_KEY(password) },
- { STRe(ca_cert) },
- { STRe(ca_path) },
- { STRe(client_cert) },
- { STRe(private_key) },
- { STR_KEYe(private_key_passwd) },
- { STRe(dh_file) },
- { STRe(subject_match) },
- { STRe(check_cert_subject) },
- { STRe(altsubject_match) },
- { STRe(domain_suffix_match) },
- { STRe(domain_match) },
- { STRe(ca_cert2) },
- { STRe(ca_path2) },
- { STRe(client_cert2) },
- { STRe(private_key2) },
- { STR_KEYe(private_key2_passwd) },
- { STRe(dh_file2) },
- { STRe(subject_match2) },
- { STRe(check_cert_subject2) },
- { STRe(altsubject_match2) },
- { STRe(domain_suffix_match2) },
- { STRe(domain_match2) },
- { STRe(phase1) },
- { STRe(phase2) },
- { STRe(pcsc) },
- { STR_KEYe(pin) },
- { STRe(engine_id) },
- { STRe(key_id) },
- { STRe(cert_id) },
- { STRe(ca_cert_id) },
- { STR_KEYe(pin2) },
- { STRe(engine2_id) },
- { STRe(key2_id) },
- { STRe(cert2_id) },
- { STRe(ca_cert2_id) },
- { INTe(engine) },
- { INTe(engine2) },
+ { FUNC_KEY(machine_password) },
+ { STRe(ca_cert, cert.ca_cert) },
+ { STRe(ca_path, cert.ca_path) },
+ { STRe(client_cert, cert.client_cert) },
+ { STRe(private_key, cert.private_key) },
+ { STR_KEYe(private_key_passwd, cert.private_key_passwd) },
+ { STRe(dh_file, cert.dh_file) },
+ { STRe(subject_match, cert.subject_match) },
+ { STRe(check_cert_subject, cert.check_cert_subject) },
+ { STRe(altsubject_match, cert.altsubject_match) },
+ { STRe(domain_suffix_match, cert.domain_suffix_match) },
+ { STRe(domain_match, cert.domain_match) },
+ { STRe(ca_cert2, phase2_cert.ca_cert) },
+ { STRe(ca_path2, phase2_cert.ca_path) },
+ { STRe(client_cert2, phase2_cert.client_cert) },
+ { STRe(private_key2, phase2_cert.private_key) },
+ { STR_KEYe(private_key2_passwd, phase2_cert.private_key_passwd) },
+ { STRe(dh_file2, phase2_cert.dh_file) },
+ { STRe(subject_match2, phase2_cert.subject_match) },
+ { STRe(check_cert_subject2, phase2_cert.check_cert_subject) },
+ { STRe(altsubject_match2, phase2_cert.altsubject_match) },
+ { STRe(domain_suffix_match2, phase2_cert.domain_suffix_match) },
+ { STRe(domain_match2, phase2_cert.domain_match) },
+ { STRe(phase1, phase1) },
+ { STRe(phase2, phase2) },
+ { STRe(machine_phase2, machine_phase2) },
+ { STRe(pcsc, pcsc) },
+ { STR_KEYe(pin, cert.pin) },
+ { STRe(engine_id, cert.engine_id) },
+ { STRe(key_id, cert.key_id) },
+ { STRe(cert_id, cert.cert_id) },
+ { STRe(ca_cert_id, cert.ca_cert_id) },
+ { STR_KEYe(pin2, phase2_cert.pin) },
+ { STRe(engine_id2, phase2_cert.engine_id) },
+ { STRe(key_id2, phase2_cert.key_id) },
+ { STRe(cert_id2, phase2_cert.cert_id) },
+ { STRe(ca_cert_id2, phase2_cert.ca_cert_id) },
+ { INTe(engine, cert.engine) },
+ { INTe(engine2, phase2_cert.engine) },
+ { STRe(machine_ca_cert, machine_cert.ca_cert) },
+ { STRe(machine_ca_path, machine_cert.ca_path) },
+ { STRe(machine_client_cert, machine_cert.client_cert) },
+ { STRe(machine_private_key, machine_cert.private_key) },
+ { STR_KEYe(machine_private_key_passwd,
+ machine_cert.private_key_passwd) },
+ { STRe(machine_dh_file, machine_cert.dh_file) },
+ { STRe(machine_subject_match, machine_cert.subject_match) },
+ { STRe(machine_check_cert_subject, machine_cert.check_cert_subject) },
+ { STRe(machine_altsubject_match, machine_cert.altsubject_match) },
+ { STRe(machine_domain_suffix_match,
+ machine_cert.domain_suffix_match) },
+ { STRe(machine_domain_match, machine_cert.domain_match) },
+ { STR_KEYe(machine_pin, machine_cert.pin) },
+ { STRe(machine_engine_id, machine_cert.engine_id) },
+ { STRe(machine_key_id, machine_cert.key_id) },
+ { STRe(machine_cert_id, machine_cert.cert_id) },
+ { STRe(machine_ca_cert_id, machine_cert.ca_cert_id) },
+ { INTe(machine_engine, machine_cert.engine) },
+ { INTe(machine_ocsp, machine_cert.ocsp) },
{ INT(eapol_flags) },
- { INTe(sim_num) },
- { STRe(openssl_ciphers) },
- { INTe(erp) },
+ { INTe(sim_num, sim_num) },
+ { STRe(openssl_ciphers, openssl_ciphers) },
+ { INTe(erp, erp) },
#endif /* IEEE8021X_EAPOL */
{ FUNC_KEY(wep_key0) },
{ FUNC_KEY(wep_key1) },
@@ -2300,9 +2459,10 @@
{ INT(priority) },
#ifdef IEEE8021X_EAPOL
{ INT(eap_workaround) },
- { STRe(pac_file) },
- { INTe(fragment_size) },
- { INTe(ocsp) },
+ { STRe(pac_file, pac_file) },
+ { INTe(fragment_size, fragment_size) },
+ { INTe(ocsp, cert.ocsp) },
+ { INTe(ocsp2, phase2_cert.ocsp) },
#endif /* IEEE8021X_EAPOL */
#ifdef CONFIG_MESH
{ INT_RANGE(mode, 0, 5) },
@@ -2314,16 +2474,16 @@
{ INT_RANGE(proactive_key_caching, 0, 1) },
{ INT_RANGE(disabled, 0, 2) },
{ STR(id_str) },
-#ifdef CONFIG_IEEE80211W
{ INT_RANGE(ieee80211w, 0, 2) },
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
{ FUNC(ocv) },
#endif /* CONFIG_OCV */
{ FUNC(peerkey) /* obsolete - removed */ },
{ INT_RANGE(mixed_cell, 0, 1) },
- { INT_RANGE(frequency, 0, 65000) },
+ { INT_RANGE(frequency, 0, 70200) },
{ INT_RANGE(fixed_freq, 0, 1) },
+ { INT_RANGE(enable_edmg, 0, 1) },
+ { INT_RANGE(edmg_channel, 9, 13) },
#ifdef CONFIG_ACS
{ INT_RANGE(acs, 0, 1) },
#endif /* CONFIG_ACS */
@@ -2514,48 +2674,44 @@
#ifdef IEEE8021X_EAPOL
+
+static void eap_peer_config_free_cert(struct eap_peer_cert_config *cert)
+{
+ os_free(cert->ca_cert);
+ os_free(cert->ca_path);
+ os_free(cert->client_cert);
+ os_free(cert->private_key);
+ str_clear_free(cert->private_key_passwd);
+ os_free(cert->dh_file);
+ os_free(cert->subject_match);
+ os_free(cert->check_cert_subject);
+ os_free(cert->altsubject_match);
+ os_free(cert->domain_suffix_match);
+ os_free(cert->domain_match);
+ str_clear_free(cert->pin);
+ os_free(cert->engine_id);
+ os_free(cert->key_id);
+ os_free(cert->cert_id);
+ os_free(cert->ca_cert_id);
+}
+
+
static void eap_peer_config_free(struct eap_peer_config *eap)
{
os_free(eap->eap_methods);
bin_clear_free(eap->identity, eap->identity_len);
os_free(eap->anonymous_identity);
os_free(eap->imsi_identity);
+ os_free(eap->machine_identity);
bin_clear_free(eap->password, eap->password_len);
- os_free(eap->ca_cert);
- os_free(eap->ca_path);
- os_free(eap->client_cert);
- os_free(eap->private_key);
- str_clear_free(eap->private_key_passwd);
- os_free(eap->dh_file);
- os_free(eap->subject_match);
- os_free(eap->check_cert_subject);
- os_free(eap->altsubject_match);
- os_free(eap->domain_suffix_match);
- os_free(eap->domain_match);
- os_free(eap->ca_cert2);
- os_free(eap->ca_path2);
- os_free(eap->client_cert2);
- os_free(eap->private_key2);
- str_clear_free(eap->private_key2_passwd);
- os_free(eap->dh_file2);
- os_free(eap->subject_match2);
- os_free(eap->check_cert_subject2);
- os_free(eap->altsubject_match2);
- os_free(eap->domain_suffix_match2);
- os_free(eap->domain_match2);
+ bin_clear_free(eap->machine_password, eap->machine_password_len);
+ eap_peer_config_free_cert(&eap->cert);
+ eap_peer_config_free_cert(&eap->phase2_cert);
+ eap_peer_config_free_cert(&eap->machine_cert);
os_free(eap->phase1);
os_free(eap->phase2);
+ os_free(eap->machine_phase2);
os_free(eap->pcsc);
- str_clear_free(eap->pin);
- os_free(eap->engine_id);
- os_free(eap->key_id);
- os_free(eap->cert_id);
- os_free(eap->ca_cert_id);
- os_free(eap->key2_id);
- os_free(eap->cert2_id);
- os_free(eap->ca_cert2_id);
- str_clear_free(eap->pin2);
- os_free(eap->engine2_id);
os_free(eap->otp);
os_free(eap->pending_req_otp);
os_free(eap->pac_file);
@@ -2563,6 +2719,7 @@
str_clear_free(eap->external_sim_resp);
os_free(eap->openssl_ciphers);
}
+
#endif /* IEEE8021X_EAPOL */
@@ -2609,6 +2766,9 @@
dl_list_del(&psk->list);
bin_clear_free(psk, sizeof(*psk));
}
+#ifdef CONFIG_SAE
+ sae_deinit_pt(ssid->pt);
+#endif /* CONFIG_SAE */
bin_clear_free(ssid, sizeof(*ssid));
}
@@ -2727,6 +2887,8 @@
#ifdef CONFIG_MBO
os_free(config->non_pref_chan);
#endif /* CONFIG_MBO */
+ os_free(config->dpp_name);
+ os_free(config->dpp_mud_url);
os_free(config);
}
@@ -2901,9 +3063,7 @@
ssid->vht_tx_mcs_nss_8 = -1;
#endif /* CONFIG_VHT_OVERRIDES */
ssid->proactive_key_caching = -1;
-#ifdef CONFIG_IEEE80211W
ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_MACSEC
ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
#endif /* CONFIG_MACSEC */
@@ -2948,6 +3108,15 @@
}
ret = -1;
}
+#ifdef CONFIG_SAE
+ if (os_strcmp(var, "ssid") == 0 ||
+ os_strcmp(var, "psk") == 0 ||
+ os_strcmp(var, "sae_password") == 0 ||
+ os_strcmp(var, "sae_password_id") == 0) {
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ }
+#endif /* CONFIG_SAE */
break;
}
if (i == NUM_SSID_FIELDS) {
@@ -4827,6 +4996,8 @@
{ INT(okc), 0 },
{ INT(pmf), 0 },
{ FUNC(sae_groups), 0 },
+ { INT_RANGE(sae_pwe, 0, 2), 0 },
+ { INT_RANGE(sae_pmkid_in_assoc, 0, 1), 0 },
{ INT(dtim_period), 0 },
{ INT(beacon_int), 0 },
{ FUNC(ap_vendor_elements), 0 },
@@ -4866,7 +5037,11 @@
{ INT_RANGE(ftm_initiator, 0, 1), 0 },
{ INT(gas_rand_addr_lifetime), 0 },
{ INT_RANGE(gas_rand_mac_addr, 0, 2), 0 },
+#ifdef CONFIG_DPP
{ INT_RANGE(dpp_config_processing, 0, 2), 0 },
+ { STR(dpp_name), 0 },
+ { STR(dpp_mud_url), 0 },
+#endif /* CONFIG_DPP */
{ INT_RANGE(coloc_intf_reporting, 0, 1), 0 },
{ INT_RANGE(bss_no_flush_when_down, 0, 1), 0 },
#ifdef CONFIG_WNM
@@ -4987,6 +5162,7 @@
"AC item", line);
return -1;
}
+ return ret;
}
#endif /* CONFIG_AP */
if (line < 0)
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 46ab9ca..922a75e 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1165,6 +1165,19 @@
int *sae_groups;
/**
+ * sae_pwe - SAE mechanism for PWE derivation
+ * 0 = hunting-and-pecking loop only
+ * 1 = hash-to-element only
+ * 2 = both hunting-and-pecking loop and hash-to-element enabled
+ */
+ int sae_pwe;
+
+ /**
+ * sae_pmkid_in_assoc - Whether to include PMKID in SAE Assoc Req
+ */
+ int sae_pmkid_in_assoc;
+
+ /**
* dtim_period - Default DTIM period in Beacon intervals
*
* This parameter can be used to set the default value for network
@@ -1492,6 +1505,16 @@
int dpp_config_processing;
/**
+ * dpp_name - Name for Enrollee's DPP Configuration Request
+ */
+ char *dpp_name;
+
+ /**
+ * dpp_mud_url - MUD URL for Enrollee's DPP Configuration Request
+ */
+ char *dpp_mud_url;
+
+ /**
* coloc_intf_reporting - Colocated interference reporting
*
* dot11CoLocIntfReportingActivated
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 6fc18ba..7651465 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration backend: text file
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -745,9 +745,9 @@
#define STR(t) write_str(f, #t, ssid)
#define INT(t) write_int(f, #t, ssid->t, 0)
-#define INTe(t) write_int(f, #t, ssid->eap.t, 0)
+#define INTe(t, m) write_int(f, #t, ssid->eap.m, 0)
#define INT_DEF(t, def) write_int(f, #t, ssid->t, def)
-#define INT_DEFe(t, def) write_int(f, #t, ssid->eap.t, def)
+#define INT_DEFe(t, m, def) write_int(f, #t, ssid->eap.m, def)
STR(ssid);
INT(scan_ssid);
@@ -774,7 +774,9 @@
STR(identity);
STR(anonymous_identity);
STR(imsi_identity);
+ STR(machine_identity);
STR(password);
+ STR(machine_password);
STR(ca_cert);
STR(ca_path);
STR(client_cert);
@@ -797,8 +799,20 @@
STR(altsubject_match2);
STR(domain_suffix_match2);
STR(domain_match2);
+ STR(machine_ca_cert);
+ STR(machine_ca_path);
+ STR(machine_client_cert);
+ STR(machine_private_key);
+ STR(machine_private_key_passwd);
+ STR(machine_dh_file);
+ STR(machine_subject_match);
+ STR(machine_check_cert_subject);
+ STR(machine_altsubject_match);
+ STR(machine_domain_suffix_match);
+ STR(machine_domain_match);
STR(phase1);
STR(phase2);
+ STR(machine_phase2);
STR(pcsc);
STR(pin);
STR(engine_id);
@@ -810,11 +824,12 @@
STR(engine2_id);
STR(cert2_id);
STR(ca_cert2_id);
- INTe(engine);
- INTe(engine2);
+ INTe(engine, cert.engine);
+ INTe(engine2, phase2_cert.engine);
+ INTe(machine_engine, machine_cert.engine);
INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
STR(openssl_ciphers);
- INTe(erp);
+ INTe(erp, erp);
#endif /* IEEE8021X_EAPOL */
for (i = 0; i < 4; i++)
write_wep_key(f, i, ssid);
@@ -823,13 +838,17 @@
#ifdef IEEE8021X_EAPOL
INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
STR(pac_file);
- INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
- INTe(ocsp);
- INT_DEFe(sim_num, DEFAULT_USER_SELECTED_SIM);
+ INT_DEFe(fragment_size, fragment_size, DEFAULT_FRAGMENT_SIZE);
+ INTe(ocsp, cert.ocsp);
+ INTe(ocsp2, phase2_cert.ocsp);
+ INTe(machine_ocsp, machine_cert.ocsp);
+ INT_DEFe(sim_num, sim_num, DEFAULT_USER_SELECTED_SIM);
#endif /* IEEE8021X_EAPOL */
INT(mode);
INT(no_auto_peer);
INT(frequency);
+ INT(enable_edmg);
+ INT(edmg_channel);
INT(fixed_freq);
#ifdef CONFIG_ACS
INT(acs);
@@ -846,10 +865,8 @@
INT(pbss);
INT(wps_disabled);
INT(fils_dh_group);
-#ifdef CONFIG_IEEE80211W
write_int(f, "ieee80211w", ssid->ieee80211w,
MGMT_FRAME_PROTECTION_DEFAULT);
-#endif /* CONFIG_IEEE80211W */
STR(id_str);
#ifdef CONFIG_P2P
write_go_p2p_dev_addr(f, ssid);
@@ -1390,6 +1407,13 @@
fprintf(f, "\n");
}
+ if (config->sae_pwe)
+ fprintf(f, "sae_pwe=%d\n", config->sae_pwe);
+
+ if (config->sae_pmkid_in_assoc)
+ fprintf(f, "sae_pmkid_in_assoc=%d\n",
+ config->sae_pmkid_in_assoc);
+
if (config->ap_vendor_elements) {
int i, len = wpabuf_len(config->ap_vendor_elements);
const u8 *p = wpabuf_head_u8(config->ap_vendor_elements);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 6fd3a01..af8317b 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -47,30 +47,6 @@
u8 p2p;
};
-/**
- * mode - IEEE 802.11 operation mode (Infrastucture/IBSS)
- *
- * 0 = infrastructure (Managed) mode, i.e., associate with an AP.
- *
- * 1 = IBSS (ad-hoc, peer-to-peer)
- *
- * 2 = AP (access point)
- *
- * 3 = P2P Group Owner (can be set in the configuration file)
- *
- * 4 = P2P Group Formation (used internally; not in configuration
- * files)
- *
- * 5 = Mesh
- *
- * Note: IBSS can only be used with key_mgmt NONE (plaintext and static
- * WEP) and WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE
- * (fixed group key TKIP/CCMP) is available for backwards compatibility,
- * but its use is deprecated. WPA-None requires following network block
- * options: proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or
- * CCMP, but not both), and psk must also be set (either directly or
- * using ASCII passphrase).
- */
enum wpas_mode {
WPAS_MODE_INFRA = 0,
WPAS_MODE_IBSS = 1,
@@ -236,6 +212,8 @@
*/
char *sae_password_id;
+ struct sae_pt *pt;
+
/**
* ext_psk - PSK/passphrase name in external storage
*
@@ -469,7 +447,6 @@
*/
char *id_str;
-#ifdef CONFIG_IEEE80211W
/**
* ieee80211w - Whether management frame protection is enabled
*
@@ -483,7 +460,6 @@
* followed).
*/
enum mfp_options ieee80211w;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
/**
@@ -509,6 +485,23 @@
int frequency;
/**
+ * enable_edmg - Enable EDMG feature in STA/AP mode
+ *
+ * This flag is used for enabling the EDMG capability in STA/AP mode.
+ */
+ int enable_edmg;
+
+ /**
+ * edmg_channel - EDMG channel number
+ *
+ * This value is used to configure the EDMG channel bonding feature.
+ * In AP mode it defines the EDMG channel to start the AP on.
+ * in STA mode it defines the EDMG channel to use for connection
+ * (if supported by AP).
+ */
+ u8 edmg_channel;
+
+ /**
* fixed_freq - Use fixed frequency for IBSS
*/
int fixed_freq;
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 3ea5c80..0f2a30a 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration backend: Windows registry
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -868,9 +868,9 @@
#define STR(t) write_str(netw, #t, ssid)
#define INT(t) write_int(netw, #t, ssid->t, 0)
-#define INTe(t) write_int(netw, #t, ssid->eap.t, 0)
+#define INTe(t, m) write_int(netw, #t, ssid->eap.m, 0)
#define INT_DEF(t, def) write_int(netw, #t, ssid->t, def)
-#define INT_DEFe(t, def) write_int(netw, #t, ssid->eap.t, def)
+#define INT_DEFe(t, m, def) write_int(netw, #t, ssid->eap.m, def)
STR(ssid);
INT(scan_ssid);
@@ -920,8 +920,8 @@
STR(engine2_id);
STR(cert2_id);
STR(ca_cert2_id);
- INTe(engine);
- INTe(engine2);
+ INTe(engine, cert.engine);
+ INTe(engine2, phase2_cert.engine);
INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
#endif /* IEEE8021X_EAPOL */
for (i = 0; i < 4; i++)
@@ -931,16 +931,14 @@
#ifdef IEEE8021X_EAPOL
INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
STR(pac_file);
- INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
+ INT_DEFe(fragment_size, fragment_size, DEFAULT_FRAGMENT_SIZE);
#endif /* IEEE8021X_EAPOL */
INT(mode);
write_int(netw, "proactive_key_caching", ssid->proactive_key_caching,
-1);
INT(disabled);
-#ifdef CONFIG_IEEE80211W
write_int(netw, "ieee80211w", ssid->ieee80211w,
MGMT_FRAME_PROTECTION_DEFAULT);
-#endif /* CONFIG_IEEE80211W */
STR(id_str);
#ifdef CONFIG_HS20
INT(update_identifier);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 8efc08d..7f8ec4a 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -11,7 +11,6 @@
#include <netinet/ip.h>
#endif /* CONFIG_TESTING_OPTIONS */
-#include <net/ethernet.h>
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/uuid.h"
@@ -58,6 +57,12 @@
#include "dpp_supplicant.h"
#include "sme.h"
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#elif !defined(__CYGWIN__) && !defined(CONFIG_NATIVE_WINDOWS)
+#include <net/ethernet.h>
+#endif
+
static int wpa_supplicant_global_iface_list(struct wpa_global *global,
char *buf, int len);
static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
@@ -2654,7 +2659,6 @@
pos += ret;
}
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
pos == start ? "" : "+");
@@ -2669,7 +2673,6 @@
return pos;
pos += ret;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SUITEB
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
@@ -2873,6 +2876,15 @@
}
if (bss_is_dmg(bss)) {
const char *s;
+
+ if (get_ie_ext((const u8 *) (bss + 1), bss->ie_len,
+ WLAN_EID_EXT_EDMG_OPERATION)) {
+ ret = os_snprintf(pos, end - pos, "[EDMG]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
ret = os_snprintf(pos, end - pos, "[DMG]");
if (os_snprintf_error(end - pos, ret))
return -1;
@@ -5241,10 +5253,8 @@
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
-#ifdef CONFIG_IEEE80211W
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
-#endif /* CONFIG_IEEE80211W */
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
0);
@@ -10624,12 +10634,10 @@
} else if (os_strcmp(buf, "RESEND_ASSOC") == 0) {
if (wpas_ctrl_resend_assoc(wpa_s) < 0)
reply_len = -1;
-#ifdef CONFIG_IEEE80211W
} else if (os_strcmp(buf, "UNPROT_DEAUTH") == 0) {
sme_event_unprot_disconnect(
wpa_s, wpa_s->bssid, NULL,
WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
-#endif /* CONFIG_IEEE80211W */
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index fc2fc2e..5e6b522 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -3803,6 +3803,12 @@
NULL,
NULL
},
+ { "MACAddressRandomizationMask", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "a{say}",
+ wpas_dbus_getter_mac_address_randomization_mask,
+ wpas_dbus_setter_mac_address_randomization_mask,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -4791,8 +4797,8 @@
if (!wpa_s->dbus_groupobj_path) {
wpa_printf(MSG_DEBUG,
- "%s: Group object '%s' already unregistered",
- __func__, wpa_s->dbus_groupobj_path);
+ "%s: Group object has already unregistered",
+ __func__);
return;
}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 6c36d91..2582092 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -984,8 +984,7 @@
const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
- const char *capabilities[10] = { NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL };
+ const char *capabilities[11];
size_t num_items = 0;
#ifdef CONFIG_FILS
struct wpa_global *global = user_data;
@@ -1012,9 +1011,7 @@
#ifdef CONFIG_INTERWORKING
capabilities[num_items++] = "interworking";
#endif /* CONFIG_INTERWORKING */
-#ifdef CONFIG_IEEE80211W
capabilities[num_items++] = "pmf";
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_MESH
capabilities[num_items++] = "mesh";
#endif /* CONFIG_MESH */
@@ -1030,6 +1027,9 @@
#ifdef CONFIG_SHA384
capabilities[num_items++] = "sha384";
#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_OWE
+ capabilities[num_items++] = "owe";
+#endif /* CONFIG_OWE */
return wpas_dbus_simple_array_property_getter(iter,
DBUS_TYPE_STRING,
@@ -2753,11 +2753,9 @@
goto nomem;
/* TODO: Ensure that driver actually supports sha256 encryption. */
-#ifdef CONFIG_IEEE80211W
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "wpa-eap-sha256"))
goto nomem;
-#endif /* CONFIG_IEEE80211W */
}
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
@@ -2771,11 +2769,9 @@
goto nomem;
/* TODO: Ensure that driver actually supports sha256 encryption. */
-#ifdef CONFIG_IEEE80211W
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "wpa-psk-sha256"))
goto nomem;
-#endif /* CONFIG_IEEE80211W */
}
if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
@@ -3990,6 +3986,173 @@
/**
+ * wpas_dbus_setter_mac_address_randomization_mask - Set masks used for
+ * MAC address randomization
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "MACAddressRandomizationMask" property.
+ */
+dbus_bool_t wpas_dbus_setter_mac_address_randomization_mask(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
+ const char *key;
+ unsigned int rand_type = 0;
+ const u8 *mask;
+ int mask_len;
+ unsigned int rand_types_to_disable = MAC_ADDR_RAND_ALL;
+
+ dbus_message_iter_recurse(iter, &variant_iter);
+ if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY) {
+ dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+ "invalid message format");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(&variant_iter, &dict_iter);
+ while (dbus_message_iter_get_arg_type(&dict_iter) ==
+ DBUS_TYPE_DICT_ENTRY) {
+ dbus_message_iter_recurse(&dict_iter, &entry_iter);
+ if (dbus_message_iter_get_arg_type(&entry_iter) !=
+ DBUS_TYPE_STRING) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: key not a string", __func__);
+ return FALSE;
+ }
+ dbus_message_iter_get_basic(&entry_iter, &key);
+ dbus_message_iter_next(&entry_iter);
+ if (dbus_message_iter_get_arg_type(&entry_iter) !=
+ DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&entry_iter) !=
+ DBUS_TYPE_BYTE) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: mask was not a byte array",
+ __func__);
+ return FALSE;
+ }
+ dbus_message_iter_recurse(&entry_iter, &array_iter);
+ dbus_message_iter_get_fixed_array(&array_iter, &mask,
+ &mask_len);
+
+ if (os_strcmp(key, "scan") == 0) {
+ rand_type = MAC_ADDR_RAND_SCAN;
+ } else if (os_strcmp(key, "sched_scan") == 0) {
+ rand_type = MAC_ADDR_RAND_SCHED_SCAN;
+ } else if (os_strcmp(key, "pno") == 0) {
+ rand_type = MAC_ADDR_RAND_PNO;
+ } else {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: bad scan type \"%s\"",
+ __func__, key);
+ return FALSE;
+ }
+
+ if (mask_len != ETH_ALEN) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: malformed MAC mask given",
+ __func__);
+ return FALSE;
+ }
+
+ if (wpas_enable_mac_addr_randomization(
+ wpa_s, rand_type, wpa_s->perm_addr, mask)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to set up MAC address randomization for %s",
+ __func__, key);
+ return FALSE;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "%s: Enabled MAC address randomization for %s with mask: "
+ MACSTR, wpa_s->ifname, key, MAC2STR(mask));
+ rand_types_to_disable &= ~rand_type;
+ dbus_message_iter_next(&dict_iter);
+ }
+
+ if (rand_types_to_disable &&
+ wpas_disable_mac_addr_randomization(wpa_s, rand_types_to_disable)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to disable MAC address randomization",
+ __func__);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_mac_address_randomization_mask(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
+ unsigned int i;
+ u8 mask_buf[ETH_ALEN];
+ /* Read docs on dbus_message_iter_append_fixed_array() for why this
+ * is necessary... */
+ u8 *mask = mask_buf;
+ static const struct {
+ const char *key;
+ unsigned int type;
+ } types[] = {
+ { "scan", MAC_ADDR_RAND_SCAN },
+ { "sched_scan", MAC_ADDR_RAND_SCHED_SCAN },
+ { "pno", MAC_ADDR_RAND_PNO }
+ };
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ "a{say}", &variant_iter) ||
+ !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ "{say}", &dict_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(types); i++) {
+ if (wpas_mac_addr_rand_scan_get_mask(wpa_s, types[i].type,
+ mask))
+ continue;
+
+ if (!dbus_message_iter_open_container(&dict_iter,
+ DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry_iter) ||
+ !dbus_message_iter_append_basic(&entry_iter,
+ DBUS_TYPE_STRING,
+ &types[i].key) ||
+ !dbus_message_iter_open_container(&entry_iter,
+ DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &array_iter) ||
+ !dbus_message_iter_append_fixed_array(&array_iter,
+ DBUS_TYPE_BYTE,
+ &mask,
+ ETH_ALEN) ||
+ !dbus_message_iter_close_container(&entry_iter,
+ &array_iter) ||
+ !dbus_message_iter_close_container(&dict_iter,
+ &entry_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+ "no memory");
+ return FALSE;
+ }
+ }
+
+ if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
* wpas_dbus_getter_sta_address - Return the address of a connected station
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -4497,7 +4660,7 @@
DBusMessageIter iter_dict, variant_iter;
const char *group;
const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
- const char *key_mgmt[15]; /* max 15 key managements may be supported */
+ const char *key_mgmt[16]; /* max 16 key managements may be supported */
int n;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -4550,6 +4713,10 @@
if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE)
key_mgmt[n++] = "ft-sae";
#endif /* CONFIG_SAE */
+#ifdef CONFIG_OWE
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_OWE)
+ key_mgmt[n++] = "owe";
+#endif /* CONFIG_OWE */
if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
key_mgmt[n++] = "wpa-none";
@@ -4608,11 +4775,9 @@
/* Management group (RSN only) */
if (ie_data->proto == WPA_PROTO_RSN) {
switch (ie_data->mgmt_group_cipher) {
-#ifdef CONFIG_IEEE80211W
case WPA_CIPHER_AES_128_CMAC:
group = "aes128cmac";
break;
-#endif /* CONFIG_IEEE80211W */
default:
group = "";
break;
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index d922ce1..afa26ef 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -177,6 +177,8 @@
DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_module_path);
DECLARE_ACCESSOR(wpas_dbus_getter_blobs);
DECLARE_ACCESSOR(wpas_dbus_getter_stas);
+DECLARE_ACCESSOR(wpas_dbus_getter_mac_address_randomization_mask);
+DECLARE_ACCESSOR(wpas_dbus_setter_mac_address_randomization_mask);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_address);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 8cdd885..19715eb 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -40,6 +40,14 @@
}
+static dbus_bool_t no_p2p_mgmt_interface(DBusError *error)
+{
+ dbus_set_error_const(error, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+ "Could not find P2P mgmt interface");
+ return FALSE;
+}
+
+
/**
* Parses out the mac address from the peer object path.
* @peer_path - object path of the form
@@ -78,6 +86,22 @@
}
+/**
+ * wpas_dbus_error_no_p2p_mgmt_iface - Return a new InterfaceUnknown error
+ * message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an unknown interface error.
+ */
+static DBusMessage * wpas_dbus_error_no_p2p_mgmt_iface(DBusMessage *message)
+{
+ wpa_printf(MSG_DEBUG, "dbus: Could not find P2P mgmt interface");
+ return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+ "Could not find P2P mgmt interface");
+}
+
+
DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
@@ -145,6 +169,10 @@
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto error_nop2p;
+ }
if (wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types,
req_dev_types, NULL, 0, 0, NULL, freq))
@@ -157,8 +185,9 @@
error_clear:
wpa_dbus_dict_entry_clear(&entry);
error:
- os_free(req_dev_types);
reply = wpas_dbus_error_invalid_args(message, entry.key);
+error_nop2p:
+ os_free(req_dev_types);
return reply;
}
@@ -166,7 +195,9 @@
DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
- wpas_p2p_stop_find(wpa_s->global->p2p_init_wpa_s);
+ wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (wpa_s)
+ wpas_p2p_stop_find(wpa_s);
return NULL;
}
@@ -185,6 +216,8 @@
return wpas_dbus_error_invalid_args(message, NULL);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
return wpas_dbus_error_unknown_error(message,
@@ -204,6 +237,8 @@
return wpas_dbus_error_no_memory(message);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_listen(wpa_s, (unsigned int) timeout)) {
return dbus_message_new_error(message,
@@ -245,6 +280,8 @@
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_ext_listen(wpa_s, period, interval))
return wpas_dbus_error_unknown_error(
@@ -350,6 +387,10 @@
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto out;
+ }
if (pg_object_path != NULL) {
char *net_id_str;
@@ -433,6 +474,12 @@
"P2P is not available for this interface");
return FALSE;
}
+ if (!wpa_s->global->p2p_init_wpa_s) {
+ if (out_reply)
+ *out_reply = wpas_dbus_error_no_p2p_mgmt_iface(
+ message);
+ return no_p2p_mgmt_interface(error);
+ }
return TRUE;
}
@@ -822,6 +869,8 @@
return wpas_dbus_error_invalid_args(message, NULL);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
WPAS_P2P_PD_FOR_GO_NEG, NULL) < 0)
@@ -1882,6 +1931,8 @@
wpa_s = peer_args->wpa_s;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return no_p2p_mgmt_interface(error);
wpa_s_go = wpas_get_p2p_client_iface(wpa_s, info->p2p_device_addr);
if (wpa_s_go) {
@@ -1963,6 +2014,9 @@
dbus_bool_t success = FALSE;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return no_p2p_mgmt_interface(error);
+
if (!wpa_s->parent->dbus_new_path)
return FALSE;
@@ -2077,6 +2131,11 @@
dbus_message_iter_init(message, &iter);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto err;
+ }
+
if (wpa_s->parent->dbus_new_path)
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL) {
@@ -2159,6 +2218,10 @@
DBUS_TYPE_INVALID);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto out;
+ }
/*
* Extract the network ID and ensure the network is actually a child of
@@ -2235,6 +2298,8 @@
struct wpa_config *config;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
config = wpa_s->conf;
ssid = config->ssid;
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c
index d80e2d4..d9009ba 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -742,7 +742,7 @@
DBusConnection *con = eloop_ctx;
struct wpa_dbus_object_desc *obj_desc = timeout_ctx;
- wpa_printf(MSG_DEBUG,
+ wpa_printf(MSG_MSGDUMP,
"dbus: %s: Timeout - sending changed properties of object %s",
__func__, obj_desc->path);
wpa_dbus_flush_object_changed_properties(con, obj_desc->path);
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index cdfb197..792ab24 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -310,10 +310,6 @@
# bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
-# IEEE 802.11w (management frame protection), also known as PMF
-# Driver support is also needed for IEEE 802.11w.
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
@@ -366,7 +362,7 @@
#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
# Add support for new DBus control interface
-# (fi.w1.hostap.wpa_supplicant1)
+# (fi.w1.wpa_supplicant1)
CONFIG_CTRL_IFACE_DBUS_NEW=y
# Add introspection support for new DBus control interface
@@ -610,6 +606,4 @@
#CONFIG_OWE=y
# Device Provisioning Protocol (DPP)
-# This requires CONFIG_IEEE80211W=y to be enabled, too. (see
-# wpa_supplicant/README-DPP for details)
CONFIG_DPP=y
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 30ef5db..ff30e9a 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -149,6 +149,8 @@
static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
+ wpa_s->suitable_network = 0;
+ wpa_s->no_suitable_network = 0;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_s->scan_runs = 0;
@@ -158,6 +160,141 @@
}
+#ifdef CONFIG_DPP2
+
+static void wpas_dpp_conn_status_result_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ enum dpp_status_error result;
+
+ if (!auth || !auth->conn_status_requested)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Connection timeout - report Connection Status Result");
+ if (wpa_s->suitable_network)
+ result = DPP_STATUS_AUTH_FAILURE;
+ else if (wpa_s->no_suitable_network)
+ result = DPP_STATUS_NO_AP;
+ else
+ result = 255; /* What to report here for unexpected state? */
+ wpas_dpp_send_conn_status_result(wpa_s, result);
+}
+
+
+static char * wpas_dpp_scan_channel_list(struct wpa_supplicant *wpa_s)
+{
+ char *str, *end, *pos;
+ size_t len;
+ unsigned int i;
+ u8 last_op_class = 0;
+ int res;
+
+ if (!wpa_s->last_scan_freqs || !wpa_s->num_last_scan_freqs)
+ return NULL;
+
+ len = wpa_s->num_last_scan_freqs * 8;
+ str = os_zalloc(len);
+ if (!str)
+ return NULL;
+ end = str + len;
+ pos = str;
+
+ for (i = 0; i < wpa_s->num_last_scan_freqs; i++) {
+ enum hostapd_hw_mode mode;
+ u8 op_class, channel;
+
+ mode = ieee80211_freq_to_channel_ext(wpa_s->last_scan_freqs[i],
+ 0, 0, &op_class, &channel);
+ if (mode == NUM_HOSTAPD_MODES)
+ continue;
+ if (op_class == last_op_class)
+ res = os_snprintf(pos, end - pos, ",%d", channel);
+ else
+ res = os_snprintf(pos, end - pos, "%s%d/%d",
+ pos == str ? "" : ",",
+ op_class, channel);
+ if (os_snprintf_error(end - pos, res)) {
+ *pos = '\0';
+ break;
+ }
+ pos += res;
+ last_op_class = op_class;
+ }
+
+ if (pos == str) {
+ os_free(str);
+ str = NULL;
+ }
+ return str;
+}
+
+
+void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
+ enum dpp_status_error result)
+{
+ struct wpabuf *msg;
+ const char *channel_list = NULL;
+ char *channel_list_buf = NULL;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
+
+ if (!auth || !auth->conn_status_requested)
+ return;
+ auth->conn_status_requested = 0;
+ wpa_printf(MSG_DEBUG, "DPP: Report connection status result %d",
+ result);
+
+ if (result == DPP_STATUS_NO_AP) {
+ channel_list_buf = wpas_dpp_scan_channel_list(wpa_s);
+ channel_list = channel_list_buf;
+ }
+
+ msg = dpp_build_conn_status_result(auth, result,
+ ssid ? ssid->ssid :
+ wpa_s->dpp_last_ssid,
+ ssid ? ssid->ssid_len :
+ wpa_s->dpp_last_ssid_len,
+ channel_list);
+ os_free(channel_list_buf);
+ if (!msg) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+ DPP_PA_CONNECTION_STATUS_RESULT);
+ offchannel_send_action(wpa_s, auth->curr_freq,
+ auth->peer_mac_addr, wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ 500, wpas_dpp_tx_status, 0);
+ wpabuf_free(msg);
+
+ /* This exchange will be terminated in the TX status handler */
+ auth->remove_on_tx_status = 1;
+
+ return;
+}
+
+
+void wpas_dpp_connected(struct wpa_supplicant *wpa_s)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (auth && auth->conn_status_requested)
+ wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_OK);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid,
@@ -183,18 +320,30 @@
#ifdef CONFIG_DPP2
if (auth->connect_on_tx_status) {
+ auth->connect_on_tx_status = 0;
wpa_printf(MSG_DEBUG,
"DPP: Try to connect after completed configuration result");
wpas_dpp_try_to_connect(wpa_s);
- dpp_auth_deinit(wpa_s->dpp_auth);
- wpa_s->dpp_auth = NULL;
+ if (auth->conn_status_requested) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Start 15 second timeout for reporting connection status result");
+ eloop_cancel_timeout(
+ wpas_dpp_conn_status_result_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(
+ 15, 0, wpas_dpp_conn_status_result_timeout,
+ wpa_s, NULL);
+ } else {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ }
return;
}
#endif /* CONFIG_DPP2 */
if (wpa_s->dpp_auth->remove_on_tx_status) {
wpa_printf(MSG_DEBUG,
- "DPP: Terminate authentication exchange due to an earlier error");
+ "DPP: Terminate authentication exchange due to a request to do so on TX status");
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
@@ -812,12 +961,13 @@
static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
struct wpa_ssid *ssid;
#ifdef CONFIG_DPP2
- if (auth->akm == DPP_AKM_SAE) {
+ if (conf->akm == DPP_AKM_SAE) {
#ifdef CONFIG_SAE
struct wpa_driver_capa capa;
int res;
@@ -844,27 +994,27 @@
wpa_config_set_network_defaults(ssid);
ssid->disabled = 1;
- ssid->ssid = os_malloc(auth->ssid_len);
+ ssid->ssid = os_malloc(conf->ssid_len);
if (!ssid->ssid)
goto fail;
- os_memcpy(ssid->ssid, auth->ssid, auth->ssid_len);
- ssid->ssid_len = auth->ssid_len;
+ os_memcpy(ssid->ssid, conf->ssid, conf->ssid_len);
+ ssid->ssid_len = conf->ssid_len;
- if (auth->connector) {
+ if (conf->connector) {
ssid->key_mgmt = WPA_KEY_MGMT_DPP;
ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
- ssid->dpp_connector = os_strdup(auth->connector);
+ ssid->dpp_connector = os_strdup(conf->connector);
if (!ssid->dpp_connector)
goto fail;
}
- if (auth->c_sign_key) {
- ssid->dpp_csign = os_malloc(wpabuf_len(auth->c_sign_key));
+ if (conf->c_sign_key) {
+ ssid->dpp_csign = os_malloc(wpabuf_len(conf->c_sign_key));
if (!ssid->dpp_csign)
goto fail;
- os_memcpy(ssid->dpp_csign, wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
- ssid->dpp_csign_len = wpabuf_len(auth->c_sign_key);
+ os_memcpy(ssid->dpp_csign, wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
+ ssid->dpp_csign_len = wpabuf_len(conf->c_sign_key);
}
if (auth->net_access_key) {
@@ -879,29 +1029,32 @@
ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry;
}
- if (!auth->connector || dpp_akm_psk(auth->akm) ||
- dpp_akm_sae(auth->akm)) {
- if (!auth->connector)
+ if (!conf->connector || dpp_akm_psk(conf->akm) ||
+ dpp_akm_sae(conf->akm)) {
+ if (!conf->connector)
ssid->key_mgmt = 0;
- if (dpp_akm_psk(auth->akm))
+ if (dpp_akm_psk(conf->akm))
ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
- if (dpp_akm_sae(auth->akm))
+ if (dpp_akm_sae(conf->akm))
ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
WPA_KEY_MGMT_FT_SAE;
ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
- if (auth->passphrase[0]) {
+ if (conf->passphrase[0]) {
if (wpa_config_set_quoted(ssid, "psk",
- auth->passphrase) < 0)
+ conf->passphrase) < 0)
goto fail;
wpa_config_update_psk(ssid);
ssid->export_keys = 1;
} else {
- ssid->psk_set = auth->psk_set;
- os_memcpy(ssid->psk, auth->psk, PMK_LEN);
+ ssid->psk_set = conf->psk_set;
+ os_memcpy(ssid->psk, conf->psk, PMK_LEN);
}
}
+ os_memcpy(wpa_s->dpp_last_ssid, conf->ssid, conf->ssid_len);
+ wpa_s->dpp_last_ssid_len = conf->ssid_len;
+
return ssid;
fail:
wpas_notify_network_removed(wpa_s, ssid);
@@ -911,14 +1064,15 @@
static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
struct wpa_ssid *ssid;
if (wpa_s->conf->dpp_config_processing < 1)
return 0;
- ssid = wpas_dpp_add_network(wpa_s, auth);
+ ssid = wpas_dpp_add_network(wpa_s, auth, conf);
if (!ssid)
return -1;
@@ -935,49 +1089,56 @@
wpa_printf(MSG_DEBUG, "DPP: Failed to update configuration");
#endif /* CONFIG_NO_CONFIG_WRITE */
+ return 0;
+}
+
+
+static void wpas_dpp_post_process_config(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth)
+{
if (wpa_s->conf->dpp_config_processing < 2)
- return 0;
+ return;
#ifdef CONFIG_DPP2
if (auth->peer_version >= 2) {
wpa_printf(MSG_DEBUG,
"DPP: Postpone connection attempt to wait for completion of DPP Configuration Result");
auth->connect_on_tx_status = 1;
- return 0;
+ return;
}
#endif /* CONFIG_DPP2 */
wpas_dpp_try_to_connect(wpa_s);
- return 0;
}
static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
- if (auth->ssid_len)
+ if (conf->ssid_len)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
- wpa_ssid_txt(auth->ssid, auth->ssid_len));
- if (auth->connector) {
+ wpa_ssid_txt(conf->ssid, conf->ssid_len));
+ if (conf->connector) {
/* TODO: Save the Connector and consider using a command
* to fetch the value instead of sending an event with
* it. The Connector could end up being larger than what
* most clients are ready to receive as an event
* message. */
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
- auth->connector);
+ conf->connector);
}
- if (auth->c_sign_key) {
+ if (conf->c_sign_key) {
char *hex;
size_t hexlen;
- hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
+ hexlen = 2 * wpabuf_len(conf->c_sign_key) + 1;
hex = os_malloc(hexlen);
if (hex) {
wpa_snprintf_hex(hex, hexlen,
- wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
+ wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY "%s",
hex);
os_free(hex);
@@ -1005,7 +1166,7 @@
}
}
- return wpas_dpp_process_config(wpa_s, auth);
+ return wpas_dpp_process_config(wpa_s, auth, conf);
}
@@ -1019,6 +1180,7 @@
struct dpp_authentication *auth = wpa_s->dpp_auth;
int res;
enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
+ unsigned int i;
wpa_s->dpp_gas_dialog_token = -1;
@@ -1056,9 +1218,14 @@
goto fail;
}
- res = wpas_dpp_handle_config_obj(wpa_s, auth);
- if (res < 0)
- goto fail;
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ res = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[i]);
+ if (res < 0)
+ goto fail;
+ }
+ if (auth->num_conf_obj)
+ wpas_dpp_post_process_config(wpa_s, auth);
status = DPP_STATUS_OK;
#ifdef CONFIG_TESTING_OPTIONS
@@ -1107,27 +1274,19 @@
{
struct dpp_authentication *auth = wpa_s->dpp_auth;
struct wpabuf *buf;
- char json[100];
int res;
+ int *supp_op_classes;
wpa_s->dpp_gas_client = 1;
- os_snprintf(json, sizeof(json),
- "{\"name\":\"Test\","
- "\"wi-fi_tech\":\"infra\","
- "\"netRole\":\"%s\"}",
- wpa_s->dpp_netrole_ap ? "ap" : "sta");
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
- json[29] = 'k'; /* replace "infra" with "knfra" */
- }
-#endif /* CONFIG_TESTING_OPTIONS */
- wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
-
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
- buf = dpp_build_conf_req(auth, json);
+ supp_op_classes = wpas_supp_op_classes(wpa_s);
+ buf = dpp_build_conf_req_helper(auth, wpa_s->conf->dpp_name,
+ wpa_s->dpp_netrole_ap,
+ wpa_s->conf->dpp_mud_url,
+ supp_op_classes);
+ os_free(supp_op_classes);
if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
@@ -1281,6 +1440,24 @@
}
+static void wpas_dpp_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->waiting_conn_status_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Connection Status Result");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT "timeout");
+ wpas_dpp_listen_stop(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+}
+
+
static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len)
{
@@ -1304,6 +1481,23 @@
status = dpp_conf_result_rx(auth, hdr, buf, len);
+ if (status == DPP_STATUS_OK && auth->send_conn_status) {
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
+ eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
+ wpa_s, NULL);
+ auth->waiting_conn_status_result = 1;
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(16, 0,
+ wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_start(wpa_s, auth->neg_freq ? auth->neg_freq :
+ auth->curr_freq);
+ return;
+ }
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
if (status == DPP_STATUS_OK)
@@ -1316,12 +1510,57 @@
}
+static void wpas_dpp_rx_conn_status_result(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ enum dpp_status_error status;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len = 0;
+ char *channel_list = NULL;
+
+ wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
+
+ if (!auth || !auth->waiting_conn_status_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for connection status result - drop");
+ return;
+ }
+
+ status = dpp_conn_status_result_rx(auth, hdr, buf, len,
+ ssid, &ssid_len, &channel_list);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT
+ "result=%d ssid=%s channel_list=%s",
+ status, wpa_ssid_txt(ssid, ssid_len),
+ channel_list ? channel_list : "N/A");
+ os_free(channel_list);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+}
+
+
static int wpas_dpp_process_conf_obj(void *ctx,
struct dpp_authentication *auth)
{
struct wpa_supplicant *wpa_s = ctx;
+ unsigned int i;
+ int res = -1;
- return wpas_dpp_handle_config_obj(wpa_s, auth);
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ res = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[i]);
+ if (res)
+ break;
+ }
+ if (!res)
+ wpas_dpp_post_process_config(wpa_s, auth);
+
+ return res;
}
#endif /* CONFIG_DPP2 */
@@ -1394,6 +1633,9 @@
status[0]);
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
" status=%u", MAC2STR(src), status[0]);
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s, status[0]);
+#endif /* CONFIG_DPP2 */
goto fail;
}
@@ -1417,6 +1659,9 @@
"DPP: Network Introduction protocol resulted in failure");
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
" fail=peer_connector_validation_failed", MAC2STR(src));
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s, res);
+#endif /* CONFIG_DPP2 */
goto fail;
}
@@ -1859,6 +2104,9 @@
case DPP_PA_CONFIGURATION_RESULT:
wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len);
break;
+ case DPP_PA_CONNECTION_STATUS_RESULT:
+ wpas_dpp_rx_conn_status_result(wpa_s, src, hdr, buf, len);
+ break;
#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
@@ -1894,6 +2142,18 @@
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return NULL;
}
+
+ if (wpa_s->dpp_auth_ok_on_ack && auth->configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Have not received ACK for Auth Confirm yet - assume it was received based on this GAS request");
+ /* wpas_dpp_auth_success() would normally have been called from
+ * TX status handler, but since there was no such handler call
+ * yet, simply send out the event message and proceed with
+ * exchange. */
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=1");
+ wpa_s->dpp_auth_ok_on_ack = 0;
+ }
+
wpa_hexdump(MSG_DEBUG,
"DPP: Received Configuration Request (GAS Query Request)",
query, query_len);
@@ -1976,7 +2236,10 @@
wpas_dpp_set_testing_options(wpa_s, auth);
if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) == 0 &&
dpp_configurator_own_config(auth, curve, 0) == 0)
- ret = wpas_dpp_handle_config_obj(wpa_s, auth);
+ ret = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[0]);
+ if (!ret)
+ wpas_dpp_post_process_config(wpa_s, auth);
dpp_auth_deinit(auth);
os_free(curve);
@@ -2299,6 +2562,9 @@
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
#ifdef CONFIG_DPP2
eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = NULL;
#endif /* CONFIG_DPP2 */
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index 9ba315f..b337982 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -1,6 +1,7 @@
/*
* wpa_supplicant - DPP
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2019, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,6 +10,8 @@
#ifndef DPP_SUPPLICANT_H
#define DPP_SUPPLICANT_H
+enum dpp_status_error;
+
int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd);
@@ -26,5 +29,8 @@
int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss);
int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd);
+void wpas_dpp_connected(struct wpa_supplicant *wpa_s);
+void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
+ enum dpp_status_error result);
#endif /* DPP_SUPPLICANT_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 471fc17..139402e 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -316,8 +316,9 @@
eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->key_mgmt == WPA_KEY_MGMT_OWE ||
- wpa_s->key_mgmt == WPA_KEY_MGMT_DPP)
+ wpa_s->key_mgmt == WPA_KEY_MGMT_DPP || wpa_s->drv_authorized_port)
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+ wpa_s->drv_authorized_port = 0;
wpa_s->ap_ies_from_associnfo = 0;
wpa_s->current_ssid = NULL;
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
@@ -326,6 +327,7 @@
wpas_rrm_reset(wpa_s);
wpa_s->wnmsleep_used = 0;
wnm_clear_coloc_intf_reporting(wpa_s);
+ wpa_s->disable_mbo_oce = 0;
#ifdef CONFIG_TESTING_OPTIONS
wpa_s->last_tk_alg = WPA_ALG_NONE;
@@ -611,7 +613,6 @@
break;
}
-#ifdef CONFIG_IEEE80211W
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
wpas_get_ssid_pmf(wpa_s, ssid) ==
MGMT_FRAME_PROTECTION_REQUIRED) {
@@ -620,7 +621,6 @@
" skip RSN IE - no mgmt frame protection");
break;
}
-#endif /* CONFIG_IEEE80211W */
if ((ie.capabilities & WPA_CAPABILITY_MFPR) &&
wpas_get_ssid_pmf(wpa_s, ssid) ==
NO_MGMT_FRAME_PROTECTION) {
@@ -629,17 +629,6 @@
" skip RSN IE - no mgmt frame protection enabled but AP requires it");
break;
}
-#ifdef CONFIG_MBO
- if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
- wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) &&
- wpas_get_ssid_pmf(wpa_s, ssid) !=
- NO_MGMT_FRAME_PROTECTION) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip RSN IE - no mgmt frame protection enabled on MBO AP");
- break;
- }
-#endif /* CONFIG_MBO */
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -647,7 +636,6 @@
return 1;
}
-#ifdef CONFIG_IEEE80211W
if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED &&
(!(ssid->key_mgmt & WPA_KEY_MGMT_OWE) || ssid->owe_only)) {
if (debug_print)
@@ -655,7 +643,6 @@
" skip - MFP Required but network not MFP Capable");
return 0;
}
-#endif /* CONFIG_IEEE80211W */
wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) {
@@ -863,6 +850,19 @@
continue;
}
+#ifdef CONFIG_SAE
+ if (flagged && ((rate_ie[j] & 0x7f) ==
+ BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY)) {
+ if (wpa_s->conf->sae_pwe == 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " SAE H2E disabled");
+ return 0;
+ }
+ continue;
+ }
+#endif /* CONFIG_SAE */
+
if (!flagged)
continue;
@@ -1262,6 +1262,19 @@
continue;
}
+#ifdef CONFIG_SAE
+ if (wpa_s->conf->sae_pwe == 1 &&
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ (!(ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX)) ||
+ ie[1] < 1 ||
+ !(ie[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - SAE H2E required, but not supported by the AP");
+ continue;
+ }
+#endif /* CONFIG_SAE */
+
#ifndef CONFIG_IBSS_RSN
if (ssid->mode == WPAS_MODE_IBSS &&
!(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
@@ -1937,6 +1950,21 @@
radio_work_done(work);
}
+ os_free(wpa_s->last_scan_freqs);
+ wpa_s->last_scan_freqs = NULL;
+ wpa_s->num_last_scan_freqs = 0;
+ if (own_request && data &&
+ data->scan_info.freqs && data->scan_info.num_freqs) {
+ wpa_s->last_scan_freqs = os_malloc(sizeof(int) *
+ data->scan_info.num_freqs);
+ if (wpa_s->last_scan_freqs) {
+ os_memcpy(wpa_s->last_scan_freqs,
+ data->scan_info.freqs,
+ sizeof(int) * data->scan_info.num_freqs);
+ wpa_s->num_last_scan_freqs = data->scan_info.num_freqs;
+ }
+ }
+
return wpas_select_network_from_last_scan(wpa_s, 1, own_request);
scan_work_done:
@@ -1990,6 +2018,8 @@
return 0;
}
+ wpa_s->suitable_network++;
+
if (ssid != wpa_s->current_ssid &&
wpa_s->wpa_state >= WPA_AUTHENTICATING) {
wpa_s->own_disconnect_req = 1;
@@ -2010,6 +2040,7 @@
*/
return 1;
} else {
+ wpa_s->no_suitable_network++;
wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
ssid = wpa_supplicant_pick_new_network(wpa_s);
if (ssid) {
@@ -2380,7 +2411,7 @@
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
- int l, len, found = 0, wpa_found, rsn_found;
+ int l, len, found = 0, found_x = 0, wpa_found, rsn_found;
const u8 *p;
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE)
u8 bssid[ETH_ALEN];
@@ -2452,22 +2483,29 @@
p, l);
break;
}
- if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
- (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
- (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
- (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
- (p[0] == WLAN_EID_RSN && p[1] >= 2)) {
+ if (!found &&
+ ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+ (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
+ (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
+ (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
+ (p[0] == WLAN_EID_RSN && p[1] >= 2))) {
if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
break;
found = 1;
wpa_find_assoc_pmkid(wpa_s);
- break;
+ }
+ if (!found_x && p[0] == WLAN_EID_RSNX) {
+ if (wpa_sm_set_assoc_rsnxe(wpa_s->wpa, p, len))
+ break;
+ found_x = 1;
}
l -= len;
p += len;
}
if (!found && data->assoc_info.req_ies)
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ if (!found_x && data->assoc_info.req_ies)
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
#ifdef CONFIG_FILS
#ifdef CONFIG_SME
@@ -2629,14 +2667,19 @@
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
}
+ if (p[0] == WLAN_EID_RSNX && p[1] >= 1)
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, p, len);
+
l -= len;
p += len;
}
if (!wpa_found && data->assoc_info.beacon_ies)
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
- if (!rsn_found && data->assoc_info.beacon_ies)
+ if (!rsn_found && data->assoc_info.beacon_ies) {
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
+ }
if (wpa_found || rsn_found)
wpa_s->ap_ies_from_associnfo = 1;
@@ -2656,7 +2699,7 @@
static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
{
- const u8 *bss_wpa = NULL, *bss_rsn = NULL;
+ const u8 *bss_wpa = NULL, *bss_rsn = NULL, *bss_rsnx = NULL;
if (!wpa_s->current_bss || !wpa_s->current_ssid)
return -1;
@@ -2667,11 +2710,14 @@
bss_wpa = wpa_bss_get_vendor_ie(wpa_s->current_bss,
WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSN);
+ bss_rsnx = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSNX);
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
- bss_rsn ? 2 + bss_rsn[1] : 0))
+ bss_rsn ? 2 + bss_rsn[1] : 0) ||
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+ bss_rsnx ? 2 + bss_rsnx[1] : 0))
return -1;
return 0;
@@ -2723,6 +2769,9 @@
u8 bssid[ETH_ALEN];
int ft_completed, already_authorized;
int new_bss = 0;
+#if defined(CONFIG_FILS) || defined(CONFIG_MBO)
+ struct wpa_bss *bss;
+#endif /* CONFIG_FILS || CONFIG_MBO */
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
@@ -2831,7 +2880,7 @@
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->key_mgmt == WPA_KEY_MGMT_DPP ||
wpa_s->key_mgmt == WPA_KEY_MGMT_OWE || ft_completed ||
- already_authorized)
+ already_authorized || wpa_s->drv_authorized_port)
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
/* 802.1X::portControl = Auto */
eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
@@ -2946,15 +2995,21 @@
wmm_ac_restore_tspecs(wpa_s);
}
+#if defined(CONFIG_FILS) || defined(CONFIG_MBO)
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+#endif /* CONFIG_FILS || CONFIG_MBO */
#ifdef CONFIG_FILS
if (wpa_key_mgmt_fils(wpa_s->key_mgmt)) {
- struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, bssid);
const u8 *fils_cache_id = wpa_bss_get_fils_cache_id(bss);
if (fils_cache_id)
wpa_sm_set_fils_cache_id(wpa_s->wpa, fils_cache_id);
}
#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_MBO
+ wpas_mbo_check_pmf(wpa_s, bss, wpa_s->current_ssid);
+#endif /* CONFIG_MBO */
}
@@ -2999,7 +3054,8 @@
int locally_generated)
{
if (wpa_s->wpa_state != WPA_4WAY_HANDSHAKE ||
- !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
+ !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+ wpa_key_mgmt_sae(wpa_s->key_mgmt))
return 0; /* Not in 4-way handshake with PSK */
/*
@@ -3062,6 +3118,10 @@
if (wpas_p2p_4way_hs_failed(wpa_s) > 0)
return; /* P2P group removed */
wpas_auth_failed(wpa_s, "WRONG_KEY");
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s,
+ DPP_STATUS_AUTH_FAILURE);
+#endif /* CONFIG_DPP2 */
}
if (!wpa_s->disconnected &&
(!wpa_s->auto_reconnect_disabled ||
@@ -3510,26 +3570,22 @@
static void wpa_supplicant_event_unprot_deauth(struct wpa_supplicant *wpa_s,
struct unprot_deauth *e)
{
-#ifdef CONFIG_IEEE80211W
wpa_printf(MSG_DEBUG, "Unprotected Deauthentication frame "
"dropped: " MACSTR " -> " MACSTR
" (reason code %u)",
MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
-#endif /* CONFIG_IEEE80211W */
}
static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s,
struct unprot_disassoc *e)
{
-#ifdef CONFIG_IEEE80211W
wpa_printf(MSG_DEBUG, "Unprotected Disassociation frame "
"dropped: " MACSTR " -> " MACSTR
" (reason code %u)",
MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
-#endif /* CONFIG_IEEE80211W */
}
@@ -3787,14 +3843,12 @@
}
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
#ifdef CONFIG_SME
if (category == WLAN_ACTION_SA_QUERY) {
sme_sa_query_rx(wpa_s, mgmt->sa, payload, plen);
return;
}
#endif /* CONFIG_SME */
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM
if (mgmt->u.action.category == WLAN_ACTION_WNM) {
@@ -3935,6 +3989,7 @@
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+ wpa_s->drv_authorized_port = 1;
}
}
@@ -4508,9 +4563,7 @@
}
#endif /* CONFIG_AP */
-#ifdef CONFIG_IEEE80211W
sme_event_ch_switch(wpa_s);
-#endif /* CONFIG_IEEE80211W */
wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
wnm_clear_coloc_intf_reporting(wpa_s);
break;
@@ -4717,6 +4770,7 @@
wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_supplicant_update_mac_addr(wpa_s);
+ wpa_supplicant_set_default_scan_ies(wpa_s);
if (wpa_s->p2p_mgmt) {
wpa_supplicant_set_state(wpa_s,
WPA_DISCONNECTED);
diff --git a/wpa_supplicant/hidl/1.3/sta_iface.cpp b/wpa_supplicant/hidl/1.3/sta_iface.cpp
index 0dba906..f1c4fbe 100644
--- a/wpa_supplicant/hidl/1.3/sta_iface.cpp
+++ b/wpa_supplicant/hidl/1.3/sta_iface.cpp
@@ -20,8 +20,8 @@
#include "interworking.h"
#include "hs20_supplicant.h"
#include "wps_supplicant.h"
-#include "dpp_supplicant.h"
#include "dpp.h"
+#include "dpp_supplicant.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/pmksa_cache.h"
}
diff --git a/wpa_supplicant/hidl/1.3/sta_network.cpp b/wpa_supplicant/hidl/1.3/sta_network.cpp
index 273687d..242d7d7 100644
--- a/wpa_supplicant/hidl/1.3/sta_network.cpp
+++ b/wpa_supplicant/hidl/1.3/sta_network.cpp
@@ -1199,7 +1199,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- path.c_str(), &(wpa_ssid->eap.ca_cert), "eap ca_cert")) {
+ path.c_str(), &(wpa_ssid->eap.cert.ca_cert), "eap ca_cert")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1209,7 +1209,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- path.c_str(), &(wpa_ssid->eap.ca_path), "eap ca_path")) {
+ path.c_str(), &(wpa_ssid->eap.cert.ca_path), "eap ca_path")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1219,7 +1219,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- path.c_str(), &(wpa_ssid->eap.client_cert),
+ path.c_str(), &(wpa_ssid->eap.cert.client_cert),
"eap client_cert")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -1230,7 +1230,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- id.c_str(), &(wpa_ssid->eap.key_id), "eap key_id")) {
+ id.c_str(), &(wpa_ssid->eap.cert.key_id), "eap key_id")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1241,7 +1241,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- match.c_str(), &(wpa_ssid->eap.subject_match),
+ match.c_str(), &(wpa_ssid->eap.cert.subject_match),
"eap subject_match")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -1253,7 +1253,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- match.c_str(), &(wpa_ssid->eap.altsubject_match),
+ match.c_str(), &(wpa_ssid->eap.cert.altsubject_match),
"eap altsubject_match")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -1263,7 +1263,7 @@
SupplicantStatus StaNetwork::setEapEngineInternal(bool enable)
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- wpa_ssid->eap.engine = enable ? 1 : 0;
+ wpa_ssid->eap.cert.engine = enable ? 1 : 0;
return {SupplicantStatusCode::SUCCESS, ""};
}
@@ -1271,7 +1271,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- id.c_str(), &(wpa_ssid->eap.engine_id), "eap engine_id")) {
+ id.c_str(), &(wpa_ssid->eap.cert.engine_id), "eap engine_id")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1282,7 +1282,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- match.c_str(), &(wpa_ssid->eap.domain_suffix_match),
+ match.c_str(), &(wpa_ssid->eap.cert.domain_suffix_match),
"eap domain_suffix_match")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -1463,7 +1463,7 @@
// the first EAP method for each network.
const std::string eap_method_str = eap_get_name(
wpa_ssid->eap.eap_methods[0].vendor,
- static_cast<EapType>(wpa_ssid->eap.eap_methods[0].method));
+ static_cast<enum eap_type>(wpa_ssid->eap.eap_methods[0].method));
size_t eap_method_idx =
std::find(
std::begin(kEapMethodStrings), std::end(kEapMethodStrings),
@@ -1557,89 +1557,89 @@
std::pair<SupplicantStatus, std::string> StaNetwork::getEapCACertInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.ca_cert) {
+ if (!wpa_ssid->eap.cert.ca_cert) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.ca_cert)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.ca_cert)};
}
std::pair<SupplicantStatus, std::string> StaNetwork::getEapCAPathInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.ca_path) {
+ if (!wpa_ssid->eap.cert.ca_path) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.ca_path)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.ca_path)};
}
std::pair<SupplicantStatus, std::string> StaNetwork::getEapClientCertInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.client_cert) {
+ if (!wpa_ssid->eap.cert.client_cert) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.client_cert)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.client_cert)};
}
std::pair<SupplicantStatus, std::string>
StaNetwork::getEapPrivateKeyIdInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.key_id) {
+ if (!wpa_ssid->eap.cert.key_id) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
- return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.key_id};
+ return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.cert.key_id};
}
std::pair<SupplicantStatus, std::string>
StaNetwork::getEapSubjectMatchInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.subject_match) {
+ if (!wpa_ssid->eap.cert.subject_match) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.subject_match)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.subject_match)};
}
std::pair<SupplicantStatus, std::string>
StaNetwork::getEapAltSubjectMatchInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.altsubject_match) {
+ if (!wpa_ssid->eap.cert.altsubject_match) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.altsubject_match)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.altsubject_match)};
}
std::pair<SupplicantStatus, bool> StaNetwork::getEapEngineInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.engine == 1};
+ return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.cert.engine == 1};
}
std::pair<SupplicantStatus, std::string> StaNetwork::getEapEngineIDInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.engine_id) {
+ if (!wpa_ssid->eap.cert.engine_id) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
- return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->eap.engine_id}};
+ return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->eap.cert.engine_id}};
}
std::pair<SupplicantStatus, std::string>
StaNetwork::getEapDomainSuffixMatchInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.domain_suffix_match) {
+ if (!wpa_ssid->eap.cert.domain_suffix_match) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- {wpa_ssid->eap.domain_suffix_match}};
+ {wpa_ssid->eap.cert.domain_suffix_match}};
}
std::pair<SupplicantStatus, std::string> StaNetwork::getIdStrInternal()
@@ -1977,9 +1977,9 @@
if (ocspType < OcspType::NONE || ocspType > OcspType::REQUIRE_ALL_CERTS_STATUS) {
return{ SupplicantStatusCode::FAILURE_ARGS_INVALID, "" };
}
- wpa_ssid->eap.ocsp = (int) ocspType;
+ wpa_ssid->eap.cert.ocsp = (int) ocspType;
wpa_printf(
- MSG_MSGDUMP, "ocsp: %d", wpa_ssid->eap.ocsp);
+ MSG_MSGDUMP, "ocsp: %d", wpa_ssid->eap.cert.ocsp);
resetInternalStateAfterParamsUpdate();
return {SupplicantStatusCode::SUCCESS, ""};
}
@@ -1988,7 +1988,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
return {{SupplicantStatusCode::SUCCESS, ""},
- (OcspType) wpa_ssid->eap.ocsp};
+ (OcspType) wpa_ssid->eap.cert.ocsp};
}
SupplicantStatus StaNetwork::setPmkCacheInternal(const std::vector<uint8_t>& serializedEntry) {
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 6934c47..36c0aff 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -111,6 +111,7 @@
wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
/* TODO: get correct RSN IE */
+ wpa_sm_set_ap_rsnxe(peer->supp, NULL, 0);
return wpa_sm_set_ap_rsn_ie(peer->supp,
(u8 *) "\x30\x14\x01\x00"
"\x00\x0f\xac\x04"
@@ -464,7 +465,7 @@
"\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x02"
- "\x00\x00", 22, NULL, 0, NULL, 0) !=
+ "\x00\x00", 22, NULL, 0, NULL, 0, NULL, 0) !=
WPA_IE_OK) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
return -1;
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index dabde82..585b7f0 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1395,7 +1395,11 @@
!roaming_consortium_match(ie, anqp,
cred->roaming_consortium,
cred->roaming_consortium_len)) &&
- !cred_roaming_consortiums_match(ie, anqp, cred))
+ !cred_roaming_consortiums_match(ie, anqp, cred) &&
+ (cred->required_roaming_consortium_len == 0 ||
+ !roaming_consortium_match(
+ ie, anqp, cred->required_roaming_consortium,
+ cred->required_roaming_consortium_len)))
continue;
if (cred_no_required_oi_match(cred, bss))
@@ -1550,7 +1554,7 @@
cred->domain_suffix_match) < 0)
return -1;
- ssid->eap.ocsp = cred->ocsp;
+ ssid->eap.cert.ocsp = cred->ocsp;
return 0;
}
@@ -2258,7 +2262,7 @@
realm++;
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Search for match with SIM/USIM domain %s",
- realm);
+ realm ? realm : "[NULL]");
if (realm &&
domain_name_list_contains(domain_names, realm, 1))
return 1;
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
index 43b1fa7..3df86ef 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -15,6 +15,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/gas.h"
+#include "rsn_supp/wpa.h"
#include "config.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
@@ -82,6 +83,35 @@
}
+void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ struct wpa_ssid *ssid)
+{
+ const u8 *rsne, *mbo, *oce;
+ struct wpa_ie_data ie;
+
+ wpa_s->disable_mbo_oce = 0;
+ if (!bss)
+ return;
+ mbo = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND);
+ oce = wpas_mbo_get_bss_attr(bss, OCE_ATTR_ID_CAPA_IND);
+ if (!mbo && !oce)
+ return;
+ if (oce && oce[1] >= 1 && (oce[2] & OCE_IS_STA_CFON))
+ return; /* STA-CFON is not required to enable PMF */
+ rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (!rsne || wpa_parse_wpa_ie(rsne, 2 + rsne[1], &ie) < 0)
+ return; /* AP is not using RSN */
+
+ if (!(ie.capabilities & WPA_CAPABILITY_MFPC))
+ wpa_s->disable_mbo_oce = 1; /* AP uses RSN without PMF */
+ if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION)
+ wpa_s->disable_mbo_oce = 1; /* STA uses RSN without PMF */
+ if (wpa_s->disable_mbo_oce)
+ wpa_printf(MSG_INFO,
+ "MBO: Disable MBO/OCE due to misbehaving AP not having enabled PMF");
+}
+
+
static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s,
struct wpabuf *mbo,
u8 start, u8 end)
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 7354c1b..5c1a47d 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -86,7 +86,6 @@
MESH_CONF_SEC_AMPE;
else
conf->security |= MESH_CONF_SEC_NONE;
-#ifdef CONFIG_IEEE80211W
conf->ieee80211w = ssid->ieee80211w;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)
@@ -94,7 +93,6 @@
else
conf->ieee80211w = NO_MGMT_FRAME_PROTECTION;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
conf->ocv = ssid->ocv;
#endif /* CONFIG_OCV */
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 4b8d6c4..e730b63 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -165,11 +165,9 @@
conf.wpa_group_rekey = -1;
conf.wpa_group_update_count = 4;
conf.wpa_pairwise_update_count = 4;
-#ifdef CONFIG_IEEE80211W
conf.ieee80211w = ieee80211w;
if (ieee80211w != NO_MGMT_FRAME_PROTECTION)
conf.group_mgmt_cipher = rsn->mgmt_group_cipher;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
conf.ocv = ocv;
#endif /* CONFIG_OCV */
@@ -186,7 +184,6 @@
return -1;
rsn->mgtk_key_id = 1;
-#ifdef CONFIG_IEEE80211W
if (ieee80211w != NO_MGMT_FRAME_PROTECTION) {
rsn->igtk_len = wpa_cipher_key_len(conf.group_mgmt_cipher);
if (random_get_bytes(rsn->igtk, rsn->igtk_len) < 0)
@@ -201,7 +198,6 @@
rsn->igtk_key_id, 1,
seq, sizeof(seq), rsn->igtk, rsn->igtk_len);
}
-#endif /* CONFIG_IEEE80211W */
/* group privacy / data frames */
wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK",
@@ -545,10 +541,8 @@
len = sizeof(*ampe);
if (cat[1] == PLINK_OPEN)
len += rsn->mgtk_len + WPA_KEY_RSC_LEN + 4;
-#ifdef CONFIG_IEEE80211W
if (cat[1] == PLINK_OPEN && rsn->igtk_len)
len += 2 + 6 + rsn->igtk_len;
-#endif /* CONFIG_IEEE80211W */
if (2 + AES_BLOCK_SIZE + 2 + len > wpabuf_tailroom(buf)) {
wpa_printf(MSG_ERROR, "protect frame: buffer too small");
@@ -591,7 +585,6 @@
WPA_PUT_LE32(pos, 0xffffffff);
pos += 4;
-#ifdef CONFIG_IEEE80211W
/*
* IGTKdata[variable]:
* Key ID[2], IPN[6], IGTK[variable]
@@ -603,7 +596,6 @@
pos += 6;
os_memcpy(pos, rsn->igtk, rsn->igtk_len);
}
-#endif /* CONFIG_IEEE80211W */
skip_keys:
wpa_hexdump_key(MSG_DEBUG, "mesh: Plaintext AMPE element",
@@ -774,7 +766,6 @@
WPA_GET_LE32(pos));
pos += 4;
-#ifdef CONFIG_IEEE80211W
/*
* IGTKdata[variable]:
* Key ID[2], IPN[6], IGTK[variable]
@@ -794,7 +785,6 @@
wpa_hexdump_key(MSG_DEBUG, "mesh: IGTKdata - IGTK",
sta->igtk, sta->igtk_len);
}
-#endif /* CONFIG_IEEE80211W */
free:
os_free(crypt);
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index ebefd48..2ebe034 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -865,10 +865,11 @@
int i;
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
- "depth=%d subject='%s'%s%s%s",
+ "depth=%d subject='%s'%s%s%s%s",
cert->depth, cert->subject, cert_hash ? " hash=" : "",
cert_hash ? cert_hash : "",
- cert->tod ? " tod=1" : "");
+ cert->tod == 2 ? " tod=2" : "",
+ cert->tod == 1 ? " tod=1" : "");
if (cert->cert) {
char *cert_hex;
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index 6a85af4..b15ac9e 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -16,13 +16,19 @@
#include "wpa_supplicant_i.h"
-static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
+static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode,
+ u8 op_class, u8 chan,
unsigned int *flags)
{
int i;
+ int is_6ghz = op_class >= 131 && op_class <= 135;
for (i = 0; i < mode->num_channels; i++) {
- if (mode->channels[i].chan == chan)
+ int chan_is_6ghz;
+
+ chan_is_6ghz = mode->channels[i].freq > 5940 &&
+ mode->channels[i].freq <= 7105;
+ if (is_6ghz == chan_is_6ghz && mode->channels[i].chan == chan)
break;
}
@@ -62,7 +68,8 @@
}
-static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode,
+ u8 op_class, u8 channel)
{
u8 center_chan;
unsigned int i;
@@ -77,7 +84,8 @@
unsigned int flags;
u8 adj_chan = center_chan - 6 + i * 4;
- if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ if (allow_channel(mode, op_class, adj_chan, &flags) ==
+ NOT_ALLOWED)
return NOT_ALLOWED;
if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
@@ -120,7 +128,7 @@
static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
- u8 channel)
+ u8 op_class, u8 channel)
{
u8 center_chan;
unsigned int i;
@@ -135,7 +143,8 @@
unsigned int flags;
u8 adj_chan = center_chan - 14 + i * 4;
- if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ if (allow_channel(mode, op_class, adj_chan, &flags) ==
+ NOT_ALLOWED)
return NOT_ALLOWED;
if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
@@ -159,42 +168,42 @@
}
-enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
- u8 bw)
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
+ u8 channel, u8 bw)
{
unsigned int flag = 0;
enum chan_allowed res, res2;
- res2 = res = allow_channel(mode, channel, &flag);
+ res2 = res = allow_channel(mode, op_class, channel, &flag);
if (bw == BW40MINUS) {
if (!(flag & HOSTAPD_CHAN_HT40MINUS))
return NOT_ALLOWED;
- res2 = allow_channel(mode, channel - 4, NULL);
+ res2 = allow_channel(mode, op_class, channel - 4, NULL);
} else if (bw == BW40PLUS) {
if (!(flag & HOSTAPD_CHAN_HT40PLUS))
return NOT_ALLOWED;
- res2 = allow_channel(mode, channel + 4, NULL);
+ res2 = allow_channel(mode, op_class, channel + 4, NULL);
} else if (bw == BW80) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 80 MHz specific version.
*/
- res2 = res = verify_80mhz(mode, channel);
+ res2 = res = verify_80mhz(mode, op_class, channel);
} else if (bw == BW160) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 160 MHz specific version.
*/
- res2 = res = verify_160mhz(mode, channel);
+ res2 = res = verify_160mhz(mode, op_class, channel);
} else if (bw == BW80P80) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 80 MHz specific version.
*/
- res2 = res = verify_80mhz(mode, channel);
+ res2 = res = verify_80mhz(mode, op_class, channel);
}
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -225,7 +234,7 @@
/* If we are configured to disable certain things, take that into
* account here. */
- if (ssid->freq_list && ssid->freq_list[0]) {
+ if (ssid && ssid->freq_list && ssid->freq_list[0]) {
for (z = 0; ; z++) {
int f = ssid->freq_list[z];
@@ -248,7 +257,7 @@
return 0;
#ifdef CONFIG_HT_OVERRIDES
- if (ssid->disable_ht) {
+ if (ssid && ssid->disable_ht) {
switch (op_class->op_class) {
case 83:
case 84:
@@ -272,7 +281,7 @@
#endif /* CONFIG_HT_OVERRIDES */
#ifdef CONFIG_VHT_OVERRIDES
- if (ssid->disable_vht) {
+ if (ssid && ssid->disable_vht) {
if (op_class->op_class >= 128 && op_class->op_class <= 130) {
/* Disable >= 80 MHz channels if VHT is disabled */
return 0;
@@ -284,7 +293,8 @@
u8 channels[] = { 42, 58, 106, 122, 138, 155 };
for (i = 0; i < ARRAY_SIZE(channels); i++) {
- if (verify_channel(mode, channels[i], op_class->bw) !=
+ if (verify_channel(mode, op_class->op_class,
+ channels[i], op_class->bw) !=
NOT_ALLOWED)
return 1;
}
@@ -294,25 +304,35 @@
if (op_class->op_class == 129) {
/* Check if either 160 MHz channels is allowed */
- return verify_channel(mode, 50, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 114, op_class->bw) != NOT_ALLOWED;
+ return verify_channel(mode, op_class->op_class, 50,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 114,
+ op_class->bw) != NOT_ALLOWED;
}
if (op_class->op_class == 130) {
/* Need at least two non-contiguous 80 MHz segments */
found = 0;
- if (verify_channel(mode, 42, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 58, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 42,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 58,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 122, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 106,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 122,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 138,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED &&
- verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 106,
+ op_class->bw) != NOT_ALLOWED &&
+ verify_channel(mode, op_class->op_class, 138,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 155, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 155,
+ op_class->bw) != NOT_ALLOWED)
found++;
if (found >= 2)
@@ -324,7 +344,8 @@
found = 0;
for (chan = op_class->min_chan; chan <= op_class->max_chan;
chan += op_class->inc) {
- if (verify_channel(mode, chan, op_class->bw) != NOT_ALLOWED) {
+ if (verify_channel(mode, op_class->op_class, chan,
+ op_class->bw) != NOT_ALLOWED) {
found = 1;
break;
}
@@ -385,3 +406,24 @@
wpabuf_free(buf);
return res;
}
+
+
+int * wpas_supp_op_classes(struct wpa_supplicant *wpa_s)
+{
+ int op;
+ unsigned int pos, max_num = 0;
+ int *classes;
+
+ for (op = 0; global_op_class[op].op_class; op++)
+ max_num++;
+ classes = os_zalloc((max_num + 1) * sizeof(int));
+ if (!classes)
+ return NULL;
+
+ for (op = 0, pos = 0; global_op_class[op].op_class; op++) {
+ if (wpas_op_class_supported(wpa_s, NULL, &global_op_class[op]))
+ classes[pos++] = global_op_class[op].op_class;
+ }
+
+ return classes;
+}
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 23bbc21..fb509a1 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -2268,6 +2268,8 @@
res->ht40 = 1;
if (wpa_s->p2p_go_vht)
res->vht = 1;
+ if (wpa_s->p2p_go_he)
+ res->he = 1;
res->max_oper_chwidth = wpa_s->p2p_go_max_oper_chwidth;
res->vht_center_freq2 = wpa_s->p2p_go_vht_center_freq2;
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index 8468b2f..b78ff10 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -101,10 +101,16 @@
#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
/* Workaround different, undefined for Windows, error codes used here */
+#ifndef ENOTCONN
#define ENOTCONN -1
+#endif
+#ifndef EOPNOTSUPP
#define EOPNOTSUPP -1
+#endif
+#ifndef ECANCELED
#define ECANCELED -1
#endif
+#endif
/* Measurement Request element + Location Subject + Maximum Age subelement */
#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4)
@@ -522,7 +528,8 @@
next_freq = freqs;
for (i = 0; i < num_chans; i++) {
u8 chan = channels ? channels[i] : op->min_chan + i * op->inc;
- enum chan_allowed res = verify_channel(mode, chan, op->bw);
+ enum chan_allowed res = verify_channel(mode, op->op_class, chan,
+ op->bw);
if (res == NOT_ALLOWED || (res == NO_IR && active))
continue;
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 7abb028..4d158a9 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -79,6 +79,33 @@
#endif /* CONFIG_WPS */
+static int wpa_setup_mac_addr_rand_params(struct wpa_driver_scan_params *params,
+ const u8 *mac_addr)
+{
+ u8 *tmp;
+
+ if (params->mac_addr) {
+ params->mac_addr_mask = NULL;
+ os_free(params->mac_addr);
+ params->mac_addr = NULL;
+ }
+
+ params->mac_addr_rand = 1;
+
+ if (!mac_addr)
+ return 0;
+
+ tmp = os_malloc(2 * ETH_ALEN);
+ if (!tmp)
+ return -1;
+
+ os_memcpy(tmp, mac_addr, 2 * ETH_ALEN);
+ params->mac_addr = tmp;
+ params->mac_addr_mask = tmp + ETH_ALEN;
+ return 0;
+}
+
+
/**
* wpa_supplicant_enabled_networks - Check whether there are enabled networks
* @wpa_s: Pointer to wpa_supplicant data
@@ -169,6 +196,10 @@
return;
}
+ if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(params, wpa_s->mac_addr_scan);
+
if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Failed to assign random MAC address for a scan");
@@ -1211,13 +1242,8 @@
#endif /* CONFIG_P2P */
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_scan) {
- params.mac_addr = wpa_s->mac_addr_scan;
- params.mac_addr_mask = wpa_s->mac_addr_scan + ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(¶ms, wpa_s->mac_addr_scan);
if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
struct wpa_bss *bss;
@@ -1286,6 +1312,7 @@
wpabuf_free(extra_ie);
os_free(params.freqs);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
@@ -1664,20 +1691,16 @@
wpa_setband_scan_freqs(wpa_s, scan_params);
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_sched_scan) {
- params.mac_addr = wpa_s->mac_addr_sched_scan;
- params.mac_addr_mask = wpa_s->mac_addr_sched_scan +
- ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(¶ms,
+ wpa_s->mac_addr_sched_scan);
wpa_scan_set_relative_rssi_params(wpa_s, scan_params);
ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params);
wpabuf_free(extra_ie);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan");
if (prev_state != wpa_s->wpa_state)
@@ -2535,23 +2558,9 @@
params->sched_scan_plans_num = src->sched_scan_plans_num;
}
- if (src->mac_addr_rand) {
- params->mac_addr_rand = src->mac_addr_rand;
-
- if (src->mac_addr && src->mac_addr_mask) {
- u8 *mac_addr;
-
- mac_addr = os_malloc(2 * ETH_ALEN);
- if (!mac_addr)
- goto failed;
-
- os_memcpy(mac_addr, src->mac_addr, ETH_ALEN);
- os_memcpy(mac_addr + ETH_ALEN, src->mac_addr_mask,
- ETH_ALEN);
- params->mac_addr = mac_addr;
- params->mac_addr_mask = mac_addr + ETH_ALEN;
- }
- }
+ if (src->mac_addr_rand &&
+ wpa_setup_mac_addr_rand_params(params, src->mac_addr))
+ goto failed;
if (src->bssid) {
u8 *bssid;
@@ -2738,18 +2747,14 @@
}
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_pno) {
- params.mac_addr = wpa_s->mac_addr_pno;
- params.mac_addr_mask = wpa_s->mac_addr_pno + ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(¶ms, wpa_s->mac_addr_pno);
wpa_scan_set_relative_rssi_params(wpa_s, ¶ms);
ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret == 0)
wpa_s->pno = 1;
else
@@ -2843,6 +2848,32 @@
}
+int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
+ unsigned int type, u8 *mask)
+{
+ const u8 *to_copy;
+
+ if ((wpa_s->mac_addr_rand_enable & type) != type)
+ return -1;
+
+ if (type == MAC_ADDR_RAND_SCAN) {
+ to_copy = wpa_s->mac_addr_scan;
+ } else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
+ to_copy = wpa_s->mac_addr_sched_scan;
+ } else if (type == MAC_ADDR_RAND_PNO) {
+ to_copy = wpa_s->mac_addr_pno;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "scan: Invalid MAC randomization type=0x%x",
+ type);
+ return -1;
+ }
+
+ os_memcpy(mask, to_copy + ETH_ALEN, ETH_ALEN);
+ return 0;
+}
+
+
int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
{
struct wpa_radio_work *work;
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 2aa0a8b..58caa78 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -52,6 +52,8 @@
int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
unsigned int type, const u8 *addr,
const u8 *mask);
+int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
+ unsigned int type, u8 *mask);
int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s);
void filter_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *res);
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index dd50201..cfb5bb3 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -37,9 +37,7 @@
static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx);
static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx);
static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx);
-#ifdef CONFIG_IEEE80211W
static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
@@ -86,11 +84,16 @@
static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
const u8 *bssid, int external,
- int reuse)
+ int reuse, int *ret_use_pt)
{
struct wpabuf *buf;
size_t len;
const char *password;
+ struct wpa_bss *bss;
+ int use_pt = 0;
+
+ if (ret_use_pt)
+ *ret_use_pt = 0;
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_s->sae_commit_override) {
@@ -119,6 +122,7 @@
os_memcmp(bssid, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) {
wpa_printf(MSG_DEBUG,
"SAE: Reuse previously generated PWE on a retry with the same AP");
+ use_pt = wpa_s->sme.sae.tmp->h2e;
goto reuse_data;
}
if (sme_set_sae_group(wpa_s) < 0) {
@@ -126,7 +130,31 @@
return NULL;
}
- if (sae_prepare_commit(wpa_s->own_addr, bssid,
+ if (wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) {
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+ if (bss) {
+ const u8 *rsnxe;
+
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (rsnxe && rsnxe[1] >= 1)
+ use_pt = !!(rsnxe[2] &
+ BIT(WLAN_RSNX_CAPAB_SAE_H2E));
+ }
+
+ if (wpa_s->conf->sae_pwe == 1 && !use_pt) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Cannot use H2E with the selected AP");
+ return NULL;
+ }
+ }
+
+ if (use_pt &&
+ sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt,
+ wpa_s->own_addr, bssid,
+ wpa_s->sme.sae_rejected_groups) < 0)
+ return NULL;
+ if (!use_pt &&
+ sae_prepare_commit(wpa_s->own_addr, bssid,
(u8 *) password, os_strlen(password),
ssid->sae_password_id,
&wpa_s->sme.sae) < 0) {
@@ -145,10 +173,13 @@
return NULL;
if (!external) {
wpabuf_put_le16(buf, 1); /* Transaction seq# */
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ wpabuf_put_le16(buf, use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT :
+ WLAN_STATUS_SUCCESS);
}
sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
ssid->sae_password_id);
+ if (ret_use_pt)
+ *ret_use_pt = use_pt;
return buf;
}
@@ -492,7 +523,6 @@
}
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
wpa_s->sme.mfp = wpas_get_ssid_pmf(wpa_s, ssid);
if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
@@ -505,7 +535,6 @@
wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED;
}
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_P2P
if (wpa_s->global->p2p) {
@@ -562,6 +591,14 @@
os_memcpy(pos, ext_capab, ext_capab_len);
}
+ if (wpa_s->rsnxe_len > 0 &&
+ wpa_s->rsnxe_len <=
+ sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) {
+ os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ wpa_s->rsnxe, wpa_s->rsnxe_len);
+ wpa_s->sme.assoc_req_ie_len += wpa_s->rsnxe_len;
+ }
+
#ifdef CONFIG_HS20
if (is_hs20_network(wpa_s, ssid, bss)) {
struct wpabuf *hs20;
@@ -623,7 +660,7 @@
#ifdef CONFIG_MBO
mbo_ie = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
- if (mbo_ie) {
+ if (!wpa_s->disable_mbo_oce && mbo_ie) {
int len;
len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie +
@@ -655,7 +692,7 @@
if (start)
resp = sme_auth_build_sae_commit(wpa_s, ssid,
bss->bssid, 0,
- start == 2);
+ start == 2, NULL);
else
resp = sme_auth_build_sae_confirm(wpa_s, 0);
if (resp == NULL) {
@@ -855,6 +892,8 @@
/* Starting new connection, so clear the possibly used WPA IE from the
* previous association. */
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
}
@@ -909,7 +948,8 @@
static int sme_external_auth_build_buf(struct wpabuf *buf,
struct wpabuf *params,
const u8 *sa, const u8 *da,
- u16 auth_transaction, u16 seq_num)
+ u16 auth_transaction, u16 seq_num,
+ u16 status_code)
{
struct ieee80211_mgmt *resp;
@@ -924,7 +964,7 @@
resp->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE);
resp->seq_ctrl = host_to_le16(seq_num << 4);
resp->u.auth.auth_transaction = host_to_le16(auth_transaction);
- resp->u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS);
+ resp->u.auth.status_code = host_to_le16(status_code);
if (params)
wpabuf_put_buf(buf, params);
@@ -937,8 +977,9 @@
struct wpa_ssid *ssid)
{
struct wpabuf *resp, *buf;
+ int use_pt;
- resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0);
+ resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0, &use_pt);
if (!resp) {
wpa_printf(MSG_DEBUG, "SAE: Failed to build SAE commit");
return -1;
@@ -953,7 +994,9 @@
wpa_s->sme.seq_num++;
sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
- bssid, 1, wpa_s->sme.seq_num);
+ bssid, 1, wpa_s->sme.seq_num,
+ use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT :
+ WLAN_STATUS_SUCCESS);
wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
wpabuf_free(resp);
wpabuf_free(buf);
@@ -972,6 +1015,8 @@
params.ssid = wpa_s->sme.ext_auth_ssid;
params.ssid_len = wpa_s->sme.ext_auth_ssid_len;
params.bssid = wpa_s->sme.ext_auth_bssid;
+ if (wpa_s->conf->sae_pmkid_in_assoc && status == WLAN_STATUS_SUCCESS)
+ params.pmkid = wpa_s->sme.sae.pmkid;
wpa_drv_send_external_auth_status(wpa_s, ¶ms);
}
@@ -1020,7 +1065,8 @@
}
wpa_s->sme.seq_num++;
sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
- da, 2, wpa_s->sme.seq_num);
+ da, 2, wpa_s->sme.seq_num,
+ WLAN_STATUS_SUCCESS);
wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
wpabuf_free(resp);
wpabuf_free(buf);
@@ -1057,6 +1103,52 @@
}
+static int sme_sae_is_group_enabled(struct wpa_supplicant *wpa_s, int group)
+{
+ int *groups = wpa_s->conf->sae_groups;
+ int default_groups[] = { 19, 20, 21, 0 };
+ int i;
+
+ if (!groups)
+ groups = default_groups;
+
+ for (i = 0; groups[i] > 0; i++) {
+ if (groups[i] == group)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int sme_check_sae_rejected_groups(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *groups)
+{
+ size_t i, count;
+ const u8 *pos;
+
+ if (!groups)
+ return 0;
+
+ pos = wpabuf_head(groups);
+ count = wpabuf_len(groups) / 2;
+ for (i = 0; i < count; i++) {
+ int enabled;
+ u16 group;
+
+ group = WPA_GET_LE16(pos);
+ pos += 2;
+ enabled = sme_sae_is_group_enabled(wpa_s, group);
+ wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
+ group, enabled ? "enabled" : "disabled");
+ if (enabled)
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
u16 status_code, const u8 *data, size_t len,
int external, const u8 *sa)
@@ -1111,6 +1203,8 @@
wpa_s->sme.sae.state == SAE_COMMITTED &&
(external || wpa_s->current_bss) && wpa_s->current_ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
+ int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
+ wpa_s->sme.sae.group);
wpa_s->sme.sae_group_index++;
if (sme_set_sae_group(wpa_s) < 0)
return -1; /* no other groups enabled */
@@ -1135,7 +1229,8 @@
return -1;
}
- if (status_code != WLAN_STATUS_SUCCESS)
+ if (status_code != WLAN_STATUS_SUCCESS &&
+ status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT)
return -1;
if (auth_transaction == 1) {
@@ -1147,12 +1242,16 @@
if ((!external && wpa_s->current_bss == NULL) ||
wpa_s->current_ssid == NULL)
return -1;
- if (wpa_s->sme.sae.state != SAE_COMMITTED)
- return -1;
+ if (wpa_s->sme.sae.state != SAE_COMMITTED) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Ignore commit message while waiting for confirm");
+ return 0;
+ }
if (groups && groups[0] <= 0)
groups = NULL;
res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
- groups);
+ groups, status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT);
if (res == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message due to reflection attack");
@@ -1161,6 +1260,12 @@
if (res != WLAN_STATUS_SUCCESS)
return -1;
+ if (wpa_s->sme.sae.tmp &&
+ sme_check_sae_rejected_groups(
+ wpa_s,
+ wpa_s->sme.sae.tmp->peer_rejected_groups) < 0)
+ return -1;
+
if (sae_process_commit(&wpa_s->sme.sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Failed to process peer "
"commit");
@@ -1176,6 +1281,8 @@
sme_external_auth_send_sae_confirm(wpa_s, sa);
return 0;
} else if (auth_transaction == 2) {
+ if (status_code != WLAN_STATUS_SUCCESS)
+ return -1;
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
if (wpa_s->sme.sae.state != SAE_CONFIRMED)
return -1;
@@ -1197,6 +1304,37 @@
}
+static int sme_sae_set_pmk(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ wpa_printf(MSG_DEBUG,
+ "SME: SAE completed - setting PMK for 4-way handshake");
+ wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
+ wpa_s->sme.sae.pmkid, bssid);
+ if (wpa_s->conf->sae_pmkid_in_assoc) {
+ /* Update the own RSNE contents now that we have set the PMK
+ * and added a PMKSA cache entry based on the successfully
+ * completed SAE exchange. In practice, this will add the PMKID
+ * into RSNE. */
+ if (wpa_s->sme.assoc_req_ie_len + 2 + PMKID_LEN >
+ sizeof(wpa_s->sme.assoc_req_ie)) {
+ wpa_msg(wpa_s, MSG_WARNING,
+ "RSN: Not enough room for inserting own PMKID into RSNE");
+ return -1;
+ }
+ if (wpa_insert_pmkid(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ wpa_s->sme.sae.pmkid) < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG,
+ "SME: Updated Association Request IEs",
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+ }
+
+ return 0;
+}
+
+
void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
const u8 *auth_frame, size_t len)
{
@@ -1230,10 +1368,8 @@
if (res != 1)
return;
- wpa_printf(MSG_DEBUG,
- "SME: SAE completed - setting PMK for 4-way handshake");
- wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
- wpa_s->sme.sae.pmkid, wpa_s->pending_bssid);
+ if (sme_sae_set_pmk(wpa_s, wpa_s->sme.ext_auth_bssid) < 0)
+ return;
}
}
@@ -1286,10 +1422,8 @@
if (res != 1)
return;
- wpa_printf(MSG_DEBUG, "SME: SAE completed - setting PMK for "
- "4-way handshake");
- wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
- wpa_s->sme.sae.pmkid, wpa_s->pending_bssid);
+ if (sme_sae_set_pmk(wpa_s, wpa_s->pending_bssid) < 0)
+ return;
}
#endif /* CONFIG_SAE */
@@ -1778,6 +1912,11 @@
elems.osen_len + 2);
} else
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ if (elems.rsnxe)
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, elems.rsnxe - 2,
+ elems.rsnxe_len + 2);
+ else
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
params.p2p = 1;
@@ -1995,15 +2134,17 @@
if (wpa_s->sme.ft_ies || wpa_s->sme.ft_used)
sme_update_ft_ies(wpa_s, NULL, NULL, 0);
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
sme_stop_sa_query(wpa_s);
-#endif /* CONFIG_IEEE80211W */
}
void sme_deinit(struct wpa_supplicant *wpa_s)
{
sme_clear_on_disassoc(wpa_s);
+#ifdef CONFIG_SAE
+ os_free(wpa_s->sme.sae_rejected_groups);
+ wpa_s->sme.sae_rejected_groups = NULL;
+#endif /* CONFIG_SAE */
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
@@ -2292,8 +2433,6 @@
}
-#ifdef CONFIG_IEEE80211W
-
static const unsigned int sa_query_max_timeout = 1000;
static const unsigned int sa_query_retry_timeout = 201;
static const unsigned int sa_query_ch_switch_max_delay = 5000; /* in usec */
@@ -2582,5 +2721,3 @@
else if (data[0] == WLAN_SA_QUERY_RESPONSE)
sme_process_sa_query_response(wpa_s, sa, data, len);
}
-
-#endif /* CONFIG_IEEE80211W */
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index c147649..270be9e 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -271,7 +271,6 @@
WNM_SLEEP_SUBELEM_GTK,
ptr);
ptr += 13 + gtk_len;
-#ifdef CONFIG_IEEE80211W
} else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) {
if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) {
wpa_printf(MSG_DEBUG, "WNM: Too short IGTK "
@@ -281,7 +280,6 @@
wpa_wnmsleep_install_key(wpa_s->wpa,
WNM_SLEEP_SUBELEM_IGTK, ptr);
ptr += 10 + WPA_IGTK_LEN;
-#endif /* CONFIG_IEEE80211W */
} else
break; /* skip the loop */
}
@@ -1371,7 +1369,7 @@
const u8 *vendor;
#endif /* CONFIG_MBO */
- if (wpa_s->conf->disable_btm)
+ if (wpa_s->disable_mbo_oce || wpa_s->conf->disable_btm)
return;
if (end - pos < 5)
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 5b2154e..47cec0b 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1427,22 +1427,18 @@
#ifdef IEEE8021X_EAPOL
"eap_workaround", "pac_file", "fragment_size", "ocsp",
#endif /* IEEE8021X_EAPOL */
-#ifdef CONFIG_MESH
- "mode", "no_auto_peer", "mesh_rssi_threshold",
-#else /* CONFIG_MESH */
"mode",
-#endif /* CONFIG_MESH */
"proactive_key_caching", "disabled", "id_str",
-#ifdef CONFIG_IEEE80211W
"ieee80211w",
-#endif /* CONFIG_IEEE80211W */
"mixed_cell", "frequency", "fixed_freq",
#ifdef CONFIG_MESH
+ "no_auto_peer", "mesh_rssi_threshold",
"mesh_basic_rates", "dot11MeshMaxRetries",
"dot11MeshRetryTimeout", "dot11MeshConfirmTimeout",
"dot11MeshHoldingTimeout",
#endif /* CONFIG_MESH */
"wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid",
+ "enable_edmg", "edmg_channel",
#ifdef CONFIG_P2P
"go_p2p_dev_addr", "p2p_client_list", "psk_list",
#endif /* CONFIG_P2P */
@@ -4021,6 +4017,22 @@
wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, HS20_T_C_ACCEPTANCE)) {
wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONF_RECEIVED)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONFOBJ_AKM)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONFOBJ_SSID)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONNECTOR)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONFOBJ_PASS)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONFOBJ_PSK)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_C_SIGN_KEY)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_NET_ACCESS_KEY)) {
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, WPA_EVENT_TERMINATING)) {
printf("wpa_supplicant is terminating - stop monitoring\n");
wpa_cli_quit = 1;
@@ -4592,8 +4604,11 @@
if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
continue;
#endif /* _DIRENT_HAVE_D_TYPE */
+ /* Skip current/previous directory and special P2P Device
+ * interfaces. */
if (os_strcmp(dent->d_name, ".") == 0 ||
- os_strcmp(dent->d_name, "..") == 0)
+ os_strcmp(dent->d_name, "..") == 0 ||
+ os_strncmp(dent->d_name, "p2p-dev-", 8) == 0)
continue;
printf("Selected interface '%s'\n", dent->d_name);
ifname = os_strdup(dent->d_name);
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index b3ad45e..f197352 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -598,7 +598,7 @@
}
dst_addr = buf;
- os_memcpy(&proto, buf + ETH_ALEN, 2);
+ os_memcpy(&proto, (char *) buf + ETH_ALEN, 2);
if (!wpa_priv_allowed_l2_proto(proto)) {
wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype "
@@ -607,7 +607,8 @@
}
res = l2_packet_send(iface->l2[idx], dst_addr, proto,
- buf + ETH_ALEN + 2, len - ETH_ALEN - 2);
+ (unsigned char *) buf + ETH_ALEN + 2,
+ len - ETH_ALEN - 2);
wpa_printf(MSG_DEBUG, "L2 send[idx=%d]: res=%d", idx, res);
}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index d1dd540..e14bffd 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -125,6 +125,9 @@
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s);
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_OWE
+static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s);
+#endif /* CONFIG_OWE */
/* Configure default/group WEP keys for static WEP */
@@ -400,7 +403,10 @@
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
wpa_s->group_cipher = WPA_CIPHER_NONE;
wpa_s->mgmt_group_cipher = 0;
@@ -422,10 +428,8 @@
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
wpa_s->pairwise_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
-#ifdef CONFIG_IEEE80211W
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
wpa_s->mgmt_group_cipher);
-#endif /* CONFIG_IEEE80211W */
pmksa_cache_clear_current(wpa_s->wpa);
}
@@ -691,13 +695,7 @@
*/
void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
{
- int i, max;
-
-#ifdef CONFIG_IEEE80211W
- max = 6;
-#else /* CONFIG_IEEE80211W */
- max = 4;
-#endif /* CONFIG_IEEE80211W */
+ int i, max = 6;
/* MLME-DELETEKEYS.request */
for (i = 0; i < max; i++) {
@@ -846,6 +844,9 @@
enum wpa_states state)
{
enum wpa_states old_state = wpa_s->wpa_state;
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+ Boolean update_fils_connect_params = FALSE;
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
wpa_supplicant_state_txt(wpa_s->wpa_state),
@@ -943,8 +944,12 @@
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
if (!fils_hlp_sent && ssid && ssid->eap.erp)
- wpas_update_fils_connect_params(wpa_s);
+ update_fils_connect_params = TRUE;
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_OWE
+ if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE))
+ wpas_update_owe_connect_params(wpa_s);
+#endif /* CONFIG_OWE */
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
state == WPA_ASSOCIATED) {
wpa_s->new_connection = 1;
@@ -984,7 +989,15 @@
if (wpa_s->wpa_state == WPA_COMPLETED ||
old_state == WPA_COMPLETED)
wpas_notify_auth_changed(wpa_s);
+#ifdef CONFIG_DPP2
+ if (wpa_s->wpa_state == WPA_COMPLETED)
+ wpas_dpp_connected(wpa_s);
+#endif /* CONFIG_DPP2 */
}
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+ if (update_fils_connect_params)
+ wpas_update_fils_connect_params(wpa_s);
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
}
@@ -1180,7 +1193,6 @@
return -1;
}
-#ifdef CONFIG_IEEE80211W
if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
@@ -1188,7 +1200,6 @@
"reject");
return -1;
}
-#endif /* CONFIG_IEEE80211W */
return 0;
}
@@ -1226,14 +1237,16 @@
{
struct wpa_ie_data ie;
int sel, proto;
- const u8 *bss_wpa, *bss_rsn, *bss_osen;
+ const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
if (bss) {
bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ bss_rsnx = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
- } else
- bss_wpa = bss_rsn = bss_osen = NULL;
+ } else {
+ bss_wpa = bss_rsn = bss_rsnx = bss_osen = NULL;
+ }
if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
@@ -1313,7 +1326,6 @@
ie.group_cipher = ssid->group_cipher;
ie.pairwise_cipher = ssid->pairwise_cipher;
ie.key_mgmt = ssid->key_mgmt;
-#ifdef CONFIG_IEEE80211W
ie.mgmt_group_cipher = 0;
if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
if (ssid->group_mgmt_cipher &
@@ -1332,7 +1344,6 @@
ie.mgmt_group_cipher =
WPA_CIPHER_AES_128_CMAC;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OWE
if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
!ssid->owe_only &&
@@ -1352,12 +1363,10 @@
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
"pairwise %d key_mgmt %d proto %d",
ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
-#ifdef CONFIG_IEEE80211W
if (ssid->ieee80211w) {
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
ie.mgmt_group_cipher);
}
-#endif /* CONFIG_IEEE80211W */
wpa_s->wpa_proto = proto;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
@@ -1368,7 +1377,9 @@
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
- bss_rsn ? 2 + bss_rsn[1] : 0))
+ bss_rsn ? 2 + bss_rsn[1] : 0) ||
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+ bss_rsnx ? 2 + bss_rsnx[1] : 0))
return -1;
}
@@ -1414,7 +1425,8 @@
if (0) {
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SHA384
- } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
+ os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: using KEY_MGMT FT/802.1X-SHA384");
@@ -1457,7 +1469,8 @@
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
- } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
+ } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X) &&
+ os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
if (!ssid->ft_eap_pmksa_caching &&
@@ -1487,7 +1500,6 @@
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1496,7 +1508,6 @@
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: using KEY_MGMT PSK with SHA256");
-#endif /* CONFIG_IEEE80211W */
} else if (sel & WPA_KEY_MGMT_IEEE8021X) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
@@ -1527,7 +1538,13 @@
wpa_s->pairwise_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
-#ifdef CONFIG_IEEE80211W
+ if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
+ wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "RSN: Management frame protection required but the selected AP does not enable it");
+ return -1;
+ }
+
sel = ie.mgmt_group_cipher;
if (ssid->group_mgmt_cipher)
sel &= ssid->group_mgmt_cipher;
@@ -1561,16 +1578,23 @@
wpa_s->mgmt_group_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
wpas_get_ssid_pmf(wpa_s, ssid));
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
#endif /* CONFIG_OCV */
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, wpa_s->conf->sae_pwe);
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
return -1;
}
+ wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe);
+ if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe,
+ &wpa_s->rsnxe_len)) {
+ wpa_msg(wpa_s, MSG_WARNING, "RSN: Failed to generate RSNXE");
+ return -1;
+ }
+
if (0) {
#ifdef CONFIG_DPP
} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
@@ -1712,7 +1736,7 @@
case 2: /* Bits 16-23 */
#ifdef CONFIG_WNM
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
- if (!wpa_s->conf->disable_btm)
+ if (!wpa_s->disable_mbo_oce && !wpa_s->conf->disable_btm)
*pos |= 0x08; /* Bit 19 - BSS Transition */
#endif /* CONFIG_WNM */
break;
@@ -1919,6 +1943,36 @@
}
+static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_SAE
+ int *groups = conf->sae_groups;
+ int default_groups[] = { 19, 20, 21, 0 };
+ const char *password;
+
+ if (!groups || groups[0] <= 0)
+ groups = default_groups;
+
+ password = ssid->sae_password;
+ if (!password)
+ password = ssid->passphrase;
+
+ if (conf->sae_pwe == 0 || !password) {
+ /* PT derivation not needed */
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ return;
+ }
+
+ if (ssid->pt)
+ return; /* PT already derived */
+ ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
+ (const u8 *) password, os_strlen(password),
+ ssid->sae_password_id);
+#endif /* CONFIG_SAE */
+}
+
+
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
/**
@@ -1965,6 +2019,14 @@
} else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
os_get_reltime(&wpa_s->roam_start);
}
+ } else {
+#ifdef CONFIG_SAE
+#ifdef CONFIG_SME
+ os_free(wpa_s->sme.sae_rejected_groups);
+ wpa_s->sme.sae_rejected_groups = NULL;
+#endif /* CONFIG_SME */
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+#endif /* CONFIG_SAE */
}
if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
@@ -2066,6 +2128,10 @@
bss->ie_len);
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_MBO
+ wpas_mbo_check_pmf(wpa_s, bss, ssid);
+#endif /* CONFIG_MBO */
+
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
ssid->mode == WPAS_MODE_INFRA) {
sme_authenticate(wpa_s, bss, ssid);
@@ -2154,6 +2220,7 @@
struct hostapd_freq_params vht_freq;
int chwidth, seg0, seg1;
u32 vht_caps = 0;
+ int is_24ghz;
freq->freq = ssid->frequency;
@@ -2205,8 +2272,8 @@
if (!mode)
return;
- /* HE can work without HT + VHT */
- freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+ is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
+ hw_mode == HOSTAPD_MODE_IEEE80211B;
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_ht) {
@@ -2219,6 +2286,10 @@
if (!freq->ht_enabled)
return;
+ /* Allow HE on 2.4 GHz without VHT: see nl80211_put_freq_params() */
+ if (is_24ghz)
+ freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+
/* Setup higher BW only for 5 GHz */
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return;
@@ -2339,6 +2410,9 @@
if (!vht_freq.vht_enabled)
return;
+ /* Enable HE for VHT */
+ vht_freq.he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+
/* setup center_freq1, bandwidth */
for (j = 0; j < ARRAY_SIZE(vht80); j++) {
if (freq->channel >= vht80[j] &&
@@ -2413,7 +2487,8 @@
}
if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
- freq->channel, freq->ht_enabled,
+ freq->channel, ssid->enable_edmg,
+ ssid->edmg_channel, freq->ht_enabled,
vht_freq.vht_enabled, freq->he_enabled,
freq->sec_channel_offset,
chwidth, seg0, seg1, vht_caps,
@@ -2816,7 +2891,7 @@
#ifdef CONFIG_MBO
mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
- if (mbo_ie) {
+ if (!wpa_s->disable_mbo_oce && mbo_ie) {
int len;
len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
@@ -2931,6 +3006,12 @@
}
#endif /* CONFIG_IEEE80211R */
+ if (wpa_s->rsnxe_len > 0 &&
+ wpa_s->rsnxe_len <= max_wpa_ie_len - wpa_ie_len) {
+ os_memcpy(wpa_ie + wpa_ie_len, wpa_s->rsnxe, wpa_s->rsnxe_len);
+ wpa_ie_len += wpa_s->rsnxe_len;
+ }
+
if (ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
@@ -2956,6 +3037,24 @@
}
+#ifdef CONFIG_OWE
+static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_driver_associate_params params;
+ u8 *wpa_ie;
+
+ os_memset(¶ms, 0, sizeof(params));
+ wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, ¶ms, NULL);
+ if (!wpa_ie)
+ return;
+
+ wpa_drv_update_connect_params(wpa_s, ¶ms, WPA_DRV_UPDATE_ASSOC_IES);
+ os_free(wpa_ie);
+}
+#endif /* CONFIG_OWE */
+
+
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
{
@@ -2984,6 +3083,117 @@
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+static u8 wpa_ie_get_edmg_oper_chans(const u8 *edmg_ie)
+{
+ if (!edmg_ie || edmg_ie[1] < 6)
+ return 0;
+ return edmg_ie[EDMG_BSS_OPERATING_CHANNELS_OFFSET];
+}
+
+
+static u8 wpa_ie_get_edmg_oper_chan_width(const u8 *edmg_ie)
+{
+ if (!edmg_ie || edmg_ie[1] < 6)
+ return 0;
+ return edmg_ie[EDMG_OPERATING_CHANNEL_WIDTH_OFFSET];
+}
+
+
+/* Returns the intersection of two EDMG configurations.
+ * Note: The current implementation is limited to CB2 only (CB1 included),
+ * i.e., the implementation supports up to 2 contiguous channels.
+ * For supporting non-contiguous (aggregated) channels and for supporting
+ * CB3 and above, this function will need to be extended.
+ */
+static struct ieee80211_edmg_config
+get_edmg_intersection(struct ieee80211_edmg_config a,
+ struct ieee80211_edmg_config b,
+ u8 primary_channel)
+{
+ struct ieee80211_edmg_config result;
+ int i, contiguous = 0;
+ int max_contiguous = 0;
+
+ result.channels = b.channels & a.channels;
+ if (!result.channels) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: cannot intersect channels 0x%x and 0x%x",
+ a.channels, b.channels);
+ goto fail;
+ }
+
+ if (!(result.channels & BIT(primary_channel - 1))) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: the primary channel %d is not one of the intersected channels 0x%x",
+ primary_channel, result.channels);
+ goto fail;
+ }
+
+ /* Find max contiguous channels */
+ for (i = 0; i < 6; i++) {
+ if (result.channels & BIT(i))
+ contiguous++;
+ else
+ contiguous = 0;
+
+ if (contiguous > max_contiguous)
+ max_contiguous = contiguous;
+ }
+
+ /* Assuming AP and STA supports ONLY contiguous channels,
+ * bw configuration can have value between 4-7.
+ */
+ if ((b.bw_config < a.bw_config))
+ result.bw_config = b.bw_config;
+ else
+ result.bw_config = a.bw_config;
+
+ if ((max_contiguous >= 2 && result.bw_config < EDMG_BW_CONFIG_5) ||
+ (max_contiguous >= 1 && result.bw_config < EDMG_BW_CONFIG_4)) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: not enough contiguous channels %d for supporting CB1 or CB2",
+ max_contiguous);
+ goto fail;
+ }
+
+ return result;
+
+fail:
+ result.channels = 0;
+ result.bw_config = 0;
+ return result;
+}
+
+
+static struct ieee80211_edmg_config
+get_supported_edmg(struct wpa_supplicant *wpa_s,
+ struct hostapd_freq_params *freq,
+ struct ieee80211_edmg_config request_edmg)
+{
+ enum hostapd_hw_mode hw_mode;
+ struct hostapd_hw_modes *mode = NULL;
+ u8 primary_channel;
+
+ if (!wpa_s->hw.modes)
+ goto fail;
+
+ hw_mode = ieee80211_freq_to_chan(freq->freq, &primary_channel);
+ if (hw_mode == NUM_HOSTAPD_MODES)
+ goto fail;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode);
+ if (!mode)
+ goto fail;
+
+ return get_edmg_intersection(mode->edmg, request_edmg, primary_channel);
+
+fail:
+ request_edmg.channels = 0;
+ request_edmg.bw_config = 0;
+ return request_edmg;
+}
+
+
#ifdef CONFIG_MBO
void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s)
{
@@ -3019,6 +3229,7 @@
struct wpa_ssid *ssid = cwork->ssid;
struct wpa_supplicant *wpa_s = work->wpa_s;
u8 *wpa_ie;
+ const u8 *edmg_ie_oper;
int use_crypt, ret, i, bssid_changed;
unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
struct wpa_driver_associate_params params;
@@ -3111,6 +3322,8 @@
/* Starting new association, so clear the possibly used WPA IE from the
* previous association. */
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, ¶ms, NULL);
if (!wpa_ie) {
@@ -3202,6 +3415,71 @@
params.beacon_int = wpa_s->conf->beacon_int;
}
+ if (bss && ssid->enable_edmg)
+ edmg_ie_oper = get_ie_ext((const u8 *) (bss + 1), bss->ie_len,
+ WLAN_EID_EXT_EDMG_OPERATION);
+ else
+ edmg_ie_oper = NULL;
+
+ if (edmg_ie_oper) {
+ params.freq.edmg.channels =
+ wpa_ie_get_edmg_oper_chans(edmg_ie_oper);
+ params.freq.edmg.bw_config =
+ wpa_ie_get_edmg_oper_chan_width(edmg_ie_oper);
+ wpa_printf(MSG_DEBUG,
+ "AP supports EDMG channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+
+ /* User may ask for specific EDMG channel for EDMG connection
+ * (must be supported by AP)
+ */
+ if (ssid->edmg_channel) {
+ struct ieee80211_edmg_config configured_edmg;
+ enum hostapd_hw_mode hw_mode;
+ u8 primary_channel;
+
+ hw_mode = ieee80211_freq_to_chan(bss->freq,
+ &primary_channel);
+ if (hw_mode == NUM_HOSTAPD_MODES)
+ goto edmg_fail;
+
+ hostapd_encode_edmg_chan(ssid->enable_edmg,
+ ssid->edmg_channel,
+ primary_channel,
+ &configured_edmg);
+
+ if (ieee802_edmg_is_allowed(params.freq.edmg,
+ configured_edmg)) {
+ params.freq.edmg = configured_edmg;
+ wpa_printf(MSG_DEBUG,
+ "Use EDMG channel %d for connection",
+ ssid->edmg_channel);
+ } else {
+ edmg_fail:
+ params.freq.edmg.channels = 0;
+ params.freq.edmg.bw_config = 0;
+ wpa_printf(MSG_WARNING,
+ "EDMG channel %d not supported by AP, fallback to DMG",
+ ssid->edmg_channel);
+ }
+ }
+
+ if (params.freq.edmg.channels) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG before: channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+ params.freq.edmg = get_supported_edmg(wpa_s,
+ ¶ms.freq,
+ params.freq.edmg);
+ wpa_printf(MSG_DEBUG,
+ "EDMG after: channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+ }
+ }
+
params.pairwise_suite = cipher_pairwise;
params.group_suite = cipher_group;
params.mgmt_group_suite = cipher_group_mgmt;
@@ -3230,7 +3508,7 @@
params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192))
- params.req_key_mgmt_offload = 1;
+ params.req_handshake_offload = 1;
if (wpa_s->conf->key_mgmt_offload) {
if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
@@ -3252,7 +3530,6 @@
params.drop_unencrypted = use_crypt;
-#ifdef CONFIG_IEEE80211W
params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
@@ -3271,7 +3548,6 @@
#endif /* CONFIG_OWE */
}
}
-#endif /* CONFIG_IEEE80211W */
params.p2p = ssid->p2p_group;
@@ -3764,9 +4040,15 @@
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+#if defined(CONFIG_SAE) && defined(CONFIG_SME)
+ os_free(wpa_s->sme.sae_rejected_groups);
+ wpa_s->sme.sae_rejected_groups = NULL;
+#endif /* CONFIG_SAE && CONFIG_SME */
wpa_s->last_owe_group = 0;
- if (ssid)
+ if (ssid) {
ssid->owe_transition_bss_select_count = 0;
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+ }
if (wpa_s->connect_without_scan ||
wpa_supplicant_fast_associate(wpa_s) != 1) {
@@ -4345,6 +4627,11 @@
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
wpas_wps_update_mac_addr(wpa_s);
+#ifdef CONFIG_FST
+ if (wpa_s->fst)
+ fst_update_mac_addr(wpa_s->fst, wpa_s->own_addr);
+#endif /* CONFIG_FST */
+
return 0;
}
@@ -5953,7 +6240,7 @@
hs20_init(wpa_s);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MBO
- if (wpa_s->conf->oce) {
+ if (!wpa_s->disable_mbo_oce && wpa_s->conf->oce) {
if ((wpa_s->conf->oce & OCE_STA) &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
wpa_s->enable_oce = OCE_STA;
@@ -6051,6 +6338,7 @@
}
os_free(wpa_s->ssids_from_scan_req);
+ os_free(wpa_s->last_scan_freqs);
os_free(wpa_s);
}
@@ -6920,8 +7208,8 @@
wpa_s->reassociate = 1;
break;
case WPA_CTRL_REQ_EAP_PIN:
- str_clear_free(eap->pin);
- eap->pin = os_strdup(value);
+ str_clear_free(eap->cert.pin);
+ eap->cert.pin = os_strdup(value);
eap->pending_req_pin = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -6935,8 +7223,8 @@
eap->pending_req_otp_len = 0;
break;
case WPA_CTRL_REQ_EAP_PASSPHRASE:
- str_clear_free(eap->private_key_passwd);
- eap->private_key_passwd = os_strdup(value);
+ str_clear_free(eap->cert.private_key_passwd);
+ eap->cert.private_key_passwd = os_strdup(value);
eap->pending_req_passphrase = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -7023,7 +7311,6 @@
int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
-#ifdef CONFIG_IEEE80211W
if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
!(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
@@ -7052,9 +7339,6 @@
}
return ssid->ieee80211w;
-#else /* CONFIG_IEEE80211W */
- return NO_MGMT_FRAME_PROTECTION;
-#endif /* CONFIG_IEEE80211W */
}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 1159bdc..ba511b9 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -311,6 +311,26 @@
# by executing the WPS protocol.
#wps_priority=0
+# Device Provisioning Protocol (DPP) parameters
+#
+# How to process DPP configuration
+# 0 = report received configuration to an external program for
+# processing; do not generate any network profile internally (default)
+# 1 = report received configuration to an external program and generate
+# a network profile internally, but do not automatically connect
+# to the created (disabled) profile; the network profile id is
+# reported to external programs
+# 2 = report received configuration to an external program, generate
+# a network profile internally, try to connect to the created
+# profile automatically
+#dpp_config_processing=0
+#
+# Name for Enrollee's DPP Configuration Request
+#dpp_name=Test
+#
+# MUD URL for Enrollee's DPP Configuration Request (optional)
+#dpp_mud_url=https://example.com/mud
+
# Maximum number of BSS entries to keep in memory
# Default: 200
# This can be used to limit memory use on the BSS entries (cached scan
@@ -405,6 +425,14 @@
# since all implementations are required to support group 19.
#sae_groups=19 20 21
+# SAE mechanism for PWE derivation
+# 0 = hunting-and-pecking loop only (default)
+# 1 = hash-to-element only
+# 2 = both hunting-and-pecking loop and hash-to-element enabled
+# Note: The default value is likely to change from 0 to 2 once the new
+# hash-to-element mechanism has received more interoperability testing.
+#sae_pwe=0
+
# Default value for DTIM period (if not overridden in network block)
#dtim_period=2
@@ -1323,6 +1351,12 @@
# certificate. See altsubject_match documentation for more details.
# domain_suffix_match2: Constraint for server domain name. See
# domain_suffix_match for more details.
+# ocsp2: See ocsp for more details.
+#
+# Separate machine credentials can be configured for EAP-TEAP Phase 2 with
+# "machine_" prefix (e.g., "machine_identity") in the configuration parameters.
+# See the parameters without that prefix for more details on the meaning and
+# format of each such parameter.
#
# fragment_size: Maximum EAP fragment size in bytes (default 1398).
# This value limits the fragment size for EAP methods that support
@@ -1522,6 +1556,16 @@
# Set to 1 to disable BSS transition management
#disable_btm=0
+# Enable EDMG capability in STA/AP mode, default value is false
+#enable_edmg=1
+
+# This value is used to configure the channel bonding feature.
+# Default value is 0.
+# Relevant only if enable_edmg is true
+# In AP mode it defines the EDMG channel to use for AP operation.
+# In STA mode it defines the EDMG channel for connection (if supported by AP).
+#edmg_channel=9
+
# Example blocks:
# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index e59cf30..c5d2535 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -614,6 +614,9 @@
int eapol_received; /* number of EAPOL packets received after the
* previous association event */
+ u8 rsnxe[20];
+ size_t rsnxe_len;
+
struct scard_data *scard;
char imsi[20];
int mnc_len;
@@ -700,6 +703,10 @@
struct wpa_ssid_value *ssids_from_scan_req;
unsigned int num_ssids_from_scan_req;
+ int *last_scan_freqs;
+ unsigned int num_last_scan_freqs;
+ unsigned int suitable_network;
+ unsigned int no_suitable_network;
u64 drv_flags;
unsigned int drv_enc;
@@ -752,6 +759,7 @@
unsigned int connection_ht:1;
unsigned int connection_vht:1;
unsigned int connection_he:1;
+ unsigned int disable_mbo_oce:1;
struct os_reltime last_mac_addr_change;
int last_mac_addr_style;
@@ -805,6 +813,7 @@
u8 ext_auth_bssid[ETH_ALEN];
u8 ext_auth_ssid[SSID_MAX_LEN];
size_t ext_auth_ssid_len;
+ int *sae_rejected_groups;
#endif /* CONFIG_SAE */
} sme;
#endif /* CONFIG_SME */
@@ -1239,6 +1248,8 @@
unsigned int dpp_resp_wait_time;
unsigned int dpp_resp_max_tries;
unsigned int dpp_resp_retry_time;
+ u8 dpp_last_ssid[SSID_MAX_LEN];
+ size_t dpp_last_ssid_len;
#ifdef CONFIG_DPP2
struct dpp_pfs *dpp_pfs;
#endif /* CONFIG_DPP2 */
@@ -1256,6 +1267,7 @@
unsigned int ieee80211ac:1;
unsigned int enabled_4addr_mode:1;
unsigned int multi_bss_support:1;
+ unsigned int drv_authorized_port:1;
};
@@ -1391,6 +1403,8 @@
int add_oce_capa);
const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr);
const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
+void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ struct wpa_ssid *ssid);
const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
enum mbo_attr_id attr);
int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
@@ -1414,11 +1428,12 @@
NOT_ALLOWED, NO_IR, ALLOWED
};
-enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
- u8 bw);
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
+ u8 channel, u8 bw);
size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
int freq, u8 *pos, size_t len);
+int * wpas_supp_op_classes(struct wpa_supplicant *wpa_s);
int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
unsigned int type, const u8 *addr,
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 62af7f6..d80b8f2 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -396,6 +396,10 @@
ie = wpa_bss_get_ie(curr, WLAN_EID_RSN);
if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
ret = -1;
+
+ ie = wpa_bss_get_ie(curr, WLAN_EID_RSNX);
+ if (wpa_sm_set_ap_rsnxe(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
+ ret = -1;
} else {
ret = -1;
}
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 5da8154..f51340f 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -533,9 +533,7 @@
if (wpa_s->conf->wps_cred_add_sae &&
cred->key_len != 2 * PMK_LEN) {
ssid->key_mgmt |= WPA_KEY_MGMT_SAE;
-#ifdef CONFIG_IEEE80211W
ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
-#endif /* CONFIG_IEEE80211W */
}
ssid->proto = WPA_PROTO_RSN;
break;
@@ -2691,7 +2689,7 @@
(attr.rf_bands == NULL ||
*attr.rf_bands & WPS_RF_50GHZ))
freq = 5000 + 5 * chan;
- else if (chan >= 1 && chan <= 4 &&
+ else if (chan >= 1 && chan <= 6 &&
(attr.rf_bands == NULL ||
*attr.rf_bands & WPS_RF_60GHZ))
freq = 56160 + 2160 * chan;