aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2020-04-07 02:13:27 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2020-04-07 02:13:27 +0000
commitce4e1673f94ef1f467f4220ce42f92db13fc68e6 (patch)
tree60ed88972e9c3ba77e3470046ceda53c7702f7e7
parent41117d2e6dbc171d0a7bdf6f6b038eb60f1f5695 (diff)
parent1337a99542601c02f0e0fc3a10cb5aa098a73dc7 (diff)
downloadwpa_supplicant_8-ce4e1673f94ef1f467f4220ce42f92db13fc68e6.tar.gz
Snap for 6370344 from 1337a99542601c02f0e0fc3a10cb5aa098a73dc7 to rvc-release
Change-Id: Id1d8525e31e66bf290051249095ae4c7ade76f92
-rw-r--r--hostapd/Android.mk18
-rw-r--r--hostapd/Makefile20
-rw-r--r--hostapd/android.config15
-rw-r--r--hostapd/config_file.c91
-rw-r--r--hostapd/ctrl_iface.c382
-rw-r--r--hostapd/defconfig11
-rw-r--r--hostapd/hostapd.conf100
-rw-r--r--hostapd/hostapd.wpa_psk6
-rw-r--r--hostapd/main.c10
-rw-r--r--hs20/client/Makefile9
-rw-r--r--hs20/client/oma_dm_client.c2
-rw-r--r--hs20/client/osu_client.c23
-rw-r--r--hs20/client/osu_client.h2
-rw-r--r--hs20/client/spp_client.c2
-rw-r--r--hs20/server/ca/ocsp-responder.sh2
-rw-r--r--hs20/server/ca/ocsp-update-cache.sh1
-rw-r--r--hs20/server/hs20_spp_server.c2
-rw-r--r--src/ap/acs.c278
-rw-r--r--src/ap/ap_config.c63
-rw-r--r--src/ap/ap_config.h28
-rw-r--r--src/ap/ap_drv_ops.c44
-rw-r--r--src/ap/ap_drv_ops.h11
-rw-r--r--src/ap/ap_list.c4
-rw-r--r--src/ap/beacon.c271
-rw-r--r--src/ap/ctrl_iface_ap.c31
-rw-r--r--src/ap/dfs.c260
-rw-r--r--src/ap/dfs.h3
-rw-r--r--src/ap/dhcp_snoop.c8
-rw-r--r--src/ap/dpp_hostapd.c185
-rw-r--r--src/ap/dpp_hostapd.h4
-rw-r--r--src/ap/drv_callbacks.c166
-rw-r--r--src/ap/fils_hlp.c36
-rw-r--r--src/ap/hostapd.c55
-rw-r--r--src/ap/hostapd.h16
-rw-r--r--src/ap/hw_features.c96
-rw-r--r--src/ap/hw_features.h10
-rw-r--r--src/ap/ieee802_11.c408
-rw-r--r--src/ap/ieee802_11.h20
-rw-r--r--src/ap/ieee802_11_auth.c172
-rw-r--r--src/ap/ieee802_11_auth.h17
-rw-r--r--src/ap/ieee802_11_he.c40
-rw-r--r--src/ap/ieee802_11_ht.c26
-rw-r--r--src/ap/ieee802_11_shared.c54
-rw-r--r--src/ap/ieee802_1x.c33
-rw-r--r--src/ap/neighbor_db.c2
-rw-r--r--src/ap/pmksa_cache_auth.c5
-rw-r--r--src/ap/sta_info.c32
-rw-r--r--src/ap/sta_info.h2
-rw-r--r--src/ap/utils.c4
-rw-r--r--src/ap/vlan_init.c5
-rw-r--r--src/ap/wmm.c6
-rw-r--r--src/ap/wnm_ap.c64
-rw-r--r--src/ap/wpa_auth.c872
-rw-r--r--src/ap/wpa_auth.h47
-rw-r--r--src/ap/wpa_auth_ft.c205
-rw-r--r--src/ap/wpa_auth_glue.c184
-rw-r--r--src/ap/wpa_auth_i.h6
-rw-r--r--src/ap/wpa_auth_ie.c43
-rw-r--r--src/ap/wps_hostapd.c74
-rw-r--r--src/common/common_module_tests.c3
-rw-r--r--src/common/defs.h51
-rw-r--r--src/common/dhcp.h2
-rw-r--r--src/common/dpp.c2039
-rw-r--r--src/common/dpp.h52
-rw-r--r--src/common/hw_features_common.c75
-rw-r--r--src/common/ieee802_11_common.c133
-rw-r--r--src/common/ieee802_11_common.h29
-rw-r--r--src/common/ieee802_11_defs.h23
-rw-r--r--src/common/privsep_commands.h1
-rw-r--r--src/common/qca-vendor.h722
-rw-r--r--src/common/sae.c133
-rw-r--r--src/common/sae.h5
-rw-r--r--src/common/wpa_common.c78
-rw-r--r--src/common/wpa_common.h30
-rw-r--r--src/common/wpa_ctrl.c5
-rw-r--r--src/common/wpa_ctrl.h11
-rw-r--r--src/crypto/Makefile2
-rw-r--r--src/crypto/crypto.h1
-rw-r--r--src/crypto/crypto_openssl.c6
-rw-r--r--src/crypto/crypto_wolfssl.c6
-rw-r--r--src/crypto/sha256.c6
-rw-r--r--src/crypto/sha384.c6
-rw-r--r--src/crypto/sha512.c6
-rw-r--r--src/crypto/tls_openssl.c85
-rw-r--r--src/drivers/driver.h299
-rw-r--r--src/drivers/driver_atheros.c13
-rw-r--r--src/drivers/driver_bsd.c467
-rw-r--r--src/drivers/driver_common.c9
-rw-r--r--src/drivers/driver_hostap.c24
-rw-r--r--src/drivers/driver_macsec_linux.c6
-rw-r--r--src/drivers/driver_ndis.c14
-rw-r--r--src/drivers/driver_nl80211.c805
-rw-r--r--src/drivers/driver_nl80211.h32
-rw-r--r--src/drivers/driver_nl80211_android.c4
-rw-r--r--src/drivers/driver_nl80211_capa.c68
-rw-r--r--src/drivers/driver_nl80211_event.c135
-rw-r--r--src/drivers/driver_nl80211_monitor.c3
-rw-r--r--src/drivers/driver_nl80211_scan.c19
-rw-r--r--src/drivers/driver_none.c8
-rw-r--r--src/drivers/driver_openbsd.c10
-rw-r--r--src/drivers/driver_privsep.c18
-rw-r--r--src/drivers/driver_wext.c86
-rw-r--r--src/drivers/driver_wext.h4
-rw-r--r--src/drivers/drivers.mak7
-rw-r--r--src/drivers/drivers.mk10
-rw-r--r--src/drivers/nl80211_copy.h246
-rw-r--r--src/eapol_auth/eapol_auth_sm.c14
-rw-r--r--src/eapol_supp/eapol_supp_sm.c18
-rw-r--r--src/eapol_supp/eapol_supp_sm.h9
-rw-r--r--src/p2p/p2p.h2
-rw-r--r--src/radius/radius.c2
-rw-r--r--src/radius/radius_client.c6
-rw-r--r--src/rsn_supp/pmksa_cache.c37
-rw-r--r--src/rsn_supp/preauth.c19
-rw-r--r--src/rsn_supp/tdls.c7
-rw-r--r--src/rsn_supp/wpa.c276
-rw-r--r--src/rsn_supp/wpa.h26
-rw-r--r--src/rsn_supp/wpa_ft.c217
-rw-r--r--src/rsn_supp/wpa_i.h32
-rw-r--r--src/rsn_supp/wpa_ie.c27
-rw-r--r--src/rsn_supp/wpa_ie.h1
-rw-r--r--src/tls/asn1.c313
-rw-r--r--src/tls/asn1.h39
-rw-r--r--src/tls/tlsv1_client_read.c10
-rw-r--r--src/tls/x509v3.c130
-rw-r--r--src/tls/x509v3.h7
-rw-r--r--src/utils/browser-android.c2
-rw-r--r--src/utils/browser-system.c2
-rw-r--r--src/utils/browser-wpadebug.c2
-rw-r--r--src/utils/browser.c210
-rw-r--r--src/utils/browser.h4
-rw-r--r--src/utils/common.c38
-rw-r--r--src/utils/common.h2
-rw-r--r--src/utils/crc32.c85
-rw-r--r--src/utils/eloop.c47
-rw-r--r--src/utils/eloop_win.c8
-rw-r--r--src/utils/http-utils.h6
-rw-r--r--src/utils/os_unix.c5
-rw-r--r--src/utils/trace.c11
-rw-r--r--src/utils/utils_module_tests.c6
-rw-r--r--src/utils/wpa_debug.c147
-rw-r--r--src/utils/wpa_debug.h2
-rw-r--r--src/wps/wps.h14
-rw-r--r--src/wps/wps_dev_attr.c17
-rw-r--r--src/wps/wps_dev_attr.h1
-rw-r--r--src/wps/wps_registrar.c61
-rw-r--r--wpa_supplicant/Android.mk21
-rw-r--r--wpa_supplicant/Makefile23
-rw-r--r--wpa_supplicant/README-DPP65
-rw-r--r--wpa_supplicant/android.config12
-rw-r--r--wpa_supplicant/ap.c19
-rw-r--r--wpa_supplicant/bss.c2
-rw-r--r--wpa_supplicant/bss.h1
-rw-r--r--wpa_supplicant/config.c25
-rw-r--r--wpa_supplicant/config.h16
-rw-r--r--wpa_supplicant/config_file.c61
-rw-r--r--wpa_supplicant/config_ssid.h82
-rw-r--r--wpa_supplicant/config_winreg.c25
-rw-r--r--wpa_supplicant/ctrl_iface.c188
-rw-r--r--wpa_supplicant/ctrl_iface_udp.c2
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c40
-rw-r--r--wpa_supplicant/defconfig19
-rw-r--r--wpa_supplicant/dpp_supplicant.c470
-rw-r--r--wpa_supplicant/dpp_supplicant.h6
-rw-r--r--wpa_supplicant/driver_i.h72
-rw-r--r--wpa_supplicant/eapol_test.c2
-rw-r--r--wpa_supplicant/events.c444
-rwxr-xr-xwpa_supplicant/examples/dpp-nfc.py692
-rw-r--r--wpa_supplicant/examples/p2p/p2p_connect.py2
-rw-r--r--wpa_supplicant/hidl/1.3/p2p_iface.cpp2
-rw-r--r--wpa_supplicant/ibss_rsn.c42
-rw-r--r--wpa_supplicant/mesh_mpm.c28
-rw-r--r--wpa_supplicant/mesh_rsn.c10
-rw-r--r--wpa_supplicant/offchannel.c6
-rw-r--r--wpa_supplicant/op_classes.c32
-rw-r--r--wpa_supplicant/p2p_supplicant.c49
-rw-r--r--wpa_supplicant/preauth_test.c13
-rw-r--r--wpa_supplicant/rrm.c10
-rw-r--r--wpa_supplicant/scan.c227
-rw-r--r--wpa_supplicant/scan.h25
-rw-r--r--wpa_supplicant/sme.c116
-rw-r--r--wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in2
-rw-r--r--wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in2
-rw-r--r--wpa_supplicant/systemd/wpa_supplicant.service.arg.in2
-rw-r--r--wpa_supplicant/wnm_sta.c9
-rw-r--r--wpa_supplicant/wpa_cli.c15
-rw-r--r--wpa_supplicant/wpa_gui-qt4/peers.cpp4
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpagui.cpp19
-rw-r--r--wpa_supplicant/wpa_priv.c27
-rw-r--r--wpa_supplicant/wpa_supplicant.c310
-rw-r--r--wpa_supplicant/wpa_supplicant.conf40
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h52
-rw-r--r--wpa_supplicant/wpas_glue.c138
-rw-r--r--wpa_supplicant/wps_supplicant.c13
194 files changed, 12393 insertions, 3334 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index eb01da5c..dff5704d 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -156,6 +156,7 @@ OBJS += src/utils/wpa_debug.c
OBJS += src/utils/wpabuf.c
OBJS += src/utils/os_$(CONFIG_OS).c
OBJS += src/utils/ip_addr.c
+OBJS += src/utils/crc32.c
OBJS += src/common/ieee802_11_common.c
OBJS += src/common/wpa_common.c
@@ -295,10 +296,6 @@ L_CFLAGS += -DCONFIG_WNM -DCONFIG_WNM_AP
OBJS += src/ap/wnm_ap.c
endif
-ifdef CONFIG_IEEE80211N
-L_CFLAGS += -DCONFIG_IEEE80211N
-endif
-
ifdef CONFIG_IEEE80211AC
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
@@ -327,6 +324,10 @@ OBJS += src/fst/fst_ctrl_iface.c
endif
endif
+ifdef CONFIG_WEP
+L_CFLAGS += -DCONFIG_WEP
+endif
+
include $(LOCAL_PATH)/src/drivers/drivers.mk
@@ -558,6 +559,7 @@ NEED_ECC=y
NEED_JSON=y
NEED_GAS=y
NEED_BASE64=y
+NEED_ASN1=y
ifdef CONFIG_DPP2
L_CFLAGS += -DCONFIG_DPP2
endif
@@ -695,12 +697,12 @@ OBJS += src/tls/tlsv1_cred.c
OBJS += src/tls/tlsv1_server.c
OBJS += src/tls/tlsv1_server_write.c
OBJS += src/tls/tlsv1_server_read.c
-OBJS += src/tls/asn1.c
OBJS += src/tls/rsa.c
OBJS += src/tls/x509v3.c
OBJS += src/tls/pkcs1.c
OBJS += src/tls/pkcs5.c
OBJS += src/tls/pkcs8.c
+NEED_ASN1=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -950,6 +952,10 @@ L_CFLAGS += -DCONFIG_INTERNAL_SHA512
OBJS += src/crypto/sha512-internal.c
endif
+ifdef NEED_ASN1
+OBJS += src/tls/asn1.c
+endif
+
ifdef NEED_DH_GROUPS
OBJS += src/crypto/dh_groups.c
endif
@@ -1008,9 +1014,7 @@ OBJS += src/ap/hw_features.c
OBJS += src/ap/dfs.c
L_CFLAGS += -DNEED_AP_MLME
endif
-ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c
-endif
ifdef CONFIG_IEEE80211AC
OBJS += src/ap/ieee802_11_vht.c
diff --git a/hostapd/Makefile b/hostapd/Makefile
index f01f5814..4adf9968 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -158,6 +158,7 @@ OBJS_c += ../src/utils/wpa_debug.o
OBJS += ../src/utils/wpabuf.o
OBJS += ../src/utils/os_$(CONFIG_OS).o
OBJS += ../src/utils/ip_addr.o
+OBJS += ../src/utils/crc32.o
OBJS += ../src/common/ieee802_11_common.o
OBJS += ../src/common/wpa_common.o
@@ -334,10 +335,6 @@ CFLAGS += -DCONFIG_WNM -DCONFIG_WNM_AP
OBJS += ../src/ap/wnm_ap.o
endif
-ifdef CONFIG_IEEE80211N
-CFLAGS += -DCONFIG_IEEE80211N
-endif
-
ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC
endif
@@ -586,6 +583,7 @@ NEED_ECC=y
NEED_JSON=y
NEED_GAS=y
NEED_BASE64=y
+NEED_ASN1=y
ifdef CONFIG_DPP2
CFLAGS += -DCONFIG_DPP2
endif
@@ -759,12 +757,12 @@ OBJS += ../src/tls/tlsv1_cred.o
OBJS += ../src/tls/tlsv1_server.o
OBJS += ../src/tls/tlsv1_server_write.o
OBJS += ../src/tls/tlsv1_server_read.o
-OBJS += ../src/tls/asn1.o
OBJS += ../src/tls/rsa.o
OBJS += ../src/tls/x509v3.o
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
+NEED_ASN1=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -835,12 +833,12 @@ OBJS += ../src/tls/tlsv1_cred.o
OBJS += ../src/tls/tlsv1_server.o
OBJS += ../src/tls/tlsv1_server_write.o
OBJS += ../src/tls/tlsv1_server_read.o
-OBJS += ../src/tls/asn1.o
OBJS += ../src/tls/rsa.o
OBJS += ../src/tls/x509v3.o
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
+NEED_ASN1=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -1088,6 +1086,10 @@ CFLAGS += -DCONFIG_INTERNAL_SHA512
OBJS += ../src/crypto/sha512-internal.o
endif
+ifdef NEED_ASN1
+OBJS += ../src/tls/asn1.o
+endif
+
ifdef NEED_DH_GROUPS
OBJS += ../src/crypto/dh_groups.o
endif
@@ -1153,9 +1155,7 @@ OBJS += ../src/ap/hw_features.o
OBJS += ../src/ap/dfs.o
CFLAGS += -DNEED_AP_MLME
endif
-ifdef CONFIG_IEEE80211N
OBJS += ../src/ap/ieee802_11_ht.o
-endif
ifdef CONFIG_IEEE80211AC
OBJS += ../src/ap/ieee802_11_vht.o
@@ -1242,6 +1242,10 @@ OBJS += ../src/fst/fst_ctrl_iface.o
endif
endif
+ifdef CONFIG_WEP
+CFLAGS += -DCONFIG_WEP
+endif
+
ALL=hostapd hostapd_cli
all: verify_config $(ALL)
diff --git a/hostapd/android.config b/hostapd/android.config
index 68fec325..c53875c5 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -125,12 +125,6 @@ CONFIG_IPV6=y
# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y
-# IEEE 802.11n (High Throughput) support
-CONFIG_IEEE80211N=y
-
-# IEEE 802.11ac (Very High Throughput) support
-CONFIG_IEEE80211AC=y
-
# Remove debugging code that is printing out debug messages to stdout.
# This can be used to reduce the size of the hostapd considerably if debugging
# code is not needed.
@@ -225,3 +219,12 @@ CONFIG_DPP=y
# WPA3-Personal (SAE)
CONFIG_SAE=y
+
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current hostapd
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+CONFIG_WEP=y
+
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 21c9ab28..1d8c0397 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -793,6 +793,7 @@ static int hostapd_config_parse_cipher(int line, const char *value)
}
+#ifdef CONFIG_WEP
static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
char *val)
{
@@ -843,6 +844,7 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
return 0;
}
+#endif /* CONFIG_WEP */
static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
@@ -1151,7 +1153,6 @@ static int add_r1kh(struct hostapd_bss_config *bss, char *value)
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211N
static int hostapd_config_ht_capab(struct hostapd_config *conf,
const char *capab)
{
@@ -1171,14 +1172,6 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
}
if (!os_strstr(capab, "[HT40+]") && !os_strstr(capab, "[HT40-]"))
conf->secondary_channel = 0;
- if (os_strstr(capab, "[SMPS-STATIC]")) {
- conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
- conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
- }
- if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
- conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
- conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
- }
if (os_strstr(capab, "[GF]"))
conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
if (os_strstr(capab, "[SHORT-GI-20]"))
@@ -1212,7 +1205,6 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
return 0;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
@@ -2471,6 +2463,13 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
bss->skip_inactivity_poll = atoi(pos);
} else if (os_strcmp(buf, "country_code") == 0) {
+ if (pos[0] < 'A' || pos[0] > 'Z' ||
+ pos[1] < 'A' || pos[1] > 'Z') {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid country_code '%s'",
+ line, pos);
+ return 1;
+ }
os_memcpy(conf->country, pos, 2);
} else if (os_strcmp(buf, "country3") == 0) {
conf->country[2] = strtol(pos, NULL, 16);
@@ -2674,6 +2673,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "erp_domain") == 0) {
os_free(bss->erp_domain);
bss->erp_domain = os_strdup(pos);
+#ifdef CONFIG_WEP
} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
int val = atoi(pos);
@@ -2701,6 +2701,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, bss->wep_rekeying_period);
return 1;
}
+#endif /* CONFIG_WEP */
} else if (os_strcmp(buf, "eap_reauth_period") == 0) {
bss->eap_reauth_period = atoi(pos);
if (bss->eap_reauth_period < 0) {
@@ -2875,6 +2876,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "wpa") == 0) {
bss->wpa = atoi(pos);
+ } else if (os_strcmp(buf, "extended_key_id") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 2) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid extended_key_id=%d; allowed range 0..2",
+ line, val);
+ return 1;
+ }
+ bss->extended_key_id = val;
} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
bss->wpa_group_rekey = atoi(pos);
bss->wpa_group_rekey_set = 1;
@@ -2884,6 +2895,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->wpa_gmk_rekey = atoi(pos);
} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
bss->wpa_ptk_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_deny_ptk0_rekey") == 0) {
+ bss->wpa_deny_ptk0_rekey = atoi(pos);
+ if (bss->wpa_deny_ptk0_rekey < 0 ||
+ bss->wpa_deny_ptk0_rekey > 2) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid wpa_deny_ptk0_rekey=%d; allowed range 0..2",
+ line, bss->wpa_deny_ptk0_rekey);
+ return 1;
+ }
} else if (os_strcmp(buf, "wpa_group_update_count") == 0) {
char *endp;
unsigned long val = strtoul(pos, &endp, 0);
@@ -3312,6 +3332,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->ignore_broadcast_ssid = atoi(pos);
} else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) {
bss->no_probe_resp_if_max_sta = atoi(pos);
+#ifdef CONFIG_WEP
} else if (os_strcmp(buf, "wep_default_key") == 0) {
bss->ssid.wep.idx = atoi(pos);
if (bss->ssid.wep.idx > 3) {
@@ -3330,6 +3351,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, buf);
return 1;
}
+#endif /* CONFIG_WEP */
#ifndef CONFIG_NO_VLAN
} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
bss->ssid.dynamic_vlan = atoi(pos);
@@ -3408,6 +3430,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "beacon_prot") == 0) {
+ bss->beacon_prot = atoi(pos);
} else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
bss->assoc_sa_query_max_timeout = atoi(pos);
if (bss->assoc_sa_query_max_timeout == 0) {
@@ -3428,7 +3452,6 @@ static int hostapd_config_fill(struct hostapd_config *conf,
if (bss->ocv && !bss->ieee80211w)
bss->ieee80211w = 1;
#endif /* CONFIG_OCV */
-#ifdef CONFIG_IEEE80211N
} else if (os_strcmp(buf, "ieee80211n") == 0) {
conf->ieee80211n = atoi(pos);
} else if (os_strcmp(buf, "ht_capab") == 0) {
@@ -3441,7 +3464,6 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->require_ht = atoi(pos);
} else if (os_strcmp(buf, "obss_interval") == 0) {
conf->obss_interval = atoi(pos);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
} else if (os_strcmp(buf, "ieee80211ac") == 0) {
conf->ieee80211ac = atoi(pos);
@@ -3474,7 +3496,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "he_mu_beamformer") == 0) {
conf->he_phy_capab.he_mu_beamformer = atoi(pos);
} else if (os_strcmp(buf, "he_bss_color") == 0) {
- conf->he_op.he_bss_color = atoi(pos);
+ conf->he_op.he_bss_color = atoi(pos) & 0x3f;
+ conf->he_op.he_bss_color_disabled = 0;
+ } else if (os_strcmp(buf, "he_bss_color_partial") == 0) {
+ conf->he_op.he_bss_color_partial = atoi(pos);
} else if (os_strcmp(buf, "he_default_pe_duration") == 0) {
conf->he_op.he_default_pe_duration = atoi(pos);
} else if (os_strcmp(buf, "he_twt_required") == 0) {
@@ -3762,6 +3787,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "server_id") == 0) {
os_free(bss->server_id);
bss->server_id = os_strdup(pos);
+ } else if (os_strcmp(buf, "wps_application_ext") == 0) {
+ wpabuf_free(bss->wps_application_ext);
+ bss->wps_application_ext = wpabuf_parse_bin(pos);
#ifdef CONFIG_WPS_NFC
} else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
bss->wps_nfc_dev_pw_id = atoi(pos);
@@ -4165,9 +4193,28 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "sae_commit_override") == 0) {
wpabuf_free(bss->sae_commit_override);
bss->sae_commit_override = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "rsne_override_eapol") == 0) {
+ wpabuf_free(bss->rsne_override_eapol);
+ bss->rsne_override_eapol = wpabuf_parse_bin(pos);
} else if (os_strcmp(buf, "rsnxe_override_eapol") == 0) {
wpabuf_free(bss->rsnxe_override_eapol);
bss->rsnxe_override_eapol = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "rsne_override_ft") == 0) {
+ wpabuf_free(bss->rsne_override_ft);
+ bss->rsne_override_ft = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "rsnxe_override_ft") == 0) {
+ wpabuf_free(bss->rsnxe_override_ft);
+ bss->rsnxe_override_ft = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "gtk_rsc_override") == 0) {
+ wpabuf_free(bss->gtk_rsc_override);
+ bss->gtk_rsc_override = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "igtk_rsc_override") == 0) {
+ wpabuf_free(bss->igtk_rsc_override);
+ bss->igtk_rsc_override = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "no_beacon_rsnxe") == 0) {
+ bss->no_beacon_rsnxe = atoi(pos);
+ } else if (os_strcmp(buf, "skip_prune_assoc") == 0) {
+ bss->skip_prune_assoc = atoi(pos);
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_SAE
} else if (os_strcmp(buf, "sae_password") == 0) {
@@ -4370,6 +4417,18 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "dpp_controller") == 0) {
if (hostapd_dpp_controller_parse(bss, pos))
return 1;
+ } else if (os_strcmp(buf, "dpp_configurator_connectivity") == 0) {
+ bss->dpp_configurator_connectivity = atoi(pos);
+ } else if (os_strcmp(buf, "dpp_pfs") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 2) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid dpp_pfs value '%s'",
+ line, pos);
+ return -1;
+ }
+ bss->dpp_pfs = val;
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
#ifdef CONFIG_OWE
@@ -4403,9 +4462,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "owe_ptk_workaround") == 0) {
+ bss->owe_ptk_workaround = atoi(pos);
+#endif /* CONFIG_OWE */
} else if (os_strcmp(buf, "coloc_intf_reporting") == 0) {
bss->coloc_intf_reporting = atoi(pos);
-#endif /* CONFIG_OWE */
} else if (os_strcmp(buf, "multi_ap") == 0) {
int val = atoi(pos);
@@ -4422,6 +4483,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->rssi_reject_assoc_timeout = atoi(pos);
} else if (os_strcmp(buf, "pbss") == 0) {
bss->pbss = atoi(pos);
+ } else if (os_strcmp(buf, "transition_disable") == 0) {
+ bss->transition_disable = strtol(pos, NULL, 16);
#ifdef CONFIG_AIRTIME_POLICY
} else if (os_strcmp(buf, "airtime_mode") == 0) {
int val = atoi(pos);
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 9758881b..d90b5dc8 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -11,7 +11,11 @@
#ifndef CONFIG_NATIVE_WINDOWS
#ifdef CONFIG_TESTING_OPTIONS
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#else
#include <net/ethernet.h>
+#endif
#include <netinet/ip.h>
#endif /* CONFIG_TESTING_OPTIONS */
@@ -55,6 +59,7 @@
#include "ap/neighbor_db.h"
#include "ap/rrm.h"
#include "ap/dpp_hostapd.h"
+#include "ap/dfs.h"
#include "wps/wps_defs.h"
#include "wps/wps.h"
#include "fst/fst_ctrl_iface.h"
@@ -65,9 +70,6 @@
#define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
#ifdef CONFIG_CTRL_IFACE_UDP
-#define COOKIE_LEN 8
-static unsigned char cookie[COOKIE_LEN];
-static unsigned char gcookie[COOKIE_LEN];
#define HOSTAPD_CTRL_IFACE_PORT 8877
#define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50
#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878
@@ -1286,6 +1288,22 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
pos += ret;
}
+ if (hapd->conf->wpa && hapd->conf->wpa_deny_ptk0_rekey) {
+ ret = os_snprintf(pos, end - pos, "wpa_deny_ptk0_rekey=%d\n",
+ hapd->conf->wpa_deny_ptk0_rekey);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->extended_key_id) {
+ ret = os_snprintf(pos, end - pos, "extended_key_id=%d\n",
+ hapd->conf->extended_key_id);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
return pos - buf;
}
@@ -1658,7 +1676,7 @@ static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
return -1;
}
- res = hostapd_drv_send_mlme(hapd, buf, len, 0);
+ res = hostapd_drv_send_mlme(hapd, buf, len, 0, NULL, 0, 0);
os_free(buf);
return res;
}
@@ -1857,7 +1875,7 @@ static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
{
struct hostapd_data *hapd = ctx;
const struct ether_header *eth;
- struct iphdr ip;
+ struct ip ip;
const u8 *pos;
unsigned int i;
char extra[30];
@@ -1873,14 +1891,14 @@ static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
os_memcpy(&ip, eth + 1, sizeof(ip));
pos = &buf[sizeof(*eth) + sizeof(ip)];
- if (ip.ihl != 5 || ip.version != 4 ||
- ntohs(ip.tot_len) > HWSIM_IP_LEN) {
+ if (ip.ip_hl != 5 || ip.ip_v != 4 ||
+ ntohs(ip.ip_len) > HWSIM_IP_LEN) {
wpa_printf(MSG_DEBUG,
"test data: RX - ignore unexpect IP header");
return;
}
- for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) {
+ for (i = 0; i < ntohs(ip.ip_len) - sizeof(ip); i++) {
if (*pos != (u8) i) {
wpa_printf(MSG_DEBUG,
"test data: RX - ignore mismatching payload");
@@ -1890,8 +1908,8 @@ static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
}
extra[0] = '\0';
- if (ntohs(ip.tot_len) != HWSIM_IP_LEN)
- os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len));
+ if (ntohs(ip.ip_len) != HWSIM_IP_LEN)
+ os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.ip_len));
wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
}
@@ -1944,7 +1962,7 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
u8 tos;
u8 buf[2 + HWSIM_PACKETLEN];
struct ether_header *eth;
- struct iphdr *ip;
+ struct ip *ip;
u8 *dpos;
unsigned int i;
size_t send_len = HWSIM_IP_LEN;
@@ -1983,17 +2001,17 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
os_memcpy(eth->ether_shost, src, ETH_ALEN);
eth->ether_type = htons(ETHERTYPE_IP);
- ip = (struct iphdr *) (eth + 1);
+ ip = (struct ip *) (eth + 1);
os_memset(ip, 0, sizeof(*ip));
- ip->ihl = 5;
- ip->version = 4;
- ip->ttl = 64;
- ip->tos = tos;
- ip->tot_len = htons(send_len);
- ip->protocol = 1;
- ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
- ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
- ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
+ ip->ip_hl = 5;
+ ip->ip_v = 4;
+ ip->ip_ttl = 64;
+ ip->ip_tos = tos;
+ ip->ip_len = htons(send_len);
+ ip->ip_p = 1;
+ ip->ip_src.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
+ ip->ip_dst.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
+ ip->ip_sum = ipv4_hdr_checksum(ip, sizeof(*ip));
dpos = (u8 *) (ip + 1);
for (i = 0; i < send_len - sizeof(*ip); i++)
*dpos++ = i;
@@ -2150,17 +2168,19 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
if (hostapd_drv_set_key(hapd->conf->iface, hapd,
hapd->last_igtk_alg,
broadcast_ether_addr,
- hapd->last_igtk_key_idx, 1, NULL, 0,
- zero, hapd->last_igtk_len) < 0)
+ hapd->last_igtk_key_idx, 0, 1, NULL, 0,
+ zero, hapd->last_igtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
return -1;
/* Set the previously configured key to reset its TSC */
return hostapd_drv_set_key(hapd->conf->iface, hapd,
hapd->last_igtk_alg,
broadcast_ether_addr,
- hapd->last_igtk_key_idx, 1, NULL, 0,
- hapd->last_igtk,
- hapd->last_igtk_len);
+ hapd->last_igtk_key_idx, 0, 1, NULL,
+ 0, hapd->last_igtk,
+ hapd->last_igtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT);
}
if (is_broadcast_ether_addr(addr)) {
@@ -2174,16 +2194,19 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
if (hostapd_drv_set_key(hapd->conf->iface, hapd,
hapd->last_gtk_alg,
broadcast_ether_addr,
- hapd->last_gtk_key_idx, 1, NULL, 0,
- zero, hapd->last_gtk_len) < 0)
+ hapd->last_gtk_key_idx, 0, 1, NULL, 0,
+ zero, hapd->last_gtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
return -1;
/* Set the previously configured key to reset its TSC */
return hostapd_drv_set_key(hapd->conf->iface, hapd,
hapd->last_gtk_alg,
broadcast_ether_addr,
- hapd->last_gtk_key_idx, 1, NULL, 0,
- hapd->last_gtk, hapd->last_gtk_len);
+ hapd->last_gtk_key_idx, 0, 1, NULL,
+ 0, hapd->last_gtk,
+ hapd->last_gtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT);
}
sta = ap_get_sta(hapd, addr);
@@ -2199,14 +2222,16 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
/* First, use a zero key to avoid any possible duplicate key avoidance
* in the driver. */
if (hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
- sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
- zero, sta->last_tk_len) < 0)
+ sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0,
+ zero, sta->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX) < 0)
return -1;
/* Set the previously configured key to reset its TSC/RSC */
return hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
- sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
- sta->last_tk, sta->last_tk_len);
+ sta->addr, sta->last_tk_key_idx, 0, 1, NULL,
+ 0, sta->last_tk, sta->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX);
}
@@ -2215,11 +2240,12 @@ static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
u8 addr[ETH_ALEN];
const char *pos = cmd;
enum wpa_alg alg;
+ enum key_flag key_flag;
int idx, set_tx;
u8 seq[6], key[WPA_TK_MAX_LEN];
size_t key_len;
- /* parameters: alg addr idx set_tx seq key */
+ /* parameters: alg addr idx set_tx seq key key_flag */
alg = atoi(pos);
pos = os_strchr(pos, ' ');
@@ -2248,13 +2274,24 @@ static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
if (*pos != ' ')
return -1;
pos++;
- key_len = os_strlen(pos) / 2;
+ if (!os_strchr(pos, ' '))
+ return -1;
+ key_len = (os_strchr(pos, ' ') - pos) / 2;
if (hexstr2bin(pos, key, key_len) < 0)
return -1;
+ pos += 2 * key_len;
+ if (*pos != ' ')
+ return -1;
+
+ pos++;
+ key_flag = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ return -1;
wpa_printf(MSG_INFO, "TESTING: Set key");
- return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx,
- set_tx, seq, 6, key, key_len);
+ return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx, 0,
+ set_tx, seq, 6, key, key_len, key_flag);
}
@@ -2269,8 +2306,9 @@ static void restore_tk(void *ctx1, void *ctx2)
* in replay protection issues for now since there is no clean way of
* preventing encryption of a single EAPOL frame. */
hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
- sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
- sta->last_tk, sta->last_tk_len);
+ sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0,
+ sta->last_tk, sta->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX);
}
@@ -2293,8 +2331,8 @@ static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd)
wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
MAC2STR(sta->addr));
hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
- sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
- NULL, 0);
+ sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
}
wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr));
@@ -2323,8 +2361,8 @@ static int hostapd_ctrl_resend_m3(struct hostapd_data *hapd, const char *cmd)
wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
MAC2STR(sta->addr));
hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
- sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
- NULL, 0);
+ sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
}
wpa_printf(MSG_INFO, "TESTING: Send M3 to " MACSTR, MAC2STR(sta->addr));
@@ -2353,8 +2391,8 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
MAC2STR(sta->addr));
hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
- sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
- NULL, 0);
+ sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
}
wpa_printf(MSG_INFO,
@@ -2364,21 +2402,204 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
plain ? restore_tk : NULL, hapd, sta);
}
+
+static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
+ char *buf, size_t buflen)
+{
+ struct sta_info *sta;
+ u8 addr[ETH_ALEN];
+ const u8 *pmk;
+ int pmk_len;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !sta->wpa_sm) {
+ wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR,
+ MAC2STR(addr));
+ return -1;
+ }
+ pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
+ if (!pmk) {
+ wpa_printf(MSG_DEBUG, "No PMK stored for " MACSTR,
+ MAC2STR(addr));
+ return -1;
+ }
+
+ return wpa_snprintf_hex(buf, buflen, pmk, pmk_len);
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
+static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params)
+{
+ switch (params->bandwidth) {
+ case 0:
+ /* bandwidth not specified: use 20 MHz by default */
+ /* fall-through */
+ case 20:
+ if (params->center_freq1 &&
+ params->center_freq1 != params->freq)
+ return -1;
+
+ if (params->center_freq2 || params->sec_channel_offset)
+ return -1;
+ break;
+ case 40:
+ if (params->center_freq2 || !params->sec_channel_offset)
+ return -1;
+
+ if (!params->center_freq1)
+ break;
+ switch (params->sec_channel_offset) {
+ case 1:
+ if (params->freq + 10 != params->center_freq1)
+ return -1;
+ break;
+ case -1:
+ if (params->freq - 10 != params->center_freq1)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case 80:
+ if (!params->center_freq1 || !params->sec_channel_offset)
+ return 1;
+
+ switch (params->sec_channel_offset) {
+ case 1:
+ if (params->freq - 10 != params->center_freq1 &&
+ params->freq + 30 != params->center_freq1)
+ return 1;
+ break;
+ case -1:
+ if (params->freq + 10 != params->center_freq1 &&
+ params->freq - 30 != params->center_freq1)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ /* Adjacent and overlapped are not allowed for 80+80 */
+ if (params->center_freq2 &&
+ params->center_freq1 - params->center_freq2 <= 80 &&
+ params->center_freq2 - params->center_freq1 <= 80)
+ return 1;
+ break;
+ case 160:
+ if (!params->center_freq1 || params->center_freq2 ||
+ !params->sec_channel_offset)
+ return -1;
+
+ switch (params->sec_channel_offset) {
+ case 1:
+ if (params->freq + 70 != params->center_freq1 &&
+ params->freq + 30 != params->center_freq1 &&
+ params->freq - 10 != params->center_freq1 &&
+ params->freq - 50 != params->center_freq1)
+ return -1;
+ break;
+ case -1:
+ if (params->freq + 50 != params->center_freq1 &&
+ params->freq + 10 != params->center_freq1 &&
+ params->freq - 30 != params->center_freq1 &&
+ params->freq - 70 != params->center_freq1)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
char *pos)
{
#ifdef NEED_AP_MLME
struct csa_settings settings;
int ret;
+ int dfs_range = 0;
unsigned int i;
+ int bandwidth;
+ u8 chan;
ret = hostapd_parse_csa_settings(pos, &settings);
if (ret)
return ret;
+ ret = hostapd_ctrl_check_freq_params(&settings.freq_params);
+ if (ret) {
+ wpa_printf(MSG_INFO,
+ "chanswitch: invalid frequency settings provided");
+ return ret;
+ }
+
+ switch (settings.freq_params.bandwidth) {
+ case 40:
+ bandwidth = CHAN_WIDTH_40;
+ break;
+ case 80:
+ if (settings.freq_params.center_freq2)
+ bandwidth = CHAN_WIDTH_80P80;
+ else
+ bandwidth = CHAN_WIDTH_80;
+ break;
+ case 160:
+ bandwidth = CHAN_WIDTH_160;
+ break;
+ default:
+ bandwidth = CHAN_WIDTH_20;
+ break;
+ }
+
+ if (settings.freq_params.center_freq1)
+ dfs_range += hostapd_is_dfs_overlap(
+ iface, bandwidth, settings.freq_params.center_freq1);
+ else
+ dfs_range += hostapd_is_dfs_overlap(
+ iface, bandwidth, settings.freq_params.freq);
+
+ if (settings.freq_params.center_freq2)
+ dfs_range += hostapd_is_dfs_overlap(
+ iface, bandwidth, settings.freq_params.center_freq2);
+
+ if (dfs_range) {
+ ret = ieee80211_freq_to_chan(settings.freq_params.freq, &chan);
+ if (ret == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_ERROR,
+ "Failed to get channel for (freq=%d, sec_channel_offset=%d, bw=%d)",
+ settings.freq_params.freq,
+ settings.freq_params.sec_channel_offset,
+ settings.freq_params.bandwidth);
+ return -1;
+ }
+
+ settings.freq_params.channel = chan;
+
+ wpa_printf(MSG_DEBUG,
+ "DFS/CAC to (channel=%u, freq=%d, sec_channel_offset=%d, bw=%d, center_freq1=%d)",
+ settings.freq_params.channel,
+ settings.freq_params.freq,
+ settings.freq_params.sec_channel_offset,
+ settings.freq_params.bandwidth,
+ settings.freq_params.center_freq1);
+
+ /* Perform CAC and switch channel */
+ hostapd_switch_channel_fallback(iface, &settings.freq_params);
+ return 0;
+ }
+
for (i = 0; i < iface->num_bss; i++) {
/* Save CHAN_SWITCH VHT config */
@@ -3232,6 +3453,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strcmp(buf, "REKEY_GTK") == 0) {
if (wpa_auth_rekey_gtk(hapd->wpa_auth) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "GET_PMK ", 8) == 0) {
+ reply_len = hostapd_ctrl_get_pmk(hapd, buf + 8, reply,
+ reply_size);
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
@@ -3348,6 +3572,24 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
if (os_snprintf_error(reply_size, reply_len))
reply_len = -1;
}
+ } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) {
+ res = hostapd_dpp_nfc_handover_req(hapd, buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) {
+ res = hostapd_dpp_nfc_handover_sel(hapd, buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
res = dpp_bootstrap_gen(hapd->iface->interfaces->dpp, buf + 18);
if (res < 0) {
@@ -3377,6 +3619,11 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp,
atoi(buf + 19),
reply, reply_size);
+ } else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) {
+ if (dpp_bootstrap_set(hapd->iface->interfaces->dpp,
+ atoi(buf + 18),
+ os_strchr(buf + 18, ' ')) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
reply_len = -1;
@@ -3456,7 +3703,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
int reply_len;
int level = MSG_DEBUG;
#ifdef CONFIG_CTRL_IFACE_UDP
- unsigned char lcookie[COOKIE_LEN];
+ unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
@@ -3481,28 +3728,30 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
#ifdef CONFIG_CTRL_IFACE_UDP
if (os_strcmp(buf, "GET_COOKIE") == 0) {
os_memcpy(reply, "COOKIE=", 7);
- wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
- cookie, COOKIE_LEN);
- reply_len = 7 + 2 * COOKIE_LEN;
+ wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
+ hapd->ctrl_iface_cookie,
+ CTRL_IFACE_COOKIE_LEN);
+ reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
goto done;
}
if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
- hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+ hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
wpa_printf(MSG_DEBUG,
"CTRL: No cookie in the request - drop request");
os_free(reply);
return;
}
- if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) {
+ if (os_memcmp(hapd->ctrl_iface_cookie, lcookie,
+ CTRL_IFACE_COOKIE_LEN) != 0) {
wpa_printf(MSG_DEBUG,
"CTRL: Invalid cookie in the request - drop request");
os_free(reply);
return;
}
- pos = buf + 7 + 2 * COOKIE_LEN;
+ pos = buf + 7 + 2 * CTRL_IFACE_COOKIE_LEN;
while (*pos == ' ')
pos++;
#endif /* CONFIG_CTRL_IFACE_UDP */
@@ -3591,7 +3840,7 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
dl_list_init(&hapd->ctrl_dst);
hapd->ctrl_sock = -1;
- os_get_random(cookie, COOKIE_LEN);
+ os_get_random(hapd->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
hints.ai_flags = AI_PASSIVE;
@@ -4170,7 +4419,7 @@ static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
- void *interfaces = eloop_ctx;
+ struct hapd_interfaces *interfaces = eloop_ctx;
char buffer[256], *buf = buffer;
int res;
struct sockaddr_storage from;
@@ -4179,7 +4428,7 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
int reply_len;
const int reply_size = 4096;
#ifdef CONFIG_CTRL_IFACE_UDP
- unsigned char lcookie[COOKIE_LEN];
+ unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */
res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
@@ -4208,28 +4457,30 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
#ifdef CONFIG_CTRL_IFACE_UDP
if (os_strcmp(buf, "GET_COOKIE") == 0) {
os_memcpy(reply, "COOKIE=", 7);
- wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
- gcookie, COOKIE_LEN);
- reply_len = 7 + 2 * COOKIE_LEN;
+ wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
+ interfaces->ctrl_iface_cookie,
+ CTRL_IFACE_COOKIE_LEN);
+ reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
goto send_reply;
}
if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
- hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+ hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
wpa_printf(MSG_DEBUG,
"CTRL: No cookie in the request - drop request");
os_free(reply);
return;
}
- if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) {
+ if (os_memcmp(interfaces->ctrl_iface_cookie, lcookie,
+ CTRL_IFACE_COOKIE_LEN) != 0) {
wpa_printf(MSG_DEBUG,
"CTRL: Invalid cookie in the request - drop request");
os_free(reply);
return;
}
- buf += 7 + 2 * COOKIE_LEN;
+ buf += 7 + 2 * CTRL_IFACE_COOKIE_LEN;
while (*buf == ' ')
buf++;
#endif /* CONFIG_CTRL_IFACE_UDP */
@@ -4373,7 +4624,7 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
}
}
- os_get_random(gcookie, COOKIE_LEN);
+ os_get_random(interface->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
hints.ai_flags = AI_PASSIVE;
@@ -4616,13 +4867,8 @@ static void hostapd_ctrl_iface_send_internal(int sock, struct dl_list *ctrl_dst,
return;
idx = 0;
if (ifname) {
-#ifdef CONFIG_CTRL_IFACE_UDP
- io[idx].iov_base = "IFACE=";
- io[idx].iov_len = 6;
-#else /* CONFIG_CTRL_IFACE_UDP */
io[idx].iov_base = "IFNAME=";
io[idx].iov_len = 7;
-#endif /* CONFIG_CTRL_IFACE_UDP */
idx++;
io[idx].iov_base = (char *) ifname;
io[idx].iov_len = os_strlen(ifname);
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 6e2eaa37..f630a223 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -148,9 +148,6 @@ CONFIG_IPV6=y
# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y
-# IEEE 802.11n (High Throughput) support
-#CONFIG_IEEE80211N=y
-
# Wireless Network Management (IEEE Std 802.11v-2011)
# Note: This is experimental and not complete implementation.
#CONFIG_WNM=y
@@ -388,3 +385,11 @@ CONFIG_IPV6=y
# Override default value for the wpa_disable_eapol_key_retries configuration
# parameter. See that parameter in hostapd.conf for more details.
#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
+
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current hostapd
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+#CONFIG_WEP=y
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 263a04e8..812c09a9 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -72,7 +72,7 @@ ctrl_interface=/var/run/hostapd
# run as non-root users. However, since the control interface can be used to
# change the network configuration, this access needs to be protected in many
# cases. By default, hostapd is configured to use gid 0 (root). If you
-# want to allow non-root users to use the contron interface, add a new group
+# want to allow non-root users to use the control interface, add a new group
# and change this value to match with that group. Add users that should have
# control interface access to this group.
#
@@ -598,8 +598,6 @@ wmm_ac_vo_acm=0
# channels if needed or creation of 40 MHz channel maybe rejected based
# on overlapping BSSes. These changes are done automatically when hostapd
# is setting up the 40 MHz channel.
-# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC]
-# (SMPS disabled if neither is set)
# HT-greenfield: [GF] (disabled if not set)
# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set)
# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set)
@@ -806,6 +804,9 @@ wmm_ac_vo_acm=0
# he_bss_color: BSS color (1-63)
#he_bss_color=1
+# he_bss_color_partial: BSS color AID equation
+#he_bss_color_partial=0
+
#he_default_pe_duration: The duration of PE field in an HE PPDU in us
# Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us
#he_default_pe_duration=0
@@ -903,6 +904,8 @@ eapol_key_index_workaround=0
# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
# reauthentication).
+# Note: Reauthentications may enforce a disconnection, check the related
+# parameter wpa_deny_ptk0_rekey for details.
#eap_reauth_period=3600
# Use PAE group address (01:80:c2:00:00:03) instead of individual target
@@ -1507,6 +1510,17 @@ own_ip_addr=127.0.0.1
# wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
#wpa=2
+# Extended Key ID support for Individually Addressed frames
+#
+# Extended Key ID allows to rekey PTK keys without the impacts the "normal"
+# PTK rekeying with only a single Key ID 0 has. It can only be used when the
+# driver supports it and RSN/WPA2 is used with a CCMP/GCMP pairwise cipher.
+#
+# 0 = force off, i.e., use only Key ID 0 (default)
+# 1 = enable and use Extended Key ID support when possible
+# 2 = identical to 1 but start with Key ID 1 when possible
+#extended_key_id=0
+
# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
# (8..63 characters) that will be converted to PSK. This conversion uses SSID
@@ -1607,8 +1621,26 @@ own_ip_addr=127.0.0.1
# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
# PTK to mitigate some attacks against TKIP deficiencies.
+# Warning: PTK rekeying is buggy with many drivers/devices and with such
+# devices, the only secure method to rekey the PTK without Extended Key ID
+# support requires a disconnection. Check the related parameter
+# wpa_deny_ptk0_rekey for details.
#wpa_ptk_rekey=600
+# Workaround for PTK rekey issues
+#
+# PTK0 rekeys (rekeying the PTK without "Extended Key ID for Individually
+# Addressed Frames") can degrade the security and stability with some cards.
+# To avoid such issues hostapd can replace those PTK rekeys (including EAP
+# reauthentications) with disconnects.
+#
+# Available options:
+# 0 = always rekey when configured/instructed (default)
+# 1 = only rekey when the local driver is explicitly indicating it can perform
+# this operation without issues
+# 2 = never allow PTK0 rekeys
+#wpa_deny_ptk0_rekey=0
+
# The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way
# Handshake are retried per 4-Way Handshake attempt.
# (dot11RSNAConfigPairwiseUpdateCount)
@@ -1677,6 +1709,12 @@ own_ip_addr=127.0.0.1
# available in deployed devices.
#group_mgmt_cipher=AES-128-CMAC
+# Beacon Protection (management frame protection for Beacon frames)
+# This depends on management frame protection being enabled (ieee80211w != 0).
+# 0 = disabled (default)
+# 1 = enabled
+#beacon_prot=0
+
# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
# (maximum time to wait for a SA Query response)
# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
@@ -1784,11 +1822,13 @@ own_ip_addr=127.0.0.1
#sae_confirm_immediate=0
# SAE mechanism for PWE derivation
-# 0 = hunting-and-pecking loop only (default)
-# 1 = hash-to-element only
+# 0 = hunting-and-pecking loop only (default without password identifier)
+# 1 = hash-to-element only (default with password identifier)
# 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.
+# When using SAE password identifier, the hash-to-element mechanism is used
+# regardless of the sae_pwe parameter value.
#sae_pwe=0
# FILS Cache Identifier (16-bit value in hexdump format)
@@ -1815,6 +1855,19 @@ own_ip_addr=127.0.0.1
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
#owe_groups=19 20 21
+# OWE PTK derivation workaround
+# Initial OWE implementation used SHA256 when deriving the PTK for all OWE
+# groups. This was supposed to change to SHA384 for group 20 and SHA512 for
+# group 21. This parameter can be used to enable workaround for interoperability
+# with stations that use SHA256 with groups 20 and 21. By default (0) only the
+# appropriate hash function is accepted. When workaround is enabled (1), the
+# appropriate hash function is tried first and if that fails, SHA256-based PTK
+# derivation is attempted. This workaround can result in reduced security for
+# groups 20 and 21, but is required for interoperability with older
+# implementations. There is no impact to group 19 behavior. The workaround is
+# disabled by default and can be enabled by uncommenting the following line.
+#owe_ptk_workaround=1
+
# OWE transition mode configuration
# Pointer to the matching open/OWE BSS
#owe_transition_bssid=<bssid>
@@ -1852,6 +1905,23 @@ own_ip_addr=127.0.0.1
# default: 30 TUs (= 30.72 milliseconds)
#fils_hlp_wait_time=30
+# Transition Disable indication
+# The AP can notify authenticated stations to disable transition mode in their
+# network profiles when the network has completed transition steps, i.e., once
+# sufficiently large number of APs in the ESS have been updated to support the
+# more secure alternative. When this indication is used, the stations are
+# expected to automatically disable transition mode and less secure security
+# options. This includes use of WEP, TKIP (including use of TKIP as the group
+# cipher), and connections without PMF.
+# Bitmap bits:
+# bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK and only
+# allow SAE to be used)
+# bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK)
+# bit 2 (0x04): WPA3-Enterprise (move to requiring PMF)
+# bit 3 (0x08): Enhanced Open (disable use of open network; require OWE)
+# (default: 0 = do not include Transition Disable KDE)
+#transition_disable=0x01
+
##### IEEE 802.11r configuration ##############################################
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
@@ -2205,6 +2275,13 @@ own_ip_addr=127.0.0.1
#wps_nfc_dh_privkey: Hexdump of DH Private Key
#wps_nfc_dev_pw: Hexdump of Device Password
+# Application Extension attribute for Beacon and Probe Response frames
+# This parameter can be used to add application extension into WPS IE. The
+# contents of this parameter starts with 16-octet (32 hexdump characters) of
+# UUID to identify the specific application and that is followed by the actual
+# application specific data.
+#wps_application_ext=<hexdump>
+
##### Wi-Fi Direct (P2P) ######################################################
# Enable P2P Device management
@@ -2227,6 +2304,17 @@ own_ip_addr=127.0.0.1
#dpp_csign
#dpp_controller
+# Configurator Connectivity indication
+# 0: no Configurator is currently connected (default)
+# 1: advertise that a Configurator is available
+#dpp_configurator_connectivity=0
+
+# DPP PFS
+# 0: allow PFS to be used or not used (default)
+# 1: require PFS to be used (note: not compatible with DPP R1)
+# 2: do not allow PFS to be used
+#dpp_pfs=0
+
#### TDLS (IEEE 802.11z-2010) #################################################
# Prohibit use of TDLS in this BSS
@@ -2607,7 +2695,7 @@ own_ip_addr=127.0.0.1
# Default is 0 = OCE disabled
#oce=0
-# RSSI-based assocition rejection
+# RSSI-based association rejection
#
# Reject STA association if RSSI is below given threshold (in dBm)
# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
diff --git a/hostapd/hostapd.wpa_psk b/hostapd/hostapd.wpa_psk
index 166e59e9..2ce5ff23 100644
--- a/hostapd/hostapd.wpa_psk
+++ b/hostapd/hostapd.wpa_psk
@@ -7,9 +7,15 @@
# keyid=<keyid_string>
# An optional VLAN ID can be specified by prefixing the line with
# vlanid=<VLAN ID>.
+# An optional WPS tag can be added by prefixing the line with
+# wps=<0/1> (default: 0). Any matching entry with that tag will be used when
+# generating a PSK for a WPS Enrollee instead of generating a new random
+# per-Enrollee PSK.
00:00:00:00:00:00 secret passphrase
00:11:22:33:44:55 another passphrase
00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
keyid=example_id 00:11:22:33:44:77 passphrase with keyid
vlanid=3 00:00:00:00:00:00 passphrase with vlanid
+wps=1 00:00:00:00:00:00 passphrase for WPS
+wps=1 11:22:33:44:55:00 dev-specific passphrase for WPS
00:00:00:00:00:00 another passphrase for all STAs
diff --git a/hostapd/main.c b/hostapd/main.c
index f08d60ef..85c1fd1c 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -220,7 +220,6 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
struct wowlan_triggers *triggs;
iface->drv_flags = capa.flags;
- iface->smps_modes = capa.smps_modes;
iface->probe_resp_offloads = capa.probe_resp_offloads;
/*
* Use default extended capa values from per-radio information
@@ -262,7 +261,7 @@ hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
struct hostapd_iface *iface;
int k;
- wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
+ wpa_printf(MSG_DEBUG, "Configuration file: %s", config_fname);
iface = hostapd_init(interfaces, config_fname);
if (!iface)
return NULL;
@@ -453,11 +452,12 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
static void show_version(void)
{
fprintf(stderr,
- "hostapd v" VERSION_STR "\n"
+ "hostapd v%s\n"
"User space daemon for IEEE 802.11 AP management,\n"
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
"Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> "
- "and contributors\n");
+ "and contributors\n",
+ VERSION_STR);
}
@@ -772,7 +772,7 @@ int main(int argc, char *argv[])
if (log_file)
wpa_debug_open_file(log_file);
- else
+ if (!log_file && !wpa_debug_syslog)
wpa_debug_setup_stdout();
#ifdef CONFIG_DEBUG_SYSLOG
if (wpa_debug_syslog)
diff --git a/hs20/client/Makefile b/hs20/client/Makefile
index 67f6f55c..cc2af03f 100644
--- a/hs20/client/Makefile
+++ b/hs20/client/Makefile
@@ -30,8 +30,17 @@ CFLAGS += -I../../src
ifndef CONFIG_NO_BROWSER
ifndef CONFIG_BROWSER_SYSTEM
+TEST_WK := $(shell pkg-config --silence-errors --cflags webkitgtk-3.0)
+ifeq ($(TEST_WK),)
+# Try webkit2
+GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkit2gtk-4.0)
+GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkit2gtk-4.0)
+CFLAGS += -DUSE_WEBKIT2
+else
GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkitgtk-3.0)
GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkitgtk-3.0)
+endif
+
CFLAGS += $(GTKCFLAGS)
LIBS += $(GTKLIBS)
endif
diff --git a/hs20/client/oma_dm_client.c b/hs20/client/oma_dm_client.c
index d75c8456..bcd68b87 100644
--- a/hs20/client/oma_dm_client.c
+++ b/hs20/client/oma_dm_client.c
@@ -407,7 +407,7 @@ static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec)
wpa_printf(MSG_INFO, "Data: %s", data);
wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
write_summary(ctx, "Launch browser to URI '%s'", data);
- res = hs20_web_browser(data);
+ res = hs20_web_browser(data, 1);
xml_node_get_text_free(ctx->xml, data);
if (res > 0) {
wpa_printf(MSG_INFO, "User response in browser completed successfully");
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index a94f40c5..11bf0db3 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -2233,7 +2233,7 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
wpa_ctrl_close(mon);
if (res < 0) {
- wpa_printf(MSG_INFO, "Could not connect");
+ wpa_printf(MSG_INFO, "Could not connect to OSU network");
write_summary(ctx, "Could not connect to OSU network");
wpa_printf(MSG_INFO, "Remove OSU network connection");
snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id);
@@ -2406,7 +2406,7 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
snprintf(fname, sizeof(fname), "file://%s/osu-providers.html", dir);
write_summary(ctx, "Start web browser with OSU provider selection page");
- ret = hs20_web_browser(fname);
+ ret = hs20_web_browser(fname, 0);
selected:
if (ret > 0 && (size_t) ret <= osu_count) {
@@ -2907,7 +2907,7 @@ static char * get_hostname(const char *url)
static int osu_cert_cb(void *_ctx, struct http_cert *cert)
{
struct hs20_osu_client *ctx = _ctx;
- unsigned int i, j;
+ size_t i, j;
int found;
char *host = NULL;
@@ -3002,7 +3002,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
size_t name_len = os_strlen(name);
wpa_printf(MSG_INFO,
- "[%i] Looking for icon file name '%s' match",
+ "[%zu] Looking for icon file name '%s' match",
j, name);
for (i = 0; i < cert->num_logo; i++) {
struct http_logo *logo = &cert->logo[i];
@@ -3010,7 +3010,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
char *pos;
wpa_printf(MSG_INFO,
- "[%i] Comparing to '%s' uri_len=%d name_len=%d",
+ "[%zu] Comparing to '%s' uri_len=%d name_len=%d",
i, logo->uri, (int) uri_len, (int) name_len);
if (uri_len < 1 + name_len) {
wpa_printf(MSG_INFO, "URI Length is too short");
@@ -3044,7 +3044,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
if (logo->hash_len != 32) {
wpa_printf(MSG_INFO,
- "[%i][%i] Icon hash length invalid (should be 32): %d",
+ "[%zu][%zu] Icon hash length invalid (should be 32): %d",
j, i, (int) logo->hash_len);
continue;
}
@@ -3054,7 +3054,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
}
wpa_printf(MSG_DEBUG,
- "[%u][%u] Icon hash did not match", j, i);
+ "[%zu][%zu] Icon hash did not match", j, i);
wpa_hexdump_ascii(MSG_DEBUG, "logo->hash",
logo->hash, 32);
wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]",
@@ -3152,7 +3152,7 @@ static void check_workarounds(struct hs20_osu_client *ctx)
static void usage(void)
{
- printf("usage: hs20-osu-client [-dddqqKt] [-S<station ifname>] \\\n"
+ printf("usage: hs20-osu-client [-dddqqKtT] [-S<station ifname>] \\\n"
" [-w<wpa_supplicant ctrl_iface dir>] "
"[-r<result file>] [-f<debug file>] \\\n"
" [-s<summary file>] \\\n"
@@ -3198,7 +3198,7 @@ int main(int argc, char *argv[])
return -1;
for (;;) {
- c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tw:x:");
+ c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tTw:x:");
if (c < 0)
break;
switch (c) {
@@ -3236,6 +3236,9 @@ int main(int argc, char *argv[])
case 't':
wpa_debug_timestamp++;
break;
+ case 'T':
+ ctx.ignore_tls = 1;
+ break;
case 'w':
wpas_ctrl_path = optarg;
break;
@@ -3403,7 +3406,7 @@ int main(int argc, char *argv[])
wpa_printf(MSG_INFO, "Launch web browser to URL %s",
argv[optind + 1]);
- ret = hs20_web_browser(argv[optind + 1]);
+ ret = hs20_web_browser(argv[optind + 1], ctx.ignore_tls);
wpa_printf(MSG_INFO, "Web browser result: %d", ret);
} else if (strcmp(argv[optind], "parse_cert") == 0) {
if (argc - optind < 2) {
diff --git a/hs20/client/osu_client.h b/hs20/client/osu_client.h
index 5c8e6d00..9b45b03f 100644
--- a/hs20/client/osu_client.h
+++ b/hs20/client/osu_client.h
@@ -50,6 +50,8 @@ struct hs20_osu_client {
const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */
#define WORKAROUND_OCSP_OPTIONAL 0x00000001
unsigned long int workarounds;
+ int ignore_tls; /* whether to ignore TLS validation issues with HTTPS
+ * server certificate */
};
diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c
index c619541a..39d10e03 100644
--- a/hs20/client/spp_client.c
+++ b/hs20/client/spp_client.c
@@ -547,7 +547,7 @@ static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec,
}
wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
write_summary(ctx, "Launch browser to URI '%s'", uri);
- res = hs20_web_browser(uri);
+ res = hs20_web_browser(uri, 1);
xml_node_get_text_free(ctx->xml, uri);
if (res > 0) {
wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'",
diff --git a/hs20/server/ca/ocsp-responder.sh b/hs20/server/ca/ocsp-responder.sh
index 8cebd745..620947d0 100644
--- a/hs20/server/ca/ocsp-responder.sh
+++ b/hs20/server/ca/ocsp-responder.sh
@@ -1,3 +1,3 @@
#!/bin/sh
-openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text
+openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text -ignore_err
diff --git a/hs20/server/ca/ocsp-update-cache.sh b/hs20/server/ca/ocsp-update-cache.sh
index 8ddef9b9..f2b23250 100644
--- a/hs20/server/ca/ocsp-update-cache.sh
+++ b/hs20/server/ca/ocsp-update-cache.sh
@@ -1,5 +1,6 @@
#!/bin/sh
+# NOTE: You may need to replace 'localhost' with your OCSP server hostname.
openssl ocsp \
-no_nonce \
-CAfile ca.pem \
diff --git a/hs20/server/hs20_spp_server.c b/hs20/server/hs20_spp_server.c
index 6c74f541..347c40a7 100644
--- a/hs20/server/hs20_spp_server.c
+++ b/hs20/server/hs20_spp_server.c
@@ -176,7 +176,7 @@ int main(int argc, char *argv[])
ctx.root_dir = optarg;
break;
case 'v':
- printf("hs20_spp_server v" VERSION_STR "\n");
+ printf("hs20_spp_server v%s\n", VERSION_STR);
return 0;
default:
usage();
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 232afa89..5c016107 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -261,13 +261,13 @@ static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
}
-void acs_cleanup(struct hostapd_iface *iface)
+static void acs_cleanup_mode(struct hostapd_hw_modes *mode)
{
int i;
struct hostapd_channel_data *chan;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED)
acs_clean_chan_surveys(chan);
@@ -276,6 +276,15 @@ void acs_cleanup(struct hostapd_iface *iface)
chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
chan->min_nf = 0;
}
+}
+
+
+void acs_cleanup(struct hostapd_iface *iface)
+{
+ int i;
+
+ for (i = 0; i < iface->num_hw_features; i++)
+ acs_cleanup_mode(&iface->hw_features[i]);
iface->chans_surveyed = 0;
iface->acs_num_completed_scans = 0;
@@ -453,21 +462,35 @@ static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan)
}
-static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
+static int acs_surveys_are_sufficient_mode(struct hostapd_hw_modes *mode)
{
int i;
struct hostapd_channel_data *chan;
- int valid = 0;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
acs_survey_list_is_sufficient(chan))
- valid++;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
+{
+ int i;
+ struct hostapd_hw_modes *mode;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode) &&
+ acs_surveys_are_sufficient_mode(mode))
+ return 1;
}
- /* We need at least survey data for one channel */
- return !!valid;
+ return 0;
}
@@ -489,14 +512,14 @@ static int is_in_chanlist(struct hostapd_iface *iface,
}
-static void acs_survey_all_chans_intereference_factor(
- struct hostapd_iface *iface)
+static void acs_survey_mode_interference_factor(
+ struct hostapd_iface *iface, struct hostapd_hw_modes *mode)
{
int i;
struct hostapd_channel_data *chan;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (!acs_usable_chan(chan))
continue;
@@ -515,14 +538,28 @@ static void acs_survey_all_chans_intereference_factor(
}
-static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
- int freq)
+static void acs_survey_all_chans_interference_factor(
+ struct hostapd_iface *iface)
+{
+ int i;
+ struct hostapd_hw_modes *mode;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ acs_survey_mode_interference_factor(iface, mode);
+ }
+}
+
+
+static struct hostapd_channel_data *
+acs_find_chan_mode(struct hostapd_hw_modes *mode, int freq)
{
struct hostapd_channel_data *chan;
int i;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
@@ -535,6 +572,26 @@ static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
}
+static struct hostapd_channel_data *
+acs_find_chan(struct hostapd_iface *iface, int freq)
+{
+ int i;
+ struct hostapd_hw_modes *mode;
+ struct hostapd_channel_data *chan;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode)) {
+ chan = acs_find_chan_mode(mode, freq);
+ if (chan)
+ return chan;
+ }
+ }
+
+ return NULL;
+}
+
+
static int is_24ghz_mode(enum hostapd_hw_mode mode)
{
return mode == HOSTAPD_MODE_IEEE80211B ||
@@ -565,58 +622,24 @@ static int is_common_24ghz_chan(int chan)
#define ACS_24GHZ_PREFER_1_6_11 0.8
#endif /* ACS_24GHZ_PREFER_1_6_11 */
-/*
- * At this point it's assumed chan->interface_factor has been computed.
- * This function should be reusable regardless of interference computation
- * option (survey, BSS, spectral, ...). chan->interference factor must be
- * summable (i.e., must be always greater than zero).
- */
-static struct hostapd_channel_data *
-acs_find_ideal_chan(struct hostapd_iface *iface)
+static void
+acs_find_ideal_chan_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode,
+ int n_chans, u32 bw,
+ struct hostapd_channel_data **rand_chan,
+ struct hostapd_channel_data **ideal_chan,
+ long double *ideal_factor)
{
- struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL,
- *rand_chan = NULL;
- long double factor, ideal_factor = 0;
+ struct hostapd_channel_data *chan, *adj_chan = NULL;
+ long double factor;
int i, j;
- int n_chans = 1;
- u32 bw;
unsigned int k;
- /* TODO: HT40- support */
-
- if (iface->conf->ieee80211n &&
- iface->conf->secondary_channel == -1) {
- wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
- return NULL;
- }
-
- if (iface->conf->ieee80211n &&
- iface->conf->secondary_channel)
- n_chans = 2;
-
- if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
- switch (hostapd_get_oper_chwidth(iface->conf)) {
- case CHANWIDTH_80MHZ:
- n_chans = 4;
- break;
- case CHANWIDTH_160MHZ:
- n_chans = 8;
- break;
- }
- }
-
- bw = num_chan_to_bw(n_chans);
-
- /* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
-
- wpa_printf(MSG_DEBUG,
- "ACS: Survey analysis for selected bandwidth %d MHz", bw);
-
- for (i = 0; i < iface->current_mode->num_channels; i++) {
+ for (i = 0; i < mode->num_channels; i++) {
double total_weight;
struct acs_bias *bias, tmp_bias;
- chan = &iface->current_mode->channels[i];
+ chan = &mode->channels[i];
/* Since in the current ACS implementation the first channel is
* always a primary channel, skip channels not available as
@@ -637,7 +660,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
/* HT40 on 5 GHz has a limited set of primary channels as per
* 11n Annex J */
- if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
+ if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
!acs_usable_ht40_chan(chan)) {
@@ -646,7 +669,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
continue;
}
- if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
+ if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
(iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
if (hostapd_get_oper_chwidth(iface->conf) ==
CHANWIDTH_80MHZ &&
@@ -698,7 +721,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
/* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
* channel interference factor. */
- if (is_24ghz_mode(iface->current_mode->mode)) {
+ if (is_24ghz_mode(mode->mode)) {
for (j = 0; j < n_chans; j++) {
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) - 5);
@@ -744,7 +767,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
break;
bias = NULL;
}
- } else if (is_24ghz_mode(iface->current_mode->mode) &&
+ } else if (is_24ghz_mode(mode->mode) &&
is_common_24ghz_chan(chan->chan)) {
tmp_bias.channel = chan->chan;
tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11;
@@ -763,14 +786,71 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
}
if (acs_usable_chan(chan) &&
- (!ideal_chan || factor < ideal_factor)) {
- ideal_factor = factor;
- ideal_chan = chan;
+ (!*ideal_chan || factor < *ideal_factor)) {
+ *ideal_factor = factor;
+ *ideal_chan = chan;
}
/* This channel would at least be usable */
- if (!rand_chan)
- rand_chan = chan;
+ if (!(*rand_chan))
+ *rand_chan = chan;
+ }
+}
+
+
+/*
+ * At this point it's assumed chan->interference_factor has been computed.
+ * This function should be reusable regardless of interference computation
+ * option (survey, BSS, spectral, ...). chan->interference factor must be
+ * summable (i.e., must be always greater than zero).
+ */
+static struct hostapd_channel_data *
+acs_find_ideal_chan(struct hostapd_iface *iface)
+{
+ struct hostapd_channel_data *ideal_chan = NULL,
+ *rand_chan = NULL;
+ long double ideal_factor = 0;
+ int i;
+ int n_chans = 1;
+ u32 bw;
+ struct hostapd_hw_modes *mode;
+
+ /* TODO: HT40- support */
+
+ if (iface->conf->ieee80211n &&
+ iface->conf->secondary_channel == -1) {
+ wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
+ return NULL;
+ }
+
+ if (iface->conf->ieee80211n &&
+ iface->conf->secondary_channel)
+ n_chans = 2;
+
+ if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
+ switch (hostapd_get_oper_chwidth(iface->conf)) {
+ case CHANWIDTH_80MHZ:
+ n_chans = 4;
+ break;
+ case CHANWIDTH_160MHZ:
+ n_chans = 8;
+ break;
+ }
+ }
+
+ bw = num_chan_to_bw(n_chans);
+
+ /* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
+
+ wpa_printf(MSG_DEBUG,
+ "ACS: Survey analysis for selected bandwidth %d MHz", bw);
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ acs_find_ideal_chan_mode(iface, mode, n_chans, bw,
+ &rand_chan, &ideal_chan,
+ &ideal_factor);
}
if (ideal_chan) {
@@ -826,7 +906,7 @@ static int acs_study_survey_based(struct hostapd_iface *iface)
return -1;
}
- acs_survey_all_chans_intereference_factor(iface);
+ acs_survey_all_chans_interference_factor(iface);
return 0;
}
@@ -918,29 +998,56 @@ fail:
}
+static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode,
+ int *freq)
+{
+ struct hostapd_channel_data *chan;
+ int i;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+
+ if (!is_in_chanlist(iface, chan))
+ continue;
+
+ *freq++ = chan->freq;
+ }
+
+ return freq;
+}
+
+
static int acs_request_scan(struct hostapd_iface *iface)
{
struct wpa_driver_scan_params params;
- struct hostapd_channel_data *chan;
int i, *freq;
+ int num_channels;
+ struct hostapd_hw_modes *mode;
os_memset(&params, 0, sizeof(params));
- params.freqs = os_calloc(iface->current_mode->num_channels + 1,
- sizeof(params.freqs[0]));
+
+ num_channels = 0;
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ num_channels += mode->num_channels;
+ }
+
+ params.freqs = os_calloc(num_channels + 1, sizeof(params.freqs[0]));
if (params.freqs == NULL)
return -1;
freq = params.freqs;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
- if (chan->flag & HOSTAPD_CHAN_DISABLED)
- continue;
- if (!is_in_chanlist(iface, chan))
- continue;
-
- *freq++ = chan->freq;
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ freq = acs_request_scan_add_freqs(iface, mode, freq);
}
+
*freq = 0;
if (params.freqs == freq) {
@@ -978,7 +1085,8 @@ enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
return HOSTAPD_CHAN_ACS;
}
- if (!iface->current_mode)
+ if (!iface->current_mode &&
+ iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
return HOSTAPD_CHAN_INVALID;
acs_cleanup(iface);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 68af3c1d..5bf4502b 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -54,16 +54,21 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->logger_syslog = (unsigned int) -1;
bss->logger_stdout = (unsigned int) -1;
+#ifdef CONFIG_WEP
bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
bss->wep_rekeying_period = 300;
/* use key0 in individual key and key1 in broadcast key */
bss->broadcast_key_idx_min = 1;
bss->broadcast_key_idx_max = 2;
+#else /* CONFIG_WEP */
+ bss->auth_algs = WPA_AUTH_ALG_OPEN;
+#endif /* CONFIG_WEP */
bss->eap_reauth_period = 3600;
bss->wpa_group_rekey = 600;
bss->wpa_gmk_rekey = 86400;
+ bss->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
bss->wpa_group_update_count = 4;
bss->wpa_pairwise_update_count = 4;
bss->wpa_disable_eapol_key_retries =
@@ -251,6 +256,9 @@ struct hostapd_config * hostapd_config_defaults(void)
HE_OPERATION_RTS_THRESHOLD_OFFSET;
/* Set default basic MCS/NSS set to single stream MCS 0-7 */
conf->he_op.he_basic_mcs_nss_set = 0xfffc;
+ conf->he_op.he_bss_color_disabled = 1;
+ conf->he_op.he_bss_color_partial = 0;
+ conf->he_op.he_bss_color = 1;
#endif /* CONFIG_IEEE80211AX */
/* The third octet of the country string uses an ASCII space character
@@ -301,6 +309,7 @@ static int hostapd_config_read_wpa_psk(const char *fname,
while (fgets(buf, sizeof(buf), f)) {
int vlan_id = 0;
+ int wps = 0;
line++;
@@ -331,6 +340,8 @@ static int hostapd_config_read_wpa_psk(const char *fname,
value = "";
if (!os_strcmp(name, "keyid")) {
keyid = value;
+ } else if (!os_strcmp(name, "wps")) {
+ wps = atoi(value);
} else if (!os_strcmp(name, "vlanid")) {
vlan_id = atoi(value);
} else {
@@ -348,8 +359,9 @@ static int hostapd_config_read_wpa_psk(const char *fname,
if (!token)
token = "";
if (hwaddr_aton(token, addr)) {
- wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
- "line %d in '%s'", token, line, fname);
+ wpa_printf(MSG_ERROR,
+ "Invalid MAC address '%s' on line %d in '%s'",
+ token, line, fname);
ret = -1;
break;
}
@@ -377,16 +389,17 @@ static int hostapd_config_read_wpa_psk(const char *fname,
ok = 0;
len = os_strlen(pos);
- if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
+ if (len == 2 * PMK_LEN &&
+ hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
ok = 1;
- else if (len >= 8 && len < 64) {
- pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
- 4096, psk->psk, PMK_LEN);
+ else if (len >= 8 && len < 64 &&
+ pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
+ 4096, psk->psk, PMK_LEN) == 0)
ok = 1;
- }
if (!ok) {
- wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in "
- "'%s'", pos, line, fname);
+ wpa_printf(MSG_ERROR,
+ "Invalid PSK '%s' on line %d in '%s'",
+ pos, line, fname);
os_free(psk);
ret = -1;
break;
@@ -404,6 +417,8 @@ static int hostapd_config_read_wpa_psk(const char *fname,
}
}
+ psk->wps = wps;
+
psk->next = ssid->wpa_psk;
ssid->wpa_psk = psk;
}
@@ -441,7 +456,9 @@ int hostapd_setup_sae_pt(struct hostapd_bss_config *conf)
struct hostapd_ssid *ssid = &conf->ssid;
struct sae_password_entry *pw;
- if (conf->sae_pwe == 0 || !wpa_key_mgmt_sae(conf->wpa_key_mgmt))
+ if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf)) ||
+ conf->sae_pwe == 3 ||
+ !wpa_key_mgmt_sae(conf->wpa_key_mgmt))
return 0; /* PT not needed */
sae_deinit_pt(ssid->pt);
@@ -623,6 +640,7 @@ void hostapd_config_free_eap_users(struct hostapd_eap_user *user)
}
+#ifdef CONFIG_WEP
static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
{
int i;
@@ -631,6 +649,7 @@ static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
keys->key[i] = NULL;
}
}
+#endif /* CONFIG_WEP */
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
@@ -719,7 +738,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
str_clear_free(conf->ssid.wpa_passphrase);
os_free(conf->ssid.wpa_psk_file);
+#ifdef CONFIG_WEP
hostapd_config_free_wep(&conf->ssid.wep);
+#endif /* CONFIG_WEP */
#ifdef CONFIG_FULL_DYNAMIC_VLAN
os_free(conf->ssid.vlan_tagged_interface);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
@@ -813,6 +834,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->upc);
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
wpabuf_free(conf->wps_vendor_ext[i]);
+ wpabuf_free(conf->wps_application_ext);
wpabuf_free(conf->wps_nfc_dh_pubkey);
wpabuf_free(conf->wps_nfc_dh_privkey);
wpabuf_free(conf->wps_nfc_dev_pw);
@@ -880,7 +902,12 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
#ifdef CONFIG_TESTING_OPTIONS
wpabuf_free(conf->own_ie_override);
wpabuf_free(conf->sae_commit_override);
+ wpabuf_free(conf->rsne_override_eapol);
wpabuf_free(conf->rsnxe_override_eapol);
+ wpabuf_free(conf->rsne_override_ft);
+ wpabuf_free(conf->rsnxe_override_ft);
+ wpabuf_free(conf->gtk_rsc_override);
+ wpabuf_free(conf->igtk_rsc_override);
#endif /* CONFIG_TESTING_OPTIONS */
os_free(conf->no_probe_resp_if_seen_on);
@@ -1090,6 +1117,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
return -1;
}
+#ifdef CONFIG_WEP
if (bss->wpa) {
int wep, i;
@@ -1107,6 +1135,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
return -1;
}
}
+#endif /* CONFIG_WEP */
if (full_config && bss->wpa &&
bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
@@ -1154,7 +1183,6 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211N
if (full_config && conf->ieee80211n &&
conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
bss->disable_11n = 1;
@@ -1162,12 +1190,14 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
"allowed, disabling HT capabilities");
}
+#ifdef CONFIG_WEP
if (full_config && conf->ieee80211n &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
bss->disable_11n = 1;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
"allowed, disabling HT capabilities");
}
+#endif /* CONFIG_WEP */
if (full_config && conf->ieee80211n && bss->wpa &&
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
@@ -1179,15 +1209,16 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
"requires CCMP/GCMP to be enabled, disabling HT "
"capabilities");
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
+#ifdef CONFIG_WEP
if (full_config && conf->ieee80211ac &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
bss->disable_11ac = 1;
wpa_printf(MSG_ERROR,
"VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
}
+#endif /* CONFIG_WEP */
if (full_config && conf->ieee80211ac && bss->wpa &&
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
@@ -1207,12 +1238,14 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
bss->wps_state = 0;
}
+#ifdef CONFIG_WEP
if (full_config && bss->wps_state &&
bss->ssid.wep.keys_set && bss->wpa == 0) {
wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
"disabled");
bss->wps_state = 0;
}
+#endif /* CONFIG_WEP */
if (full_config && bss->wps_state && bss->wpa &&
(!(bss->wpa & 2) ||
@@ -1336,11 +1369,13 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config)
{
+#ifdef CONFIG_WEP
if (bss->individual_wep_key_len == 0) {
/* individual keys are not use; can use key idx0 for
* broadcast keys */
bss->broadcast_key_idx_min = 0;
}
+#endif /* CONFIG_WEP */
if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
bss->rsn_pairwise = bss->wpa_pairwise;
@@ -1366,6 +1401,7 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
} else if (bss->ieee802_1x) {
int cipher = WPA_CIPHER_NONE;
bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+#ifdef CONFIG_WEP
bss->ssid.wep.default_len = bss->default_wep_key_len;
if (full_config && bss->default_wep_key_len) {
cipher = bss->default_wep_key_len >= 13 ?
@@ -1376,11 +1412,13 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
else
cipher = WPA_CIPHER_WEP40;
}
+#endif /* CONFIG_WEP */
bss->wpa_group = cipher;
bss->wpa_pairwise = cipher;
bss->rsn_pairwise = cipher;
if (full_config)
bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+#ifdef CONFIG_WEP
} else if (bss->ssid.wep.keys_set) {
int cipher = WPA_CIPHER_WEP40;
if (bss->ssid.wep.len[0] >= 13)
@@ -1391,6 +1429,7 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
bss->rsn_pairwise = cipher;
if (full_config)
bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
+#endif /* CONFIG_WEP */
} else if (bss->osen) {
bss->ssid.security_policy = SECURITY_OSEN;
bss->wpa_group = WPA_CIPHER_CCMP;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 83b8aee6..2a0bf076 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -67,6 +67,7 @@ struct hostapd_radius_servers;
struct ft_remote_r0kh;
struct ft_remote_r1kh;
+#ifdef CONFIG_WEP
#define NUM_WEP_KEYS 4
struct hostapd_wep_keys {
u8 idx;
@@ -75,10 +76,13 @@ struct hostapd_wep_keys {
int keys_set;
size_t default_len; /* key length used for dynamic key generation */
};
+#endif /* CONFIG_WEP */
typedef enum hostap_security_policy {
SECURITY_PLAINTEXT = 0,
+#ifdef CONFIG_WEP
SECURITY_STATIC_WEP = 1,
+#endif /* CONFIG_WEP */
SECURITY_IEEE_802_1X = 2,
SECURITY_WPA_PSK = 3,
SECURITY_WPA = 4,
@@ -88,6 +92,7 @@ typedef enum hostap_security_policy {
struct hostapd_ssid {
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
+ u32 short_ssid;
unsigned int ssid_set:1;
unsigned int utf8_ssid:1;
unsigned int wpa_passphrase_set:1;
@@ -101,7 +106,9 @@ struct hostapd_ssid {
char *wpa_psk_file;
struct sae_pt *pt;
+#ifdef CONFIG_WEP
struct hostapd_wep_keys wep;
+#endif /* CONFIG_WEP */
#define DYNAMIC_VLAN_DISABLED 0
#define DYNAMIC_VLAN_OPTIONAL 1
@@ -151,6 +158,7 @@ struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next;
int group;
char keyid[KEYID_LEN];
+ int wps;
u8 psk[PMK_LEN];
u8 addr[ETH_ALEN];
u8 p2p_dev_addr[ETH_ALEN];
@@ -319,10 +327,12 @@ struct hostapd_bss_config {
size_t eap_req_id_text_len;
int eapol_key_index_workaround;
+#ifdef CONFIG_WEP
size_t default_wep_key_len;
int individual_wep_key_len;
int wep_rekeying_period;
int broadcast_key_idx_min, broadcast_key_idx_max;
+#endif /* CONFIG_WEP */
int eap_reauth_period;
int erp_send_reauth_start;
char *erp_domain;
@@ -344,9 +354,11 @@ struct hostapd_bss_config {
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
+ int extended_key_id;
int wpa_key_mgmt;
enum mfp_options ieee80211w;
int group_mgmt_cipher;
+ int beacon_prot;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
unsigned int assoc_sa_query_max_timeout;
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
@@ -367,6 +379,7 @@ struct hostapd_bss_config {
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ enum ptk0_rekey_handling wpa_deny_ptk0_rekey;
u32 wpa_group_update_count;
u32 wpa_pairwise_update_count;
int wpa_disable_eapol_key_retries;
@@ -497,6 +510,7 @@ struct hostapd_bss_config {
char *model_url;
char *upc;
struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+ struct wpabuf *wps_application_ext;
int wps_nfc_pw_from_config;
int wps_nfc_dev_pw_id;
struct wpabuf *wps_nfc_dh_pubkey;
@@ -664,7 +678,14 @@ struct hostapd_bss_config {
struct wpabuf *own_ie_override;
int sae_reflection_attack;
struct wpabuf *sae_commit_override;
+ struct wpabuf *rsne_override_eapol;
struct wpabuf *rsnxe_override_eapol;
+ struct wpabuf *rsne_override_ft;
+ struct wpabuf *rsnxe_override_ft;
+ struct wpabuf *gtk_rsc_override;
+ struct wpabuf *igtk_rsc_override;
+ int no_beacon_rsnxe;
+ int skip_prune_assoc;
#endif /* CONFIG_TESTING_OPTIONS */
#define MESH_ENABLED BIT(0)
@@ -720,6 +741,8 @@ struct hostapd_bss_config {
struct wpabuf *dpp_csign;
#ifdef CONFIG_DPP2
struct dpp_controller_conf *dpp_controller;
+ int dpp_configurator_connectivity;
+ int dpp_pfs;
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
@@ -729,12 +752,15 @@ struct hostapd_bss_config {
size_t owe_transition_ssid_len;
char owe_transition_ifname[IFNAMSIZ + 1];
int *owe_groups;
+ int owe_ptk_workaround;
#endif /* CONFIG_OWE */
int coloc_intf_reporting;
u8 send_probe_response;
+ u8 transition_disable;
+
#define BACKHAUL_BSS 1
#define FRONTHAUL_BSS 2
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
@@ -848,6 +874,8 @@ struct he_phy_capabilities_info {
*/
struct he_operation {
u8 he_bss_color;
+ u8 he_bss_color_disabled;
+ u8 he_bss_color_partial;
u8 he_default_pe_duration;
u8 he_twt_required;
u16 he_rts_threshold;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 75858668..1f284f0f 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -588,7 +588,7 @@ int hostapd_set_frag(struct hostapd_data *hapd, int frag)
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
int total_flags, int flags_or, int flags_and)
{
- if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
+ if (!hapd->driver || !hapd->drv_priv || !hapd->driver->sta_set_flags)
return 0;
return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
flags_or, flags_and);
@@ -680,36 +680,41 @@ int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
+ int key_idx, int vlan_id, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+ const u8 *key, size_t key_len, enum key_flag key_flag)
{
+ struct wpa_driver_set_key_params params;
+
if (hapd->driver == NULL || hapd->driver->set_key == NULL)
return 0;
- return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
- key_idx, set_tx, seq, seq_len, key,
- key_len);
-}
+ os_memset(&params, 0, sizeof(params));
+ params.ifname = ifname;
+ params.alg = alg;
+ params.addr = addr;
+ params.key_idx = key_idx;
+ params.set_tx = set_tx;
+ params.seq = seq;
+ params.seq_len = seq_len;
+ params.key = key;
+ params.key_len = key_len;
+ params.vlan_id = vlan_id;
+ params.key_flag = key_flag;
-int hostapd_drv_send_mlme(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack)
-{
- if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
- return 0;
- return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
- NULL, 0);
+ return hapd->driver->set_key(hapd->drv_priv, &params);
}
-int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack,
- const u16 *csa_offs, size_t csa_offs_len)
+int hostapd_drv_send_mlme(struct hostapd_data *hapd,
+ const void *msg, size_t len, int noack,
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt)
{
- if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
+ if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
- csa_offs, csa_offs_len);
+ csa_offs, csa_offs_len, no_encrypt, 0);
}
@@ -933,6 +938,7 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
}
params.freq_list = freq_list;
+ params.edmg_enabled = hapd->iface->conf->enable_edmg;
params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index fa413df0..56d1ad86 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -89,14 +89,13 @@ int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
int hostapd_drv_set_key(const char *ifname,
struct hostapd_data *hapd,
enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
+ int key_idx, int vlan_id, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len);
+ const u8 *key, size_t key_len, enum key_flag key_flag);
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack);
-int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack,
- const u16 *csa_offs, size_t csa_offs_len);
+ const void *msg, size_t len, int noack,
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt);
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason);
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index 8bf6ddec..20be7f8f 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -228,7 +228,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
set_beacon++;
}
-#ifdef CONFIG_IEEE80211N
if (!iface->olbc_ht && !ap->ht_support &&
(ap->channel == 0 ||
ap->channel == iface->conf->channel ||
@@ -241,7 +240,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
MAC2STR(ap->addr), ap->channel);
set_beacon++;
}
-#endif /* CONFIG_IEEE80211N */
if (set_beacon)
ieee802_11_update_beacons(iface);
@@ -285,14 +283,12 @@ void ap_list_timer(struct hostapd_iface *iface)
iface->olbc = 0;
set_beacon++;
}
-#ifdef CONFIG_IEEE80211N
if (!olbc_ht && iface->olbc_ht) {
wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
iface->olbc_ht = 0;
hostapd_ht_operation_update(iface);
set_beacon++;
}
-#endif /* CONFIG_IEEE80211N */
}
if (set_beacon)
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 331c09bc..47ced9a1 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -36,27 +36,6 @@
#ifdef NEED_AP_MLME
-static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
- size_t len)
-{
- size_t i;
-
- for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
- if (hapd->conf->radio_measurements[i])
- break;
- }
-
- if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
- return eid;
-
- *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
- *eid++ = RRM_CAPABILITIES_IE_LEN;
- os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
-
- return eid + RRM_CAPABILITIES_IE_LEN;
-}
-
-
static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
{
if (len < 2 + 5)
@@ -287,17 +266,101 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
}
-static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
+static const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
+{
+ const u8 *ies;
+ size_t ies_len;
+
+ ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
+ if (!ies)
+ return NULL;
+
+ return get_ie(ies, ies_len, eid);
+}
+
+
+static const u8 * hostapd_vendor_wpa_ie(struct hostapd_data *hapd,
+ u32 vendor_type)
+{
+ const u8 *ies;
+ size_t ies_len;
+
+ ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
+ if (!ies)
+ return NULL;
+
+ return get_vendor_ie(ies, ies_len, vendor_type);
+}
+
+
+static u8 * hostapd_get_rsne(struct hostapd_data *hapd, u8 *pos, size_t len)
{
const u8 *ie;
- size_t ielen;
- ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
- if (ie == NULL || ielen > len)
- return eid;
+ ie = hostapd_wpa_ie(hapd, WLAN_EID_RSN);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_mde(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+ ie = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_rsnxe(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->no_beacon_rsnxe) {
+ wpa_printf(MSG_INFO, "TESTING: Do not add RSNXE into Beacon");
+ return pos;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_wpa_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
- os_memcpy(eid, ie, ielen);
- return eid + ielen;
+ ie = hostapd_vendor_wpa_ie(hapd, WPA_IE_VENDOR_TYPE);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_osen_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+ ie = hostapd_vendor_wpa_ie(hapd, OSEN_IE_VENDOR_TYPE);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
}
@@ -405,6 +468,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
buflen += hostapd_mbo_ie_len(hapd);
buflen += hostapd_eid_owe_trans_len(hapd);
+ buflen += hostapd_eid_dpp_cc_len(hapd);
resp = os_zalloc(buflen);
if (resp == NULL)
@@ -455,14 +519,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
/* Extended supported rates */
pos = hostapd_eid_ext_supp_rates(hapd, pos);
- /* RSN, MDIE */
- if (!(hapd->conf->wpa == WPA_PROTO_WPA ||
- (hapd->conf->osen && !hapd->conf->wpa)))
- pos = hostapd_eid_wpa(hapd, pos, epos - pos);
-
+ pos = hostapd_get_rsne(hapd, pos, epos - pos);
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
-
pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
+ pos = hostapd_get_mde(hapd, pos, epos - pos);
/* eCSA IE */
csa_pos = hostapd_eid_ecsa(hapd, pos);
@@ -471,15 +531,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = csa_pos;
pos = hostapd_eid_supported_op_classes(hapd, pos);
-
-#ifdef CONFIG_IEEE80211N
- /* Secondary Channel Offset element */
- /* TODO: The standard doesn't specify a position for this element. */
- pos = hostapd_eid_secondary_channel(hapd, pos);
-
pos = hostapd_eid_ht_capabilities(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos);
-#endif /* CONFIG_IEEE80211N */
pos = hostapd_eid_ext_capab(hapd, pos);
@@ -509,13 +562,14 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#endif /* CONFIG_IEEE80211AC */
pos = hostapd_eid_fils_indic(hapd, pos, 0);
+ pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
pos = hostapd_eid_he_operation(hapd, pos);
- pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
pos = hostapd_eid_spatial_reuse(hapd, pos);
+ pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
}
#endif /* CONFIG_IEEE80211AX */
@@ -524,10 +578,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_vendor_vht(hapd, pos);
#endif /* CONFIG_IEEE80211AC */
- /* WPA */
- if (hapd->conf->wpa == WPA_PROTO_WPA ||
- (hapd->conf->osen && !hapd->conf->wpa))
- pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+ /* WPA / OSEN */
+ pos = hostapd_get_wpa_ie(hapd, pos, epos - pos);
+ pos = hostapd_get_osen_ie(hapd, pos, epos - pos);
/* Wi-Fi Alliance WMM */
pos = hostapd_eid_wmm(hapd, pos);
@@ -560,6 +613,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
pos = hostapd_eid_owe_trans(hapd, pos, (u8 *) resp + buflen - pos);
+ pos = hostapd_eid_dpp_cc(hapd, pos, (u8 *) resp + buflen - pos);
if (hapd->conf->vendor_elements) {
os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
@@ -581,7 +635,9 @@ enum ssid_match_result {
static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
const u8 *ssid, size_t ssid_len,
const u8 *ssid_list,
- size_t ssid_list_len)
+ size_t ssid_list_len,
+ const u8 *short_ssid_list,
+ size_t short_ssid_list_len)
{
const u8 *pos, *end;
int wildcard = 0;
@@ -592,20 +648,30 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0)
return EXACT_SSID_MATCH;
- if (ssid_list == NULL)
- return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+ if (ssid_list) {
+ pos = ssid_list;
+ end = ssid_list + ssid_list_len;
+ while (end - pos >= 2) {
+ if (2 + pos[1] > end - pos)
+ break;
+ if (pos[1] == 0)
+ wildcard = 1;
+ if (pos[1] == hapd->conf->ssid.ssid_len &&
+ os_memcmp(pos + 2, hapd->conf->ssid.ssid,
+ pos[1]) == 0)
+ return EXACT_SSID_MATCH;
+ pos += 2 + pos[1];
+ }
+ }
- pos = ssid_list;
- end = ssid_list + ssid_list_len;
- while (end - pos >= 2) {
- if (2 + pos[1] > end - pos)
- break;
- if (pos[1] == 0)
- wildcard = 1;
- if (pos[1] == hapd->conf->ssid.ssid_len &&
- os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0)
- return EXACT_SSID_MATCH;
- pos += 2 + pos[1];
+ if (short_ssid_list) {
+ pos = short_ssid_list;
+ end = short_ssid_list + short_ssid_list_len;
+ while (end - pos >= 4) {
+ if (hapd->conf->ssid.short_ssid == WPA_GET_LE32(pos))
+ return EXACT_SSID_MATCH;
+ pos += 4;
+ }
}
return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
@@ -743,11 +809,7 @@ void handle_probe_req(struct hostapd_data *hapd,
int ret;
u16 csa_offs[2];
size_t csa_offs_len;
- u32 session_timeout, acct_interim_interval;
- struct vlan_description vlan_id;
- struct hostapd_sta_wpa_psk_short *psk = NULL;
- char *identity = NULL;
- char *radius_cui = NULL;
+ struct radius_sta rad_info;
if (len < IEEE80211_HDRLEN)
return;
@@ -756,10 +818,8 @@ void handle_probe_req(struct hostapd_data *hapd,
sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
ie_len = len - IEEE80211_HDRLEN;
- ret = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
- &session_timeout,
- &acct_interim_interval, &vlan_id,
- &psk, &identity, &radius_cui, 1);
+ ret = hostapd_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
+ &rad_info, 1);
if (ret == HOSTAPD_ACL_REJECT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Ignore Probe Request frame from " MACSTR
@@ -838,7 +898,7 @@ void handle_probe_req(struct hostapd_data *hapd,
#endif /* CONFIG_P2P */
if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 &&
- elems.ssid_list_len == 0) {
+ elems.ssid_list_len == 0 && elems.short_ssid_list_len == 0) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
"broadcast SSID ignored", MAC2STR(mgmt->sa));
return;
@@ -870,7 +930,8 @@ void handle_probe_req(struct hostapd_data *hapd,
#endif /* CONFIG_TAXONOMY */
res = ssid_match(hapd, elems.ssid, elems.ssid_len,
- elems.ssid_list, elems.ssid_list_len);
+ elems.ssid_list, elems.ssid_list_len,
+ elems.short_ssid_list, elems.short_ssid_list_len);
if (res == NO_SSID_MATCH) {
if (!(mgmt->da[0] & 0x01)) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
@@ -883,6 +944,12 @@ void handle_probe_req(struct hostapd_data *hapd,
return;
}
+ if (hapd->conf->ignore_broadcast_ssid && res == WILDCARD_SSID_MATCH) {
+ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
+ "broadcast SSID ignored", MAC2STR(mgmt->sa));
+ return;
+ }
+
#ifdef CONFIG_INTERWORKING
if (hapd->conf->interworking &&
elems.interworking && elems.interworking_len >= 1) {
@@ -987,9 +1054,9 @@ void handle_probe_req(struct hostapd_data *hapd,
hapd->cs_c_off_ecsa_proberesp;
}
- ret = hostapd_drv_send_mlme_csa(hapd, resp, resp_len, noack,
- csa_offs_len ? csa_offs : NULL,
- csa_offs_len);
+ ret = hostapd_drv_send_mlme(hapd, resp, resp_len, noack,
+ csa_offs_len ? csa_offs : NULL,
+ csa_offs_len, 0);
if (ret < 0)
wpa_printf(MSG_INFO, "handle_probe_req: send failed");
@@ -1060,7 +1127,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
size_t resp_len = 0;
#ifdef NEED_AP_MLME
u16 capab_info;
- u8 *pos, *tailpos, *csa_pos;
+ u8 *pos, *tailpos, *tailend, *csa_pos;
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
@@ -1099,6 +1166,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tail_len += hostapd_mbo_ie_len(hapd);
tail_len += hostapd_eid_owe_trans_len(hapd);
+ tail_len += hostapd_eid_dpp_cc_len(hapd);
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
@@ -1107,6 +1175,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
os_free(tail);
return -1;
}
+ tailend = tail + tail_len;
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_BEACON);
@@ -1147,8 +1216,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
head_len = pos - (u8 *) head;
- tailpos = hostapd_eid_country(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE - tailpos);
+ tailpos = hostapd_eid_country(hapd, tailpos, tailend - tailpos);
/* Power Constraint element */
tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
@@ -1165,19 +1233,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
/* Extended supported rates */
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
- /* RSN, MDIE */
- 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);
-
+ tailpos = hostapd_get_rsne(hapd, tailpos, tailend - tailpos);
+ tailpos = hostapd_eid_bss_load(hapd, tailpos, tailend - tailpos);
tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE -
- tailpos);
-
- tailpos = hostapd_eid_bss_load(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE - tailpos);
+ tailend - tailpos);
+ tailpos = hostapd_get_mde(hapd, tailpos, tailend - tailpos);
/* eCSA IE */
csa_pos = hostapd_eid_ecsa(hapd, tailpos);
@@ -1186,15 +1246,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = csa_pos;
tailpos = hostapd_eid_supported_op_classes(hapd, tailpos);
-
-#ifdef CONFIG_IEEE80211N
- /* Secondary Channel Offset element */
- /* TODO: The standard doesn't specify a position for this element. */
- tailpos = hostapd_eid_secondary_channel(hapd, tailpos);
-
tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
tailpos = hostapd_eid_ht_operation(hapd, tailpos);
-#endif /* CONFIG_IEEE80211N */
tailpos = hostapd_eid_ext_capab(hapd, tailpos);
@@ -1226,14 +1279,15 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#endif /* CONFIG_IEEE80211AC */
tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
+ tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
tailpos = hostapd_eid_he_capab(hapd, tailpos,
IEEE80211_MODE_AP);
tailpos = hostapd_eid_he_operation(hapd, tailpos);
- tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
tailpos = hostapd_eid_spatial_reuse(hapd, tailpos);
+ tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
}
#endif /* CONFIG_IEEE80211AX */
@@ -1242,12 +1296,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */
- /* 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);
+ /* WPA / OSEN */
+ tailpos = hostapd_get_wpa_ie(hapd, tailpos, tailend - tailpos);
+ tailpos = hostapd_get_osen_ie(hapd, tailpos, tailend - tailpos);
/* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos);
@@ -1280,6 +1331,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
tailpos = hostapd_eid_owe_trans(hapd, tailpos,
tail + tail_len - tailpos);
+ tailpos = hostapd_eid_dpp_cc(hapd, tailpos, tail + tail_len - tailpos);
if (hapd->conf->vendor_elements) {
os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
@@ -1318,10 +1370,13 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
params->auth_algs = hapd->conf->auth_algs;
params->wpa_version = hapd->conf->wpa;
- params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+ params->privacy = hapd->conf->wpa;
+#ifdef CONFIG_WEP
+ params->privacy |= hapd->conf->ssid.wep.keys_set ||
(hapd->conf->ieee802_1x &&
(hapd->conf->default_wep_key_len ||
hapd->conf->individual_wep_key_len));
+#endif /* CONFIG_WEP */
switch (hapd->conf->ignore_broadcast_ssid) {
case 0:
params->hide_ssid = NO_SSID_HIDING;
@@ -1334,7 +1389,6 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
break;
}
params->isolate = hapd->conf->isolate;
- params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK;
#ifdef NEED_AP_MLME
params->cts_protect = !!(ieee802_11_erp_info(hapd) &
ERP_INFO_USE_PROTECTION);
@@ -1430,6 +1484,13 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
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;
+ params.he_bss_color_disabled =
+ hapd->iface->conf->he_op.he_bss_color_disabled;
+ params.he_bss_color_partial =
+ hapd->iface->conf->he_op.he_bss_color_partial;
+ params.he_bss_color = hapd->iface->conf->he_op.he_bss_color;
+ params.twt_responder = hostapd_get_he_twt_responder(hapd,
+ IEEE80211_MODE_AP);
#endif /* CONFIG_IEEE80211AX */
hapd->reenable_beacon = 0;
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 9fd1b81a..ef53a825 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -345,7 +345,6 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211AC */
-#ifdef CONFIG_IEEE80211N
if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
res = os_snprintf(buf + len, buflen - len,
"ht_caps_info=0x%04x\n",
@@ -354,7 +353,6 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
if (!os_snprintf_error(buflen - len, res))
len += res;
}
-#endif /* CONFIG_IEEE80211N */
if (sta->ext_capability &&
buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
@@ -462,9 +460,6 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
int ret;
u8 *pos;
- if (!hapd->drv_priv || !hapd->driver->send_frame)
- return -1;
-
mgmt = os_zalloc(sizeof(*mgmt) + 100);
if (mgmt == NULL)
return -1;
@@ -498,8 +493,8 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
pos += 2;
*pos++ = minor_reason_code;
- ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
- pos - (u8 *) mgmt, 1);
+ ret = hostapd_drv_send_mlme(hapd, mgmt, pos - (u8 *) mgmt, 0, NULL, 0,
+ 0);
os_free(mgmt);
return ret < 0 ? -1 : 0;
@@ -529,8 +524,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
- if (!hapd->drv_priv || !hapd->driver->send_frame)
- return -1;
+
pos += 6;
encrypt = atoi(pos);
os_memset(&mgmt, 0, sizeof(mgmt));
@@ -540,10 +534,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code = host_to_le16(reason);
- if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
- IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth),
- encrypt) < 0)
+ if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth),
+ 0, NULL, 0, !encrypt) < 0)
return -1;
return 0;
}
@@ -592,8 +586,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
- if (!hapd->drv_priv || !hapd->driver->send_frame)
- return -1;
+
pos += 6;
encrypt = atoi(pos);
os_memset(&mgmt, 0, sizeof(mgmt));
@@ -603,10 +596,10 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code = host_to_le16(reason);
- if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
- IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth),
- encrypt) < 0)
+ if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth),
+ 0, NULL, 0, !encrypt) < 0)
return -1;
return 0;
}
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index f70ecc94..3c078b9c 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -144,30 +144,44 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
int i;
u32 bw = num_chan_to_bw(num_chans);
- if (first_chan_idx + num_chans > mode->num_channels)
+ if (first_chan_idx + num_chans > mode->num_channels) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: some channels in range not defined");
return 0;
+ }
first_chan = &mode->channels[first_chan_idx];
/* hostapd DFS implementation assumes the first channel as primary.
* If it's not allowed to use the first channel as primary, decline the
* whole channel range. */
- if (!chan_pri_allowed(first_chan))
+ if (!chan_pri_allowed(first_chan)) {
+ wpa_printf(MSG_DEBUG, "DFS: primary chanenl not allowed");
return 0;
+ }
for (i = 0; i < num_chans; i++) {
chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
first_chan_idx);
- if (!chan)
+ if (!chan) {
+ wpa_printf(MSG_DEBUG, "DFS: no channel data for %d",
+ first_chan->freq + i * 20);
return 0;
+ }
/* HT 40 MHz secondary channel availability checked only for
* primary channel */
- if (!chan_bw_allowed(chan, bw, 1, !i))
+ if (!chan_bw_allowed(chan, bw, 1, !i)) {
+ wpa_printf(MSG_DEBUG, "DFS: bw now allowed for %d",
+ first_chan->freq + i * 20);
return 0;
+ }
- if (!dfs_channel_available(chan, skip_radar))
+ if (!dfs_channel_available(chan, skip_radar)) {
+ wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
+ first_chan->freq + i * 20);
return 0;
+ }
}
return 1;
@@ -210,22 +224,36 @@ static int dfs_find_channel(struct hostapd_iface *iface,
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
(!dfs_is_chan_allowed(chan, n_chans) ||
- !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)))
+ !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: channel %d (%d) is incompatible",
+ chan->freq, chan->chan);
continue;
+ }
/* Skip incompatible chandefs */
- if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
+ if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: range not available for %d (%d)",
+ chan->freq, chan->chan);
continue;
+ }
- if (!is_in_chanlist(iface, chan))
+ if (!is_in_chanlist(iface, chan)) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: channel %d (%d) not in chanlist",
+ chan->freq, chan->chan);
continue;
+ }
if (ret_chan && idx == channel_idx) {
- wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
+ wpa_printf(MSG_DEBUG, "Selected channel %d (%d)",
+ chan->freq, chan->chan);
*ret_chan = chan;
return idx;
}
- wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
+ wpa_printf(MSG_DEBUG, "Adding channel %d (%d)",
+ chan->freq, chan->chan);
channel_idx++;
}
return channel_idx;
@@ -235,6 +263,7 @@ static int dfs_find_channel(struct hostapd_iface *iface,
static void dfs_adjust_center_freq(struct hostapd_iface *iface,
struct hostapd_channel_data *chan,
int secondary_channel,
+ int sec_chan_idx_80p80,
u8 *oper_centr_freq_seg0_idx,
u8 *oper_centr_freq_seg1_idx)
{
@@ -261,8 +290,14 @@ static void dfs_adjust_center_freq(struct hostapd_iface *iface,
case CHANWIDTH_160MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 14;
break;
+ case CHANWIDTH_80P80MHZ:
+ *oper_centr_freq_seg0_idx = chan->chan + 6;
+ *oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
+ break;
+
default:
- wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
+ wpa_printf(MSG_INFO,
+ "DFS: Unsupported channel width configuration");
*oper_centr_freq_seg0_idx = 0;
break;
}
@@ -441,8 +476,11 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan = NULL;
+ struct hostapd_channel_data *chan2 = NULL;
int num_available_chandefs;
- int chan_idx;
+ int chan_idx, chan_idx2;
+ int sec_chan_idx_80p80 = -1;
+ int i;
u32 _rand;
wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
@@ -459,6 +497,8 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
/* Get the count first */
num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
+ wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
+ num_available_chandefs);
if (num_available_chandefs == 0)
return NULL;
@@ -466,6 +506,12 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
return NULL;
chan_idx = _rand % num_available_chandefs;
dfs_find_channel(iface, &chan, chan_idx, skip_radar);
+ if (!chan) {
+ wpa_printf(MSG_DEBUG, "DFS: no random channel found");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "DFS: got random channel %d (%d)",
+ chan->freq, chan->chan);
/* dfs_find_channel() calculations assume HT40+ */
if (iface->conf->secondary_channel)
@@ -473,8 +519,45 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
else
*secondary_channel = 0;
+ /* Get secondary channel for HT80P80 */
+ if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80P80MHZ) {
+ if (num_available_chandefs <= 1) {
+ wpa_printf(MSG_ERROR,
+ "only 1 valid chan, can't support 80+80");
+ return NULL;
+ }
+
+ /*
+ * Loop all channels except channel1 to find a valid channel2
+ * that is not adjacent to channel1.
+ */
+ for (i = 0; i < num_available_chandefs - 1; i++) {
+ /* start from chan_idx + 1, end when chan_idx - 1 */
+ chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
+ dfs_find_channel(iface, &chan2, chan_idx2, skip_radar);
+ if (chan2 && abs(chan2->chan - chan->chan) > 12) {
+ /* two channels are not adjacent */
+ sec_chan_idx_80p80 = chan2->chan;
+ wpa_printf(MSG_DEBUG,
+ "DFS: got second chan: %d (%d)",
+ chan2->freq, chan2->chan);
+ break;
+ }
+ }
+
+ /* Check if we got a valid secondary channel which is not
+ * adjacent to the first channel.
+ */
+ if (sec_chan_idx_80p80 == -1) {
+ wpa_printf(MSG_INFO,
+ "DFS: failed to get chan2 for 80+80");
+ return NULL;
+ }
+ }
+
dfs_adjust_center_freq(iface, chan,
*secondary_channel,
+ sec_chan_idx_80p80,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx);
@@ -773,7 +856,7 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
}
-static int hostapd_config_dfs_chan_available(struct hostapd_iface *iface)
+int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
{
int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
@@ -821,7 +904,7 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
* another radio.
*/
if (iface->state != HAPD_IFACE_ENABLED &&
- hostapd_config_dfs_chan_available(iface)) {
+ hostapd_is_dfs_chan_available(iface)) {
hostapd_setup_interface_complete(iface, 0);
iface->cac_started = 0;
}
@@ -851,6 +934,41 @@ int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
}
+static struct hostapd_channel_data *
+dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
+ u8 *oper_centr_freq_seg0_idx,
+ u8 *oper_centr_freq_seg1_idx, int *skip_radar)
+{
+ struct hostapd_channel_data *channel;
+
+ for (;;) {
+ channel = dfs_get_valid_channel(iface, secondary_channel,
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx,
+ *skip_radar);
+ if (channel) {
+ wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d",
+ channel->chan);
+ return channel;
+ }
+
+ if (*skip_radar) {
+ *skip_radar = 0;
+ } else {
+ if (iface->conf->vht_oper_chwidth == CHANWIDTH_USE_HT)
+ break;
+ *skip_radar = 1;
+ iface->conf->vht_oper_chwidth--;
+ }
+ }
+
+ wpa_printf(MSG_INFO,
+ "%s: no DFS channels left, waiting for NOP to finish",
+ __func__);
+ return NULL;
+}
+
+
static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
@@ -868,8 +986,14 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
skip_radar);
if (!channel) {
- wpa_printf(MSG_ERROR, "No valid channel available");
- return err;
+ channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
+ &skip_radar);
+ if (!channel) {
+ wpa_printf(MSG_ERROR, "No valid channel available");
+ return err;
+ }
}
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
@@ -898,11 +1022,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
int secondary_channel;
u8 oper_centr_freq_seg0_idx;
u8 oper_centr_freq_seg1_idx;
+ u8 new_vht_oper_chwidth;
int skip_radar = 1;
struct csa_settings csa_settings;
unsigned int i;
int err = 1;
struct hostapd_hw_modes *cmode = iface->current_mode;
+ u8 current_vht_oper_chwidth = iface->conf->vht_oper_chwidth;
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no",
@@ -936,28 +1062,25 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
* requires to perform a CAC first.
*/
skip_radar = 0;
- channel = dfs_get_valid_channel(iface, &secondary_channel,
- &oper_centr_freq_seg0_idx,
- &oper_centr_freq_seg1_idx,
- skip_radar);
- if (!channel) {
- wpa_printf(MSG_INFO,
- "%s: no DFS channels left, waiting for NOP to finish",
- __func__);
+ channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
+ &skip_radar);
+ if (!channel)
return err;
+ if (!skip_radar) {
+ iface->freq = channel->freq;
+ iface->conf->channel = channel->chan;
+ iface->conf->secondary_channel = secondary_channel;
+ hostapd_set_oper_centr_freq_seg0_idx(
+ iface->conf, oper_centr_freq_seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(
+ iface->conf, oper_centr_freq_seg1_idx);
+
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+ return 0;
}
-
- iface->freq = channel->freq;
- iface->conf->channel = channel->chan;
- iface->conf->secondary_channel = secondary_channel;
- hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
- oper_centr_freq_seg0_idx);
- hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
- oper_centr_freq_seg1_idx);
-
- hostapd_disable_iface(iface);
- hostapd_enable_iface(iface);
- return 0;
}
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
@@ -966,6 +1089,9 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
"freq=%d chan=%d sec_chan=%d", channel->freq,
channel->chan, secondary_channel);
+ new_vht_oper_chwidth = iface->conf->vht_oper_chwidth;
+ iface->conf->vht_oper_chwidth = current_vht_oper_chwidth;
+
/* Setup CSA request */
os_memset(&csa_settings, 0, sizeof(csa_settings));
csa_settings.cs_count = 5;
@@ -980,7 +1106,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
iface->conf->ieee80211ac,
iface->conf->ieee80211ax,
secondary_channel,
- hostapd_get_oper_chwidth(iface->conf),
+ new_vht_oper_chwidth,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx,
cmode->vht_capab,
@@ -1004,6 +1130,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
+ iface->conf->vht_oper_chwidth = new_vht_oper_chwidth;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
oper_centr_freq_seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
@@ -1040,8 +1167,10 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
return 0;
/* mark radar frequency as invalid */
- set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
- cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
+ res = set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+ cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
+ if (!res)
+ return 0;
/* Skip if reported radar event not overlapped our channels */
res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
@@ -1161,3 +1290,56 @@ int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
__func__, iface->freq);
return 2;
}
+
+
+int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
+ int center_freq)
+{
+ struct hostapd_channel_data *chan;
+ struct hostapd_hw_modes *mode = iface->current_mode;
+ int half_width;
+ int res = 0;
+ int i;
+
+ if (!iface->conf->ieee80211h || !mode ||
+ mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 0;
+
+ switch (width) {
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ half_width = 10;
+ break;
+ case CHAN_WIDTH_40:
+ half_width = 20;
+ break;
+ case CHAN_WIDTH_80:
+ case CHAN_WIDTH_80P80:
+ half_width = 40;
+ break;
+ case CHAN_WIDTH_160:
+ half_width = 80;
+ break;
+ default:
+ wpa_printf(MSG_WARNING, "DFS chanwidth %d not supported",
+ width);
+ return 0;
+ }
+
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+
+ if (!(chan->flag & HOSTAPD_CHAN_RADAR))
+ continue;
+
+ if (center_freq - chan->freq < half_width &&
+ chan->freq - center_freq < half_width)
+ res++;
+ }
+
+ wpa_printf(MSG_DEBUG, "DFS: (%d, %d): in range: %s",
+ center_freq - half_width, center_freq + half_width,
+ res ? "yes" : "no");
+
+ return res;
+}
diff --git a/src/ap/dfs.h b/src/ap/dfs.h
index f0fa6f68..606c1b39 100644
--- a/src/ap/dfs.h
+++ b/src/ap/dfs.h
@@ -25,9 +25,12 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
int ht_enabled,
int chan_offset, int chan_width, int cf1, int cf2);
int hostapd_is_dfs_required(struct hostapd_iface *iface);
+int hostapd_is_dfs_chan_available(struct hostapd_iface *iface);
int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2);
int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
+int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
+ int center_freq);
#endif /* DFS_H */
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
index ed37fc8f..edc77da2 100644
--- a/src/ap/dhcp_snoop.c
+++ b/src/ap/dhcp_snoop.c
@@ -39,22 +39,22 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
const u8 *end, *pos;
int res, msgtype = 0, prefixlen = 32;
u32 subnet_mask = 0;
- u16 tot_len;
+ u16 ip_len;
exten_len = len - ETH_HLEN - (sizeof(*b) - sizeof(b->exten));
if (exten_len < 4)
return;
b = (const struct bootp_pkt *) &buf[ETH_HLEN];
- tot_len = ntohs(b->iph.tot_len);
- if (tot_len > (unsigned int) (len - ETH_HLEN))
+ ip_len = ntohs(b->iph.ip_len);
+ if (ip_len > (unsigned int) (len - ETH_HLEN))
return;
if (WPA_GET_BE32(b->exten) != DHCP_MAGIC)
return;
/* Parse DHCP options */
- end = (const u8 *) b + tot_len;
+ end = (const u8 *) b + ip_len;
pos = &b->exten[4];
while (pos < end && *pos != DHCP_OPT_END) {
const u8 *opt = pos++;
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 1a3a815c..c86f01ba 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -1,7 +1,7 @@
/*
* hostapd / DPP integration
* Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -81,6 +81,71 @@ int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd)
}
+int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
+
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Request");
+ return -1;
+ }
+
+ if (dpp_nfc_update_bi(own_bi, peer_bi) < 0)
+ return -1;
+
+ return peer_bi->id;
+}
+
+
+int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
+
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Select");
+ return -1;
+ }
+
+ if (peer_bi->curve != own_bi->curve) {
+ wpa_printf(MSG_INFO,
+ "DPP: Peer (NFC Handover Selector) used different curve");
+ return -1;
+ }
+
+ return peer_bi->id;
+}
+
+
static void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx,
void *timeout_ctx)
{
@@ -478,15 +543,15 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
dpp_auth_deinit(hapd->dpp_auth);
}
- hapd->dpp_auth = dpp_auth_init(hapd->msg_ctx, peer_bi, own_bi,
+ hapd->dpp_auth = dpp_auth_init(hapd->iface->interfaces->dpp,
+ hapd->msg_ctx, peer_bi, own_bi,
allowed_roles, neg_freq,
hapd->iface->hw_features,
hapd->iface->num_hw_features);
if (!hapd->dpp_auth)
goto fail;
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
- hapd->dpp_auth, cmd) < 0) {
+ if (dpp_set_configurator(hapd->dpp_auth, cmd) < 0) {
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
goto fail;
@@ -598,7 +663,8 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
}
hapd->dpp_auth_ok_on_ack = 0;
- hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles,
+ hapd->dpp_auth = dpp_auth_req_rx(hapd->iface->interfaces->dpp,
+ hapd->msg_ctx, hapd->dpp_allowed_roles,
hapd->dpp_qr_mutual,
peer_bi, own_bi, freq, hdr, buf, len);
if (!hapd->dpp_auth) {
@@ -606,8 +672,7 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
return;
}
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
- hapd->dpp_auth,
+ if (dpp_set_configurator(hapd->dpp_auth,
hapd->dpp_configurator_params) < 0) {
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
@@ -643,7 +708,8 @@ static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
* message. */
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
conf->connector);
- } else if (conf->passphrase[0]) {
+ }
+ if (conf->passphrase[0]) {
char hex[64 * 2 + 1];
wpa_snprintf_hex(hex, sizeof(hex),
@@ -697,6 +763,33 @@ static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
}
+static int hostapd_dpp_handle_key_pkg(struct hostapd_data *hapd,
+ struct dpp_asymmetric_key *key)
+{
+#ifdef CONFIG_DPP2
+ int res;
+
+ if (!key)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+
+ while (key) {
+ res = dpp_configurator_from_backup(
+ hapd->iface->interfaces->dpp, key);
+ if (res < 0)
+ return -1;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFIGURATOR_ID "%d",
+ res);
+ key = key->next;
+ }
+#endif /* CONFIG_DPP2 */
+
+ return 0;
+}
+
+
static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
enum gas_query_ap_result result,
const struct wpabuf *adv_proto,
@@ -741,6 +834,9 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
}
hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
+ if (hostapd_dpp_handle_key_pkg(hapd, auth->conf_key_pkg) < 0)
+ goto fail;
+
status = DPP_STATUS_OK;
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_REJECT_CONFIG) {
@@ -1037,6 +1133,70 @@ static void hostapd_dpp_rx_conn_status_result(struct hostapd_data *hapd,
}
+static void
+hostapd_dpp_rx_presence_announcement(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *r_bootstrap;
+ u16 r_bootstrap_len;
+ struct dpp_bootstrap_info *peer_bi;
+ struct dpp_authentication *auth;
+
+ wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR,
+ MAC2STR(src));
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+ peer_bi = dpp_bootstrap_find_chirp(hapd->iface->interfaces->dpp,
+ r_bootstrap);
+ if (!peer_bi) {
+ if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
+ src, hdr, buf, len, freq, NULL,
+ r_bootstrap) == 0)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching bootstrapping information found");
+ return;
+ }
+
+ if (hapd->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Presence Announcement during ongoing Authentication");
+ return;
+ }
+
+ auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ peer_bi, NULL, DPP_CAPAB_CONFIGURATOR, freq, NULL,
+ 0);
+ if (!auth)
+ return;
+ hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
+ if (dpp_set_configurator(hapd->dpp_auth,
+ hapd->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(auth);
+ return;
+ }
+
+ auth->neg_freq = freq;
+
+ if (!is_zero_ether_addr(peer_bi->mac_addr))
+ os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+
+ hapd->dpp_auth = auth;
+ if (hostapd_dpp_auth_init_next(hapd) < 0) {
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ }
+}
+
#endif /* CONFIG_DPP2 */
@@ -1486,6 +1646,10 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
case DPP_PA_CONNECTION_STATUS_RESULT:
hostapd_dpp_rx_conn_status_result(hapd, src, hdr, buf, len);
break;
+ case DPP_PA_PRESENCE_ANNOUNCEMENT:
+ hostapd_dpp_rx_presence_announcement(hapd, src, hdr, buf, len,
+ freq);
+ break;
#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
@@ -1580,14 +1744,13 @@ int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd)
int ret = -1;
char *curve = NULL;
- auth = os_zalloc(sizeof(*auth));
+ auth = dpp_alloc_auth(hapd->iface->interfaces->dpp, hapd->msg_ctx);
if (!auth)
return -1;
curve = get_param(cmd, " curve=");
hostapd_dpp_set_testing_options(hapd, auth);
- if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
- auth, cmd) == 0 &&
+ if (dpp_set_configurator(auth, cmd) == 0 &&
dpp_configurator_own_config(auth, curve, 1) == 0) {
hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
ret = 0;
diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h
index e151c2fc..b1fa99ed 100644
--- a/src/ap/dpp_hostapd.h
+++ b/src/ap/dpp_hostapd.h
@@ -1,7 +1,7 @@
/*
* hostapd / DPP integration
* Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,8 @@
int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd);
void hostapd_dpp_listen_stop(struct hostapd_data *hapd);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 8a4b0ef6..559bb87c 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -109,7 +109,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *req_ies, size_t req_ies_len, int reassoc)
{
struct sta_info *sta;
- int new_assoc, res;
+ int new_assoc;
+ enum wpa_validate_result res;
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
@@ -220,7 +221,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
#endif /* CONFIG_P2P */
-#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
if (elems.ht_capabilities &&
(hapd->iface->conf->ht_capab &
@@ -234,7 +234,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
ht40_intolerant_add(hapd->iface, sta);
}
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_INTERWORKING
if (elems.ext_capab && elems.ext_capab_len > 4) {
@@ -325,33 +324,67 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len,
elems.owe_dh, elems.owe_dh_len);
- if (res != WPA_IE_OK) {
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ switch (res) {
+ case WPA_IE_OK:
+ reason = WLAN_REASON_UNSPECIFIED;
+ status = WLAN_STATUS_SUCCESS;
+ break;
+ case WPA_INVALID_IE:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_INVALID_GROUP:
+ reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ break;
+ case WPA_INVALID_PAIRWISE:
+ reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
+ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+ break;
+ case WPA_INVALID_AKMP:
+ reason = WLAN_REASON_AKMP_NOT_VALID;
+ status = WLAN_STATUS_AKMP_NOT_VALID;
+ break;
+ case WPA_NOT_ENABLED:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_ALLOC_FAIL:
+ reason = WLAN_REASON_UNSPECIFIED;
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ break;
+ case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_INVALID_MGMT_GROUP_CIPHER:
+ reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
+ status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+ break;
+ case WPA_INVALID_MDIE:
+ reason = WLAN_REASON_INVALID_MDE;
+ status = WLAN_STATUS_INVALID_MDIE;
+ break;
+ case WPA_INVALID_PROTO:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_INVALID_PMKID:
+ reason = WLAN_REASON_INVALID_PMKID;
+ status = WLAN_STATUS_INVALID_PMKID;
+ break;
+ case WPA_DENIED_OTHER_REASON:
+ reason = WLAN_REASON_UNSPECIFIED;
+ status = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ break;
+ }
+ if (status != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG,
"WPA/RSN information element rejected? (res %u)",
res);
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
- if (res == WPA_INVALID_GROUP) {
- reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
- status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
- } else if (res == WPA_INVALID_PAIRWISE) {
- reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
- status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
- } else if (res == WPA_INVALID_AKMP) {
- reason = WLAN_REASON_AKMP_NOT_VALID;
- status = WLAN_STATUS_AKMP_NOT_VALID;
- } 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;
- } else if (res == WPA_INVALID_PMKID) {
- reason = WLAN_REASON_INVALID_PMKID;
- status = WLAN_STATUS_INVALID_PMKID;
- } else {
- reason = WLAN_REASON_INVALID_IE;
- status = WLAN_STATUS_INVALID_IE;
- }
goto fail;
}
@@ -469,6 +502,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
return WLAN_STATUS_INVALID_IE;
#endif /* CONFIG_HS20 */
}
+#ifdef CONFIG_WPS
+skip_wpa_check:
+#endif /* CONFIG_WPS */
#ifdef CONFIG_MBO
if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
@@ -480,13 +516,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
#endif /* CONFIG_MBO */
-#ifdef CONFIG_WPS
-skip_wpa_check:
-#endif /* CONFIG_WPS */
-
#ifdef CONFIG_IEEE80211R_AP
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
- sta->auth_alg, req_ies, req_ies_len);
+ sta->auth_alg, req_ies, req_ies_len,
+ !elems.rsnxe);
if (!p) {
wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -577,18 +610,18 @@ skip_wpa_check:
npos = owe_assoc_req_process(hapd, sta,
elems.owe_dh, elems.owe_dh_len,
p, sizeof(buf) - (p - buf),
- &reason);
+ &status);
if (npos)
p = npos;
+
if (!npos &&
- reason == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
- status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ status == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
p - buf);
return 0;
}
- if (!npos || reason != WLAN_STATUS_SUCCESS)
+ if (!npos || status != WLAN_STATUS_SUCCESS)
goto fail;
}
#endif /* CONFIG_OWE */
@@ -625,6 +658,11 @@ skip_wpa_check:
pfs_fail:
#endif /* CONFIG_DPP2 */
+ if (elems.rrm_enabled &&
+ elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
+ os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
+ sizeof(sta->rrm_enabled_capa));
+
#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
@@ -709,6 +747,7 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@@ -906,6 +945,12 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
} else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
"freq=%d dfs=%d", freq, is_dfs);
+ } else if (is_dfs &&
+ hostapd_is_dfs_required(hapd->iface) &&
+ !hostapd_is_dfs_chan_available(hapd->iface) &&
+ !hapd->iface->cac_started) {
+ hostapd_disable_iface(hapd->iface);
+ hostapd_enable_iface(hapd->iface);
}
for (i = 0; i < hapd->iface->num_bss; i++)
@@ -1005,32 +1050,35 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
goto out;
}
+ hapd->iconf->edmg_channel = acs_res->edmg_channel;
+
if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
/* set defaults for backwards compatibility */
hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0);
hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT);
- if (acs_res->ch_width == 80) {
- hostapd_set_oper_centr_freq_seg0_idx(
- hapd->iconf, acs_res->vht_seg0_center_ch);
- hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_80MHZ);
- } else if (acs_res->ch_width == 160) {
- if (acs_res->vht_seg1_center_ch == 0) {
+ if (acs_res->ch_width == 40) {
+ if (is_6ghz_freq(acs_res->pri_freq))
hostapd_set_oper_centr_freq_seg0_idx(
hapd->iconf,
acs_res->vht_seg0_center_ch);
+ } else if (acs_res->ch_width == 80) {
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf, acs_res->vht_seg0_center_ch);
+ if (acs_res->vht_seg1_center_ch == 0) {
hostapd_set_oper_chwidth(hapd->iconf,
- CHANWIDTH_160MHZ);
+ CHANWIDTH_80MHZ);
} else {
- hostapd_set_oper_centr_freq_seg0_idx(
- hapd->iconf,
- acs_res->vht_seg0_center_ch);
+ hostapd_set_oper_chwidth(hapd->iconf,
+ CHANWIDTH_80P80MHZ);
hostapd_set_oper_centr_freq_seg1_idx(
hapd->iconf,
acs_res->vht_seg1_center_ch);
- hostapd_set_oper_chwidth(hapd->iconf,
- CHANWIDTH_80P80MHZ);
}
+ } else if (acs_res->ch_width == 160) {
+ hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_160MHZ);
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf, acs_res->vht_seg1_center_ch);
}
}
@@ -1426,15 +1474,33 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
#endif /* HOSTAPD */
+static struct hostapd_channel_data *
+hostapd_get_mode_chan(struct hostapd_hw_modes *mode, unsigned int freq)
+{
+ int i;
+ struct hostapd_channel_data *chan;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+ if ((unsigned int) chan->freq == freq)
+ return chan;
+ }
+
+ return NULL;
+}
+
+
static struct hostapd_channel_data * hostapd_get_mode_channel(
struct hostapd_iface *iface, unsigned int freq)
{
int i;
struct hostapd_channel_data *chan;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
- if ((unsigned int) chan->freq == freq)
+ for (i = 0; i < iface->num_hw_features; i++) {
+ if (hostapd_hw_skip_mode(iface, &iface->hw_features[i]))
+ continue;
+ chan = hostapd_get_mode_chan(&iface->hw_features[i], freq);
+ if (chan)
return chan;
}
diff --git a/src/ap/fils_hlp.c b/src/ap/fils_hlp.c
index 6da514a4..0310aab5 100644
--- a/src/ap/fils_hlp.c
+++ b/src/ap/fils_hlp.c
@@ -158,7 +158,7 @@ static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
ssize_t res;
u8 msgtype = 0;
int rapid_commit = 0;
- struct iphdr *iph;
+ struct ip *iph;
struct udphdr *udph;
struct wpabuf *resp;
const u8 *rpos;
@@ -259,14 +259,14 @@ static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6);
wpabuf_put_be16(resp, ETH_P_IP);
iph = wpabuf_put(resp, sizeof(*iph));
- iph->version = 4;
- iph->ihl = sizeof(*iph) / 4;
- iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
- iph->ttl = 1;
- iph->protocol = 17; /* UDP */
- iph->saddr = hapd->conf->dhcp_server.u.v4.s_addr;
- iph->daddr = dhcp->client_ip;
- iph->check = ip_checksum(iph, sizeof(*iph));
+ iph->ip_v = 4;
+ iph->ip_hl = sizeof(*iph) / 4;
+ iph->ip_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
+ iph->ip_ttl = 1;
+ iph->ip_p = 17; /* UDP */
+ iph->ip_src.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
+ iph->ip_dst.s_addr = dhcp->client_ip;
+ iph->ip_sum = ip_checksum(iph, sizeof(*iph));
udph = wpabuf_put(resp, sizeof(*udph));
udph->uh_sport = htons(DHCP_SERVER_PORT);
udph->uh_dport = htons(DHCP_CLIENT_PORT);
@@ -479,13 +479,13 @@ static int fils_process_hlp_udp(struct hostapd_data *hapd,
struct sta_info *sta, const u8 *dst,
const u8 *pos, size_t len)
{
- const struct iphdr *iph;
+ const struct ip *iph;
const struct udphdr *udph;
u16 sport, dport, ulen;
if (len < sizeof(*iph) + sizeof(*udph))
return 0;
- iph = (const struct iphdr *) pos;
+ iph = (const struct ip *) pos;
udph = (const struct udphdr *) (iph + 1);
sport = ntohs(udph->uh_sport);
dport = ntohs(udph->uh_dport);
@@ -510,24 +510,24 @@ static int fils_process_hlp_ip(struct hostapd_data *hapd,
struct sta_info *sta, const u8 *dst,
const u8 *pos, size_t len)
{
- const struct iphdr *iph;
- u16 tot_len;
+ const struct ip *iph;
+ uint16_t ip_len;
if (len < sizeof(*iph))
return 0;
- iph = (const struct iphdr *) pos;
+ iph = (const struct ip *) pos;
if (ip_checksum(iph, sizeof(*iph)) != 0) {
wpa_printf(MSG_DEBUG,
"FILS: HLP request IPv4 packet had invalid header checksum - dropped");
return 0;
}
- tot_len = ntohs(iph->tot_len);
- if (tot_len > len)
+ ip_len = ntohs(iph->ip_len);
+ if (ip_len > len)
return 0;
wpa_printf(MSG_DEBUG,
"FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u",
- iph->saddr, iph->daddr, iph->protocol);
- switch (iph->protocol) {
+ iph->ip_src.s_addr, iph->ip_dst.s_addr, iph->ip_p);
+ switch (iph->ip_p) {
case 17:
return fils_process_hlp_udp(hapd, sta, dst, pos, len);
}
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index e4950e3e..f2e964ac 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -13,6 +13,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/crc32.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "common/hw_features_common.h"
@@ -57,8 +58,10 @@
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
+#ifdef CONFIG_WEP
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
+#endif /* CONFIG_WEP */
static int setup_interface2(struct hostapd_iface *iface);
static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
@@ -88,7 +91,9 @@ void hostapd_reconfig_encryption(struct hostapd_data *hapd)
return;
hostapd_set_privacy(hapd, 0);
+#ifdef CONFIG_WEP
hostapd_setup_encryption(hapd->conf->iface, hapd);
+#endif /* CONFIG_WEP */
}
@@ -141,7 +146,9 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
wpa_deinit(hapd->wpa_auth);
hapd->wpa_auth = NULL;
hostapd_set_privacy(hapd, 0);
+#ifdef CONFIG_WEP
hostapd_setup_encryption(hapd->conf->iface, hapd);
+#endif /* CONFIG_WEP */
hostapd_set_generic_elem(hapd, (u8 *) "", 0);
}
@@ -169,7 +176,9 @@ static void hostapd_clear_old(struct hostapd_iface *iface)
for (j = 0; j < iface->num_bss; j++) {
hostapd_flush_old_stations(iface->bss[j],
WLAN_REASON_PREV_AUTH_NOT_VALID);
+#ifdef CONFIG_WEP
hostapd_broadcast_wep_clear(iface->bss[j]);
+#endif /* CONFIG_WEP */
#ifndef CONFIG_NO_RADIUS
/* TODO: update dynamic data based on changed configuration
@@ -283,6 +292,8 @@ int hostapd_reload_config(struct hostapd_iface *iface)
}
+#ifdef CONFIG_WEP
+
static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
const char *ifname)
{
@@ -291,8 +302,8 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
if (!ifname || !hapd->drv_priv)
return;
for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
- 0, NULL, 0, NULL, 0)) {
+ if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, 0,
+ 0, NULL, 0, NULL, 0, KEY_FLAG_GROUP)) {
wpa_printf(MSG_DEBUG, "Failed to clear default "
"encryption keys (ifname=%s keyidx=%d)",
ifname, i);
@@ -301,8 +312,8 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
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,
- NULL, i, 0, NULL,
- 0, NULL, 0)) {
+ NULL, i, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_GROUP)) {
wpa_printf(MSG_DEBUG, "Failed to clear "
"default mgmt encryption keys "
"(ifname=%s keyidx=%d)", ifname, i);
@@ -325,11 +336,12 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
struct hostapd_ssid *ssid = &hapd->conf->ssid;
idx = ssid->wep.idx;
- if (ssid->wep.default_len &&
+ if (ssid->wep.default_len && ssid->wep.key[idx] &&
hostapd_drv_set_key(hapd->conf->iface,
- hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
+ hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, 0,
1, NULL, 0, ssid->wep.key[idx],
- ssid->wep.len[idx])) {
+ ssid->wep.len[idx],
+ KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
errors++;
}
@@ -337,6 +349,8 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
return errors;
}
+#endif /* CONFIG_WEP */
+
static void hostapd_free_hapd_data(struct hostapd_data *hapd)
{
@@ -479,11 +493,9 @@ static void sta_track_deinit(struct hostapd_iface *iface)
static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
-#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
hostapd_stop_setup_timers(iface);
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
if (iface->current_mode)
acs_cleanup(iface);
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
@@ -524,6 +536,8 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
}
+#ifdef CONFIG_WEP
+
static void hostapd_clear_wep(struct hostapd_data *hapd)
{
if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) {
@@ -552,10 +566,13 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
for (i = 0; i < 4; i++) {
if (hapd->conf->ssid.wep.key[i] &&
- hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
+ hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, 0,
i == hapd->conf->ssid.wep.idx, NULL, 0,
hapd->conf->ssid.wep.key[i],
- hapd->conf->ssid.wep.len[i])) {
+ hapd->conf->ssid.wep.len[i],
+ i == hapd->conf->ssid.wep.idx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX)) {
wpa_printf(MSG_WARNING, "Could not set WEP "
"encryption.");
return -1;
@@ -568,6 +585,8 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
return 0;
}
+#endif /* CONFIG_WEP */
+
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
{
@@ -603,7 +622,9 @@ static void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
{
hostapd_free_stas(hapd);
hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+#ifdef CONFIG_WEP
hostapd_clear_wep(hapd);
+#endif /* CONFIG_WEP */
}
@@ -1158,9 +1179,11 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_set_privacy(hapd, 0);
+#ifdef CONFIG_WEP
hostapd_broadcast_wep_clear(hapd);
if (hostapd_setup_encryption(conf->iface, hapd))
return -1;
+#endif /* CONFIG_WEP */
/*
* Fetch the SSID from the system and use it or,
@@ -1190,8 +1213,14 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
}
+ /*
+ * Short SSID calculation is identical to FCS and it is defined in
+ * IEEE P802.11-REVmd/D3.0, 9.4.2.170.3 (Calculating the Short-SSID).
+ */
+ conf->ssid.short_ssid = crc32(conf->ssid.ssid, conf->ssid.ssid_len);
+
if (!hostapd_drv_none(hapd)) {
- wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
+ wpa_printf(MSG_DEBUG, "Using interface %s with hwaddr " MACSTR
" and ssid \"%s\"",
conf->iface, MAC2STR(hapd->own_addr),
wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len));
@@ -2338,12 +2367,10 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
hostapd_bss_deinit(iface->bss[j]);
}
-#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
hostapd_stop_setup_timers(iface);
eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 016fe3b7..439e7274 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -38,6 +38,10 @@ union wps_event_data;
struct mesh_conf;
#endif /* CONFIG_MESH */
+#ifdef CONFIG_CTRL_IFACE_UDP
+#define CTRL_IFACE_COOKIE_LEN 8
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
struct hostapd_iface;
struct hapd_interfaces {
@@ -72,6 +76,11 @@ struct hapd_interfaces {
#ifdef CONFIG_DPP
struct dpp_global *dpp;
#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+ unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
};
enum hostapd_chan_status {
@@ -395,6 +404,10 @@ struct hostapd_data {
#ifdef CONFIG_SQLITE
sqlite3 *rad_attr_db;
#endif /* CONFIG_SQLITE */
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+ unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
};
@@ -464,9 +477,6 @@ struct hostapd_iface {
u64 drv_flags;
- /* SMPS modes supported by the driver (WPA_DRIVER_SMPS_MODE_*) */
- unsigned int smps_modes;
-
/*
* A bitmap of supported protocols for probe response offload. See
* struct wpa_driver_capa in driver.h
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index ba10752e..f6e69030 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -224,7 +224,6 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
}
-#ifdef CONFIG_IEEE80211N
static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
{
int pri_freq, sec_freq;
@@ -561,26 +560,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 0;
}
- switch (conf & HT_CAP_INFO_SMPS_MASK) {
- case HT_CAP_INFO_SMPS_STATIC:
- if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) {
- wpa_printf(MSG_ERROR,
- "Driver does not support configured HT capability [SMPS-STATIC]");
- return 0;
- }
- break;
- case HT_CAP_INFO_SMPS_DYNAMIC:
- if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) {
- wpa_printf(MSG_ERROR,
- "Driver does not support configured HT capability [SMPS-DYNAMIC]");
- return 0;
- }
- break;
- case HT_CAP_INFO_SMPS_DISABLED:
- default:
- break;
- }
-
if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
!(hw & HT_CAP_INFO_GREEN_FIELD)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
@@ -687,12 +666,9 @@ static int ieee80211ax_supported_he_capab(struct hostapd_iface *iface)
}
#endif /* CONFIG_IEEE80211AX */
-#endif /* CONFIG_IEEE80211N */
-
int hostapd_check_ht_capab(struct hostapd_iface *iface)
{
-#ifdef CONFIG_IEEE80211N
int ret;
if (is_6ghz_freq(iface->freq))
@@ -725,7 +701,6 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
return ret;
if (!ieee80211n_allowed_ht40_channel_pair(iface))
return -1;
-#endif /* CONFIG_IEEE80211N */
return 0;
}
@@ -810,7 +785,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
/* 60 GHz channels 1..6 */
for (i = 0; i < 6; i++) {
- int freq = 56160 + 2160 * i;
+ int freq = 56160 + 2160 * (i + 1);
if (edmg.channels & BIT(i)) {
contiguous++;
@@ -879,10 +854,11 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
if (!iface->conf->secondary_channel)
return 1;
+ if (hostapd_is_usable_chan(iface, iface->freq +
+ iface->conf->secondary_channel * 20, 0))
+ return 1;
if (!iface->conf->ht40_plus_minus_allowed)
- return hostapd_is_usable_chan(
- iface,
- iface->freq + iface->conf->secondary_channel * 20, 0);
+ return 0;
/* Both HT40+ and HT40- are set, pick a valid secondary channel */
secondary_freq = iface->freq + 20;
@@ -903,10 +879,43 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
}
+static void hostapd_determine_mode(struct hostapd_iface *iface)
+{
+ int i;
+ enum hostapd_hw_mode target_mode;
+
+ if (iface->current_mode ||
+ iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
+ return;
+
+ if (iface->freq < 4000)
+ target_mode = HOSTAPD_MODE_IEEE80211G;
+ else if (iface->freq > 50000)
+ target_mode = HOSTAPD_MODE_IEEE80211AD;
+ else
+ target_mode = HOSTAPD_MODE_IEEE80211A;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ struct hostapd_hw_modes *mode;
+
+ mode = &iface->hw_features[i];
+ if (mode->mode == target_mode) {
+ iface->current_mode = mode;
+ iface->conf->hw_mode = mode->mode;
+ break;
+ }
+ }
+
+ if (!iface->current_mode)
+ wpa_printf(MSG_ERROR, "ACS: Cannot decide mode");
+}
+
+
static enum hostapd_chan_status
hostapd_check_chans(struct hostapd_iface *iface)
{
if (iface->freq) {
+ hostapd_determine_mode(iface);
if (hostapd_is_usable_chans(iface))
return HOSTAPD_CHAN_VALID;
else
@@ -1032,9 +1041,15 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
}
if (iface->current_mode == NULL) {
- if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) ||
- !(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY))
- {
+ if ((iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
+ (iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY)) {
+ wpa_printf(MSG_DEBUG,
+ "Using offloaded hw_mode=any ACS");
+ } else if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
+ iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211ANY) {
+ wpa_printf(MSG_DEBUG,
+ "Using internal ACS for hw_mode=any");
+ } else {
wpa_printf(MSG_ERROR,
"Hardware does not support configured mode");
hostapd_logger(iface->bss[0], NULL,
@@ -1109,3 +1124,20 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
}
return 0;
}
+
+
+int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode)
+{
+ int i;
+
+ if (iface->current_mode)
+ return mode != iface->current_mode;
+ if (mode->mode != HOSTAPD_MODE_IEEE80211B)
+ return 0;
+ for (i = 0; i < iface->num_hw_features; i++) {
+ if (iface->hw_features[i].mode == HOSTAPD_MODE_IEEE80211G)
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index 902a19f9..dd24f95b 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -25,6 +25,8 @@ 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);
+int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode);
#else /* NEED_AP_MLME */
static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@@ -49,7 +51,7 @@ static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
static inline const char * hostapd_hw_mode_txt(int mode)
{
- return NULL;
+ return "UNKNOWN";
}
static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
@@ -77,6 +79,12 @@ static inline void hostapd_stop_setup_timers(struct hostapd_iface *iface)
{
}
+static inline int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode)
+{
+ return 0;
+}
+
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 5b704255..e54217ce 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -88,6 +88,7 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
int i, num, count;
+ int h2e_required;
if (hapd->iface->current_rates == NULL)
return eid;
@@ -98,8 +99,11 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
num++;
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
num++;
- if (hapd->conf->sae_pwe == 1 &&
- wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt))
+ h2e_required = (hapd->conf->sae_pwe == 1 ||
+ hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
+ hapd->conf->sae_pwe != 3 &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
+ if (h2e_required)
num++;
if (num > 8) {
/* rest of the rates are encoded in Extended supported
@@ -127,9 +131,7 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
}
- if (hapd->conf->sae_pwe == 1 &&
- wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
- count < 8) {
+ if (h2e_required && count < 8) {
count++;
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
}
@@ -142,6 +144,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
int i, num, count;
+ int h2e_required;
if (hapd->iface->current_rates == NULL)
return eid;
@@ -151,8 +154,11 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
num++;
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
num++;
- if (hapd->conf->sae_pwe == 1 &&
- wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt))
+ h2e_required = (hapd->conf->sae_pwe == 1 ||
+ hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
+ hapd->conf->sae_pwe != 3 &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
+ if (h2e_required)
num++;
if (num <= 8)
return eid;
@@ -183,8 +189,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
}
- if (hapd->conf->sae_pwe == 1 &&
- wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt)) {
+ if (h2e_required) {
count++;
if (count > 8)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
@@ -194,10 +199,31 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
}
+u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
+ size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
+ if (hapd->conf->radio_measurements[i])
+ break;
+ }
+
+ if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
+ return eid;
+
+ *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
+ *eid++ = RRM_CAPABILITIES_IE_LEN;
+ os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
+
+ return eid + RRM_CAPABILITIES_IE_LEN;
+}
+
+
u16 hostapd_own_capab_info(struct hostapd_data *hapd)
{
int capab = WLAN_CAPABILITY_ESS;
- int privacy;
+ int privacy = 0;
int dfs;
int i;
@@ -213,12 +239,14 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
hapd->iconf->preamble == SHORT_PREAMBLE)
capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
+#ifdef CONFIG_WEP
privacy = hapd->conf->ssid.wep.keys_set;
if (hapd->conf->ieee802_1x &&
(hapd->conf->default_wep_key_len ||
hapd->conf->individual_wep_key_len))
privacy = 1;
+#endif /* CONFIG_WEP */
if (hapd->conf->wpa)
privacy = 1;
@@ -258,6 +286,7 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
}
+#ifdef CONFIG_WEP
#ifndef CONFIG_NO_RC4
static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
u16 auth_transaction, const u8 *challenge,
@@ -314,9 +343,10 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
return 0;
}
#endif /* CONFIG_NO_RC4 */
+#endif /* CONFIG_WEP */
-static int send_auth_reply(struct hostapd_data *hapd,
+static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *dst, const u8 *bssid,
u16 auth_alg, u16 auth_transaction, u16 resp,
const u8 *ies, size_t ies_len, const char *dbg)
@@ -349,7 +379,37 @@ static int send_auth_reply(struct hostapd_data *hapd,
" auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
MAC2STR(dst), auth_alg, auth_transaction,
resp, (unsigned long) ies_len, dbg);
- if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_SAE
+ if (hapd->conf->sae_confirm_immediate == 2 &&
+ auth_alg == WLAN_AUTH_SAE) {
+ if (auth_transaction == 1 && sta &&
+ (resp == WLAN_STATUS_SUCCESS ||
+ resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT)) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Postpone SAE Commit transmission until Confirm is ready");
+ os_free(sta->sae_postponed_commit);
+ sta->sae_postponed_commit = buf;
+ sta->sae_postponed_commit_len = rlen;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (auth_transaction == 2 && sta && sta->sae_postponed_commit) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm");
+ if (hostapd_drv_send_mlme(hapd,
+ sta->sae_postponed_commit,
+ sta->sae_postponed_commit_len,
+ 0, NULL, 0, 0) < 0)
+ wpa_printf(MSG_INFO, "send_auth_reply: send failed");
+ os_free(sta->sae_postponed_commit);
+ sta->sae_postponed_commit = NULL;
+ sta->sae_postponed_commit_len = 0;
+ }
+ }
+#endif /* CONFIG_SAE */
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_INFO, "send_auth_reply: send failed");
else
reply_res = WLAN_STATUS_SUCCESS;
@@ -369,7 +429,7 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
struct sta_info *sta;
int reply_res;
- reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT,
+ reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT,
auth_transaction, status, ies, ies_len,
"auth-ft-finish");
@@ -423,7 +483,9 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
use_pt = sta->sae->tmp->h2e;
}
- if (status_code == WLAN_STATUS_SUCCESS)
+ if (rx_id && hapd->conf->sae_pwe != 3)
+ use_pt = 1;
+ else if (status_code == WLAN_STATUS_SUCCESS)
use_pt = 0;
else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
use_pt = 1;
@@ -474,10 +536,13 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
(rx_id ? 3 + os_strlen(rx_id) : 0));
- if (buf == NULL)
- return NULL;
- sae_write_commit(sta->sae, buf, sta->sae->tmp ?
- sta->sae->tmp->anti_clogging_token : NULL, rx_id);
+ if (buf &&
+ sae_write_commit(sta->sae, buf, sta->sae->tmp ?
+ sta->sae->tmp->anti_clogging_token : NULL,
+ rx_id) < 0) {
+ wpabuf_free(buf);
+ buf = NULL;
+ }
return buf;
}
@@ -514,7 +579,8 @@ static int auth_sae_send_commit(struct hostapd_data *hapd,
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,
+ reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
+ WLAN_AUTH_SAE, 1,
status, wpabuf_head(data),
wpabuf_len(data), "sae-send-commit");
@@ -535,7 +601,8 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd,
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
+ reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
+ WLAN_AUTH_SAE, 2,
WLAN_STATUS_SUCCESS, wpabuf_head(data),
wpabuf_len(data), "sae-send-confirm");
@@ -575,13 +642,15 @@ static int use_sae_anti_clogging(struct hostapd_data *hapd)
}
-static u8 sae_token_hash(struct hostapd_data *hapd, const u8 *addr)
+static int sae_token_hash(struct hostapd_data *hapd, const u8 *addr, u8 *idx)
{
u8 hash[SHA256_MAC_LEN];
- hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
- addr, ETH_ALEN, hash);
- return hash[0];
+ if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ addr, ETH_ALEN, hash) < 0)
+ return -1;
+ *idx = hash[0];
+ return 0;
}
@@ -594,9 +663,8 @@ static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
u16 token_idx;
u8 idx;
- if (token_len != SHA256_MAC_LEN)
+ if (token_len != SHA256_MAC_LEN || sae_token_hash(hapd, addr, &idx) < 0)
return -1;
- idx = sae_token_hash(hapd, addr);
token_idx = hapd->sae_pending_token_idx[idx];
if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from "
@@ -621,7 +689,7 @@ static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
- int group, const u8 *addr)
+ int group, const u8 *addr, int h2e)
{
struct wpabuf *buf;
u8 *token;
@@ -647,13 +715,23 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
sizeof(hapd->sae_pending_token_idx));
}
- buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN);
+ buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
if (buf == NULL)
return NULL;
wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
- p_idx = sae_token_hash(hapd, addr);
+ if (h2e) {
+ /* Encapsulate Anti-clogging Token field in a container IE */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
+ }
+
+ if (sae_token_hash(hapd, addr, &p_idx) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
token_idx = hapd->sae_pending_token_idx[p_idx];
if (!token_idx) {
hapd->sae_token_idx++;
@@ -795,6 +873,9 @@ void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
mlme_authenticate_indication(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
+ crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
+ sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
+ sta->sae->peer_commit_scalar = NULL;
wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
sta->sae->pmk, sta->sae->pmkid);
sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
@@ -1028,11 +1109,20 @@ static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
{
- return (hapd->conf->sae_pwe == 0 &&
+ int sae_pwe = hapd->conf->sae_pwe;
+ int id_in_use;
+
+ id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
+ if (id_in_use == 2 && sae_pwe != 3)
+ sae_pwe = 1;
+ else if (id_in_use == 1 && sae_pwe == 0)
+ sae_pwe = 2;
+
+ return ((sae_pwe == 0 || sae_pwe == 3) &&
status_code == WLAN_STATUS_SUCCESS) ||
- (hapd->conf->sae_pwe == 1 &&
+ (sae_pwe == 1 &&
status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) ||
- (hapd->conf->sae_pwe == 2 &&
+ (sae_pwe == 2 &&
(status_code == WLAN_STATUS_SUCCESS ||
status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT));
}
@@ -1103,7 +1193,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
pos = mgmt->u.auth.variable;
end = ((const u8 *) mgmt) + len;
- send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp, pos, end - pos,
"auth-sae-reflection-attack");
goto remove_sta;
@@ -1111,7 +1201,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
if (hapd->conf->sae_commit_override && auth_transaction == 1) {
wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
- send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp,
wpabuf_head(hapd->conf->sae_commit_override),
wpabuf_len(hapd->conf->sae_commit_override),
@@ -1286,11 +1376,17 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
}
if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
+ int h2e = 0;
+
wpa_printf(MSG_DEBUG,
"SAE: Request anti-clogging token from "
MACSTR, MAC2STR(sta->addr));
+ if (sta->sae->tmp)
+ h2e = sta->sae->tmp->h2e;
+ if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+ h2e = 1;
data = auth_build_token_req(hapd, sta->sae->group,
- sta->addr);
+ sta->addr, h2e);
resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
if (hapd->conf->mesh & MESH_ENABLED)
sae_set_state(sta, SAE_NOTHING,
@@ -1365,7 +1461,7 @@ reply:
data = wpabuf_alloc_copy(pos, 2);
sae_sme_send_external_auth_status(hapd, sta, resp);
- send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp,
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0, "auth-sae");
@@ -1515,27 +1611,37 @@ static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
#endif /* CONFIG_SAE */
-static u16 wpa_res_to_status_code(int res)
+static u16 wpa_res_to_status_code(enum wpa_validate_result res)
{
- if (res == WPA_INVALID_GROUP)
+ switch (res) {
+ case WPA_IE_OK:
+ return WLAN_STATUS_SUCCESS;
+ case WPA_INVALID_IE:
+ return WLAN_STATUS_INVALID_IE;
+ case WPA_INVALID_GROUP:
return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
- if (res == WPA_INVALID_PAIRWISE)
+ case WPA_INVALID_PAIRWISE:
return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
- if (res == WPA_INVALID_AKMP)
+ case WPA_INVALID_AKMP:
return WLAN_STATUS_AKMP_NOT_VALID;
- if (res == WPA_ALLOC_FAIL)
+ case WPA_NOT_ENABLED:
+ return WLAN_STATUS_INVALID_IE;
+ case WPA_ALLOC_FAIL:
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
+ case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
- if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
+ case WPA_INVALID_MGMT_GROUP_CIPHER:
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
- if (res == WPA_INVALID_MDIE)
+ case WPA_INVALID_MDIE:
return WLAN_STATUS_INVALID_MDIE;
- if (res == WPA_INVALID_PMKID)
- return WLAN_STATUS_INVALID_PMKID;
- if (res != WPA_IE_OK)
+ case WPA_INVALID_PROTO:
return WLAN_STATUS_INVALID_IE;
- return WLAN_STATUS_SUCCESS;
+ case WPA_INVALID_PMKID:
+ return WLAN_STATUS_INVALID_PMKID;
+ case WPA_DENIED_OTHER_REASON:
+ return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ }
+ return WLAN_STATUS_INVALID_IE;
}
@@ -1555,7 +1661,7 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
u16 resp = WLAN_STATUS_SUCCESS;
const u8 *end;
struct ieee802_11_elems elems;
- int res;
+ enum wpa_validate_result res;
struct wpa_ie_data rsn;
struct rsn_pmksa_cache_entry *pmksa = NULL;
@@ -1731,11 +1837,11 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
FILS_SESSION_LEN);
os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
- /* FILS Wrapped Data */
- if (elems.fils_wrapped_data) {
+ /* Wrapped Data */
+ if (elems.wrapped_data) {
wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
- elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
+ elems.wrapped_data,
+ elems.wrapped_data_len);
if (!pmksa) {
#ifndef CONFIG_NO_RADIUS
if (!sta->eapol_sm) {
@@ -1745,8 +1851,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG,
"FILS: Forward EAP-Initiate/Re-auth to authentication server");
ieee802_1x_encapsulate_radius(
- hapd, sta, elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
+ hapd, sta, elems.wrapped_data,
+ elems.wrapped_data_len);
sta->fils_pending_cb = cb;
wpa_printf(MSG_DEBUG,
"FILS: Will send Authentication frame once the response from authentication server is available");
@@ -1755,8 +1861,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
* to maintain a copy of the EAP-Initiate/Reauth
* message. */
if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
- elems.fils_wrapped_data,
- elems.fils_wrapped_data_len,
+ elems.wrapped_data,
+ elems.wrapped_data_len,
sta->fils_erp_pmkid) == 0)
sta->fils_erp_pmkid_set = 1;
return;
@@ -1899,12 +2005,12 @@ prepare_auth_resp_fils(struct hostapd_data *hapd,
wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
- /* FILS Wrapped Data */
+ /* Wrapped Data */
if (!pmksa && erp_resp) {
wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
/* Element ID Extension */
- wpabuf_put_u8(data, WLAN_EID_EXT_FILS_WRAPPED_DATA);
+ wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
wpabuf_put_buf(data, erp_resp);
if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
@@ -2006,7 +2112,7 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
auth_alg = (pub ||
resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
- send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp,
+ send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0, "auth-fils-finish");
wpabuf_free(data);
@@ -2050,28 +2156,18 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
#endif /* CONFIG_FILS */
-int
-ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
- const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui, int is_probe_req)
+static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *msg, size_t len,
+ struct radius_sta *info)
{
int res;
- os_memset(vlan_id, 0, sizeof(*vlan_id));
- res = hostapd_allowed_address(hapd, addr, msg, len,
- session_timeout, acct_interim_interval,
- vlan_id, psk, identity, radius_cui,
- is_probe_req);
+ res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
if (res == HOSTAPD_ACL_REJECT) {
- if (!is_probe_req)
- wpa_printf(MSG_DEBUG,
- "Station " MACSTR
- " not allowed to authenticate",
- MAC2STR(addr));
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not allowed to authenticate",
+ MAC2STR(addr));
return HOSTAPD_ACL_REJECT;
}
@@ -2091,12 +2187,15 @@ ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
static int
ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
- int res, u32 session_timeout,
- u32 acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui)
+ int res, struct radius_sta *info)
{
+ u32 session_timeout = info->session_timeout;
+ u32 acct_interim_interval = info->acct_interim_interval;
+ struct vlan_description *vlan_id = &info->vlan_id;
+ struct hostapd_sta_wpa_psk_short *psk = info->psk;
+ char *identity = info->identity;
+ char *radius_cui = info->radius_cui;
+
if (vlan_id->notempty &&
!hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
@@ -2113,20 +2212,22 @@ ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
hostapd_free_psk_list(sta->psk);
- if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
- sta->psk = *psk;
- *psk = NULL;
- } else {
+ if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
+ hostapd_copy_psk_list(&sta->psk, psk);
+ else
sta->psk = NULL;
- }
os_free(sta->identity);
- sta->identity = *identity;
- *identity = NULL;
+ if (identity)
+ sta->identity = os_strdup(identity);
+ else
+ sta->identity = NULL;
os_free(sta->radius_cui);
- sta->radius_cui = *radius_cui;
- *radius_cui = NULL;
+ if (radius_cui)
+ sta->radius_cui = os_strdup(radius_cui);
+ else
+ sta->radius_cui = NULL;
if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
sta->acct_interim_interval = acct_interim_interval;
@@ -2154,14 +2255,10 @@ static void handle_auth(struct hostapd_data *hapd,
int res, reply_res;
u16 fc;
const u8 *challenge = NULL;
- u32 session_timeout, acct_interim_interval;
- struct vlan_description vlan_id;
- struct hostapd_sta_wpa_psk_short *psk = NULL;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0;
- char *identity = NULL;
- char *radius_cui = NULL;
u16 seq_ctrl;
+ struct radius_sta rad_info;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
@@ -2312,10 +2409,8 @@ static void handle_auth(struct hostapd_data *hapd,
}
}
- res = ieee802_11_allowed_address(
- hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout,
- &acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui,
- 0);
+ res = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
+ &rad_info);
if (res == HOSTAPD_ACL_REJECT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Ignore Authentication frame from " MACSTR
@@ -2398,9 +2493,7 @@ static void handle_auth(struct hostapd_data *hapd,
sta->auth_rssi = rssi;
#endif /* CONFIG_MBO */
- res = ieee802_11_set_radius_info(
- hapd, sta, res, session_timeout, acct_interim_interval,
- &vlan_id, &psk, &identity, &radius_cui);
+ res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
if (res) {
wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2471,6 +2564,7 @@ static void handle_auth(struct hostapd_data *hapd,
sta->auth_alg = WLAN_AUTH_OPEN;
mlme_authenticate_indication(hapd, sta);
break;
+#ifdef CONFIG_WEP
#ifndef CONFIG_NO_RC4
case WLAN_AUTH_SHARED_KEY:
resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
@@ -2489,6 +2583,7 @@ static void handle_auth(struct hostapd_data *hapd,
}
break;
#endif /* CONFIG_NO_RC4 */
+#endif /* CONFIG_WEP */
#ifdef CONFIG_IEEE80211R_AP
case WLAN_AUTH_FT:
sta->auth_alg = WLAN_AUTH_FT;
@@ -2542,11 +2637,7 @@ static void handle_auth(struct hostapd_data *hapd,
}
fail:
- os_free(identity);
- os_free(radius_cui);
- hostapd_free_psk_list(psk);
-
- reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
+ reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg,
auth_transaction + 1, resp, resp_ies,
resp_ies_len, "handle-auth");
@@ -2963,7 +3054,7 @@ u16 owe_process_rsn_ie(struct hostapd_data *hapd,
u16 status;
u8 *owe_buf, ie[256 * 2];
size_t ie_len = 0;
- int res;
+ enum wpa_validate_result res;
if (!rsn_ie || rsn_ie_len < 2) {
wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
@@ -3068,7 +3159,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (resp != WLAN_STATUS_SUCCESS)
return resp;
-#ifdef CONFIG_IEEE80211N
resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@@ -3079,7 +3169,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
"mandatory HT PHY - reject association");
return WLAN_STATUS_ASSOC_DENIED_NO_HT;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac) {
@@ -3176,7 +3265,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
}
if (hapd->conf->wpa && wpa_ie) {
- int res;
+ enum wpa_validate_result res;
+
wpa_ie -= 2;
wpa_ie_len += 2;
if (sta->wpa_sm == NULL)
@@ -3324,7 +3414,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
pfs_fail:
#endif /* CONFIG_DPP2 */
-#ifdef CONFIG_IEEE80211N
if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
hostapd_logger(hapd, sta->addr,
@@ -3334,7 +3423,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
"association");
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_HS20
} else if (hapd->conf->osen) {
if (elems.osen == NULL) {
@@ -3479,7 +3567,7 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
reply.u.deauth.reason_code = host_to_le16(reason_code);
- if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_INFO, "Failed to send deauth: %s",
strerror(errno));
}
@@ -3535,10 +3623,8 @@ static int add_associated_sta(struct hostapd_data *hapd,
sta->ft_over_ds = 0;
}
-#ifdef CONFIG_IEEE80211N
if (sta->flags & WLAN_STA_HT)
hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (sta->flags & WLAN_STA_VHT)
hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
@@ -3586,7 +3672,8 @@ static int add_associated_sta(struct hostapd_data *hapd,
static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 status_code, int reassoc,
- const u8 *ies, size_t ies_len, int rssi)
+ const u8 *ies, size_t ies_len, int rssi,
+ int omit_rsnxe)
{
int send_len;
u8 *buf;
@@ -3637,6 +3724,9 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
/* Extended supported rates */
p = hostapd_eid_ext_supp_rates(hapd, p);
+ /* Radio measurement capabilities */
+ p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
+
#ifdef CONFIG_MBO
if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
rssi != 0) {
@@ -3653,7 +3743,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
* Transition Information, RSN, [RIC Response] */
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
buf + buflen - p,
- sta->auth_alg, ies, ies_len);
+ sta->auth_alg, ies, ies_len,
+ omit_rsnxe);
if (!p) {
wpa_printf(MSG_DEBUG,
"FT: Failed to write AssocResp IEs");
@@ -3683,10 +3774,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
-#ifdef CONFIG_IEEE80211N
p = hostapd_eid_ht_capabilities(hapd, p);
p = hostapd_eid_ht_operation(hapd, p);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
@@ -3734,7 +3823,23 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_FST */
- p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->rsnxe_override_ft &&
+ buf + buflen - p >=
+ (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
+ sta && sta->auth_alg == WLAN_AUTH_FT) {
+ wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
+ os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
+ wpabuf_len(hapd->conf->rsnxe_override_ft));
+ p += wpabuf_len(hapd->conf->rsnxe_override_ft);
+ goto rsnxe_done;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!omit_rsnxe)
+ p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
+#ifdef CONFIG_TESTING_OPTIONS
+rsnxe_done:
+#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_OWE
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
@@ -3865,7 +3970,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_FILS */
- if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
strerror(errno));
res = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -3880,12 +3985,12 @@ done:
#ifdef CONFIG_OWE
u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *owe_dh, u8 owe_dh_len,
- u8 *owe_buf, size_t owe_buf_len, u16 *reason)
+ u8 *owe_buf, size_t owe_buf_len, u16 *status)
{
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->conf->own_ie_override) {
wpa_printf(MSG_DEBUG, "OWE: Using IE override");
- *reason = WLAN_STATUS_SUCCESS;
+ *status = WLAN_STATUS_SUCCESS;
return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
owe_buf_len, NULL, 0);
}
@@ -3895,18 +4000,18 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
owe_buf_len, NULL, 0);
- *reason = WLAN_STATUS_SUCCESS;
+ *status = WLAN_STATUS_SUCCESS;
return owe_buf;
}
if (sta->owe_pmk && sta->external_dh_updated) {
wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
- *reason = WLAN_STATUS_SUCCESS;
+ *status = WLAN_STATUS_SUCCESS;
return owe_buf;
}
- *reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
- if (*reason != WLAN_STATUS_SUCCESS)
+ *status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
+ if (*status != WLAN_STATUS_SUCCESS)
return NULL;
owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
@@ -3917,7 +4022,7 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
if (!pub) {
- *reason = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ *status = WLAN_STATUS_UNSPECIFIED_FAILURE;
return owe_buf;
}
@@ -3952,7 +4057,7 @@ void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
sta->fils_pending_assoc_is_reassoc,
sta->fils_pending_assoc_req,
- sta->fils_pending_assoc_req_len, 0);
+ sta->fils_pending_assoc_req_len, 0, 0);
os_free(sta->fils_pending_assoc_req);
sta->fils_pending_assoc_req = NULL;
sta->fils_pending_assoc_req_len = 0;
@@ -3997,12 +4102,10 @@ static void handle_assoc(struct hostapd_data *hapd,
int left, i;
struct sta_info *sta;
u8 *tmp = NULL;
- struct hostapd_sta_wpa_psk_short *psk = NULL;
- char *identity = NULL;
- char *radius_cui = NULL;
#ifdef CONFIG_FILS
int delay_assoc = 0;
#endif /* CONFIG_FILS */
+ int omit_rsnxe = 0;
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
sizeof(mgmt->u.assoc_req))) {
@@ -4079,13 +4182,11 @@ static void handle_assoc(struct hostapd_data *hapd,
hapd->iface->current_mode->mode ==
HOSTAPD_MODE_IEEE80211AD) {
int acl_res;
- u32 session_timeout, acct_interim_interval;
- struct vlan_description vlan_id;
+ struct radius_sta info;
- acl_res = ieee802_11_allowed_address(
- hapd, mgmt->sa, (const u8 *) mgmt, len,
- &session_timeout, &acct_interim_interval,
- &vlan_id, &psk, &identity, &radius_cui, 0);
+ acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
+ (const u8 *) mgmt,
+ len, &info);
if (acl_res == HOSTAPD_ACL_REJECT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Ignore Association Request frame from "
@@ -4110,9 +4211,7 @@ static void handle_assoc(struct hostapd_data *hapd,
}
acl_res = ieee802_11_set_radius_info(
- hapd, sta, acl_res, session_timeout,
- acct_interim_interval, &vlan_id, &psk,
- &identity, &radius_cui);
+ hapd, sta, acl_res, &info);
if (acl_res) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
@@ -4219,6 +4318,7 @@ static void handle_assoc(struct hostapd_data *hapd,
resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
if (resp != WLAN_STATUS_SUCCESS)
goto fail;
+ omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
if (hostapd_get_aid(hapd, sta) < 0) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -4271,9 +4371,7 @@ static void handle_assoc(struct hostapd_data *hapd,
ieee802_11_set_beacons(hapd->iface);
}
-#ifdef CONFIG_IEEE80211N
update_ht_state(hapd, sta);
-#endif /* CONFIG_IEEE80211N */
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -4313,9 +4411,6 @@ static void handle_assoc(struct hostapd_data *hapd,
#endif /* CONFIG_FILS */
fail:
- os_free(identity);
- os_free(radius_cui);
- hostapd_free_psk_list(psk);
/*
* In case of a successful response, add the station to the driver.
@@ -4377,7 +4472,7 @@ static void handle_assoc(struct hostapd_data *hapd,
#endif /* CONFIG_FILS */
reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
- left, rssi);
+ left, rssi, omit_rsnxe);
os_free(tmp);
/*
@@ -4418,6 +4513,7 @@ static void handle_disassoc(struct hostapd_data *hapd,
ap_sta_set_authorized(hapd, sta, 0);
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disassociated");
@@ -4484,6 +4580,7 @@ static void handle_deauth(struct hostapd_data *hapd,
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
WLAN_STA_ASSOC_REQ_OK);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "deauthenticated");
@@ -4615,14 +4712,12 @@ static int handle_action(struct hostapd_data *hapd,
#endif /* CONFIG_FST */
case WLAN_ACTION_PUBLIC:
case WLAN_ACTION_PROTECTED_DUAL:
-#ifdef CONFIG_IEEE80211N
if (len >= IEEE80211_HDRLEN + 2 &&
mgmt->u.action.u.public_action.action ==
WLAN_PA_20_40_BSS_COEX) {
hostapd_2040_coex_action(hapd, mgmt, len);
return 1;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_DPP
if (len >= IEEE80211_HDRLEN + 6 &&
mgmt->u.action.u.vs_public_action.action ==
@@ -4705,7 +4800,7 @@ static int handle_action(struct hostapd_data *hapd,
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
resp->u.action.category |= 0x80;
- if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
"Action frame");
}
@@ -4903,6 +4998,7 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
struct sta_info *sta,
char *ifname_wds)
{
+#ifdef CONFIG_WEP
int i;
struct hostapd_ssid *ssid = &hapd->conf->ssid;
@@ -4912,14 +5008,18 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
for (i = 0; i < 4; i++) {
if (ssid->wep.key[i] &&
hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
- i == ssid->wep.idx, NULL, 0,
- ssid->wep.key[i], ssid->wep.len[i])) {
+ 0, i == ssid->wep.idx, NULL, 0,
+ ssid->wep.key[i], ssid->wep.len[i],
+ i == ssid->wep.idx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX)) {
wpa_printf(MSG_WARNING,
"Could not set WEP keys for WDS interface; %s",
ifname_wds);
break;
}
}
+#endif /* CONFIG_WEP */
}
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index f592da54..c7bdb4b2 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -16,8 +16,7 @@ struct hostapd_frame_info;
struct ieee80211_ht_capabilities;
struct ieee80211_vht_capabilities;
struct ieee80211_mgmt;
-struct vlan_description;
-struct hostapd_sta_wpa_psk_short;
+struct radius_sta;
enum ieee80211_op_mode;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
@@ -50,9 +49,10 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
+ size_t len);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
@@ -95,6 +95,8 @@ u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
enum ieee80211_op_mode opmode, const u8 *he_capab,
size_t he_capab_len);
+int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
+ enum ieee80211_op_mode mode);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
@@ -162,7 +164,7 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
const u8 *msk, size_t msk_len);
u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *owe_dh, u8 owe_dh_len,
- u8 *owe_buf, size_t owe_buf_len, u16 *reason);
+ u8 *owe_buf, size_t owe_buf_len, u16 *status);
u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *rsn_ie, size_t rsn_ie_len,
const u8 *owe_dh, size_t owe_dh_len);
@@ -180,13 +182,9 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd);
u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, size_t len);
-int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
- const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui,
- int is_probe_req);
+
+size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd);
+u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len);
int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
int ap_seg1_idx, int *bandwidth, int *seg1_idx);
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 931d4d06..783ee6de 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -32,12 +32,7 @@ struct hostapd_cached_radius_acl {
macaddr addr;
int accepted; /* HOSTAPD_ACL_* */
struct hostapd_cached_radius_acl *next;
- u32 session_timeout;
- u32 acct_interim_interval;
- struct vlan_description vlan_id;
- struct hostapd_sta_wpa_psk_short *psk;
- char *identity;
- char *radius_cui;
+ struct radius_sta info;
};
@@ -54,9 +49,9 @@ struct hostapd_acl_query_data {
#ifndef CONFIG_NO_RADIUS
static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
{
- os_free(e->identity);
- os_free(e->radius_cui);
- hostapd_free_psk_list(e->psk);
+ os_free(e->info.identity);
+ os_free(e->info.radius_cui);
+ hostapd_free_psk_list(e->info.psk);
os_free(e);
}
@@ -73,25 +68,8 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
}
-static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
- struct hostapd_sta_wpa_psk_short *src)
-{
- if (!psk)
- return;
-
- if (src)
- src->ref++;
-
- *psk = src;
-}
-
-
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
- u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui)
+ struct radius_sta *out)
{
struct hostapd_cached_radius_acl *entry;
struct os_reltime now;
@@ -105,27 +83,8 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
if (os_reltime_expired(&now, &entry->timestamp,
RADIUS_ACL_TIMEOUT))
return -1; /* entry has expired */
- if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
- if (session_timeout)
- *session_timeout = entry->session_timeout;
- if (acct_interim_interval)
- *acct_interim_interval =
- entry->acct_interim_interval;
- if (vlan_id)
- *vlan_id = entry->vlan_id;
- copy_psk_list(psk, entry->psk);
- if (identity) {
- if (entry->identity)
- *identity = os_strdup(entry->identity);
- else
- *identity = NULL;
- }
- if (radius_cui) {
- if (entry->radius_cui)
- *radius_cui = os_strdup(entry->radius_cui);
- else
- *radius_cui = NULL;
- }
+ *out = entry->info;
+
return entry->accepted;
}
@@ -238,42 +197,28 @@ int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
* @addr: MAC address of the STA
* @msg: Authentication message
* @len: Length of msg in octets
- * @session_timeout: Buffer for returning session timeout (from RADIUS)
- * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
- * @vlan_id: Buffer for returning VLAN ID
- * @psk: Linked list buffer for returning WPA PSK
- * @identity: Buffer for returning identity (from RADIUS)
- * @radius_cui: Buffer for returning CUI (from RADIUS)
+ * @out.session_timeout: Buffer for returning session timeout (from RADIUS)
+ * @out.acct_interim_interval: Buffer for returning account interval (from
+ * RADIUS)
+ * @out.vlan_id: Buffer for returning VLAN ID
+ * @out.psk: Linked list buffer for returning WPA PSK
+ * @out.identity: Buffer for returning identity (from RADIUS)
+ * @out.radius_cui: Buffer for returning CUI (from RADIUS)
* @is_probe_req: Whether this query for a Probe Request frame
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
*
- * The caller is responsible for freeing the returned *identity and *radius_cui
- * values with os_free().
+ * The caller is responsible for properly cloning the returned out->identity and
+ * out->radius_cui and out->psk values.
*/
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
- const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui,
+ const u8 *msg, size_t len, struct radius_sta *out,
int is_probe_req)
{
int res;
- if (session_timeout)
- *session_timeout = 0;
- if (acct_interim_interval)
- *acct_interim_interval = 0;
- if (vlan_id)
- os_memset(vlan_id, 0, sizeof(*vlan_id));
- if (psk)
- *psk = NULL;
- if (identity)
- *identity = NULL;
- if (radius_cui)
- *radius_cui = NULL;
-
- res = hostapd_check_acl(hapd, addr, vlan_id);
+ os_memset(out, 0, sizeof(*out));
+
+ res = hostapd_check_acl(hapd, addr, &out->vlan_id);
if (res != HOSTAPD_ACL_PENDING)
return res;
@@ -290,12 +235,10 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
};
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
- vlan_id = NULL;
+ os_memset(&out->vlan_id, 0, sizeof(out->vlan_id));
/* Check whether ACL cache has an entry for this station */
- res = hostapd_acl_cache_get(hapd, addr, session_timeout,
- acct_interim_interval, vlan_id, psk,
- identity, radius_cui);
+ res = hostapd_acl_cache_get(hapd, addr, out);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
return res;
@@ -307,14 +250,6 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
/* pending query in RADIUS retransmit queue;
* do not generate a new one */
- if (identity) {
- os_free(*identity);
- *identity = NULL;
- }
- if (radius_cui) {
- os_free(*radius_cui);
- *radius_cui = NULL;
- }
return HOSTAPD_ACL_PENDING;
}
query = query->next;
@@ -488,8 +423,8 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
passphraselen);
psk->is_passphrase = 1;
}
- psk->next = cache->psk;
- cache->psk = psk;
+ psk->next = cache->info.psk;
+ cache->info.psk = psk;
psk = NULL;
}
skip:
@@ -518,6 +453,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_data *hapd = data;
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
+ struct radius_sta *info;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
query = hapd->acl_queries;
@@ -555,65 +491,66 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
}
os_get_reltime(&cache->timestamp);
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
+ info = &cache->info;
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
u8 *buf;
size_t len;
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
- &cache->session_timeout) == 0)
+ &info->session_timeout) == 0)
cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
else
cache->accepted = HOSTAPD_ACL_ACCEPT;
if (radius_msg_get_attr_int32(
msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
- &cache->acct_interim_interval) == 0 &&
- cache->acct_interim_interval < 60) {
+ &info->acct_interim_interval) == 0 &&
+ info->acct_interim_interval < 60) {
wpa_printf(MSG_DEBUG, "Ignored too small "
"Acct-Interim-Interval %d for STA " MACSTR,
- cache->acct_interim_interval,
+ info->acct_interim_interval,
MAC2STR(query->addr));
- cache->acct_interim_interval = 0;
+ info->acct_interim_interval = 0;
}
if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED)
- cache->vlan_id.notempty = !!radius_msg_get_vlanid(
- msg, &cache->vlan_id.untagged,
- MAX_NUM_TAGGED_VLAN, cache->vlan_id.tagged);
+ info->vlan_id.notempty = !!radius_msg_get_vlanid(
+ msg, &info->vlan_id.untagged,
+ MAX_NUM_TAGGED_VLAN, info->vlan_id.tagged);
decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
msg, req, cache);
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
&buf, &len, NULL) == 0) {
- cache->identity = os_zalloc(len + 1);
- if (cache->identity)
- os_memcpy(cache->identity, buf, len);
+ info->identity = os_zalloc(len + 1);
+ if (info->identity)
+ os_memcpy(info->identity, buf, len);
}
if (radius_msg_get_attr_ptr(
msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
&buf, &len, NULL) == 0) {
- cache->radius_cui = os_zalloc(len + 1);
- if (cache->radius_cui)
- os_memcpy(cache->radius_cui, buf, len);
+ info->radius_cui = os_zalloc(len + 1);
+ if (info->radius_cui)
+ os_memcpy(info->radius_cui, buf, len);
}
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
- !cache->psk)
+ !info->psk)
cache->accepted = HOSTAPD_ACL_REJECT;
- if (cache->vlan_id.notempty &&
- !hostapd_vlan_valid(hapd->conf->vlan, &cache->vlan_id)) {
+ if (info->vlan_id.notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, &info->vlan_id)) {
hostapd_logger(hapd, query->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Invalid VLAN %d%s received from RADIUS server",
- cache->vlan_id.untagged,
- cache->vlan_id.tagged[0] ? "+" : "");
- os_memset(&cache->vlan_id, 0, sizeof(cache->vlan_id));
+ info->vlan_id.untagged,
+ info->vlan_id.tagged[0] ? "+" : "");
+ os_memset(&info->vlan_id, 0, sizeof(info->vlan_id));
}
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
- !cache->vlan_id.notempty)
+ !info->vlan_id.notempty)
cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
@@ -622,7 +559,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
#ifdef CONFIG_DRIVER_RADIUS_ACL
hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
- cache->session_timeout);
+ info->session_timeout);
#else /* CONFIG_DRIVER_RADIUS_ACL */
#ifdef NEED_AP_MLME
/* Re-send original authentication frame for 802.11 processing */
@@ -685,6 +622,19 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
}
+void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+ struct hostapd_sta_wpa_psk_short *src)
+{
+ if (!psk)
+ return;
+
+ if (src)
+ src->ref++;
+
+ *psk = src;
+}
+
+
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
{
if (psk && psk->ref) {
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index 5aece518..9410f55c 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -16,18 +16,25 @@ enum {
HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
};
+struct radius_sta {
+ u32 session_timeout;
+ u32 acct_interim_interval;
+ struct vlan_description vlan_id;
+ struct hostapd_sta_wpa_psk_short *psk;
+ char *identity;
+ char *radius_cui;
+};
+
int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
struct vlan_description *vlan_id);
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
- const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui,
+ const u8 *msg, size_t len, struct radius_sta *out,
int is_probe_req);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
void hostapd_acl_expire(struct hostapd_data *hapd);
+void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+ struct hostapd_sta_wpa_psk_short *src);
#endif /* IEEE802_11_AUTH_H */
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index abd39409..57c6b18f 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -192,9 +192,12 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
params |= (hapd->iface->conf->he_op.he_rts_threshold <<
HE_OPERATION_RTS_THRESHOLD_OFFSET);
- if (hapd->iface->conf->he_op.he_bss_color)
- params |= (hapd->iface->conf->he_op.he_bss_color <<
- HE_OPERATION_BSS_COLOR_OFFSET);
+ if (hapd->iface->conf->he_op.he_bss_color_disabled)
+ params |= HE_OPERATION_BSS_COLOR_DISABLED;
+ if (hapd->iface->conf->he_op.he_bss_color_partial)
+ params |= HE_OPERATION_BSS_COLOR_PARTIAL;
+ params |= hapd->iface->conf->he_op.he_bss_color <<
+ HE_OPERATION_BSS_COLOR_OFFSET;
/* HE minimum required basic MCS and NSS for STAs */
oper->he_mcs_nss_set =
@@ -206,17 +209,25 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
if (is_6ghz_op_class(hapd->iconf->op_class)) {
u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
+ u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
if (!seg0)
seg0 = hapd->iconf->channel;
params |= HE_OPERATION_6GHZ_OPER_INFO;
+
+ /* 6 GHz Operation Information field */
*pos++ = hapd->iconf->channel; /* Primary Channel */
- *pos++ = center_idx_to_bw_6ghz(seg0); /* Control: Channel Width
- */
- /* Channel Center Freq Seg0/Seg0 */
+
+ /* Control: Channel Width */
+ if (seg1)
+ *pos++ = 3;
+ else
+ *pos++ = center_idx_to_bw_6ghz(seg0);
+
+ /* Channel Center Freq Seg0/Seg1 */
*pos++ = seg0;
- *pos++ = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
+ *pos++ = seg1;
/* Minimum Rate */
*pos++ = 6; /* TODO: what should be set here? */
}
@@ -402,3 +413,18 @@ u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_SUCCESS;
}
+
+
+int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
+ enum ieee80211_op_mode mode)
+{
+ u8 *mac_cap;
+
+ if (!hapd->iface->current_mode ||
+ !hapd->iface->current_mode->he_capab[mode].he_supported)
+ return 0;
+
+ mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap;
+
+ return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER);
+}
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 6db93658..59ecbdce 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -109,33 +109,9 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
}
-u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
-{
- u8 sec_ch;
-
- if (!hapd->cs_freq_params.channel ||
- !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)
- sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
- else if (hapd->cs_freq_params.sec_channel_offset == 1)
- sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
- else
- return eid;
-
- *eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
- *eid++ = 1;
- *eid++ = sec_ch;
-
- return eid;
-}
-
-
/*
op_mode
-Set to 0 (HT pure) under the followign conditions
+Set to 0 (HT pure) under the following conditions
- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
Set to 1 (HT non-member protection) if there may be non-HT STAs
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 1e1cc382..113b4ef0 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -112,7 +112,8 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
end += oci_ie_len;
}
#endif /* CONFIG_OCV */
- if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0, NULL, 0, 0)
+ < 0)
wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
os_free(mgmt);
@@ -193,7 +194,8 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
end += oci_ie_len;
}
#endif /* CONFIG_OCV */
- if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0, NULL, 0, 0)
+ < 0)
wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
os_free(resp);
@@ -375,6 +377,11 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
*pos |= 0x01;
#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax &&
+ hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
+ *pos |= 0x40; /* Bit 78 - TWT responder */
+#endif /* CONFIG_IEEE80211AX */
break;
case 10: /* Bits 80-87 */
#ifdef CONFIG_SAE
@@ -390,6 +397,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
* Identifiers Used Exclusively */
}
#endif /* CONFIG_SAE */
+ if (hapd->conf->beacon_prot)
+ *pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
break;
}
}
@@ -438,12 +447,19 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
!wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
len = 10;
#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211AX
+ if (len < 10 && hapd->iconf->ieee80211ax &&
+ hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
+ len = 10;
+#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_SAE
if (len < 11 && hapd->conf->wpa &&
wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
hostapd_sae_pw_id_in_use(hapd->conf))
len = 11;
#endif /* CONFIG_SAE */
+ if (len < 11 && hapd->conf->beacon_prot)
+ len = 11;
if (len < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len;
if (len == 0)
@@ -858,6 +874,36 @@ u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid,
}
+size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_DPP2
+ if (hapd->conf->dpp_configurator_connectivity)
+ return 6;
+#endif /* CONFIG_DPP2 */
+ return 0;
+}
+
+
+u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+#ifdef CONFIG_DPP2
+ u8 *pos = eid;
+
+ if (!hapd->conf->dpp_configurator_connectivity || len < 6)
+ return pos;
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4;
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ *pos++ = DPP_CC_OUI_TYPE;
+
+ return pos;
+#endif /* CONFIG_DPP2 */
+ return eid;
+}
+
+
void ap_copy_sta_supp_op_classes(struct sta_info *sta,
const u8 *supp_op_classes,
size_t supp_op_classes_len)
@@ -1012,7 +1058,9 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
!wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) ||
- (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2) ||
+ (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2 &&
+ !hostapd_sae_pw_id_in_use(hapd->conf)) ||
+ hapd->conf->sae_pwe == 3 ||
len < 3)
return pos;
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index d0810310..6d4d4355 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -137,6 +137,7 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
}
+#ifdef CONFIG_WEP
#ifndef CONFIG_FIPS
#ifndef CONFIG_NO_RC4
@@ -284,8 +285,9 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
/* TODO: set encryption in TX callback, i.e., only after STA
* has ACKed EAPOL-Key frame */
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)) {
+ sta->addr, 0, 0, 1, NULL, 0, ikey,
+ hapd->conf->individual_wep_key_len,
+ KEY_FLAG_PAIRWISE_RX_TX)) {
wpa_printf(MSG_ERROR,
"Could not set individual WEP encryption");
}
@@ -296,6 +298,7 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
#endif /* CONFIG_NO_RC4 */
#endif /* CONFIG_FIPS */
+#endif /* CONFIG_WEP */
const char *radius_mode_txt(struct hostapd_data *hapd)
@@ -2113,6 +2116,8 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
}
+#ifdef CONFIG_WEP
+
static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
{
struct eapol_authenticator *eapol = hapd->eapol_auth;
@@ -2177,9 +2182,10 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
* after new broadcast key has been sent to all stations. */
if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
broadcast_ether_addr,
- eapol->default_wep_key_idx, 1, NULL, 0,
+ eapol->default_wep_key_idx, 0, 1, NULL, 0,
eapol->default_wep_key,
- hapd->conf->default_wep_key_len)) {
+ hapd->conf->default_wep_key_len,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_WARNING,
"failed to configure a new broadcast key");
@@ -2196,6 +2202,8 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
}
}
+#endif /* CONFIG_WEP */
+
static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
const u8 *data, size_t datalen)
@@ -2359,6 +2367,7 @@ static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx)
}
+#ifdef CONFIG_WEP
static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
{
#ifndef CONFIG_FIPS
@@ -2370,6 +2379,7 @@ static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
#endif /* CONFIG_NO_RC4 */
#endif /* CONFIG_FIPS */
}
+#endif /* CONFIG_WEP */
static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
@@ -2420,7 +2430,6 @@ static int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
int ieee802_1x_init(struct hostapd_data *hapd)
{
- int i;
struct eapol_auth_config conf;
struct eapol_auth_cb cb;
@@ -2431,7 +2440,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
conf.ctx = hapd;
conf.eap_reauth_period = hapd->conf->eap_reauth_period;
conf.wpa = hapd->conf->wpa;
+#ifdef CONFIG_WEP
conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
+#endif /* CONFIG_WEP */
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;
@@ -2446,7 +2457,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
cb.logger = ieee802_1x_logger;
cb.set_port_authorized = ieee802_1x_set_port_authorized;
cb.abort_auth = _ieee802_1x_abort_auth;
+#ifdef CONFIG_WEP
cb.tx_key = _ieee802_1x_tx_key;
+#endif /* CONFIG_WEP */
cb.eapol_event = ieee802_1x_eapol_event;
#ifdef CONFIG_ERP
cb.erp_get_key = ieee802_1x_erp_get_key;
@@ -2467,17 +2480,21 @@ int ieee802_1x_init(struct hostapd_data *hapd)
return -1;
#endif /* CONFIG_NO_RADIUS */
+#ifdef CONFIG_WEP
if (hapd->conf->default_wep_key_len) {
+ int i;
+
for (i = 0; i < 4; i++)
hostapd_drv_set_key(hapd->conf->iface, hapd,
- WPA_ALG_NONE, NULL, i, 0, NULL, 0,
- NULL, 0);
+ WPA_ALG_NONE, NULL, i, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_GROUP);
ieee802_1x_rekey(hapd, NULL);
if (!hapd->eapol_auth->default_wep_key)
return -1;
}
+#endif /* CONFIG_WEP */
return 0;
}
@@ -2497,7 +2514,9 @@ void ieee802_1x_erp_flush(struct hostapd_data *hapd)
void ieee802_1x_deinit(struct hostapd_data *hapd)
{
+#ifdef CONFIG_WEP
eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
+#endif /* CONFIG_WEP */
if (hapd->driver && hapd->drv_priv &&
(hapd->conf->ieee802_1x || hapd->conf->wpa))
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index 4012ae4c..01bf8862 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -256,6 +256,8 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
if (vht)
bssid_info |= NEI_REP_BSSID_INFO_VHT;
+ if (he)
+ bssid_info |= NEI_REP_BSSID_INFO_HE;
}
/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 15e2c494..fe5f8171 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -516,6 +516,11 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
for (entry = pmksa->pmksa; entry; entry = entry->next) {
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
continue;
+ if (wpa_key_mgmt_sae(entry->akmp)) {
+ if (os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
+ return entry;
+ continue;
+ }
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
entry->akmp);
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index cbb8752e..903be28d 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -164,6 +164,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
/* just in case */
ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_set_sta_flags(hapd, sta);
if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
@@ -233,9 +234,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
sta->assoc_ie_taxonomy = NULL;
#endif /* CONFIG_TAXONOMY */
-#ifdef CONFIG_IEEE80211N
ht40_intolerant_remove(hapd->iface, sta);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_P2P
if (sta->no_p2p_set) {
@@ -246,10 +245,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
}
#endif /* CONFIG_P2P */
-#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
+#ifdef NEED_AP_MLME
if (hostapd_ht_operation_update(hapd->iface) > 0)
set_beacon++;
-#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
+#endif /* NEED_AP_MLME */
#ifdef CONFIG_MESH
if (hapd->mesh_sta_free_cb)
@@ -373,6 +372,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->ifname_wds);
+#ifdef CONFIG_TESTING_OPTIONS
+ os_free(sta->sae_postponed_commit);
+#endif /* CONFIG_TESTING_OPTIONS */
+
os_free(sta);
}
@@ -542,6 +545,7 @@ skip_poll:
case STA_DISASSOC_FROM_CLI:
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~WLAN_STA_ASSOC;
+ hostapd_set_sta_flags(hapd, sta);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
if (!sta->acct_terminate_cause)
sta->acct_terminate_cause =
@@ -586,7 +590,8 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
- if (!(sta->flags & WLAN_STA_AUTH)) {
+ if (!(sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC |
+ WLAN_STA_AUTHORIZED))) {
if (sta->flags & WLAN_STA_GAS) {
wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
"entry " MACSTR, MAC2STR(sta->addr));
@@ -809,6 +814,7 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
sta->timeout_next = STA_DEAUTH;
}
ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_set_sta_flags(hapd, sta);
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DISASSOC)",
@@ -859,6 +865,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_set_sta_flags(hapd, sta);
sta->timeout_next = STA_REMOVE;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
@@ -1024,6 +1031,13 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
int ret;
int old_vlanid = sta->vlan_id_bound;
+ if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) {
+ wpa_printf(MSG_DEBUG,
+ "Do not override WDS VLAN assignment for STA "
+ MACSTR, MAC2STR(sta->addr));
+ return 0;
+ }
+
iface = hapd->conf->iface;
if (hapd->conf->ssid.vlan[0])
iface = hapd->conf->ssid.vlan;
@@ -1045,7 +1059,8 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
if (sta->vlan_id == old_vlanid)
goto skip_counting;
- if (sta->vlan_id > 0 && vlan == NULL) {
+ if (sta->vlan_id > 0 && !vlan &&
+ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
"binding station to (vlan_id=%d)",
@@ -1129,6 +1144,8 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
if (sta->sa_query_count > 0 &&
ap_check_sa_query_timeout(hapd, sta))
return;
+ if (sta->sa_query_count >= 1000)
+ return;
nbuf = os_realloc_array(sta->sa_query_trans_id,
sta->sa_query_count + 1,
@@ -1316,9 +1333,10 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
if (sta == NULL)
return;
ap_sta_set_authorized(hapd, sta, 0);
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DEAUTH)",
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index de806b48..8ff6ac62 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -276,6 +276,8 @@ struct sta_info {
int last_tk_key_idx;
u8 last_tk[WPA_TK_MAX_LEN];
size_t last_tk_len;
+ u8 *sae_postponed_commit;
+ size_t sae_postponed_commit_len;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_AIRTIME_POLICY
unsigned int airtime_weight;
diff --git a/src/ap/utils.c b/src/ap/utils.c
index fcb371be..bedad6eb 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -56,6 +56,10 @@ static int prune_associations(struct hostapd_iface *iface, void *ctx)
ohapd = iface->bss[j];
if (ohapd == data->hapd)
continue;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (ohapd->conf->skip_prune_assoc)
+ continue;
+#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_FST
/* Don't prune STAs belong to same FST */
if (ohapd->iface->fst &&
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index e293a003..53eacfb4 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -22,7 +22,9 @@
static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
int existsok)
{
- int ret, i;
+ int ret;
+#ifdef CONFIG_WEP
+ int i;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (!hapd->conf->ssid.wep.key[i])
@@ -32,6 +34,7 @@ static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
vlan->ifname);
return -1;
}
+#endif /* CONFIG_WEP */
if (!iface_exists(vlan->ifname))
ret = hostapd_vlan_if_add(hapd, vlan->ifname);
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index 9f52dee3..9ebb01e3 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -111,9 +111,11 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
u8 *pos = eid;
struct wmm_parameter_element *wmm =
(struct wmm_parameter_element *) (pos + 2);
- struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM] = { 0 };
+ struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM];
int e;
+ os_memset(wmmp, 0, sizeof(wmmp));
+
if (!hapd->conf->wmm_enabled)
return eid;
wmm_calc_regulatory_limit(hapd, wmmp);
@@ -209,7 +211,7 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
len = ((u8 *) (t + 1)) - buf;
- if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, m, len, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_INFO, "wmm_send_action: send failed");
}
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index e4dcfe9e..67281b38 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -54,6 +54,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
size_t len;
size_t gtk_elem_len = 0;
size_t igtk_elem_len = 0;
+ size_t bigtk_elem_len = 0;
struct wnm_sleep_element wnmsleep_ie;
u8 *wnmtfs_ie, *oci_ie;
u8 wnmsleep_ie_len, oci_ie_len;
@@ -122,8 +123,10 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
#define MAX_GTK_SUBELEM_LEN 45
#define MAX_IGTK_SUBELEM_LEN 26
+#define MAX_BIGTK_SUBELEM_LEN 26
mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
+ MAX_BIGTK_SUBELEM_LEN +
oci_ie_len);
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
@@ -157,10 +160,19 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
pos += igtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
(int) igtk_elem_len);
+ if (hapd->conf->beacon_prot) {
+ res = wpa_wnmsleep_bigtk_subelem(sta->wpa_sm, pos);
+ if (res < 0)
+ goto fail;
+ bigtk_elem_len = res;
+ pos += bigtk_elem_len;
+ wpa_printf(MSG_DEBUG, "Pass 4 bigtk_len = %d",
+ (int) bigtk_elem_len);
+ }
WPA_PUT_LE16((u8 *)
&mgmt->u.action.u.wnm_sleep_resp.keydata_len,
- gtk_elem_len + igtk_elem_len);
+ gtk_elem_len + igtk_elem_len + bigtk_elem_len);
}
os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
/* copy TFS IE here */
@@ -176,7 +188,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
#endif /* CONFIG_OCV */
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
- igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
+ igtk_elem_len + bigtk_elem_len +
+ wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
/* In driver, response frame should be forced to sent when STA is in
* PS mode */
@@ -189,8 +202,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
/* when entering wnmsleep
* 1. pause the node in driver
- * 2. mark the node so that AP won't update GTK/IGTK during
- * WNM Sleep
+ * 2. mark the node so that AP won't update GTK/IGTK/BIGTK
+ * during WNM Sleep
*/
if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
@@ -201,7 +214,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
}
/* when exiting wnmsleep
* 1. unmark the node
- * 2. start GTK/IGTK update if MFP is not used
+ * 2. start GTK/IGTK/BIGTK update if MFP is not used
* 3. unpause the node in driver
*/
if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT ||
@@ -221,6 +234,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
#undef MAX_GTK_SUBELEM_LEN
#undef MAX_IGTK_SUBELEM_LEN
+#undef MAX_BIGTK_SUBELEM_LEN
fail:
os_free(wnmtfs_ie);
os_free(oci_ie);
@@ -508,6 +522,30 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
}
+static void wnm_beacon_protection_failure(struct hostapd_data *hapd,
+ const u8 *addr)
+{
+ struct sta_info *sta;
+
+ if (!hapd->conf->beacon_prot)
+ return;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for received WNM-Notification Request",
+ MAC2STR(addr));
+ return;
+ }
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Beacon protection failure reported");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_UNPROT_BEACON "reporter="
+ MACSTR, MAC2STR(addr));
+}
+
+
static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *buf,
size_t len)
@@ -526,8 +564,14 @@ static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
MAC2STR(addr), dialog_token, type);
wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements",
buf, len);
- if (type == WLAN_EID_VENDOR_SPECIFIC)
+ switch (type) {
+ case WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE:
+ wnm_beacon_protection_failure(hapd, addr);
+ break;
+ case WNM_NOTIF_TYPE_VENDOR_SPECIFIC:
mbo_ap_wnm_notification_req(hapd, addr, buf, len);
+ break;
+ }
}
@@ -641,7 +685,7 @@ int wnm_send_disassoc_imminent(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to "
MACSTR, disassoc_timer, MAC2STR(sta->addr));
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
"Management Request frame");
return -1;
@@ -714,7 +758,7 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
os_memcpy(pos, url, url_len);
pos += url_len;
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
"Management Request frame");
return -1;
@@ -790,7 +834,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
mbo_len);
}
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG,
"Failed to send BSS Transition Management Request frame");
os_free(buf);
@@ -834,7 +878,7 @@ int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "WNM: Sending Collocated Interference Request to "
MACSTR " (dialog_token=%u auto_report=%u timeout=%u)",
MAC2STR(sta->addr), dialog_token, auto_report, timeout);
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG,
"WNM: Failed to send Collocated Interference Request frame");
return -1;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 6611b0e5..e0ffb271 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -56,13 +56,14 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, unsigned int pmk_len,
- struct wpa_ptk *ptk);
+ struct wpa_ptk *ptk, int force_sha256);
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_put(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
+static int ieee80211w_kde_len(struct wpa_state_machine *sm);
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
static const u32 eapol_key_timeout_first = 100; /* ms */
@@ -105,7 +106,7 @@ static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
const u8 *addr, wpa_eapol_variable var)
{
- if (wpa_auth->cb->get_eapol == NULL)
+ if (!wpa_auth->cb->get_eapol)
return -1;
return wpa_auth->cb->get_eapol(wpa_auth->cb_ctx, addr, var);
}
@@ -117,7 +118,7 @@ static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
const u8 *prev_psk, size_t *psk_len,
int *vlan_id)
{
- if (wpa_auth->cb->get_psk == NULL)
+ if (!wpa_auth->cb->get_psk)
return NULL;
return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
prev_psk, psk_len, vlan_id);
@@ -127,7 +128,7 @@ static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
const u8 *addr, u8 *msk, size_t *len)
{
- if (wpa_auth->cb->get_msk == NULL)
+ if (!wpa_auth->cb->get_msk)
return -1;
return wpa_auth->cb->get_msk(wpa_auth->cb_ctx, addr, msk, len);
}
@@ -136,21 +137,46 @@ static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
int vlan_id,
enum wpa_alg alg, const u8 *addr, int idx,
- u8 *key, size_t key_len)
+ u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
- if (wpa_auth->cb->set_key == NULL)
+ if (!wpa_auth->cb->set_key)
return -1;
return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
- key, key_len);
+ key, key_len, key_flag);
}
static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
const u8 *addr, int idx, u8 *seq)
{
- if (wpa_auth->cb->get_seqnum == NULL)
+ int res;
+
+ if (!wpa_auth->cb->get_seqnum)
return -1;
- return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
+ res = wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!addr && idx < 4 && wpa_auth->conf.gtk_rsc_override_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Override GTK RSC %016llx --> %016llx",
+ (long long unsigned) WPA_GET_LE64(seq),
+ (long long unsigned)
+ WPA_GET_LE64(wpa_auth->conf.gtk_rsc_override));
+ os_memcpy(seq, wpa_auth->conf.gtk_rsc_override,
+ WPA_KEY_RSC_LEN);
+ }
+ if (!addr && idx >= 4 && idx <= 5 &&
+ wpa_auth->conf.igtk_rsc_override_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Override IGTK RSC %016llx --> %016llx",
+ (long long unsigned) WPA_GET_LE64(seq),
+ (long long unsigned)
+ WPA_GET_LE64(wpa_auth->conf.igtk_rsc_override));
+ os_memcpy(seq, wpa_auth->conf.igtk_rsc_override,
+ WPA_KEY_RSC_LEN);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ return res;
}
@@ -158,7 +184,7 @@ static inline int
wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *data, size_t data_len, int encrypt)
{
- if (wpa_auth->cb->send_eapol == NULL)
+ if (!wpa_auth->cb->send_eapol)
return -1;
return wpa_auth->cb->send_eapol(wpa_auth->cb_ctx, addr, data, data_len,
encrypt);
@@ -169,7 +195,7 @@ wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth,
const u8 *addr)
{
- if (wpa_auth->cb->start_ampe == NULL)
+ if (!wpa_auth->cb->start_ampe)
return -1;
return wpa_auth->cb->start_ampe(wpa_auth->cb_ctx, addr);
}
@@ -180,7 +206,7 @@ int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_state_machine *sm, void *ctx),
void *cb_ctx)
{
- if (wpa_auth->cb->for_each_sta == NULL)
+ if (!wpa_auth->cb->for_each_sta)
return 0;
return wpa_auth->cb->for_each_sta(wpa_auth->cb_ctx, cb, cb_ctx);
}
@@ -190,7 +216,7 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_authenticator *a, void *ctx),
void *cb_ctx)
{
- if (wpa_auth->cb->for_each_auth == NULL)
+ if (!wpa_auth->cb->for_each_auth)
return 0;
return wpa_auth->cb->for_each_auth(wpa_auth->cb_ctx, cb, cb_ctx);
}
@@ -199,7 +225,7 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt)
{
- if (wpa_auth->cb->logger == NULL)
+ if (!wpa_auth->cb->logger)
return;
wpa_auth->cb->logger(wpa_auth->cb_ctx, addr, level, txt);
}
@@ -212,7 +238,7 @@ void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
int maxlen;
va_list ap;
- if (wpa_auth->cb->logger == NULL)
+ if (!wpa_auth->cb->logger)
return;
maxlen = os_strlen(fmt) + 100;
@@ -233,7 +259,7 @@ void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
const u8 *addr, u16 reason)
{
- if (wpa_auth->cb->disconnect == NULL)
+ if (!wpa_auth->cb->disconnect)
return;
wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR " (reason %u)",
MAC2STR(addr), reason);
@@ -266,8 +292,8 @@ static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
struct wpa_authenticator *wpa_auth = eloop_ctx;
if (random_get_bytes(wpa_auth->group->GMK, WPA_GMK_LEN)) {
- wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
- "initialization.");
+ wpa_printf(MSG_ERROR,
+ "Failed to get random data for WPA initialization.");
} else {
wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd");
wpa_hexdump_key(MSG_DEBUG, "GMK",
@@ -391,7 +417,7 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
struct wpa_group *group;
group = os_zalloc(sizeof(struct wpa_group));
- if (group == NULL)
+ if (!group)
return NULL;
group->GTKAuthenticator = TRUE;
@@ -399,9 +425,8 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
if (random_pool_ready() != 1) {
- wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
- "for secure operations - update keys later when "
- "the first station connects");
+ wpa_printf(MSG_INFO,
+ "WPA: Not enough entropy in random pool for secure operations - update keys later when the first station connects");
}
/*
@@ -411,16 +436,16 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
* on embedded devices.
*/
if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0) {
- wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
- "initialization.");
+ wpa_printf(MSG_ERROR,
+ "Failed to get random data for WPA initialization.");
os_free(group);
return NULL;
}
group->GInit = TRUE;
if (delay_init) {
- wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start "
- "until Beacon frames have been configured");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Delay group state machine start until Beacon frames have been configured");
/* Initialization is completed in wpa_init_keys(). */
} else {
wpa_group_sm_step(wpa_auth, group);
@@ -447,7 +472,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
struct wpa_authenticator *wpa_auth;
wpa_auth = os_zalloc(sizeof(struct wpa_authenticator));
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return NULL;
os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
@@ -461,7 +486,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
}
wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
- if (wpa_auth->group == NULL) {
+ if (!wpa_auth->group) {
os_free(wpa_auth->wpa_ie);
os_free(wpa_auth);
return NULL;
@@ -469,7 +494,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb,
wpa_auth);
- if (wpa_auth->pmksa == NULL) {
+ if (!wpa_auth->pmksa) {
wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
os_free(wpa_auth->group);
os_free(wpa_auth->wpa_ie);
@@ -479,7 +504,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
#ifdef CONFIG_IEEE80211R_AP
wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
- if (wpa_auth->ft_pmk_cache == NULL) {
+ if (!wpa_auth->ft_pmk_cache) {
wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
os_free(wpa_auth->group);
os_free(wpa_auth->wpa_ie);
@@ -518,8 +543,8 @@ int wpa_init_keys(struct wpa_authenticator *wpa_auth)
{
struct wpa_group *group = wpa_auth->group;
- wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial "
- "keys");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Start group state machine to set initial keys");
wpa_group_sm_step(wpa_auth, group);
group->GInit = FALSE;
wpa_group_sm_step(wpa_auth, group);
@@ -575,7 +600,8 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_auth_config *conf)
{
struct wpa_group *group;
- if (wpa_auth == NULL)
+
+ if (!wpa_auth)
return 0;
os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
@@ -609,7 +635,7 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
return NULL;
sm = os_zalloc(sizeof(struct wpa_state_machine));
- if (sm == NULL)
+ if (!sm)
return NULL;
os_memcpy(sm->addr, addr, ETH_ALEN);
if (p2p_dev_addr)
@@ -626,14 +652,13 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm)
{
- if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+ if (!wpa_auth || !wpa_auth->conf.wpa || !sm)
return -1;
#ifdef CONFIG_IEEE80211R_AP
if (sm->ft_completed) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "FT authentication already completed - do not "
- "start 4-way handshake");
+ "FT authentication already completed - do not start 4-way handshake");
/* Go to PTKINITDONE state to allow GTK rekeying */
sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
sm->Pair = TRUE;
@@ -676,7 +701,7 @@ void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
/* WPA/RSN was not used - clear WPA state. This is needed if the STA
* reassociates back to the same AP while the previous entry for the
* STA has not yet been removed. */
- if (sm == NULL)
+ if (!sm)
return;
sm->wpa_key_mgmt = 0;
@@ -688,8 +713,9 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
#ifdef CONFIG_P2P
if (WPA_GET_BE32(sm->ip_addr)) {
u32 start;
- wpa_printf(MSG_DEBUG, "P2P: Free assigned IP "
- "address %u.%u.%u.%u from " MACSTR,
+ wpa_printf(MSG_DEBUG,
+ "P2P: Free assigned IP address %u.%u.%u.%u from "
+ MACSTR,
sm->ip_addr[0], sm->ip_addr[1],
sm->ip_addr[2], sm->ip_addr[3],
MAC2STR(sm->addr));
@@ -719,31 +745,34 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ struct wpa_authenticator *wpa_auth;
+
+ if (!sm)
return;
- if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "strict rekeying - force GTK rekey since STA "
- "is leaving");
+ wpa_auth = sm->wpa_auth;
+ if (wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "strict rekeying - force GTK rekey since STA is leaving");
if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk,
- sm->wpa_auth, NULL) == -1)
- eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
- NULL);
+ wpa_auth, NULL) == -1)
+ eloop_register_timeout(0, 500000, wpa_rekey_gtk,
+ wpa_auth, NULL);
}
- eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
+ eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
sm->pending_1_of_4_timeout = 0;
eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
- eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+ eloop_cancel_timeout(wpa_rekey_ptk, wpa_auth, sm);
#ifdef CONFIG_IEEE80211R_AP
wpa_ft_sta_deinit(sm);
#endif /* CONFIG_IEEE80211R_AP */
if (sm->in_step_loop) {
/* Must not free state machine while wpa_sm_step() is running.
* Freeing will be completed in the end of wpa_sm_step(). */
- wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state "
- "machine deinit for " MACSTR, MAC2STR(sm->addr));
+ wpa_printf(MSG_DEBUG,
+ "WPA: Registering pending STA state machine deinit for "
+ MACSTR, MAC2STR(sm->addr));
sm->pending_deinit = 1;
} else
wpa_free_sta_sm(sm);
@@ -752,11 +781,23 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
static void wpa_request_new_ptk(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return;
- sm->PTKRequest = TRUE;
- sm->PTK_valid = 0;
+ if (!sm->use_ext_key_id && sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+ wpa_printf(MSG_INFO,
+ "WPA: PTK0 rekey not allowed, disconnect " MACSTR,
+ MAC2STR(sm->addr));
+ sm->Disconnect = TRUE;
+ /* Try to encourage the STA to reconnect */
+ sm->disconnect_reason =
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+ } else {
+ if (sm->use_ext_key_id)
+ sm->keyidx_active ^= 1; /* flip Key ID */
+ sm->PTKRequest = TRUE;
+ sm->PTK_valid = 0;
+ }
}
@@ -781,7 +822,7 @@ static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr,
int i;
for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
if (ctr[i].valid &&
- (replay_counter == NULL ||
+ (!replay_counter ||
os_memcmp(replay_counter, ctr[i].counter,
WPA_REPLAY_COUNTER_LEN) == 0))
ctr[i].valid = FALSE;
@@ -798,9 +839,9 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
struct rsn_mdie *mdie;
if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 ||
- ie.num_pmkid != 1 || ie.pmkid == NULL) {
- wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in "
- "FT 4-way handshake message 2/4");
+ ie.num_pmkid != 1 || !ie.pmkid) {
+ wpa_printf(MSG_DEBUG,
+ "FT: No PMKR1Name in FT 4-way handshake message 2/4");
return -1;
}
@@ -809,8 +850,9 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
sm->sup_pmk_r1_name, PMKID_LEN);
if (!kde->mdie || !kde->ftie) {
- wpa_printf(MSG_DEBUG, "FT: No %s in FT 4-way handshake "
- "message 2/4", kde->mdie ? "FTIE" : "MDIE");
+ wpa_printf(MSG_DEBUG,
+ "FT: No %s in FT 4-way handshake message 2/4",
+ kde->mdie ? "FTIE" : "MDIE");
return -1;
}
@@ -844,18 +886,15 @@ static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
{
/* Supplicant reported a Michael MIC error */
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key Error Request "
- "(STA detected Michael MIC failure (group=%d))",
+ "received EAPOL-Key Error Request (STA detected Michael MIC failure (group=%d))",
group);
if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "ignore Michael MIC failure report since "
- "group cipher is not TKIP");
+ "ignore Michael MIC failure report since group cipher is not TKIP");
} else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "ignore Michael MIC failure report since "
- "pairwise cipher is not TKIP");
+ "ignore Michael MIC failure report since pairwise cipher is not TKIP");
} else {
if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
return 1; /* STA entry was removed */
@@ -888,7 +927,7 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
sm->p2p_dev_addr, pmk, &pmk_len,
&vlan_id);
- if (pmk == NULL)
+ if (!pmk)
break;
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
@@ -901,7 +940,8 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
pmk_len = sm->pmk_len;
}
- if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0)
+ if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0) <
+ 0)
break;
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
@@ -956,7 +996,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
size_t keyhdrlen, mic_len;
u8 *mic;
- if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+ if (!wpa_auth || !wpa_auth->conf.wpa || !sm)
return;
wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL data", data, data_len);
@@ -975,20 +1015,19 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
key_data = mic + mic_len + 2;
key_data_length = WPA_GET_BE16(mic + mic_len);
wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
- " key_info=0x%x type=%u mic_len=%u key_data_length=%u",
+ " key_info=0x%x type=%u mic_len=%zu key_data_length=%u",
MAC2STR(sm->addr), key_info, key->type,
- (unsigned int) mic_len, key_data_length);
+ mic_len, key_data_length);
wpa_hexdump(MSG_MSGDUMP,
"WPA: EAPOL-Key header (ending before Key MIC)",
key, sizeof(*key));
wpa_hexdump(MSG_MSGDUMP, "WPA: EAPOL-Key Key MIC",
mic, mic_len);
if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
- wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
- "key_data overflow (%d > %lu)",
+ wpa_printf(MSG_INFO,
+ "WPA: Invalid EAPOL-Key frame - key_data overflow (%d > %zu)",
key_data_length,
- (unsigned long) (data_len - sizeof(*hdr) -
- keyhdrlen));
+ data_len - sizeof(*hdr) - keyhdrlen);
return;
}
@@ -998,18 +1037,18 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
* Some deployed station implementations seem to send
* msg 4/4 with incorrect type value in WPA2 mode.
*/
- wpa_printf(MSG_DEBUG, "Workaround: Allow EAPOL-Key "
- "with unexpected WPA type in RSN mode");
+ wpa_printf(MSG_DEBUG,
+ "Workaround: Allow EAPOL-Key with unexpected WPA type in RSN mode");
} else if (key->type != EAPOL_KEY_TYPE_RSN) {
- wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
- "unexpected type %d in RSN mode",
+ wpa_printf(MSG_DEBUG,
+ "Ignore EAPOL-Key with unexpected type %d in RSN mode",
key->type);
return;
}
} else {
if (key->type != EAPOL_KEY_TYPE_WPA) {
- wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
- "unexpected type %d in WPA mode",
+ wpa_printf(MSG_DEBUG,
+ "Ignore EAPOL-Key with unexpected type %d in WPA mode",
key->type);
return;
}
@@ -1054,9 +1093,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
- "advertised support for "
- "AES-128-CMAC, but did not "
- "use it");
+ "advertised support for AES-128-CMAC, but did not use it");
return;
}
@@ -1065,8 +1102,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
- "did not use HMAC-SHA1-AES "
- "with CCMP/GCMP");
+ "did not use HMAC-SHA1-AES with CCMP/GCMP");
return;
}
}
@@ -1084,8 +1120,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
os_memcmp(key->replay_counter, sm->req_replay_counter,
WPA_REPLAY_COUNTER_LEN) <= 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
- "received EAPOL-Key request with "
- "replayed counter");
+ "received EAPOL-Key request with replayed counter");
return;
}
}
@@ -1108,9 +1143,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
* even if we have already sent out EAPOL-Key 3/4.
*/
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "Process SNonce update from STA "
- "based on retransmitted EAPOL-Key "
- "1/4");
+ "Process SNonce update from STA based on retransmitted EAPOL-Key 1/4");
sm->update_snonce = 1;
os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN);
sm->alt_snonce_valid = TRUE;
@@ -1139,12 +1172,12 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
key->replay_counter) &&
sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "ignore retransmitted EAPOL-Key %s - "
- "SNonce did not change", msgtxt);
+ "ignore retransmitted EAPOL-Key %s - SNonce did not change",
+ msgtxt);
} else {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "received EAPOL-Key %s with "
- "unexpected replay counter", msgtxt);
+ "received EAPOL-Key %s with unexpected replay counter",
+ msgtxt);
}
for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
if (!sm->key_replay[i].valid)
@@ -1175,8 +1208,7 @@ continue_processing:
(!sm->update_snonce ||
sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key msg 2/4 in "
- "invalid state (%d) - dropped",
+ "received EAPOL-Key msg 2/4 in invalid state (%d) - dropped",
sm->wpa_ptk_state);
return;
}
@@ -1191,9 +1223,8 @@ continue_processing:
* Counter update and the station will be allowed to
* continue.
*/
- wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to "
- "collect more entropy for random number "
- "generation");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Reject 4-way handshake to collect more entropy for random number generation");
random_mark_pool_ready();
wpa_sta_disconnect(wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -1204,8 +1235,7 @@ continue_processing:
if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
!sm->PTK_valid) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key msg 4/4 in "
- "invalid state (%d) - dropped",
+ "received EAPOL-Key msg 4/4 in invalid state (%d) - dropped",
sm->wpa_ptk_state);
return;
}
@@ -1214,8 +1244,7 @@ continue_processing:
if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING
|| !sm->PTK_valid) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key msg 2/2 in "
- "invalid state (%d) - dropped",
+ "received EAPOL-Key msg 2/2 in invalid state (%d) - dropped",
sm->wpa_ptk_group_state);
return;
}
@@ -1294,8 +1323,7 @@ continue_processing:
WPA_REPLAY_COUNTER_LEN);
} else {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key request with "
- "invalid MIC");
+ "received EAPOL-Key request with invalid MIC");
return;
}
@@ -1311,8 +1339,7 @@ continue_processing:
return; /* STA entry was removed */
} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key Request for new "
- "4-Way Handshake");
+ "received EAPOL-Key Request for new 4-Way Handshake");
wpa_request_new_ptk(sm);
} else if (key_data_length > 0 &&
wpa_parse_kde_ies(key_data, key_data_length,
@@ -1320,8 +1347,7 @@ continue_processing:
kde.mac_addr) {
} else {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key Request for GTK "
- "rekeying");
+ "received EAPOL-Key Request for GTK rekeying");
eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
wpa_rekey_gtk(wpa_auth, NULL);
}
@@ -1354,7 +1380,7 @@ continue_processing:
os_free(sm->last_rx_eapol_key);
sm->last_rx_eapol_key = os_memdup(data, data_len);
- if (sm->last_rx_eapol_key == NULL)
+ if (!sm->last_rx_eapol_key)
return;
sm->last_rx_eapol_key_len = data_len;
@@ -1433,6 +1459,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
const u8 *kde, size_t kde_len,
int keyidx, int encr, int force_version)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
size_t len, mic_len, keyhdrlen;
@@ -1461,15 +1488,14 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
pairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
- wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d "
- "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d "
- "encr=%d)",
+ wpa_printf(MSG_DEBUG,
+ "WPA: Send EAPOL(version=%d secure=%d mic=%d ack=%d install=%d pairwise=%d kde_len=%zu keyidx=%d encr=%d)",
version,
(key_info & WPA_KEY_INFO_SECURE) ? 1 : 0,
(key_info & WPA_KEY_INFO_MIC) ? 1 : 0,
(key_info & WPA_KEY_INFO_ACK) ? 1 : 0,
(key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0,
- pairwise, (unsigned long) kde_len, keyidx, encr);
+ pairwise, kde_len, keyidx, encr);
key_data_len = kde_len;
@@ -1487,9 +1513,9 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
len += AES_BLOCK_SIZE;
hdr = os_zalloc(len);
- if (hdr == NULL)
+ if (!hdr)
return;
- hdr->version = wpa_auth->conf.eapol_version;
+ hdr->version = conf->eapol_version;
hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
hdr->length = host_to_be16(len - sizeof(*hdr));
key = (struct wpa_eapol_key *) (hdr + 1);
@@ -1505,7 +1531,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT;
WPA_PUT_BE16(key->key_info, key_info);
- alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
+ alg = pairwise ? sm->pairwise : conf->wpa_group;
if (sm->wpa == WPA_VERSION_WPA2 && !pairwise)
WPA_PUT_BE16(key->key_length, 0);
else
@@ -1559,7 +1585,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_FILS */
} else if (encr && kde) {
buf = os_zalloc(key_data_len);
- if (buf == NULL) {
+ if (!buf) {
os_free(hdr);
return;
}
@@ -1576,8 +1602,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_printf(MSG_DEBUG,
- "WPA: Encrypt Key Data using AES-WRAP (KEK length %u)",
- (unsigned int) sm->PTK.kek_len);
+ "WPA: Encrypt Key Data using AES-WRAP (KEK length %zu)",
+ sm->PTK.kek_len);
if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
(key_data_len - 8) / 8, buf, key_data)) {
os_free(hdr);
@@ -1611,8 +1637,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
if (key_info & WPA_KEY_INFO_MIC) {
if (!sm->PTK_valid || !mic_len) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTK not valid when sending EAPOL-Key "
- "frame");
+ "PTK not valid when sending EAPOL-Key frame");
os_free(hdr);
return;
}
@@ -1625,9 +1650,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
}
#ifdef CONFIG_TESTING_OPTIONS
if (!pairwise &&
- wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
- drand48() <
- wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
+ conf->corrupt_gtk_rekey_mic_probability > 0.0 &&
+ drand48() < conf->corrupt_gtk_rekey_mic_probability) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"Corrupting group EAPOL-Key Key MIC");
key_mic[0]++;
@@ -1635,8 +1659,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_TESTING_OPTIONS */
}
- wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx,
- 1);
+ wpa_auth_set_eapol(wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, 1);
wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len,
sm->pairwise_set);
os_free(hdr);
@@ -1653,7 +1676,7 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
u32 ctr;
- if (sm == NULL)
+ if (!sm)
return;
__wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len,
@@ -1673,8 +1696,9 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
#ifdef TEST_FUZZ
timeout_ms = 1;
#endif /* TEST_FUZZ */
- wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
- "counter %u)", timeout_ms, ctr);
+ wpa_printf(MSG_DEBUG,
+ "WPA: Use EAPOL-Key timeout of %u ms (retry counter %u)",
+ timeout_ms, ctr);
eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
wpa_send_eapol_timeout, wpa_auth, sm);
}
@@ -1714,9 +1738,14 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
sm->PTK_valid = FALSE;
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
- 0))
+ 0, KEY_FLAG_PAIRWISE))
wpa_printf(MSG_DEBUG,
"RSN: PTK removal from the driver failed");
+ if (sm->use_ext_key_id &&
+ wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 1, NULL,
+ 0, KEY_FLAG_PAIRWISE))
+ wpa_printf(MSG_DEBUG,
+ "RSN: PTK Key ID 1 removal from the driver failed");
sm->pairwise_set = FALSE;
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
}
@@ -1726,7 +1755,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
{
int remove_ptk = 1;
- if (sm == NULL)
+ if (!sm)
return -1;
wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
@@ -1766,8 +1795,8 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
* sure that the WPA state machines gets initialized
* properly at this point.
*/
- wpa_printf(MSG_DEBUG, "WPA state machine had not been "
- "started - initialize now");
+ wpa_printf(MSG_DEBUG,
+ "WPA state machine had not been started - initialize now");
sm->started = 1;
sm->Init = TRUE;
if (wpa_sm_step(sm) == 1)
@@ -1776,6 +1805,22 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
sm->AuthenticationRequest = TRUE;
break;
}
+
+ if (!sm->use_ext_key_id &&
+ sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+ wpa_printf(MSG_INFO,
+ "WPA: PTK0 rekey not allowed, disconnect "
+ MACSTR, MAC2STR(sm->addr));
+ sm->Disconnect = TRUE;
+ /* Try to encourage the STA to reconnect */
+ sm->disconnect_reason =
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+ break;
+ }
+
+ if (sm->use_ext_key_id)
+ sm->keyidx_active ^= 1; /* flip Key ID */
+
if (sm->GUpdateStationKeys) {
/*
* Reauthentication cancels the pending group key
@@ -1789,8 +1834,8 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
break;
case WPA_ASSOC_FT:
#ifdef CONFIG_IEEE80211R_AP
- wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration "
- "after association");
+ wpa_printf(MSG_DEBUG,
+ "FT: Retry PTK configuration after association");
wpa_ft_install_ptk(sm);
/* Using FT protocol, not WPA auth state machine */
@@ -1923,11 +1968,11 @@ static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,
* GMK and Counter here to improve their strength if there was not
* enough entropy available immediately after system startup.
*/
- wpa_printf(MSG_DEBUG, "WPA: Re-initialize GMK/Counter on first "
- "station");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Re-initialize GMK/Counter on first station");
if (random_pool_ready() != 1) {
- wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
- "to proceed - reject first 4-way handshake");
+ wpa_printf(MSG_INFO,
+ "WPA: Not enough entropy in random pool to proceed - reject first 4-way handshake");
group->reject_4way_hs_for_entropy = TRUE;
} else {
group->first_sta_seen = TRUE;
@@ -1961,8 +2006,8 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
* stronger protection against potential precomputation attacks.
*/
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
- wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
- "ANonce.");
+ wpa_printf(MSG_ERROR,
+ "WPA: Failed to get random data for ANonce.");
sm->Disconnect = TRUE;
return;
}
@@ -2019,13 +2064,13 @@ SM_STATE(WPA_PTK, INITPMK)
pmk_len = PMK_LEN_SUITE_B_192;
else
pmk_len = PMK_LEN;
- wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
- "(MSK len=%lu PMK len=%u)", (unsigned long) len,
- pmk_len);
+ wpa_printf(MSG_DEBUG,
+ "WPA: PMK from EAPOL state machine (MSK len=%zu PMK len=%u)",
+ len, pmk_len);
if (len < pmk_len) {
wpa_printf(MSG_DEBUG,
- "WPA: MSK not long enough (%u) to create PMK (%u)",
- (unsigned int) len, (unsigned int) pmk_len);
+ "WPA: MSK not long enough (%zu) to create PMK (%u)",
+ len, pmk_len);
sm->Disconnect = TRUE;
return;
}
@@ -2208,10 +2253,11 @@ SM_STATE(WPA_PTK, PTKSTART)
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, unsigned int pmk_len,
- struct wpa_ptk *ptk)
+ struct wpa_ptk *ptk, int force_sha256)
{
const u8 *z = NULL;
size_t z_len = 0;
+ int akmp;
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -2237,9 +2283,12 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
}
#endif /* CONFIG_DPP2 */
+ akmp = sm->wpa_key_mgmt;
+ if (force_sha256)
+ akmp |= WPA_KEY_MGMT_PSK_SHA256;
return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
- ptk, sm->wpa_key_mgmt, sm->pairwise, z, z_len);
+ ptk, akmp, sm->pairwise, z, z_len);
}
@@ -2453,9 +2502,9 @@ int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies,
if (elems.fils_key_confirm_len != sm->fils_key_auth_len) {
wpa_printf(MSG_DEBUG,
- "FILS: Unexpected Key-Auth length %d (expected %d)",
+ "FILS: Unexpected Key-Auth length %d (expected %zu)",
elems.fils_key_confirm_len,
- (int) sm->fils_key_auth_len);
+ sm->fils_key_auth_len);
return -1;
}
@@ -2648,8 +2697,13 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
u8 *gtk, dummy_gtk[32];
size_t gtk_len;
struct wpa_group *gsm;
+ size_t plain_len;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
- plain = wpabuf_alloc(1000);
+ plain_len = 1000 + ieee80211w_kde_len(sm);
+ if (conf->transition_disable)
+ plain_len += 2 + RSN_SELECTOR_LEN + 1;
+ plain = wpabuf_alloc(plain_len);
if (!plain)
return NULL;
@@ -2678,8 +2732,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
/* GTK KDE */
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- if (sm->wpa_auth->conf.disable_gtk ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
@@ -2697,11 +2750,18 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
gtk, gtk_len);
wpabuf_put(plain, tmp2 - tmp);
- /* IGTK KDE */
+ /* IGTK KDE and BIGTK KDE */
tmp = wpabuf_put(plain, 0);
tmp2 = ieee80211w_kde_add(sm, tmp);
wpabuf_put(plain, tmp2 - tmp);
+ if (conf->transition_disable) {
+ tmp = wpabuf_put(plain, 0);
+ tmp2 = wpa_add_kde(tmp, WFA_KEY_DATA_TRANSITION_DISABLE,
+ &conf->transition_disable, 1, NULL, 0);
+ wpabuf_put(plain, tmp2 - tmp);
+ }
+
*len = (u8 *) wpabuf_put(plain, 0) - len - 1;
#ifdef CONFIG_OCV
@@ -2747,7 +2807,7 @@ int fils_set_tk(struct wpa_state_machine *sm)
wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver");
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk, klen)) {
+ sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) {
wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
return -1;
}
@@ -2779,8 +2839,8 @@ u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf,
os_memcpy(pos, wpabuf_head(plain), wpabuf_len(plain));
pos += wpabuf_len(plain);
- wpa_printf(MSG_DEBUG, "%s: plain buf_len: %u", __func__,
- (unsigned int) wpabuf_len(plain));
+ wpa_printf(MSG_DEBUG, "%s: plain buf_len: %zu", __func__,
+ wpabuf_len(plain));
wpabuf_clear_free(plain);
sm->fils_completed = 1;
return pos;
@@ -2819,6 +2879,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
struct wpa_eapol_key *key;
struct wpa_eapol_ie_parse kde;
int vlan_id = 0;
+ int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
sm->EAPOLKeyReceived = FALSE;
@@ -2836,7 +2897,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
sm->p2p_dev_addr, pmk, &pmk_len,
&vlan_id);
- if (pmk == NULL)
+ if (!pmk)
break;
psk_found = 1;
#ifdef CONFIG_IEEE80211R_AP
@@ -2856,7 +2917,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
pmk_len = sm->pmksa->pmk_len;
}
- if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
+ if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK,
+ owe_ptk_workaround == 2) < 0)
break;
if (mic_len &&
@@ -2880,6 +2942,16 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
}
#endif /* CONFIG_FILS */
+#ifdef CONFIG_OWE
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && pmk_len > 32 &&
+ owe_ptk_workaround == 1) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Try PTK derivation workaround with SHA256");
+ owe_ptk_workaround = 2;
+ continue;
+ }
+#endif /* CONFIG_OWE */
+
if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
wpa_key_mgmt_sae(sm->wpa_key_mgmt))
break;
@@ -2922,7 +2994,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
eapol_key_ie_len = kde.wpa_ie_len;
}
ft = sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt);
- if (sm->wpa_ie == NULL ||
+ if (!sm->wpa_ie ||
wpa_compare_rsn_ie(ft, sm->wpa_ie, sm->wpa_ie_len,
eapol_key_ie, eapol_key_ie_len)) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -3016,10 +3088,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
if (os_memcmp_const(sm->sup_pmk_r1_name, sm->pmk_r1_name,
WPA_PMK_NAME_LEN) != 0) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PMKR1Name mismatch in FT 4-way "
- "handshake");
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from "
- "Supplicant",
+ "PMKR1Name mismatch in FT 4-way handshake");
+ wpa_hexdump(MSG_DEBUG,
+ "FT: PMKR1Name from Supplicant",
sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
@@ -3063,22 +3134,29 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
static int ieee80211w_kde_len(struct wpa_state_machine *sm)
{
+ size_t len = 0;
+
if (sm->mgmt_frame_prot) {
- size_t len;
- len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
- return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len;
+ len += 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN;
+ len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+ }
+ if (sm->mgmt_frame_prot && sm->wpa_auth->conf.beacon_prot) {
+ len += 2 + RSN_SELECTOR_LEN + WPA_BIGTK_KDE_PREFIX_LEN;
+ len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
}
- return 0;
+ return len;
}
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
{
struct wpa_igtk_kde igtk;
+ struct wpa_bigtk_kde bigtk;
struct wpa_group *gsm = sm->group;
u8 rsc[WPA_KEY_RSC_LEN];
- size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+ size_t len = wpa_cipher_key_len(conf->group_mgmt_cipher);
if (!sm->mgmt_frame_prot)
return pos;
@@ -3091,8 +3169,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
else
os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len);
- if (sm->wpa_auth->conf.disable_gtk ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random IGTK to each STA to prevent use of
* IGTK in the BSS.
@@ -3104,6 +3181,21 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
(const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
NULL, 0);
+ if (!conf->beacon_prot)
+ return pos;
+
+ bigtk.keyid[0] = gsm->GN_bigtk;
+ bigtk.keyid[1] = 0;
+ if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, rsc) < 0)
+ os_memset(bigtk.pn, 0, sizeof(bigtk.pn));
+ else
+ os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn));
+ os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
+ (const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
+ NULL, 0);
+
return pos;
}
@@ -3138,41 +3230,73 @@ static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
}
+#ifdef CONFIG_TESTING_OPTIONS
+static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid,
+ const u8 *ie, size_t ie_len)
+{
+ const u8 *elem;
+ u8 *buf;
+
+ wpa_printf(MSG_DEBUG, "TESTING: %s EAPOL override", name);
+ wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie before override",
+ old_buf, *len);
+ buf = os_malloc(*len + ie_len);
+ if (!buf)
+ return NULL;
+ os_memcpy(buf, old_buf, *len);
+ elem = get_ie(buf, *len, eid);
+ if (elem) {
+ u8 elem_len = 2 + elem[1];
+
+ os_memmove((void *) elem, elem + elem_len,
+ *len - (elem - buf) - elem_len);
+ *len -= elem_len;
+ }
+ os_memcpy(buf + *len, ie, ie_len);
+ *len += ie_len;
+ wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie after EAPOL override",
+ buf, *len);
+
+ return buf;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, dummy_gtk[32];
- size_t gtk_len, kde_len;
+ size_t gtk_len, kde_len, wpa_ie_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
- int wpa_ie_len, secure, gtkidx, encr = 0;
- u8 *wpa_ie_buf = NULL;
+ int secure, gtkidx, encr = 0;
+ u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL;
+ u8 hdr[2];
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
sm->TimeoutEvt = FALSE;
sm->TimeoutCtr++;
- if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
- sm->TimeoutCtr > 1) {
+ if (conf->wpa_disable_eapol_key_retries && sm->TimeoutCtr > 1) {
/* Do not allow retransmission of EAPOL-Key msg 3/4 */
return;
}
- if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
+ if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
}
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
- GTK[GN], IGTK, [FTIE], [TIE * 2])
+ GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
*/
os_memset(rsc, 0, WPA_KEY_RSC_LEN);
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
/* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */
wpa_ie = sm->wpa_auth->wpa_ie;
wpa_ie_len = sm->wpa_auth->wpa_ie_len;
- if (sm->wpa == WPA_VERSION_WPA &&
- (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
- wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
+ if (sm->wpa == WPA_VERSION_WPA && (conf->wpa & WPA_PROTO_RSN) &&
+ wpa_ie_len > wpa_ie[1] + 2U && wpa_ie[0] == WLAN_EID_RSN) {
/* WPA-only STA, remove RSN IE and possible MDIE */
wpa_ie = wpa_ie + wpa_ie[1] + 2;
if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
@@ -3180,42 +3304,45 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
wpa_ie_len = wpa_ie[1] + 2;
}
#ifdef CONFIG_TESTING_OPTIONS
- if (sm->wpa_auth->conf.rsnxe_override_eapol_len) {
- u8 *obuf = sm->wpa_auth->conf.rsnxe_override_eapol;
- size_t olen = sm->wpa_auth->conf.rsnxe_override_eapol_len;
- const u8 *rsnxe;
-
- wpa_hexdump(MSG_DEBUG,
- "TESTING: wpa_ie before RSNXE EAPOL override",
- wpa_ie, wpa_ie_len);
- wpa_ie_buf = os_malloc(wpa_ie_len + olen);
+ if (conf->rsne_override_eapol_set) {
+ wpa_ie_buf2 = replace_ie(
+ "RSNE", wpa_ie, &wpa_ie_len, WLAN_EID_RSN,
+ conf->rsne_override_eapol,
+ conf->rsne_override_eapol_len);
+ if (!wpa_ie_buf2)
+ goto done;
+ wpa_ie = wpa_ie_buf2;
+ }
+ if (conf->rsnxe_override_eapol_set) {
+ wpa_ie_buf = replace_ie(
+ "RSNXE", wpa_ie, &wpa_ie_len, WLAN_EID_RSNX,
+ conf->rsnxe_override_eapol,
+ conf->rsnxe_override_eapol_len);
if (!wpa_ie_buf)
- return;
- os_memcpy(wpa_ie_buf, wpa_ie, wpa_ie_len);
+ goto done;
wpa_ie = wpa_ie_buf;
- rsnxe = get_ie(wpa_ie, wpa_ie_len, WLAN_EID_RSNX);
- if (rsnxe) {
- u8 rsnxe_len = 2 + rsnxe[1];
-
- os_memmove((void *) rsnxe, rsnxe + rsnxe_len,
- wpa_ie_len - (rsnxe - wpa_ie) - rsnxe_len);
- wpa_ie_len -= rsnxe_len;
- }
- os_memcpy(wpa_ie + wpa_ie_len, obuf, olen);
- wpa_ie_len += olen;
- wpa_hexdump(MSG_DEBUG,
- "TESTING: wpa_ie after RSNXE EAPOL override",
- wpa_ie, wpa_ie_len);
}
#endif /* CONFIG_TESTING_OPTIONS */
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"sending 3/4 msg of 4-Way Handshake");
if (sm->wpa == WPA_VERSION_WPA2) {
+ if (sm->use_ext_key_id && sm->TimeoutCtr == 1 &&
+ wpa_auth_set_key(sm->wpa_auth, 0,
+ wpa_cipher_to_alg(sm->pairwise),
+ sm->addr,
+ sm->keyidx_active, sm->PTK.tk,
+ wpa_cipher_key_len(sm->pairwise),
+ KEY_FLAG_PAIRWISE_RX)) {
+ wpa_sta_disconnect(sm->wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
+
/* WPA2 send GTK in the 4-way handshake */
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- if (sm->wpa_auth->conf.disable_gtk ||
+ if (conf->disable_gtk ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random GTK to each STA to prevent use
@@ -3244,13 +3371,16 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
* WPA if the supplicant used it first.
*/
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "STA used Secure bit in WPA msg 2/4 - "
- "set Secure for 3/4 as workaround");
+ "STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround");
secure = 1;
}
}
kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+
+ if (sm->use_ext_key_id)
+ kde_len += 2 + RSN_SELECTOR_LEN + 2;
+
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@@ -3263,8 +3393,12 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
if (WPA_GET_BE32(sm->ip_addr) > 0)
kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4;
#endif /* CONFIG_P2P */
+
+ if (conf->transition_disable)
+ kde_len += 2 + RSN_SELECTOR_LEN + 1;
+
kde = os_malloc(kde_len);
- if (kde == NULL)
+ if (!kde)
goto done;
pos = kde;
@@ -3278,18 +3412,23 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
elen = pos - kde;
res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert "
- "PMKR1Name into RSN IE in EAPOL-Key data");
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data");
goto done;
}
pos -= wpa_ie_len;
pos += elen;
}
#endif /* CONFIG_IEEE80211R_AP */
+ hdr[1] = 0;
+
+ if (sm->use_ext_key_id) {
+ hdr[0] = sm->keyidx_active & 0x01;
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
+ }
+
if (gtk) {
- u8 hdr[2];
hdr[0] = gtkidx & 0x03;
- hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gtk_len);
}
@@ -3300,9 +3439,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
int res;
- struct wpa_auth_config *conf;
- conf = &sm->wpa_auth->conf;
if (sm->assoc_resp_ftie &&
kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
os_memcpy(pos, sm->assoc_resp_ftie,
@@ -3316,11 +3453,11 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
conf->r0_key_holder_len,
NULL, NULL, pos,
kde + kde_len - pos,
- NULL, 0);
+ NULL, 0, 0);
}
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
- "into EAPOL-Key Key Data");
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert FTIE into EAPOL-Key Key Data");
goto done;
}
pos += res;
@@ -3344,13 +3481,17 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
if (WPA_GET_BE32(sm->ip_addr) > 0) {
u8 addr[3 * 4];
os_memcpy(addr, sm->ip_addr, 4);
- os_memcpy(addr + 4, sm->wpa_auth->conf.ip_addr_mask, 4);
- os_memcpy(addr + 8, sm->wpa_auth->conf.ip_addr_go, 4);
+ os_memcpy(addr + 4, conf->ip_addr_mask, 4);
+ os_memcpy(addr + 8, conf->ip_addr_go, 4);
pos = wpa_add_kde(pos, WFA_KEY_DATA_IP_ADDR_ALLOC,
addr, sizeof(addr), NULL, 0);
}
#endif /* CONFIG_P2P */
+ if (conf->transition_disable)
+ pos = wpa_add_kde(pos, WFA_KEY_DATA_TRANSITION_DISABLE,
+ &conf->transition_disable, 1, NULL, 0);
+
wpa_send_eapol(sm->wpa_auth, sm,
(secure ? WPA_KEY_INFO_SECURE : 0) |
(wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
@@ -3361,6 +3502,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
done:
os_free(kde);
os_free(wpa_ie_buf);
+ os_free(wpa_ie_buf2);
}
@@ -3371,8 +3513,17 @@ SM_STATE(WPA_PTK, PTKINITDONE)
if (sm->Pair) {
enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
int klen = wpa_cipher_key_len(sm->pairwise);
- if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk, klen)) {
+ int res;
+
+ if (sm->use_ext_key_id)
+ res = wpa_auth_set_key(sm->wpa_auth, 0, 0, sm->addr,
+ sm->keyidx_active, NULL, 0,
+ KEY_FLAG_PAIRWISE_RX_TX_MODIFY);
+ else
+ res = wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr,
+ 0, sm->PTK.tk, klen,
+ KEY_FLAG_PAIRWISE_RX_TX);
+ if (res) {
wpa_sta_disconnect(sm->wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
@@ -3419,6 +3570,7 @@ SM_STATE(WPA_PTK, PTKINITDONE)
SM_STEP(WPA_PTK)
{
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ struct wpa_auth_config *conf = &wpa_auth->conf;
if (sm->Init)
SM_ENTER(WPA_PTK, INITIALIZE);
@@ -3453,7 +3605,7 @@ SM_STEP(WPA_PTK)
break;
case WPA_PTK_AUTHENTICATION2:
if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
- wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
+ wpa_auth_get_eapol(wpa_auth, sm->addr,
WPA_EAPOL_keyRun) > 0)
SM_ENTER(WPA_PTK, INITPMK);
else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
@@ -3464,7 +3616,7 @@ SM_STEP(WPA_PTK)
SM_ENTER(WPA_PTK, INITPMK);
break;
case WPA_PTK_INITPMK:
- if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
+ if (wpa_auth_get_eapol(wpa_auth, sm->addr,
WPA_EAPOL_keyAvailable) > 0) {
SM_ENTER(WPA_PTK, PTKSTART);
#ifdef CONFIG_DPP
@@ -3473,13 +3625,13 @@ SM_STEP(WPA_PTK)
#endif /* CONFIG_DPP */
} else {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"INITPMK - keyAvailable = false");
SM_ENTER(WPA_PTK, DISCONNECT);
}
break;
case WPA_PTK_INITPSK:
- if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
+ if (wpa_auth_get_psk(wpa_auth, sm->addr, sm->p2p_dev_addr,
NULL, NULL, NULL)) {
SM_ENTER(WPA_PTK, PTKSTART);
#ifdef CONFIG_SAE
@@ -3487,7 +3639,7 @@ SM_STEP(WPA_PTK)
SM_ENTER(WPA_PTK, PTKSTART);
#endif /* CONFIG_SAE */
} else {
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"no PSK configured for the STA");
wpa_auth->dot11RSNA4WayHandshakeFailures++;
SM_ENTER(WPA_PTK, DISCONNECT);
@@ -3497,13 +3649,11 @@ SM_STEP(WPA_PTK)
if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
sm->EAPOLKeyPairwise)
SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
- else if (sm->TimeoutCtr >
- sm->wpa_auth->conf.wpa_pairwise_update_count) {
+ else if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(
- sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTKSTART: Retry limit %u reached",
- sm->wpa_auth->conf.wpa_pairwise_update_count);
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTKSTART: Retry limit %u reached",
+ conf->wpa_pairwise_update_count);
SM_ENTER(WPA_PTK, DISCONNECT);
} else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK, PTKSTART);
@@ -3527,14 +3677,13 @@ SM_STEP(WPA_PTK)
sm->EAPOLKeyPairwise && sm->MICVerified)
SM_ENTER(WPA_PTK, PTKINITDONE);
else if (sm->TimeoutCtr >
- sm->wpa_auth->conf.wpa_pairwise_update_count ||
- (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
+ conf->wpa_pairwise_update_count ||
+ (conf->wpa_disable_eapol_key_retries &&
sm->TimeoutCtr > 1)) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(
- sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTKINITNEGOTIATING: Retry limit %u reached",
- sm->wpa_auth->conf.wpa_pairwise_update_count);
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTKINITNEGOTIATING: Retry limit %u reached",
+ conf->wpa_pairwise_update_count);
SM_ENTER(WPA_PTK, DISCONNECT);
} else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
@@ -3565,16 +3714,16 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
u8 *kde_buf = NULL, *pos, hdr[2];
size_t kde_len;
u8 *gtk, dummy_gtk[32];
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
sm->GTimeoutCtr++;
- if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
- sm->GTimeoutCtr > 1) {
+ if (conf->wpa_disable_eapol_key_retries && sm->GTimeoutCtr > 1) {
/* Do not allow retransmission of EAPOL-Key group msg 1/2 */
return;
}
- if (sm->GTimeoutCtr > sm->wpa_auth->conf.wpa_group_update_count) {
+ if (sm->GTimeoutCtr > conf->wpa_group_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
@@ -3591,8 +3740,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
"sending 1/2 msg of Group Key Handshake");
gtk = gsm->GTK[gsm->GN - 1];
- if (sm->wpa_auth->conf.disable_gtk ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
@@ -3605,7 +3753,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
- if (kde_buf == NULL)
+ if (!kde_buf)
return;
kde = pos = kde_buf;
@@ -3638,8 +3786,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
{
-#ifdef CONFIG_OCV
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+#ifdef CONFIG_OCV
const u8 *key_data, *mic;
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
@@ -3704,7 +3852,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
sm->GUpdateStationKeys = FALSE;
sm->GTimeoutCtr = 0;
/* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
- wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
"group key handshake completed (%s)",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
sm->has_GTK = TRUE;
@@ -3761,7 +3909,9 @@ SM_STEP(WPA_PTK_GROUP)
static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
int ret = 0;
+ size_t len;
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
@@ -3772,9 +3922,8 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
wpa_hexdump_key(MSG_DEBUG, "GTK",
group->GTK[group->GN - 1], group->GTK_len);
- if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
- size_t len;
- len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ len = wpa_cipher_key_len(conf->group_mgmt_cipher);
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
@@ -3785,6 +3934,19 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
group->IGTK[group->GN_igtk - 4], len);
}
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
+ conf->beacon_prot) {
+ len = wpa_cipher_key_len(conf->group_mgmt_cipher);
+ os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+ inc_byte_array(group->Counter, WPA_NONCE_LEN);
+ if (wpa_gmk_to_gtk(group->GMK, "BIGTK key expansion",
+ wpa_auth->addr, group->GNonce,
+ group->BIGTK[group->GN_bigtk - 6], len) < 0)
+ ret = -1;
+ wpa_hexdump_key(MSG_DEBUG, "BIGTK",
+ group->BIGTK[group->GN_bigtk - 6], len);
+ }
+
return ret;
}
@@ -3792,8 +3954,9 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
- "GTK_INIT (VLAN-ID %d)", group->vlan_id);
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state GTK_INIT (VLAN-ID %d)",
+ group->vlan_id);
group->changed = FALSE; /* GInit is not cleared here; avoid loop */
group->wpa_group_state = WPA_GROUP_GTK_INIT;
@@ -3803,6 +3966,8 @@ static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
group->GM = 2;
group->GN_igtk = 4;
group->GM_igtk = 5;
+ group->GN_bigtk = 6;
+ group->GM_bigtk = 7;
/* GTK[GN] = CalcGTK() */
wpa_gtk_update(wpa_auth, group);
}
@@ -3826,8 +3991,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
* station needs to be counted here anyway.
*/
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "GUpdateStationKeys was already set when "
- "marking station for GTK rekeying");
+ "GUpdateStationKeys was already set when marking station for GTK rekeying");
}
/* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */
@@ -3846,7 +4010,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
/* update GTK when exiting WNM-Sleep Mode */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
{
- if (sm == NULL || sm->is_wnmsleep)
+ if (!sm || sm->is_wnmsleep)
return;
wpa_group_update_sta(sm, NULL);
@@ -3920,6 +4084,36 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
return pos - start;
}
+
+int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+ struct wpa_group *gsm = sm->group;
+ u8 *start = pos;
+ size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+ /*
+ * BIGTK subelement:
+ * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
+ */
+ *pos++ = WNM_SLEEP_SUBELEM_BIGTK;
+ *pos++ = 2 + 6 + len;
+ WPA_PUT_LE16(pos, gsm->GN_bigtk);
+ pos += 2;
+ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos) != 0)
+ return 0;
+ pos += 6;
+
+ os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+ pos += len;
+
+ wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit",
+ gsm->GN_bigtk);
+ wpa_hexdump_key(MSG_DEBUG, "WNM: BIGTK in WNM-Sleep Mode exit",
+ gsm->IGTK[gsm->GN_bigtk - 6], len);
+
+ return pos - start;
+}
+
#endif /* CONFIG_WNM_AP */
@@ -3928,8 +4122,9 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
{
int tmp;
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
- "SETKEYS (VLAN-ID %d)", group->vlan_id);
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state SETKEYS (VLAN-ID %d)",
+ group->vlan_id);
group->changed = TRUE;
group->wpa_group_state = WPA_GROUP_SETKEYS;
group->GTKReKey = FALSE;
@@ -3939,14 +4134,17 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
tmp = group->GM_igtk;
group->GM_igtk = group->GN_igtk;
group->GN_igtk = tmp;
+ tmp = group->GM_bigtk;
+ group->GM_bigtk = group->GN_bigtk;
+ group->GN_bigtk = tmp;
/* "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. */
wpa_gtk_update(wpa_auth, group);
if (group->GKeyDoneStations) {
- wpa_printf(MSG_DEBUG, "wpa_group_setkeys: Unexpected "
- "GKeyDoneStations=%d when starting new GTK rekey",
+ wpa_printf(MSG_DEBUG,
+ "wpa_group_setkeys: Unexpected GKeyDoneStations=%d when starting new GTK rekey",
group->GKeyDoneStations);
group->GKeyDoneStations = 0;
}
@@ -3959,25 +4157,35 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
int ret = 0;
if (wpa_auth_set_key(wpa_auth, group->vlan_id,
- wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
+ wpa_cipher_to_alg(conf->wpa_group),
broadcast_ether_addr, group->GN,
- group->GTK[group->GN - 1], group->GTK_len) < 0)
+ group->GTK[group->GN - 1], group->GTK_len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
ret = -1;
- if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
enum wpa_alg alg;
size_t len;
- alg = wpa_cipher_to_alg(wpa_auth->conf.group_mgmt_cipher);
- len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+ alg = wpa_cipher_to_alg(conf->group_mgmt_cipher);
+ len = wpa_cipher_key_len(conf->group_mgmt_cipher);
if (ret == 0 &&
wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
broadcast_ether_addr, group->GN_igtk,
- group->IGTK[group->GN_igtk - 4], len) < 0)
+ group->IGTK[group->GN_igtk - 4], len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
+ ret = -1;
+
+ if (ret == 0 && conf->beacon_prot &&
+ wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
+ broadcast_ether_addr, group->GN_bigtk,
+ group->BIGTK[group->GN_bigtk - 6], len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
ret = -1;
}
@@ -3989,7 +4197,7 @@ static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx)
{
if (sm->group == ctx) {
wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR
- " for discconnection due to fatal failure",
+ " for disconnection due to fatal failure",
MAC2STR(sm->addr));
sm->Disconnect = TRUE;
}
@@ -4001,7 +4209,8 @@ static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx)
static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state FATAL_FAILURE");
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state FATAL_FAILURE");
group->changed = TRUE;
group->wpa_group_state = WPA_GROUP_FATAL_FAILURE;
wpa_auth_for_each_sta(wpa_auth, wpa_group_disconnect_cb, group);
@@ -4011,8 +4220,9 @@ static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth,
static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
- "SETKEYSDONE (VLAN-ID %d)", group->vlan_id);
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state SETKEYSDONE (VLAN-ID %d)",
+ group->vlan_id);
group->changed = TRUE;
group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
@@ -4049,7 +4259,7 @@ static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
static int wpa_sm_step(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
if (sm->in_step_loop) {
@@ -4079,8 +4289,9 @@ static int wpa_sm_step(struct wpa_state_machine *sm)
sm->in_step_loop = 0;
if (sm->pending_deinit) {
- wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state "
- "machine deinit for " MACSTR, MAC2STR(sm->addr));
+ wpa_printf(MSG_DEBUG,
+ "WPA: Completing pending STA state machine deinit for "
+ MACSTR, MAC2STR(sm->addr));
wpa_free_sta_sm(sm);
return 1;
}
@@ -4097,7 +4308,7 @@ static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx)
void wpa_auth_sm_notify(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return;
eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
}
@@ -4108,7 +4319,7 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
int tmp, i;
struct wpa_group *group;
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return;
group = wpa_auth->group;
@@ -4120,6 +4331,9 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
tmp = group->GM_igtk;
group->GM_igtk = group->GN_igtk;
group->GN_igtk = tmp;
+ tmp = group->GM_bigtk;
+ group->GM_bigtk = group->GN_bigtk;
+ group->GN_bigtk = tmp;
wpa_gtk_update(wpa_auth, group);
wpa_group_config_group_keys(wpa_auth, group);
}
@@ -4138,6 +4352,7 @@ static const char * wpa_bool_txt(int val)
int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
{
+ struct wpa_auth_config *conf;
int len = 0, ret;
char pmkid_txt[PMKID_LEN * 2 + 1];
#ifdef CONFIG_RSN_PREAUTH
@@ -4146,8 +4361,9 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
const int preauth = 0;
#endif /* CONFIG_RSN_PREAUTH */
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return len;
+ conf = &wpa_auth->conf;
ret = os_snprintf(buf + len, buflen - len,
"dot11RSNAOptionImplemented=TRUE\n"
@@ -4155,8 +4371,8 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
"dot11RSNAEnabled=%s\n"
"dot11RSNAPreauthenticationEnabled=%s\n",
wpa_bool_txt(preauth),
- wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
- wpa_bool_txt(wpa_auth->conf.rsn_preauth));
+ wpa_bool_txt(conf->wpa & WPA_PROTO_RSN),
+ wpa_bool_txt(conf->rsn_preauth));
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -4191,10 +4407,10 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
"dot11RSNA4WayHandshakeFailures=%u\n"
"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
RSN_VERSION,
- !!wpa_auth->conf.wpa_strict_rekey,
- wpa_auth->conf.wpa_group_update_count,
- wpa_auth->conf.wpa_pairwise_update_count,
- wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
+ !!conf->wpa_strict_rekey,
+ conf->wpa_group_update_count,
+ conf->wpa_pairwise_update_count,
+ wpa_cipher_key_len(conf->wpa_group) * 8,
dot11RSNAConfigPMKLifetime,
dot11RSNAConfigPMKReauthThreshold,
dot11RSNAConfigSATimeout,
@@ -4230,7 +4446,7 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
int len = 0, ret;
u32 pairwise = 0;
- if (sm == NULL)
+ if (!sm)
return 0;
/* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */
@@ -4311,7 +4527,7 @@ const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len)
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return -1;
return sm->wpa_key_mgmt;
}
@@ -4319,7 +4535,7 @@ int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
return sm->wpa;
}
@@ -4344,7 +4560,7 @@ int wpa_auth_sta_fils_tk_already_set(struct wpa_state_machine *sm)
int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
struct rsn_pmksa_cache_entry *entry)
{
- if (sm == NULL || sm->pmksa != entry)
+ if (!sm || sm->pmksa != entry)
return -1;
sm->pmksa = NULL;
return 0;
@@ -4367,7 +4583,7 @@ void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm)
const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
{
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return NULL;
*len = wpa_auth->wpa_ie_len;
return wpa_auth->wpa_ie;
@@ -4378,7 +4594,7 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
unsigned int pmk_len,
int session_timeout, struct eapol_state_machine *eapol)
{
- if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 ||
+ if (!sm || sm->wpa != WPA_VERSION_WPA2 ||
sm->wpa_auth->conf.disable_pmksa_caching)
return -1;
@@ -4414,7 +4630,7 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
int session_timeout,
struct eapol_state_machine *eapol)
{
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return -1;
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from preauth", pmk, len);
@@ -4475,7 +4691,7 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
{
struct rsn_pmksa_cache_entry *pmksa;
- if (wpa_auth == NULL || wpa_auth->pmksa == NULL)
+ if (!wpa_auth || !wpa_auth->pmksa)
return;
pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
if (pmksa) {
@@ -4641,13 +4857,13 @@ wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
{
struct wpa_group *group;
- if (wpa_auth == NULL || wpa_auth->group == NULL)
+ if (!wpa_auth || !wpa_auth->group)
return NULL;
wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
vlan_id);
group = wpa_group_init(wpa_auth, vlan_id, 0);
- if (group == NULL)
+ if (!group)
return NULL;
group->next = wpa_auth->group->next;
@@ -4667,7 +4883,7 @@ int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id)
{
struct wpa_group *group;
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return 0;
group = wpa_auth->group;
@@ -4677,9 +4893,9 @@ int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id)
group = group->next;
}
- if (group == NULL) {
+ if (!group) {
group = wpa_auth_add_group(wpa_auth, vlan_id);
- if (group == NULL)
+ if (!group)
return -1;
}
@@ -4708,7 +4924,7 @@ int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id)
struct wpa_group *group;
int ret = 0;
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return 0;
group = wpa_auth->group;
@@ -4718,7 +4934,7 @@ int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id)
group = group->next;
}
- if (group == NULL)
+ if (!group)
return -1;
wpa_printf(MSG_DEBUG,
@@ -4753,7 +4969,7 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
{
struct wpa_group *group;
- if (sm == NULL || sm->wpa_auth == NULL)
+ if (!sm || !sm->wpa_auth)
return 0;
group = sm->wpa_auth->group;
@@ -4763,9 +4979,9 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
group = group->next;
}
- if (group == NULL) {
+ if (!group) {
group = wpa_auth_add_group(sm->wpa_auth, vlan_id);
- if (group == NULL)
+ if (!group)
return -1;
}
@@ -4775,8 +4991,9 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
return -1;
- wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
- "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
+ wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR
+ " to use group state machine for VLAN ID %d",
+ MAC2STR(sm->addr), vlan_id);
wpa_group_get(sm->wpa_auth, group);
wpa_group_put(sm->wpa_auth, sm->group);
@@ -4789,7 +5006,7 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int ack)
{
- if (wpa_auth == NULL || sm == NULL)
+ if (!wpa_auth || !sm)
return;
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR
" ack=%d", MAC2STR(sm->addr), ack);
@@ -4805,8 +5022,8 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
* the station has received the frame.
*/
int timeout_ms = eapol_key_timeout_subseq;
- wpa_printf(MSG_DEBUG, "WPA: Increase initial EAPOL-Key 1/4 "
- "timeout by %u ms because of acknowledged frame",
+ wpa_printf(MSG_DEBUG,
+ "WPA: Increase initial EAPOL-Key 1/4 timeout by %u ms because of acknowledged frame",
timeout_ms);
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
eloop_register_timeout(timeout_ms / 1000,
@@ -4826,7 +5043,7 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
int wpa_auth_uses_sae(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
}
@@ -4834,7 +5051,7 @@ int wpa_auth_uses_sae(struct wpa_state_machine *sm)
int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE;
}
@@ -4843,7 +5060,7 @@ int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm)
#ifdef CONFIG_P2P
int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr)
{
- if (sm == NULL || WPA_GET_BE32(sm->ip_addr) == 0)
+ if (!sm || WPA_GET_BE32(sm->ip_addr) == 0)
return -1;
os_memcpy(addr, sm->ip_addr, 4);
return 0;
@@ -4919,7 +5136,7 @@ int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384,
return wpa_write_ftie(conf, use_sha384, conf->r0_key_holder,
conf->r0_key_holder_len,
- NULL, NULL, buf, len, NULL, 0);
+ NULL, NULL, buf, len, NULL, 0, 0);
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -4999,9 +5216,10 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
int wpa_ie_len, secure, gtkidx, encr = 0;
+ u8 hdr[2];
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
- GTK[GN], IGTK, [FTIE], [TIE * 2])
+ GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
*/
/* Use 0 RSC */
@@ -5044,13 +5262,16 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
* WPA if the supplicant used it first.
*/
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "STA used Secure bit in WPA msg 2/4 - "
- "set Secure for 3/4 as workaround");
+ "STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround");
secure = 1;
}
}
kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+
+ if (sm->use_ext_key_id)
+ kde_len += 2 + RSN_SELECTOR_LEN + 2;
+
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@@ -5060,7 +5281,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
}
#endif /* CONFIG_IEEE80211R_AP */
kde = os_malloc(kde_len);
- if (kde == NULL)
+ if (!kde)
return -1;
pos = kde;
@@ -5074,8 +5295,8 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
elen = pos - kde;
res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert "
- "PMKR1Name into RSN IE in EAPOL-Key data");
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data");
os_free(kde);
return -1;
}
@@ -5083,10 +5304,15 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
pos += elen;
}
#endif /* CONFIG_IEEE80211R_AP */
+ hdr[1] = 0;
+
+ if (sm->use_ext_key_id) {
+ hdr[0] = sm->keyidx_active & 0x01;
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
+ }
+
if (gtk) {
- u8 hdr[2];
hdr[0] = gtkidx & 0x03;
- hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gtk_len);
}
@@ -5121,11 +5347,11 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
conf->r0_key_holder_len,
NULL, NULL, pos,
kde + kde_len - pos,
- NULL, 0);
+ NULL, 0, 0);
}
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
- "into EAPOL-Key Key Data");
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert FTIE into EAPOL-Key Key Data");
os_free(kde);
return -1;
}
@@ -5182,7 +5408,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
- if (kde_buf == NULL)
+ if (!kde_buf)
return -1;
kde = pos = kde_buf;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 933a4b8e..868aaa1f 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -169,6 +169,7 @@ struct ft_remote_r1kh {
struct wpa_auth_config {
int wpa;
+ int extended_key_id;
int wpa_key_mgmt;
int wpa_pairwise;
int wpa_group;
@@ -176,6 +177,7 @@ struct wpa_auth_config {
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ int wpa_deny_ptk0_rekey;
u32 wpa_group_update_count;
u32 wpa_pairwise_update_count;
int wpa_disable_eapol_key_retries;
@@ -188,6 +190,7 @@ struct wpa_auth_config {
int okc;
int tx_status;
enum mfp_options ieee80211w;
+ int beacon_prot;
int group_mgmt_cipher;
int sae_require_mfp;
#ifdef CONFIG_OCV
@@ -219,8 +222,22 @@ struct wpa_auth_config {
double corrupt_gtk_rekey_mic_probability;
u8 own_ie_override[MAX_OWN_IE_OVERRIDE];
size_t own_ie_override_len;
+ u8 rsne_override_eapol[MAX_OWN_IE_OVERRIDE];
+ size_t rsne_override_eapol_len;
u8 rsnxe_override_eapol[MAX_OWN_IE_OVERRIDE];
size_t rsnxe_override_eapol_len;
+ u8 rsne_override_ft[MAX_OWN_IE_OVERRIDE];
+ size_t rsne_override_ft_len;
+ u8 rsnxe_override_ft[MAX_OWN_IE_OVERRIDE];
+ size_t rsnxe_override_ft_len;
+ u8 gtk_rsc_override[WPA_KEY_RSC_LEN];
+ u8 igtk_rsc_override[WPA_KEY_RSC_LEN];
+ unsigned int rsne_override_eapol_set:1;
+ unsigned int rsnxe_override_eapol_set:1;
+ unsigned int rsne_override_ft_set:1;
+ unsigned int rsnxe_override_ft_set:1;
+ unsigned int gtk_rsc_override_set:1;
+ unsigned int igtk_rsc_override_set:1;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
u8 ip_addr_go[4];
@@ -233,6 +250,11 @@ struct wpa_auth_config {
u8 fils_cache_id[FILS_CACHE_ID_LEN];
#endif /* CONFIG_FILS */
int sae_pwe;
+ int owe_ptk_workaround;
+ u8 transition_disable;
+#ifdef CONFIG_DPP2
+ int dpp_pfs;
+#endif /* CONFIG_DPP2 */
};
typedef enum {
@@ -259,7 +281,8 @@ struct wpa_auth_callbacks {
int *vlan_id);
int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
- const u8 *addr, int idx, u8 *key, size_t key_len);
+ const u8 *addr, int idx, u8 *key, size_t key_len,
+ enum key_flag key_flag);
int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
size_t data_len, int encrypt);
@@ -311,19 +334,21 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth);
int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_auth_config *conf);
-enum {
+enum wpa_validate_result {
WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
- WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID
+ WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID,
+ WPA_DENIED_OTHER_REASON
};
-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);
+enum wpa_validate_result
+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,
struct wpa_state_machine *sm,
const u8 *osen_ie, size_t osen_ie_len);
@@ -407,7 +432,8 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
#ifdef CONFIG_IEEE80211R_AP
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
size_t max_len, int auth_alg,
- const u8 *req_ies, size_t req_ies_len);
+ const u8 *req_ies, size_t req_ies_len,
+ int omit_rsnxe);
void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
u16 auth_transaction, const u8 *ies, size_t ies_len,
void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
@@ -431,6 +457,7 @@ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
+int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_auth_uses_sae(struct wpa_state_machine *sm);
int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index a599be22..476a2be6 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -808,7 +808,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem,
- size_t subelem_len)
+ size_t subelem_len, int rsnxe_used)
{
u8 *pos = buf, *ielen;
size_t hdrlen = use_sha384 ? sizeof(struct rsn_ftie_sha384) :
@@ -826,7 +826,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
os_memset(hdr, 0, sizeof(*hdr));
pos += sizeof(*hdr);
- WPA_PUT_LE16(hdr->mic_control, 0);
+ WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used);
if (anonce)
os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
if (snonce)
@@ -836,7 +836,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
os_memset(hdr, 0, sizeof(*hdr));
pos += sizeof(*hdr);
- WPA_PUT_LE16(hdr->mic_control, 0);
+ WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used);
if (anonce)
os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
if (snonce)
@@ -951,8 +951,9 @@ wpa_ft_rrb_seq_req(struct wpa_authenticator *wpa_auth,
goto err;
}
- wpa_printf(MSG_DEBUG, "FT: Send out sequence number request to " MACSTR,
- MAC2STR(src_addr));
+ wpa_printf(MSG_DEBUG, "FT: Send sequence number request from " MACSTR
+ " to " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
item = os_zalloc(sizeof(*item));
if (!item)
goto err;
@@ -1997,9 +1998,6 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
key = r0kh->key;
key_len = sizeof(r0kh->key);
- wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
- "address " MACSTR, MAC2STR(r0kh->addr));
-
if (r0kh->seq->rx.num_last == 0) {
/* A sequence request will be sent out anyway when pull
* response is received. Send it out now to avoid one RTT. */
@@ -2008,6 +2006,10 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
key_len, NULL, 0, NULL, 0, NULL);
}
+ wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request from " MACSTR
+ " to remote R0KH address " MACSTR,
+ MAC2STR(sm->wpa_auth->addr), MAC2STR(r0kh->addr));
+
if (first &&
random_get_bytes(sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
@@ -2280,6 +2282,54 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
}
+static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
+{
+ u8 *subelem, *pos;
+ struct wpa_group *gsm = sm->group;
+ size_t subelem_len;
+ const u8 *kek;
+ size_t kek_len;
+ size_t bigtk_len;
+
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ kek = sm->PTK.kek2;
+ kek_len = sm->PTK.kek2_len;
+ } else {
+ kek = sm->PTK.kek;
+ kek_len = sm->PTK.kek_len;
+ }
+
+ bigtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+ /* Sub-elem ID[1] | Length[1] | KeyID[2] | BIPN[6] | Key Length[1] |
+ * Key[16+8] */
+ subelem_len = 1 + 1 + 2 + 6 + 1 + bigtk_len + 8;
+ subelem = os_zalloc(subelem_len);
+ if (subelem == NULL)
+ return NULL;
+
+ pos = subelem;
+ *pos++ = FTIE_SUBELEM_BIGTK;
+ *pos++ = subelem_len - 2;
+ WPA_PUT_LE16(pos, gsm->GN_bigtk);
+ pos += 2;
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos);
+ pos += 6;
+ *pos++ = bigtk_len;
+ if (aes_wrap(kek, kek_len, bigtk_len / 8,
+ gsm->IGTK[gsm->GN_bigtk - 6], pos)) {
+ wpa_printf(MSG_DEBUG,
+ "FT: BIGTK subelem encryption failed: kek_len=%d",
+ (int) kek_len);
+ os_free(subelem);
+ return NULL;
+ }
+
+ *len = subelem_len;
+ return subelem;
+}
+
+
static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
u8 *pos, u8 *end, u8 id, u8 descr_count,
const u8 *ies, size_t ies_len)
@@ -2413,13 +2463,15 @@ static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end,
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
size_t max_len, int auth_alg,
- const u8 *req_ies, size_t req_ies_len)
+ const u8 *req_ies, size_t req_ies_len,
+ int omit_rsnxe)
{
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];
+ u8 rsnxe_buf[10], *rsnxe = rsnxe_buf;
size_t rsnxe_len;
+ int rsnxe_used;
int res;
struct wpa_auth_config *conf;
struct wpa_ft_ies parse;
@@ -2440,6 +2492,32 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
end = pos + max_len;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (auth_alg == WLAN_AUTH_FT &&
+ sm->wpa_auth->conf.rsne_override_ft_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: RSNE FT override for MIC calculation");
+ rsnie = sm->wpa_auth->conf.rsne_override_ft;
+ rsnie_len = sm->wpa_auth->conf.rsne_override_ft_len;
+ if (end - pos < (long int) rsnie_len)
+ return pos;
+ os_memcpy(pos, rsnie, rsnie_len);
+ rsnie = pos;
+ pos += rsnie_len;
+ if (rsnie_len > PMKID_LEN && sm->pmk_r1_name_valid) {
+ int idx;
+
+ /* Replace all 0xff PMKID with the valid PMKR1Name */
+ for (idx = 0; idx < PMKID_LEN; idx++) {
+ if (rsnie[rsnie_len - 1 - idx] != 0xff)
+ break;
+ }
+ if (idx == PMKID_LEN)
+ os_memcpy(&rsnie[rsnie_len - PMKID_LEN],
+ sm->pmk_r1_name, WPA_PMK_NAME_LEN);
+ }
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
if (auth_alg == WLAN_AUTH_FT ||
((auth_alg == WLAN_AUTH_FILS_SK ||
auth_alg == WLAN_AUTH_FILS_SK_PFS ||
@@ -2509,6 +2587,29 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
subelem_len += igtk_len;
os_free(igtk);
}
+ if (sm->mgmt_frame_prot && conf->beacon_prot) {
+ u8 *bigtk;
+ size_t bigtk_len;
+ u8 *nbuf;
+
+ bigtk = wpa_ft_bigtk_subelem(sm, &bigtk_len);
+ if (!bigtk) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to add BIGTK subelement");
+ os_free(subelem);
+ return NULL;
+ }
+ nbuf = os_realloc(subelem, subelem_len + bigtk_len);
+ if (!nbuf) {
+ os_free(subelem);
+ os_free(bigtk);
+ return NULL;
+ }
+ subelem = nbuf;
+ os_memcpy(subelem + subelem_len, bigtk, bigtk_len);
+ subelem_len += bigtk_len;
+ os_free(bigtk);
+ }
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
@@ -2544,9 +2645,11 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
anonce = NULL;
snonce = NULL;
}
+ rsnxe_used = (auth_alg == WLAN_AUTH_FT) &&
+ (conf->sae_pwe == 1 || conf->sae_pwe == 2);
res = wpa_write_ftie(conf, use_sha384, r0kh_id, r0kh_id_len,
anonce, snonce, pos, end - pos,
- subelem, subelem_len);
+ subelem, subelem_len, rsnxe_used);
os_free(subelem);
if (res < 0)
return NULL;
@@ -2582,10 +2685,24 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
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 (omit_rsnxe) {
+ rsnxe_len = 0;
+ } else {
+ res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe,
+ sizeof(rsnxe_buf));
+ if (res < 0)
+ return NULL;
+ rsnxe_len = res;
+ }
+#ifdef CONFIG_TESTING_OPTIONS
+ if (auth_alg == WLAN_AUTH_FT &&
+ sm->wpa_auth->conf.rsnxe_override_ft_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: RSNXE FT override for MIC calculation");
+ rsnxe = sm->wpa_auth->conf.rsnxe_override_ft;
+ rsnxe_len = sm->wpa_auth->conf.rsnxe_override_ft_len;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (auth_alg == WLAN_AUTH_FT && rsnxe_len)
*elem_count += 1;
@@ -2620,12 +2737,13 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
int vlan_id,
enum wpa_alg alg, const u8 *addr, int idx,
- u8 *key, size_t key_len)
+ u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
if (wpa_auth->cb->set_key == NULL)
return -1;
return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
- key, key_len);
+ key, key_len, key_flag);
}
@@ -2657,8 +2775,8 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
* again after association to get the PTK configured, but that could be
* optimized by adding the STA entry earlier.
*/
- if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk, klen))
+ if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, sm->keyidx_active,
+ sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX))
return;
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
@@ -3057,7 +3175,8 @@ pmk_r1_derived:
pos += ret;
ret = wpa_write_ftie(conf, use_sha384, parse.r0kh_id, parse.r0kh_id_len,
- sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
+ sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0,
+ 0);
if (ret < 0)
goto fail;
pos += ret;
@@ -3129,10 +3248,13 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
int use_sha384;
const u8 *anonce, *snonce, *fte_mic;
u8 fte_elem_count;
+ int rsnxe_used;
+ struct wpa_auth_config *conf;
if (sm == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ conf = &sm->wpa_auth->conf;
use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
@@ -3161,8 +3283,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
mdie = (struct rsn_mdie *) parse.mdie;
if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
- os_memcmp(mdie->mobility_domain,
- sm->wpa_auth->conf.mobility_domain,
+ os_memcmp(mdie->mobility_domain, conf->mobility_domain,
MOBILITY_DOMAIN_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
return WLAN_STATUS_INVALID_MDIE;
@@ -3179,6 +3300,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
} else {
@@ -3192,6 +3314,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
}
@@ -3237,14 +3360,14 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_INVALID_FTIE;
}
- if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
+ if (os_memcmp_const(parse.r1kh_id, conf->r1_key_holder,
FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
"ReassocReq");
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
parse.r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID",
- sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
+ conf->r1_key_holder, FT_R1KH_ID_LEN);
return WLAN_STATUS_INVALID_FTIE;
}
@@ -3306,6 +3429,13 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_INVALID_FTIE;
}
+ if (rsnxe_used && (conf->sae_pwe == 1 || conf->sae_pwe == 2) &&
+ !parse.rsnxe) {
+ wpa_printf(MSG_INFO,
+ "FT: FTE indicated that STA uses RSNXE, but RSNXE was not included");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
@@ -3687,6 +3817,10 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
goto out;
}
+ wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull response from " MACSTR
+ " to " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
+
resp[0].type = FT_RRB_S1KH_ID;
resp[0].len = f_s1kh_id_len;
resp[0].data = f_s1kh_id;
@@ -4193,6 +4327,10 @@ static int wpa_ft_rrb_rx_seq_req(struct wpa_authenticator *wpa_auth,
goto out;
}
+ wpa_printf(MSG_DEBUG, "FT: Send sequence number response from " MACSTR
+ " to " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
+
seq_resp_auth[0].type = FT_RRB_NONCE;
seq_resp_auth[0].len = f_nonce_len;
seq_resp_auth[0].data = f_nonce;
@@ -4452,9 +4590,11 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
size_t alen, elen;
int no_defer = 0;
- wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP "
- MACSTR, MAC2STR(src_addr));
- wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - oui_suffix=%d", oui_suffix);
+ wpa_printf(MSG_DEBUG, "FT: RRB-OUI(" MACSTR
+ ") received frame from remote AP "
+ MACSTR " oui_suffix=%u dst=" MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr), oui_suffix,
+ MAC2STR(dst_addr));
wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", data, data_len);
if (is_multicast_ether_addr(src_addr)) {
@@ -4464,13 +4604,8 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
return;
}
- if (is_multicast_ether_addr(dst_addr)) {
- wpa_printf(MSG_DEBUG,
- "FT: RRB-OUI received frame from remote AP " MACSTR
- " to multicast address " MACSTR,
- MAC2STR(src_addr), MAC2STR(dst_addr));
+ if (is_multicast_ether_addr(dst_addr))
no_defer = 1;
- }
if (data_len < sizeof(u16)) {
wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame too short");
@@ -4545,6 +4680,10 @@ static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
return -1;
}
+ wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 push from " MACSTR
+ " to remote R0KH address " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(r1kh->addr));
+
if (wpa_ft_rrb_build_r0(r1kh->key, sizeof(r1kh->key), push, pmk_r0,
r1kh->id, s1kh_id, push_auth, wpa_auth->addr,
FT_PACKET_R0KH_R1KH_PUSH,
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 7fb0923e..7a1ed24e 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -37,8 +37,11 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
struct hostapd_config *iconf,
struct wpa_auth_config *wconf)
{
+ int sae_pw_id;
+
os_memset(wconf, 0, sizeof(*wconf));
wconf->wpa = conf->wpa;
+ wconf->extended_key_id = conf->extended_key_id;
wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
wconf->wpa_pairwise = conf->wpa_pairwise;
wconf->wpa_group = conf->wpa_group;
@@ -65,6 +68,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
#endif /* CONFIG_OCV */
wconf->okc = conf->okc;
wconf->ieee80211w = conf->ieee80211w;
+ wconf->beacon_prot = conf->beacon_prot;
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
wconf->sae_require_mfp = conf->sae_require_mfp;
#ifdef CONFIG_IEEE80211R_AP
@@ -118,14 +122,58 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wpabuf_head(conf->own_ie_override),
wconf->own_ie_override_len);
}
+ if (conf->rsne_override_eapol &&
+ wpabuf_len(conf->rsne_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsne_override_eapol_set = 1;
+ wconf->rsne_override_eapol_len =
+ wpabuf_len(conf->rsne_override_eapol);
+ os_memcpy(wconf->rsne_override_eapol,
+ wpabuf_head(conf->rsne_override_eapol),
+ wconf->rsne_override_eapol_len);
+ }
if (conf->rsnxe_override_eapol &&
wpabuf_len(conf->rsnxe_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsnxe_override_eapol_set = 1;
wconf->rsnxe_override_eapol_len =
wpabuf_len(conf->rsnxe_override_eapol);
os_memcpy(wconf->rsnxe_override_eapol,
wpabuf_head(conf->rsnxe_override_eapol),
wconf->rsnxe_override_eapol_len);
}
+ if (conf->rsne_override_ft &&
+ wpabuf_len(conf->rsne_override_ft) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsne_override_ft_set = 1;
+ wconf->rsne_override_ft_len =
+ wpabuf_len(conf->rsne_override_ft);
+ os_memcpy(wconf->rsne_override_ft,
+ wpabuf_head(conf->rsne_override_ft),
+ wconf->rsne_override_ft_len);
+ }
+ if (conf->rsnxe_override_ft &&
+ wpabuf_len(conf->rsnxe_override_ft) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsnxe_override_ft_set = 1;
+ wconf->rsnxe_override_ft_len =
+ wpabuf_len(conf->rsnxe_override_ft);
+ os_memcpy(wconf->rsnxe_override_ft,
+ wpabuf_head(conf->rsnxe_override_ft),
+ wconf->rsnxe_override_ft_len);
+ }
+ if (conf->gtk_rsc_override &&
+ wpabuf_len(conf->gtk_rsc_override) > 0 &&
+ wpabuf_len(conf->gtk_rsc_override) <= WPA_KEY_RSC_LEN) {
+ os_memcpy(wconf->gtk_rsc_override,
+ wpabuf_head(conf->gtk_rsc_override),
+ wpabuf_len(conf->gtk_rsc_override));
+ wconf->gtk_rsc_override_set = 1;
+ }
+ if (conf->igtk_rsc_override &&
+ wpabuf_len(conf->igtk_rsc_override) > 0 &&
+ wpabuf_len(conf->igtk_rsc_override) <= WPA_KEY_RSC_LEN) {
+ os_memcpy(wconf->igtk_rsc_override,
+ wpabuf_head(conf->igtk_rsc_override),
+ wpabuf_len(conf->igtk_rsc_override));
+ wconf->igtk_rsc_override_set = 1;
+ }
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
@@ -139,6 +187,18 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
FILS_CACHE_ID_LEN);
#endif /* CONFIG_FILS */
wconf->sae_pwe = conf->sae_pwe;
+ sae_pw_id = hostapd_sae_pw_id_in_use(conf);
+ if (sae_pw_id == 2 && wconf->sae_pwe != 3)
+ wconf->sae_pwe = 1;
+ else if (sae_pw_id == 1 && wconf->sae_pwe == 0)
+ wconf->sae_pwe = 2;
+#ifdef CONFIG_OWE
+ wconf->owe_ptk_workaround = conf->owe_ptk_workaround;
+#endif /* CONFIG_OWE */
+ wconf->transition_disable = conf->transition_disable;
+#ifdef CONFIG_DPP2
+ wconf->dpp_pfs = conf->dpp_pfs;
+#endif /* CONFIG_DPP2 */
}
@@ -362,19 +422,27 @@ static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk,
static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
const u8 *addr, int idx, u8 *key,
- size_t key_len)
+ size_t key_len, enum key_flag key_flag)
{
struct hostapd_data *hapd = ctx;
const char *ifname = hapd->conf->iface;
if (vlan_id > 0) {
ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
- if (ifname == NULL)
- return -1;
+ if (!ifname) {
+ if (!(hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_VLAN_OFFLOAD))
+ return -1;
+ ifname = hapd->conf->iface;
+ }
}
#ifdef CONFIG_TESTING_OPTIONS
- if (addr && !is_broadcast_ether_addr(addr)) {
+ if (key_flag & KEY_FLAG_MODIFY) {
+ /* We are updating an already installed key. Don't overwrite
+ * the already stored key information with zeros.
+ */
+ } else if (addr && !is_broadcast_ether_addr(addr)) {
struct sta_info *sta;
sta = ap_get_sta(hapd, addr);
@@ -402,8 +470,8 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
hapd->last_gtk_len = key_len;
}
#endif /* CONFIG_TESTING_OPTIONS */
- return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
- key, key_len);
+ return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, vlan_id, 1,
+ NULL, 0, key, key_len, key_flag);
}
@@ -623,10 +691,6 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
}
#endif /* CONFIG_IEEE80211R_AP */
- if (hapd->driver && hapd->driver->send_ether)
- return hapd->driver->send_ether(hapd->drv_priv, dst,
- hapd->own_addr, proto,
- data, data_len);
if (hapd->l2 == NULL)
return -1;
@@ -688,6 +752,12 @@ static void hostapd_oui_deliver_later(void *eloop_ctx, void *timeout_ctx)
dl_list_for_each_safe(data, n, &hapd->l2_oui_queue,
struct oui_deliver_later_data, list) {
oui_ctx = hostapd_wpa_get_oui(hapd, data->oui_suffix);
+ wpa_printf(MSG_DEBUG, "RRB(%s): %s src=" MACSTR " dst=" MACSTR
+ " oui_suffix=%u data_len=%u data=%p",
+ hapd->conf->iface, __func__,
+ MAC2STR(data->src_addr), MAC2STR(data->dst_addr),
+ data->oui_suffix, (unsigned int) data->data_len,
+ data);
if (hapd->wpa_auth && oui_ctx) {
eth_p_oui_deliver(oui_ctx, data->src_addr,
data->dst_addr,
@@ -712,16 +782,26 @@ static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx)
{
struct wpa_auth_oui_iface_iter_data *idata = ctx;
struct oui_deliver_later_data *data;
- struct hostapd_data *hapd;
+ struct hostapd_data *hapd, *src_hapd = idata->src_hapd;
size_t j;
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
- if (hapd == idata->src_hapd)
- continue;
+ if (hapd == src_hapd)
+ continue; /* don't deliver back to same interface */
+ if (!wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) ||
+ hapd->conf->ssid.ssid_len !=
+ src_hapd->conf->ssid.ssid_len ||
+ os_memcmp(hapd->conf->ssid.ssid,
+ src_hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len) != 0 ||
+ os_memcmp(hapd->conf->mobility_domain,
+ src_hapd->conf->mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN) != 0)
+ continue; /* no matching FT SSID/mobility domain */
if (!is_multicast_ether_addr(idata->dst_addr) &&
os_memcmp(hapd->own_addr, idata->dst_addr, ETH_ALEN) != 0)
- continue;
+ continue; /* destination address does not match */
/* defer eth_p_oui_deliver until next eloop step as this is
* when it would be triggerd from reading from sock
@@ -733,14 +813,20 @@ static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx)
data = os_zalloc(sizeof(*data) + idata->data_len);
if (!data)
return 1;
+ wpa_printf(MSG_DEBUG,
+ "RRB(%s): local delivery to %s dst=" MACSTR
+ " oui_suffix=%u data_len=%u data=%p",
+ src_hapd->conf->iface, hapd->conf->iface,
+ MAC2STR(idata->dst_addr), idata->oui_suffix,
+ (unsigned int) idata->data_len, data);
- os_memcpy(data->src_addr, idata->src_hapd->own_addr, ETH_ALEN);
+ os_memcpy(data->src_addr, src_hapd->own_addr, ETH_ALEN);
os_memcpy(data->dst_addr, idata->dst_addr, ETH_ALEN);
os_memcpy(data + 1, idata->data, idata->data_len);
data->data_len = idata->data_len;
data->oui_suffix = idata->oui_suffix;
- dl_list_add(&hapd->l2_oui_queue, &data->list);
+ dl_list_add_tail(&hapd->l2_oui_queue, &data->list);
if (!eloop_is_timeout_registered(hostapd_oui_deliver_later,
hapd, NULL))
@@ -748,7 +834,11 @@ static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx)
hostapd_oui_deliver_later,
hapd, NULL);
- return 1;
+ /* If dst_addr is a multicast address, do not return any
+ * non-zero value here. Otherwise, the iteration of
+ * for_each_interface() will be stopped. */
+ if (!is_multicast_ether_addr(idata->dst_addr))
+ return 1;
}
return 0;
@@ -764,6 +854,10 @@ static int hostapd_wpa_auth_send_oui(void *ctx, const u8 *dst, u8 oui_suffix,
struct hostapd_data *hapd = ctx;
struct eth_p_oui_ctx *oui_ctx;
+ wpa_printf(MSG_DEBUG, "RRB(%s): send to dst=" MACSTR
+ " oui_suffix=%u data_len=%u",
+ hapd->conf->iface, MAC2STR(dst), oui_suffix,
+ (unsigned int) data_len);
#ifdef CONFIG_IEEE80211R_AP
if (hapd->iface->interfaces &&
hapd->iface->interfaces->for_each_interface) {
@@ -807,26 +901,32 @@ static int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id)
#ifndef CONFIG_NO_VLAN
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
- struct vlan_description vlan_desc;
sta = ap_get_sta(hapd, addr);
if (!sta)
return -1;
- os_memset(&vlan_desc, 0, sizeof(vlan_desc));
- vlan_desc.notempty = 1;
- vlan_desc.untagged = vlan_id;
- if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
- wpa_printf(MSG_INFO, "Invalid VLAN ID %d in wpa_psk_file",
- vlan_id);
- return -1;
- }
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
+ struct vlan_description vlan_desc;
- if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) {
- wpa_printf(MSG_INFO,
- "Failed to assign VLAN ID %d from wpa_psk_file to "
- MACSTR, vlan_id, MAC2STR(sta->addr));
- return -1;
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ vlan_desc.notempty = 1;
+ vlan_desc.untagged = vlan_id;
+ if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+ wpa_printf(MSG_INFO,
+ "Invalid VLAN ID %d in wpa_psk_file",
+ vlan_id);
+ return -1;
+ }
+
+ if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) {
+ wpa_printf(MSG_INFO,
+ "Failed to assign VLAN ID %d from wpa_psk_file to "
+ MACSTR, vlan_id, MAC2STR(sta->addr));
+ return -1;
+ }
+ } else {
+ sta->vlan_id = vlan_id;
}
wpa_printf(MSG_INFO,
@@ -888,7 +988,7 @@ static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
os_memcpy(&m->u, data, data_len);
- res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0);
+ res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0, NULL, 0, 0);
os_free(m);
return res;
}
@@ -1318,6 +1418,22 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
_conf.tx_status = 1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
_conf.ap_mlme = 1;
+
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) &&
+ (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER ||
+ (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK &&
+ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ "Disable PTK0 rekey support - replaced with disconnect");
+ _conf.wpa_deny_ptk0_rekey = 1;
+ }
+
+ if (_conf.extended_key_id &&
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID))
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Extended Key ID supported");
+ else
+ _conf.extended_key_id = 0;
+
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
if (hapd->wpa_auth == NULL) {
wpa_printf(MSG_ERROR, "WPA initialization failed.");
@@ -1352,9 +1468,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
hapd->conf->iface;
hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB,
hostapd_rrb_receive, hapd, 1);
- if (hapd->l2 == NULL &&
- (hapd->driver == NULL ||
- hapd->driver->send_ether == NULL)) {
+ if (!hapd->l2) {
wpa_printf(MSG_ERROR, "Failed to open l2_packet "
"interface");
return -1;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index a993f500..bc59d6a4 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -61,6 +61,8 @@ struct wpa_state_machine {
unsigned int pmk_len;
u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */
struct wpa_ptk PTK;
+ u8 keyidx_active;
+ Boolean use_ext_key_id;
Boolean PTK_valid;
Boolean pairwise_set;
Boolean tk_already_set;
@@ -193,7 +195,9 @@ struct wpa_group {
Boolean first_sta_seen;
Boolean reject_4way_hs_for_entropy;
u8 IGTK[2][WPA_IGTK_MAX_LEN];
+ u8 BIGTK[2][WPA_IGTK_MAX_LEN];
int GN_igtk, GM_igtk;
+ int GN_bigtk, GM_bigtk;
/* Number of references except those in struct wpa_group->next */
unsigned int references;
unsigned int num_setup_iface;
@@ -292,7 +296,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem,
- size_t subelem_len);
+ size_t subelem_len, int rsnxe_used);
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk);
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 2e6d0591..2ac1df47 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -297,6 +297,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
if (rsn_testing)
capab |= BIT(8) | BIT(15);
#endif /* CONFIG_RSN_TESTING */
+ if (conf->extended_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
WPA_PUT_LE16(pos, capab);
pos += 2;
@@ -546,13 +548,15 @@ static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
}
-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)
+enum wpa_validate_result
+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)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
struct wpa_ie_data data;
int ciphers, key_mgmt, res, version;
u32 selector;
@@ -860,6 +864,16 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP &&
+ ((conf->dpp_pfs == 1 && !owe_dh) ||
+ (conf->dpp_pfs == 2 && owe_dh))) {
+ wpa_printf(MSG_DEBUG, "DPP: PFS %s",
+ conf->dpp_pfs == 1 ? "required" : "not allowed");
+ return WPA_DENIED_OTHER_REASON;
+ }
+#endif /* CONFIG_DPP2 */
+
sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
if (sm->pairwise < 0)
return WPA_INVALID_PAIRWISE;
@@ -944,6 +958,23 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
#endif /* CONFIG_DPP */
+ if (conf->extended_key_id && sm->wpa == WPA_VERSION_WPA2 &&
+ sm->pairwise != WPA_CIPHER_TKIP &&
+ (data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) {
+ sm->use_ext_key_id = TRUE;
+ if (conf->extended_key_id == 2 &&
+ !wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
+ !wpa_key_mgmt_fils(sm->wpa_key_mgmt))
+ sm->keyidx_active = 1;
+ else
+ sm->keyidx_active = 0;
+ wpa_printf(MSG_DEBUG,
+ "RSN: Extended Key ID supported (start with %d)",
+ sm->keyidx_active);
+ } else {
+ sm->use_ext_key_id = FALSE;
+ }
+
if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
os_free(sm->wpa_ie);
sm->wpa_ie = os_malloc(wpa_ie_len);
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 175b9fc0..1d77b946 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -125,6 +125,7 @@ static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
os_memcpy(p->addr, mac_addr, ETH_ALEN);
os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
os_memcpy(p->psk, psk, PMK_LEN);
+ p->wps = 1;
if (hapd->new_psk_cb) {
hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr,
@@ -137,16 +138,17 @@ static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
if (ssid->wpa_psk_file) {
FILE *f;
char hex[PMK_LEN * 2 + 1];
+
/* Add the new PSK to PSK list file */
f = fopen(ssid->wpa_psk_file, "a");
- if (f == NULL) {
- wpa_printf(MSG_DEBUG, "Failed to add the PSK to "
- "'%s'", ssid->wpa_psk_file);
+ if (!f) {
+ wpa_printf(MSG_DEBUG, "Failed to add the PSK to '%s'",
+ ssid->wpa_psk_file);
return -1;
}
wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len);
- fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex);
+ fprintf(f, "wps=1 " MACSTR " %s\n", MAC2STR(mac_addr), hex);
fclose(f);
}
@@ -269,6 +271,44 @@ static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr,
}
+static int hostapd_wps_lookup_pskfile_cb(void *ctx, const u8 *mac_addr,
+ const u8 **psk)
+{
+ const struct hostapd_data *hapd = ctx;
+ const struct hostapd_wpa_psk *wpa_psk;
+ const u8 *any_psk = NULL;
+ const u8 *dev_psk = NULL;
+
+ for (wpa_psk = hapd->conf->ssid.wpa_psk; wpa_psk;
+ wpa_psk = wpa_psk->next) {
+ if (!wpa_psk->wps)
+ continue;
+
+ if (!any_psk && is_zero_ether_addr(wpa_psk->addr))
+ any_psk = wpa_psk->psk;
+
+ if (mac_addr && !dev_psk &&
+ os_memcmp(mac_addr, wpa_psk->addr, ETH_ALEN) == 0) {
+ dev_psk = wpa_psk->psk;
+ break;
+ }
+ }
+
+ if (dev_psk) {
+ *psk = dev_psk;
+ } else if (any_psk) {
+ *psk = any_psk;
+ } else {
+ *psk = NULL;
+ wpa_printf(MSG_DEBUG,
+ "WPS: No appropriate PSK in wpa_psk_file");
+ return 0;
+ }
+
+ return 1;
+}
+
+
static void wps_reload_config(void *eloop_data, void *user_ctx)
{
struct hostapd_iface *iface = eloop_data;
@@ -611,8 +651,10 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
(str_starts(buf, "ssid=") ||
str_starts(buf, "ssid2=") ||
str_starts(buf, "auth_algs=") ||
+#ifdef CONFIG_WEP
str_starts(buf, "wep_default_key=") ||
str_starts(buf, "wep_key") ||
+#endif /* CONFIG_WEP */
str_starts(buf, "wps_state=") ||
(pmf_changed && str_starts(buf, "ieee80211w=")) ||
str_starts(buf, "wpa=") ||
@@ -985,6 +1027,21 @@ static int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd,
}
+static int hostapd_wps_set_application_ext(struct hostapd_data *hapd,
+ struct wps_context *wps)
+{
+ wpabuf_free(wps->dev.application_ext);
+
+ if (!hapd->conf->wps_application_ext) {
+ wps->dev.application_ext = NULL;
+ return 0;
+ }
+
+ wps->dev.application_ext = wpabuf_dup(hapd->conf->wps_application_ext);
+ return wps->dev.application_ext ? 0 : -1;
+}
+
+
static void hostapd_free_wps(struct wps_context *wps)
{
int i;
@@ -1074,7 +1131,8 @@ int hostapd_init_wps(struct hostapd_data *hapd,
os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type,
WPS_DEV_TYPE_LEN);
- if (hostapd_wps_set_vendor_ext(hapd, wps) < 0)
+ if (hostapd_wps_set_vendor_ext(hapd, wps) < 0 ||
+ hostapd_wps_set_application_ext(hapd, wps) < 0)
goto fail;
wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
@@ -1140,6 +1198,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
conf->ssid.wpa_psk->psk, PMK_LEN);
wps->network_key_len = 2 * PMK_LEN;
+#ifdef CONFIG_WEP
} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
wps->network_key = os_malloc(conf->ssid.wep.len[0]);
if (wps->network_key == NULL)
@@ -1147,6 +1206,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
os_memcpy(wps->network_key, conf->ssid.wep.key[0],
conf->ssid.wep.len[0]);
wps->network_key_len = conf->ssid.wep.len[0];
+#endif /* CONFIG_WEP */
}
if (conf->ssid.wpa_psk) {
@@ -1197,14 +1257,13 @@ int hostapd_init_wps(struct hostapd_data *hapd,
cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
cfg.reg_success_cb = hostapd_wps_reg_success_cb;
cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb;
+ cfg.lookup_pskfile_cb = hostapd_wps_lookup_pskfile_cb;
cfg.cb_ctx = hapd;
cfg.skip_cred_build = conf->skip_cred_build;
cfg.extra_cred = conf->extra_cred;
cfg.extra_cred_len = conf->extra_cred_len;
cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
conf->skip_cred_build;
- if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
- cfg.static_wep_only = 1;
cfg.dualband = interface_count(hapd->iface) > 1;
if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) ==
(WPS_RF_50GHZ | WPS_RF_24GHZ))
@@ -1311,6 +1370,7 @@ void hostapd_update_wps(struct hostapd_data *hapd)
#endif /* CONFIG_WPS_UPNP */
hostapd_wps_set_vendor_ext(hapd, hapd->wps);
+ hostapd_wps_set_application_ext(hapd, hapd->wps);
if (hapd->conf->wps_state)
wps_registrar_update_ie(hapd->wps->registrar);
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 7694c96b..a58bf666 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -434,7 +434,8 @@ static int sae_tests(void)
goto fail;
/* Check that output matches the test vector */
- sae_write_commit(&sae, buf, NULL, pwid);
+ if (sae_write_commit(&sae, buf, NULL, pwid) < 0)
+ goto fail;
wpa_hexdump_buf(MSG_DEBUG, "SAE: Commit message", buf);
if (wpabuf_len(buf) != sizeof(local_commit) ||
diff --git a/src/common/defs.h b/src/common/defs.h
index e2fa4b29..f62c3cee 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -82,6 +82,13 @@ static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
WPA_KEY_MGMT_FT_FILS_SHA384));
}
+static inline int wpa_key_mgmt_wpa_psk_no_sae(int akm)
+{
+ return !!(akm & (WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256));
+}
+
static inline int wpa_key_mgmt_wpa_psk(int akm)
{
return !!(akm & (WPA_KEY_MGMT_PSK |
@@ -193,7 +200,6 @@ enum wpa_alg {
WPA_ALG_TKIP,
WPA_ALG_CCMP,
WPA_ALG_IGTK,
- WPA_ALG_PMK,
WPA_ALG_GCMP,
WPA_ALG_SMS4,
WPA_ALG_KRK,
@@ -423,4 +429,47 @@ enum chan_width {
CHAN_WIDTH_UNKNOWN
};
+enum key_flag {
+ KEY_FLAG_MODIFY = BIT(0),
+ KEY_FLAG_DEFAULT = BIT(1),
+ KEY_FLAG_RX = BIT(2),
+ KEY_FLAG_TX = BIT(3),
+ KEY_FLAG_GROUP = BIT(4),
+ KEY_FLAG_PAIRWISE = BIT(5),
+ KEY_FLAG_PMK = BIT(6),
+ /* Used flag combinations */
+ KEY_FLAG_RX_TX = KEY_FLAG_RX | KEY_FLAG_TX,
+ KEY_FLAG_GROUP_RX_TX = KEY_FLAG_GROUP | KEY_FLAG_RX_TX,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT = KEY_FLAG_GROUP_RX_TX |
+ KEY_FLAG_DEFAULT,
+ KEY_FLAG_GROUP_RX = KEY_FLAG_GROUP | KEY_FLAG_RX,
+ KEY_FLAG_GROUP_TX_DEFAULT = KEY_FLAG_GROUP | KEY_FLAG_TX |
+ KEY_FLAG_DEFAULT,
+ KEY_FLAG_PAIRWISE_RX_TX = KEY_FLAG_PAIRWISE | KEY_FLAG_RX_TX,
+ KEY_FLAG_PAIRWISE_RX = KEY_FLAG_PAIRWISE | KEY_FLAG_RX,
+ KEY_FLAG_PAIRWISE_RX_TX_MODIFY = KEY_FLAG_PAIRWISE_RX_TX |
+ KEY_FLAG_MODIFY,
+ /* Max allowed flags for each key type */
+ KEY_FLAG_PAIRWISE_MASK = KEY_FLAG_PAIRWISE_RX_TX_MODIFY,
+ KEY_FLAG_GROUP_MASK = KEY_FLAG_GROUP_RX_TX_DEFAULT,
+ KEY_FLAG_PMK_MASK = KEY_FLAG_PMK,
+};
+
+static inline int check_key_flag(enum key_flag key_flag)
+{
+ return !!(!key_flag ||
+ ((key_flag & (KEY_FLAG_PAIRWISE | KEY_FLAG_MODIFY)) &&
+ (key_flag & ~KEY_FLAG_PAIRWISE_MASK)) ||
+ ((key_flag & KEY_FLAG_GROUP) &&
+ (key_flag & ~KEY_FLAG_GROUP_MASK)) ||
+ ((key_flag & KEY_FLAG_PMK) &&
+ (key_flag & ~KEY_FLAG_PMK_MASK)));
+}
+
+enum ptk0_rekey_handling {
+ PTK0_REKEY_ALLOW_ALWAYS,
+ PTK0_REKEY_ALLOW_LOCAL_OK,
+ PTK0_REKEY_ALLOW_NEVER
+};
+
#endif /* DEFS_H */
diff --git a/src/common/dhcp.h b/src/common/dhcp.h
index e38512c2..7dc67d5b 100644
--- a/src/common/dhcp.h
+++ b/src/common/dhcp.h
@@ -39,7 +39,7 @@ struct dhcp_data {
} STRUCT_PACKED;
struct bootp_pkt {
- struct iphdr iph;
+ struct ip iph;
struct udphdr udph;
u8 op;
u8 htype;
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 7542c666..d8690ad5 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -1,7 +1,7 @@
/*
* DPP functionality shared between hostapd and wpa_supplicant
* Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -29,6 +29,7 @@
#include "crypto/aes_siv.h"
#include "crypto/sha384.h"
#include "crypto/sha512.h"
+#include "tls/asn1.h"
#include "drivers/driver.h"
#include "dpp.h"
@@ -72,6 +73,14 @@ static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
*ps = sig->s;
}
+
+static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
+{
+ if (pkey->type != EVP_PKEY_EC)
+ return NULL;
+ return pkey->pkey.ec;
+}
+
#endif
@@ -130,6 +139,7 @@ struct dpp_global {
struct dl_list tcp_init; /* struct dpp_connection */
void *cb_ctx;
int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
+ void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
#endif /* CONFIG_DPP2 */
};
@@ -453,6 +463,76 @@ static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
}
+#ifdef CONFIG_DPP2
+
+static int dpp_pbkdf2_f(size_t hash_len,
+ const u8 *password, size_t password_len,
+ const u8 *salt, size_t salt_len,
+ unsigned int iterations, unsigned int count, u8 *digest)
+{
+ unsigned char tmp[DPP_MAX_HASH_LEN], tmp2[DPP_MAX_HASH_LEN];
+ unsigned int i;
+ size_t j;
+ u8 count_buf[4];
+ const u8 *addr[2];
+ size_t len[2];
+
+ addr[0] = salt;
+ len[0] = salt_len;
+ addr[1] = count_buf;
+ len[1] = 4;
+
+ /* F(P, S, c, i) = U1 xor U2 xor ... Uc
+ * U1 = PRF(P, S || i)
+ * U2 = PRF(P, U1)
+ * Uc = PRF(P, Uc-1)
+ */
+
+ WPA_PUT_BE32(count_buf, count);
+ if (dpp_hmac_vector(hash_len, password, password_len, 2, addr, len,
+ tmp))
+ return -1;
+ os_memcpy(digest, tmp, hash_len);
+
+ for (i = 1; i < iterations; i++) {
+ if (dpp_hmac(hash_len, password, password_len, tmp, hash_len,
+ tmp2))
+ return -1;
+ os_memcpy(tmp, tmp2, hash_len);
+ for (j = 0; j < hash_len; j++)
+ digest[j] ^= tmp2[j];
+ }
+
+ return 0;
+}
+
+
+static int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
+ const u8 *salt, size_t salt_len, unsigned int iterations,
+ u8 *buf, size_t buflen)
+{
+ unsigned int count = 0;
+ unsigned char *pos = buf;
+ size_t left = buflen, plen;
+ unsigned char digest[DPP_MAX_HASH_LEN];
+
+ while (left > 0) {
+ count++;
+ if (dpp_pbkdf2_f(hash_len, password, password_len,
+ salt, salt_len, iterations, count, digest))
+ return -1;
+ plen = left > hash_len ? hash_len : left;
+ os_memcpy(pos, digest, plen);
+ pos += plen;
+ left -= plen;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
{
int num_bytes, offset;
@@ -820,7 +900,10 @@ void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
return;
os_free(info->uri);
os_free(info->info);
+ os_free(info->chan);
+ os_free(info->pk);
EVP_PKEY_free(info->pubkey);
+ str_clear_free(info->configurator_params);
os_free(info);
}
@@ -982,6 +1065,32 @@ static const struct dpp_curve_params * dpp_get_curve_nid(int nid)
}
+static int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
+ const u8 *data, size_t data_len)
+{
+ const u8 *addr[2];
+ size_t len[2];
+
+ addr[0] = data;
+ len[0] = data_len;
+ if (sha256_vector(1, addr, len, bi->pubkey_hash) < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
+ bi->pubkey_hash, SHA256_MAC_LEN);
+
+ addr[0] = (const u8 *) "chirp";
+ len[0] = 5;
+ addr[1] = data;
+ len[1] = data_len;
+ if (sha256_vector(2, addr, len, bi->pubkey_hash_chirp) < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG, "DPP: Public key hash (chirp)",
+ bi->pubkey_hash_chirp, SHA256_MAC_LEN);
+
+ return 0;
+}
+
+
static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
{
const char *end;
@@ -1020,14 +1129,11 @@ static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
data, data_len);
- if (sha256_vector(1, (const u8 **) &data, &data_len,
- bi->pubkey_hash) < 0) {
+ if (dpp_bi_pubkey_hash(bi, data, data_len) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
os_free(data);
return -1;
}
- wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
- bi->pubkey_hash, SHA256_MAC_LEN);
/* DER encoded ASN.1 SubjectPublicKeyInfo
*
@@ -1445,41 +1551,31 @@ fail:
}
-int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
+static int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
{
struct wpabuf *der;
int res;
- const u8 *addr[1];
- size_t len[1];
der = dpp_bootstrap_key_der(bi->pubkey);
if (!der)
return -1;
wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
der);
-
- addr[0] = wpabuf_head(der);
- len[0] = wpabuf_len(der);
- res = sha256_vector(1, addr, len, bi->pubkey_hash);
+ res = dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der));
if (res < 0)
wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
- else
- wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
- SHA256_MAC_LEN);
wpabuf_free(der);
return res;
}
-char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
- const u8 *privkey, size_t privkey_len)
+static int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
+ const u8 *privkey, size_t privkey_len)
{
char *base64 = NULL;
char *pos, *end;
size_t len;
struct wpabuf *der = NULL;
- const u8 *addr[1];
- int res;
if (!curve) {
bi->curve = &dpp_curves[0];
@@ -1488,7 +1584,7 @@ char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
if (!bi->curve) {
wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
curve);
- return NULL;
+ return -1;
}
}
if (privkey)
@@ -1505,15 +1601,10 @@ char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
der);
- addr[0] = wpabuf_head(der);
- len = wpabuf_len(der);
- res = sha256_vector(1, addr, &len, bi->pubkey_hash);
- if (res < 0) {
+ if (dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der)) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
goto fail;
}
- wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
- SHA256_MAC_LEN);
base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
wpabuf_free(der);
@@ -1528,11 +1619,13 @@ char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
break;
os_memmove(pos, pos + 1, end - pos);
}
- return base64;
+ os_free(bi->pk);
+ bi->pk = base64;
+ return 0;
fail:
os_free(base64);
wpabuf_free(der);
- return NULL;
+ return -1;
}
@@ -1916,9 +2009,11 @@ static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
#ifdef CONFIG_DPP2
/* Protocol Version */
- wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
- wpabuf_put_le16(msg, 1);
- wpabuf_put_u8(msg, 2);
+ if (auth->peer_version >= 2) {
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, 2);
+ }
#endif /* CONFIG_DPP2 */
attr_end = wpabuf_put(msg, 0);
@@ -2159,6 +2254,7 @@ static int dpp_channel_local_list(struct dpp_authentication *auth,
static int dpp_prepare_channel_list(struct dpp_authentication *auth,
+ unsigned int neg_freq,
struct hostapd_hw_modes *own_modes,
u16 num_modes)
{
@@ -2166,6 +2262,14 @@ static int dpp_prepare_channel_list(struct dpp_authentication *auth,
char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
unsigned int i;
+ if (!own_modes) {
+ if (!neg_freq)
+ return -1;
+ auth->num_freq = 1;
+ auth->freq[0] = neg_freq;
+ return 0;
+ }
+
if (auth->peer_bi->num_freq > 0)
res = dpp_channel_intersect(auth, own_modes, num_modes);
else
@@ -2198,11 +2302,42 @@ static int dpp_prepare_channel_list(struct dpp_authentication *auth,
}
+static int dpp_gen_uri(struct dpp_bootstrap_info *bi)
+{
+ char macstr[ETH_ALEN * 2 + 10];
+ size_t len;
+
+ len = 4; /* "DPP:" */
+ if (bi->chan)
+ len += 3 + os_strlen(bi->chan); /* C:...; */
+ if (is_zero_ether_addr(bi->mac_addr))
+ macstr[0] = '\0';
+ else
+ os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";",
+ MAC2STR(bi->mac_addr));
+ len += os_strlen(macstr); /* M:...; */
+ if (bi->info)
+ len += 3 + os_strlen(bi->info); /* I:...; */
+ len += 4 + os_strlen(bi->pk); /* K:...;; */
+
+ os_free(bi->uri);
+ bi->uri = os_malloc(len + 1);
+ if (!bi->uri)
+ return -1;
+ os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%sK:%s;;",
+ bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
+ bi->chan ? ";" : "",
+ macstr,
+ bi->info ? "I:" : "", bi->info ? bi->info : "",
+ bi->info ? ";" : "",
+ bi->pk);
+ return 0;
+}
+
+
static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
{
struct dpp_bootstrap_info *bi;
- char *pk = NULL;
- size_t len;
if (auth->own_bi)
return 0; /* already generated */
@@ -2211,33 +2346,38 @@ static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
if (!bi)
return -1;
bi->type = DPP_BOOTSTRAP_QR_CODE;
- pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0);
- if (!pk)
- goto fail;
-
- len = 4; /* "DPP:" */
- len += 4 + os_strlen(pk);
- bi->uri = os_malloc(len + 1);
- if (!bi->uri)
+ if (dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0) < 0 ||
+ dpp_gen_uri(bi) < 0)
goto fail;
- os_snprintf(bi->uri, len + 1, "DPP:K:%s;;", pk);
wpa_printf(MSG_DEBUG,
"DPP: Auto-generated own bootstrapping key info: URI %s",
bi->uri);
auth->tmp_own_bi = auth->own_bi = bi;
- os_free(pk);
-
return 0;
fail:
- os_free(pk);
dpp_bootstrap_info_free(bi);
return -1;
}
-struct dpp_authentication * dpp_auth_init(void *msg_ctx,
+struct dpp_authentication *
+dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx)
+{
+ struct dpp_authentication *auth;
+
+ auth = os_zalloc(sizeof(*auth));
+ if (!auth)
+ return NULL;
+ auth->global = dpp;
+ auth->msg_ctx = msg_ctx;
+ auth->conf_resp_status = 255;
+ return auth;
+}
+
+
+struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx,
struct dpp_bootstrap_info *peer_bi,
struct dpp_bootstrap_info *own_bi,
u8 dpp_allowed_roles,
@@ -2254,10 +2394,12 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx,
u8 test_hash[SHA256_MAC_LEN];
#endif /* CONFIG_TESTING_OPTIONS */
- auth = os_zalloc(sizeof(*auth));
+ auth = dpp_alloc_auth(dpp, msg_ctx);
if (!auth)
return NULL;
- auth->msg_ctx = msg_ctx;
+ if (peer_bi->configurator_params &&
+ dpp_set_configurator(auth, peer_bi->configurator_params) < 0)
+ goto fail;
auth->initiator = 1;
auth->waiting_auth_resp = 1;
auth->allowed_roles = dpp_allowed_roles;
@@ -2267,7 +2409,7 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx,
auth->curve = peer_bi->curve;
if (dpp_autogen_bootstrap_key(auth) < 0 ||
- dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
+ dpp_prepare_channel_list(auth, neg_freq, own_modes, num_modes) < 0)
goto fail;
#ifdef CONFIG_TESTING_OPTIONS
@@ -2363,6 +2505,8 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx,
}
#endif /* CONFIG_TESTING_OPTIONS */
+ if (neg_freq && auth->num_freq == 1 && auth->freq[0] == neg_freq)
+ neg_freq = 0;
auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
i_pubkey_hash, neg_freq);
if (!auth->req_msg)
@@ -3149,8 +3293,8 @@ static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
struct dpp_authentication *
-dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
- struct dpp_bootstrap_info *peer_bi,
+dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles,
+ int qr_mutual, struct dpp_bootstrap_info *peer_bi,
struct dpp_bootstrap_info *own_bi,
unsigned int freq, const u8 *hdr, const u8 *attr_start,
size_t attr_len)
@@ -3191,10 +3335,12 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
wrapped_data, wrapped_data_len);
attr_len = wrapped_data - 4 - attr_start;
- auth = os_zalloc(sizeof(*auth));
+ auth = dpp_alloc_auth(dpp, msg_ctx);
if (!auth)
goto fail;
- auth->msg_ctx = msg_ctx;
+ if (peer_bi && peer_bi->configurator_params &&
+ dpp_set_configurator(auth, peer_bi->configurator_params) < 0)
+ goto fail;
auth->peer_bi = peer_bi;
auth->own_bi = own_bi;
auth->curve = own_bi->curve;
@@ -4137,7 +4283,11 @@ int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
}
#endif /* CONFIG_TESTING_OPTIONS */
- if (auth->initiator || !auth->own_bi) {
+ if (auth->initiator || !auth->own_bi || !auth->waiting_auth_conf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: initiator=%d own_bi=%d waiting_auth_conf=%d",
+ auth->initiator, !!auth->own_bi,
+ auth->waiting_auth_conf);
dpp_auth_fail(auth, "Unexpected Authentication Confirm");
return -1;
}
@@ -4404,6 +4554,10 @@ static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
conf = conf_ap;
}
+ pos = os_strstr(cmd, " conf=configurator");
+ if (pos)
+ auth->provision_configurator = 1;
+
if (!conf)
return 0;
@@ -4558,25 +4712,38 @@ dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
}
-int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
- struct dpp_authentication *auth,
- const char *cmd)
+int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd)
{
const char *pos;
+ char *tmp = NULL;
+ int ret = -1;
- if (!cmd)
+ if (!cmd || auth->configurator_set)
return 0;
+ auth->configurator_set = 1;
+
+ if (cmd[0] != ' ') {
+ size_t len;
+
+ len = os_strlen(cmd);
+ tmp = os_malloc(len + 2);
+ if (!tmp)
+ goto fail;
+ tmp[0] = ' ';
+ os_memcpy(tmp + 1, cmd, len + 1);
+ cmd = tmp;
+ }
wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
pos = os_strstr(cmd, " configurator=");
if (pos) {
pos += 14;
- auth->conf = dpp_configurator_get_id(dpp, atoi(pos));
+ auth->conf = dpp_configurator_get_id(auth->global, atoi(pos));
if (!auth->conf) {
wpa_printf(MSG_INFO,
"DPP: Could not find the specified configurator");
- return -1;
+ goto fail;
}
}
@@ -4593,11 +4760,28 @@ int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
}
if (dpp_configuration_parse(auth, cmd) < 0) {
- wpa_msg(msg_ctx, MSG_INFO,
+ wpa_msg(auth->msg_ctx, MSG_INFO,
"DPP: Failed to set configurator parameters");
- return -1;
+ goto fail;
+ }
+ ret = 0;
+fail:
+ os_free(tmp);
+ return ret;
+}
+
+
+static void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key)
+{
+ while (key) {
+ struct dpp_asymmetric_key *next = key->next;
+
+ EVP_PKEY_free(key->csign);
+ str_clear_free(key->config_template);
+ str_clear_free(key->connector_template);
+ os_free(key);
+ key = next;
}
- return 0;
}
@@ -4622,6 +4806,7 @@ void dpp_auth_deinit(struct dpp_authentication *auth)
os_free(conf->connector);
wpabuf_free(conf->c_sign_key);
}
+ dpp_free_asymmetric_key(auth->conf_key_pkg);
wpabuf_free(auth->net_access_key);
dpp_bootstrap_info_free(auth->tmp_own_bi);
#ifdef CONFIG_TESTING_OPTIONS
@@ -5051,17 +5236,499 @@ dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
return NULL;
}
- if (dpp_akm_dpp(conf->akm))
+ if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
return dpp_build_conf_obj_dpp(auth, conf);
return dpp_build_conf_obj_legacy(auth, conf);
}
+#ifdef CONFIG_DPP2
+
+static struct wpabuf * dpp_build_conf_params(void)
+{
+ struct wpabuf *buf;
+ size_t len;
+ /* TODO: proper template values */
+ const char *conf_template = "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
+ const char *connector_template = NULL;
+
+ len = 100 + os_strlen(conf_template);
+ if (connector_template)
+ len += os_strlen(connector_template);
+ buf = wpabuf_alloc(len);
+ if (!buf)
+ return NULL;
+
+ /*
+ * DPPConfigurationParameters ::= SEQUENCE {
+ * configurationTemplate UTF8String,
+ * connectorTemplate UTF8String OPTIONAL}
+ */
+
+ asn1_put_utf8string(buf, conf_template);
+ if (connector_template)
+ asn1_put_utf8string(buf, connector_template);
+ return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf * dpp_build_attribute(void)
+{
+ struct wpabuf *conf_params, *attr;
+
+ /*
+ * aa-DPPConfigurationParameters ATTRIBUTE ::=
+ * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
+ *
+ * Attribute ::= SEQUENCE {
+ * type OBJECT IDENTIFIER,
+ * values SET SIZE(1..MAX) OF Type
+ */
+ conf_params = dpp_build_conf_params();
+ conf_params = asn1_encaps(conf_params, ASN1_CLASS_UNIVERSAL,
+ ASN1_TAG_SET);
+ if (!conf_params)
+ return NULL;
+
+ attr = wpabuf_alloc(100 + wpabuf_len(conf_params));
+ if (!attr) {
+ wpabuf_clear_free(conf_params);
+ return NULL;
+ }
+
+ asn1_put_oid(attr, &asn1_dpp_config_params_oid);
+ wpabuf_put_buf(attr, conf_params);
+ wpabuf_clear_free(conf_params);
+
+ return asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf * dpp_build_key_alg(const struct dpp_curve_params *curve)
+{
+ const struct asn1_oid *oid;
+ struct wpabuf *params, *res;
+
+ switch (curve->ike_group) {
+ case 19:
+ oid = &asn1_prime256v1_oid;
+ break;
+ case 20:
+ oid = &asn1_secp384r1_oid;
+ break;
+ case 21:
+ oid = &asn1_secp521r1_oid;
+ break;
+ case 28:
+ oid = &asn1_brainpoolP256r1_oid;
+ break;
+ case 29:
+ oid = &asn1_brainpoolP384r1_oid;
+ break;
+ case 30:
+ oid = &asn1_brainpoolP512r1_oid;
+ break;
+ default:
+ return NULL;
+ }
+
+ params = wpabuf_alloc(20);
+ if (!params)
+ return NULL;
+ asn1_put_oid(params, oid); /* namedCurve */
+
+ res = asn1_build_alg_id(&asn1_ec_public_key_oid, params);
+ wpabuf_free(params);
+ return res;
+}
+
+
+static struct wpabuf * dpp_build_key_pkg(struct dpp_authentication *auth)
+{
+ struct wpabuf *key = NULL, *attr, *alg, *priv_key = NULL;
+ EC_KEY *eckey;
+ unsigned char *der = NULL;
+ int der_len;
+
+ eckey = EVP_PKEY_get0_EC_KEY(auth->conf->csign);
+ if (!eckey)
+ return NULL;
+
+ EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
+ der_len = i2d_ECPrivateKey(eckey, &der);
+ if (der_len > 0)
+ priv_key = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+
+ alg = dpp_build_key_alg(auth->conf->curve);
+
+ /* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
+ attr = dpp_build_attribute();
+ attr = asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SET);
+ if (!priv_key || !attr || !alg)
+ goto fail;
+
+ /*
+ * OneAsymmetricKey ::= SEQUENCE {
+ * version Version,
+ * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ * privateKey PrivateKey,
+ * attributes [0] Attributes OPTIONAL,
+ * ...,
+ * [[2: publicKey [1] BIT STRING OPTIONAL ]],
+ * ...
+ * }
+ */
+
+ key = wpabuf_alloc(100 + wpabuf_len(alg) + wpabuf_len(priv_key) +
+ wpabuf_len(attr));
+ if (!key)
+ goto fail;
+
+ asn1_put_integer(key, 1); /* version = v2(1) */
+
+ /* PrivateKeyAlgorithmIdentifier */
+ wpabuf_put_buf(key, alg);
+
+ /* PrivateKey ::= OCTET STRING */
+ asn1_put_octet_string(key, priv_key);
+
+ /* [0] Attributes OPTIONAL */
+ asn1_put_hdr(key, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0, wpabuf_len(attr));
+ wpabuf_put_buf(key, attr);
+
+fail:
+ wpabuf_clear_free(attr);
+ wpabuf_clear_free(priv_key);
+ wpabuf_free(alg);
+
+ /*
+ * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
+ *
+ * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
+ *
+ * OneAsymmetricKey ::= SEQUENCE
+ */
+ return asn1_encaps(asn1_encaps(key,
+ ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE),
+ ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf * dpp_build_pbkdf2_alg_id(const struct wpabuf *salt,
+ size_t hash_len)
+{
+ struct wpabuf *params = NULL, *buf = NULL, *prf = NULL;
+ const struct asn1_oid *oid;
+
+ /*
+ * PBKDF2-params ::= SEQUENCE {
+ * salt CHOICE {
+ * specified OCTET STRING,
+ * otherSource AlgorithmIdentifier}
+ * iterationCount INTEGER (1..MAX),
+ * keyLength INTEGER (1..MAX),
+ * prf AlgorithmIdentifier}
+ *
+ * salt is an 64 octet value, iterationCount is 1000, keyLength is based
+ * on Configurator signing key length, prf is
+ * id-hmacWithSHA{256,384,512} based on Configurator signing key.
+ */
+
+ if (hash_len == 32)
+ oid = &asn1_pbkdf2_hmac_sha256_oid;
+ else if (hash_len == 48)
+ oid = &asn1_pbkdf2_hmac_sha384_oid;
+ else if (hash_len == 64)
+ oid = &asn1_pbkdf2_hmac_sha512_oid;
+ else
+ goto fail;
+ prf = asn1_build_alg_id(oid, NULL);
+ if (!prf)
+ goto fail;
+ params = wpabuf_alloc(100 + wpabuf_len(salt) + wpabuf_len(prf));
+ if (!params)
+ goto fail;
+ asn1_put_octet_string(params, salt); /* salt.specified */
+ asn1_put_integer(params, 1000); /* iterationCount */
+ asn1_put_integer(params, hash_len); /* keyLength */
+ wpabuf_put_buf(params, prf);
+ params = asn1_encaps(params, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+ if (!params)
+ goto fail;
+ buf = asn1_build_alg_id(&asn1_pbkdf2_oid, params);
+fail:
+ wpabuf_free(params);
+ wpabuf_free(prf);
+ return buf;
+}
+
+
+static struct wpabuf *
+dpp_build_pw_recipient_info(struct dpp_authentication *auth, size_t hash_len,
+ const struct wpabuf *cont_enc_key)
+{
+ struct wpabuf *pwri = NULL, *enc_key = NULL, *key_der_alg = NULL,
+ *key_enc_alg = NULL, *salt;
+ u8 kek[DPP_MAX_HASH_LEN];
+ const u8 *key;
+ size_t key_len;
+
+ salt = wpabuf_alloc(64);
+ if (!salt || os_get_random(wpabuf_put(salt, 64), 64) < 0)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: PBKDF2 salt", salt);
+
+ /* TODO: For initial testing, use ke as the key. Replace this with a
+ * new key once that has been defined. */
+ key = auth->ke;
+ key_len = auth->curve->hash_len;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
+
+ if (dpp_pbkdf2(hash_len, key, key_len, wpabuf_head(salt), 64, 1000,
+ kek, hash_len)) {
+ wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
+ kek, hash_len);
+
+ enc_key = wpabuf_alloc(hash_len + AES_BLOCK_SIZE);
+ if (!enc_key ||
+ aes_siv_encrypt(kek, hash_len, wpabuf_head(cont_enc_key),
+ wpabuf_len(cont_enc_key), 0, NULL, NULL,
+ wpabuf_put(enc_key, hash_len + AES_BLOCK_SIZE)) < 0)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: encryptedKey", enc_key);
+
+ /*
+ * PasswordRecipientInfo ::= SEQUENCE {
+ * version CMSVersion,
+ * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
+ * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ * encryptedKey EncryptedKey}
+ *
+ * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
+ * parameters contains PBKDF2-params SEQUENCE.
+ */
+
+ key_der_alg = dpp_build_pbkdf2_alg_id(salt, hash_len);
+ key_enc_alg = asn1_build_alg_id(&asn1_aes_siv_cmac_aead_256_oid, NULL);
+ if (!key_der_alg || !key_enc_alg)
+ goto fail;
+ pwri = wpabuf_alloc(100 + wpabuf_len(key_der_alg) +
+ wpabuf_len(key_enc_alg) + wpabuf_len(enc_key));
+ if (!pwri)
+ goto fail;
+
+ /* version = 0 */
+ asn1_put_integer(pwri, 0);
+
+ /* [0] KeyDerivationAlgorithmIdentifier */
+ asn1_put_hdr(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0,
+ wpabuf_len(key_der_alg));
+ wpabuf_put_buf(pwri, key_der_alg);
+
+ /* KeyEncryptionAlgorithmIdentifier */
+ wpabuf_put_buf(pwri, key_enc_alg);
+
+ /* EncryptedKey ::= OCTET STRING */
+ asn1_put_octet_string(pwri, enc_key);
+
+fail:
+ wpabuf_clear_free(key_der_alg);
+ wpabuf_free(key_enc_alg);
+ wpabuf_free(enc_key);
+ wpabuf_free(salt);
+ forced_memzero(kek, sizeof(kek));
+ return asn1_encaps(pwri, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf *
+dpp_build_recipient_info(struct dpp_authentication *auth, size_t hash_len,
+ const struct wpabuf *cont_enc_key)
+{
+ struct wpabuf *pwri;
+
+ /*
+ * RecipientInfo ::= CHOICE {
+ * ktri KeyTransRecipientInfo,
+ * kari [1] KeyAgreeRecipientInfo,
+ * kekri [2] KEKRecipientInfo,
+ * pwri [3] PasswordRecipientInfo,
+ * ori [4] OtherRecipientInfo}
+ *
+ * Shall always use the pwri CHOICE.
+ */
+
+ pwri = dpp_build_pw_recipient_info(auth, hash_len, cont_enc_key);
+ return asn1_encaps(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 3);
+}
+
+
+static struct wpabuf *
+dpp_build_enc_cont_info(struct dpp_authentication *auth, size_t hash_len,
+ const struct wpabuf *cont_enc_key)
+{
+ struct wpabuf *key_pkg, *enc_cont_info = NULL, *enc_cont = NULL,
+ *enc_alg;
+ const struct asn1_oid *oid;
+ size_t enc_cont_len;
+
+ /*
+ * EncryptedContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
+ */
+
+ if (hash_len == 32)
+ oid = &asn1_aes_siv_cmac_aead_256_oid;
+ else if (hash_len == 48)
+ oid = &asn1_aes_siv_cmac_aead_384_oid;
+ else if (hash_len == 64)
+ oid = &asn1_aes_siv_cmac_aead_512_oid;
+ else
+ return NULL;
+
+ key_pkg = dpp_build_key_pkg(auth);
+ enc_alg = asn1_build_alg_id(oid, NULL);
+ if (!key_pkg || !enc_alg)
+ goto fail;
+
+ wpa_hexdump_buf_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
+ key_pkg);
+
+ enc_cont_len = wpabuf_len(key_pkg) + AES_BLOCK_SIZE;
+ enc_cont = wpabuf_alloc(enc_cont_len);
+ if (!enc_cont ||
+ aes_siv_encrypt(wpabuf_head(cont_enc_key), wpabuf_len(cont_enc_key),
+ wpabuf_head(key_pkg), wpabuf_len(key_pkg),
+ 0, NULL, NULL,
+ wpabuf_put(enc_cont, enc_cont_len)) < 0)
+ goto fail;
+
+ enc_cont_info = wpabuf_alloc(100 + wpabuf_len(enc_alg) +
+ wpabuf_len(enc_cont));
+ if (!enc_cont_info)
+ goto fail;
+
+ /* ContentType ::= OBJECT IDENTIFIER */
+ asn1_put_oid(enc_cont_info, &asn1_dpp_asymmetric_key_package_oid);
+
+ /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
+ wpabuf_put_buf(enc_cont_info, enc_alg);
+
+ /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+ * EncryptedContent ::= OCTET STRING */
+ asn1_put_hdr(enc_cont_info, ASN1_CLASS_CONTEXT_SPECIFIC, 0, 0,
+ wpabuf_len(enc_cont));
+ wpabuf_put_buf(enc_cont_info, enc_cont);
+
+fail:
+ wpabuf_clear_free(key_pkg);
+ wpabuf_free(enc_cont);
+ wpabuf_free(enc_alg);
+ return enc_cont_info;
+}
+
+
+static struct wpabuf * dpp_gen_random(size_t len)
+{
+ struct wpabuf *key;
+
+ key = wpabuf_alloc(len);
+ if (!key || os_get_random(wpabuf_put(key, len), len) < 0) {
+ wpabuf_free(key);
+ key = NULL;
+ }
+ wpa_hexdump_buf_key(MSG_DEBUG, "DPP: content-encryption key", key);
+ return key;
+}
+
+
+static struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth)
+{
+ struct wpabuf *env = NULL;
+ struct wpabuf *recipient_info = NULL, *enc_cont_info = NULL;
+ struct wpabuf *cont_enc_key = NULL;
+ size_t hash_len;
+
+ if (!auth->conf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No Configurator instance selected for the session - cannot build DPPEnvelopedData");
+ return NULL;
+ }
+
+ if (!auth->provision_configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configurator provisioning not allowed");
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Building DPPEnvelopedData");
+
+ hash_len = auth->conf->curve->hash_len;
+ cont_enc_key = dpp_gen_random(hash_len);
+ if (!cont_enc_key)
+ goto fail;
+ recipient_info = dpp_build_recipient_info(auth, hash_len, cont_enc_key);
+ enc_cont_info = dpp_build_enc_cont_info(auth, hash_len, cont_enc_key);
+ if (!recipient_info || !enc_cont_info)
+ goto fail;
+
+ env = wpabuf_alloc(wpabuf_len(recipient_info) +
+ wpabuf_len(enc_cont_info) +
+ 100);
+ if (!env)
+ goto fail;
+
+ /*
+ * DPPEnvelopedData ::= EnvelopedData
+ *
+ * EnvelopedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * encryptedContentInfo EncryptedContentInfo,
+ * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
+ *
+ * For DPP, version is 3, both originatorInfo and
+ * unprotectedAttrs are omitted, and recipientInfos contains a single
+ * RecipientInfo.
+ */
+
+ /* EnvelopedData.version = 3 */
+ asn1_put_integer(env, 3);
+
+ /* RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo */
+ asn1_put_set(env, recipient_info);
+
+ /* EncryptedContentInfo ::= SEQUENCE */
+ asn1_put_sequence(env, enc_cont_info);
+
+ env = asn1_encaps(env, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: DPPEnvelopedData", env);
+out:
+ wpabuf_clear_free(cont_enc_key);
+ wpabuf_clear_free(recipient_info);
+ wpabuf_free(enc_cont_info);
+ return env;
+fail:
+ wpabuf_free(env);
+ env = NULL;
+ goto out;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
static struct wpabuf *
dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
u16 e_nonce_len, enum dpp_netrole netrole)
{
- struct wpabuf *conf, *conf2 = NULL;
+ struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL;
size_t clear_len, attr_len;
struct wpabuf *clear = NULL, *msg = NULL;
u8 *wrapped;
@@ -5069,13 +5736,21 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
size_t len[1];
enum dpp_status_error status;
- conf = dpp_build_conf_obj(auth, netrole, 0);
- if (conf) {
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
- wpabuf_head(conf), wpabuf_len(conf));
- conf2 = dpp_build_conf_obj(auth, netrole, 1);
+ if (netrole == DPP_NETROLE_CONFIGURATOR) {
+#ifdef CONFIG_DPP2
+ env_data = dpp_build_enveloped_data(auth);
+#endif /* CONFIG_DPP2 */
+ } else {
+ conf = dpp_build_conf_obj(auth, netrole, 0);
+ if (conf) {
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "DPP: configurationObject JSON",
+ wpabuf_head(conf), wpabuf_len(conf));
+ conf2 = dpp_build_conf_obj(auth, netrole, 1);
+ }
}
- status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
+ status = (conf || env_data) ? DPP_STATUS_OK :
+ DPP_STATUS_CONFIGURE_FAILURE;
auth->conf_resp_status = status;
/* { E-nonce, configurationObject[, sendConnStatus]}ke */
@@ -5084,6 +5759,8 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
clear_len += 4 + wpabuf_len(conf);
if (conf2)
clear_len += 4 + wpabuf_len(conf2);
+ if (env_data)
+ clear_len += 4 + wpabuf_len(env_data);
if (auth->peer_version >= 2 && auth->send_conn_status &&
netrole == DPP_NETROLE_STA)
clear_len += 4;
@@ -5142,6 +5819,11 @@ skip_e_nonce:
wpa_printf(MSG_DEBUG,
"DPP: Second Config Object available, but peer does not support more than one");
}
+ if (env_data) {
+ wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
+ wpabuf_put_le16(clear, wpabuf_len(env_data));
+ wpabuf_put_buf(clear, env_data);
+ }
if (auth->peer_version >= 2 && auth->send_conn_status &&
netrole == DPP_NETROLE_STA) {
@@ -5196,9 +5878,10 @@ skip_wrapped_data:
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Configuration Response attributes", msg);
out:
- wpabuf_free(conf);
- wpabuf_free(conf2);
- wpabuf_free(clear);
+ wpabuf_clear_free(conf);
+ wpabuf_clear_free(conf2);
+ wpabuf_clear_free(env_data);
+ wpabuf_clear_free(clear);
return msg;
fail:
@@ -6047,7 +6730,8 @@ static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
conf->connector = os_strdup(signed_connector);
dpp_copy_csign(conf, csign_pub);
- dpp_copy_netaccesskey(auth, conf);
+ if (dpp_akm_dpp(conf->akm))
+ dpp_copy_netaccesskey(auth, conf);
ret = 0;
fail:
@@ -6159,6 +6843,7 @@ static int dpp_parse_conf_obj(struct dpp_authentication *auth,
struct json_token *root, *token, *discovery, *cred;
struct dpp_config_obj *conf;
struct wpabuf *ssid64 = NULL;
+ int legacy;
root = json_parse((const char *) conf_obj, conf_obj_len);
if (!root)
@@ -6246,10 +6931,21 @@ static int dpp_parse_conf_obj(struct dpp_authentication *auth,
}
conf->akm = dpp_akm_from_str(token->string);
- if (dpp_akm_legacy(conf->akm)) {
+ legacy = dpp_akm_legacy(conf->akm);
+ if (legacy && auth->peer_version >= 2) {
+ struct json_token *csign, *s_conn;
+
+ csign = json_get_member(cred, "csign");
+ s_conn = json_get_member(cred, "signedConnector");
+ if (csign && csign->type == JSON_OBJECT &&
+ s_conn && s_conn->type == JSON_STRING)
+ legacy = 0;
+ }
+ if (legacy) {
if (dpp_parse_cred_legacy(conf, cred) < 0)
goto fail;
- } else if (dpp_akm_dpp(conf->akm)) {
+ } else if (dpp_akm_dpp(conf->akm) ||
+ (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
goto fail;
} else {
@@ -6268,11 +6964,716 @@ fail:
}
+#ifdef CONFIG_DPP2
+
+struct dpp_enveloped_data {
+ const u8 *enc_cont;
+ size_t enc_cont_len;
+ const u8 *enc_key;
+ size_t enc_key_len;
+ const u8 *salt;
+ size_t pbkdf2_key_len;
+ size_t prf_hash_len;
+};
+
+
+static int dpp_parse_recipient_infos(const u8 *pos, size_t len,
+ struct dpp_enveloped_data *data)
+{
+ struct asn1_hdr hdr;
+ const u8 *end = pos + len;
+ const u8 *next, *e_end;
+ struct asn1_oid oid;
+ int val;
+ const u8 *params;
+ size_t params_len;
+
+ wpa_hexdump(MSG_MSGDUMP, "DPP: RecipientInfos", pos, len);
+
+ /*
+ * RecipientInfo ::= CHOICE {
+ * ktri KeyTransRecipientInfo,
+ * kari [1] KeyAgreeRecipientInfo,
+ * kekri [2] KEKRecipientInfo,
+ * pwri [3] PasswordRecipientInfo,
+ * ori [4] OtherRecipientInfo}
+ *
+ * Shall always use the pwri CHOICE.
+ */
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 3) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected CHOICE [3] (pwri) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: PasswordRecipientInfo",
+ hdr.payload, hdr.length);
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ /*
+ * PasswordRecipientInfo ::= SEQUENCE {
+ * version CMSVersion,
+ * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
+ * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ * encryptedKey EncryptedKey}
+ *
+ * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
+ * parameters contains PBKDF2-params SEQUENCE.
+ */
+
+ if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
+ return -1;
+ pos = hdr.payload;
+
+ if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+ return -1;
+ if (val != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: pwri.version != 0");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Remaining PasswordRecipientInfo after version",
+ pos, end - pos);
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected keyDerivationAlgorithm [0] - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ pos = hdr.payload;
+ e_end = pos + hdr.length;
+
+ /* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */
+ if (asn1_get_alg_id(pos, e_end - pos, &oid, &params, &params_len,
+ &next) < 0)
+ return -1;
+ if (!asn1_oid_equal(&oid, &asn1_pbkdf2_oid)) {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s",
+ buf);
+ return -1;
+ }
+
+ /*
+ * PBKDF2-params ::= SEQUENCE {
+ * salt CHOICE {
+ * specified OCTET STRING,
+ * otherSource AlgorithmIdentifier}
+ * iterationCount INTEGER (1..MAX),
+ * keyLength INTEGER (1..MAX),
+ * prf AlgorithmIdentifier}
+ *
+ * salt is an 64 octet value, iterationCount is 1000, keyLength is based
+ * on Configurator signing key length, prf is
+ * id-hmacWithSHA{256,384,512} based on Configurator signing key.
+ */
+ if (!params ||
+ asn1_get_sequence(params, params_len, &hdr, &e_end) < 0)
+ return -1;
+ pos = hdr.payload;
+
+ if (asn1_get_next(pos, e_end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected OCTETSTRING (salt.specified) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: salt.specified",
+ hdr.payload, hdr.length);
+ if (hdr.length != 64) {
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected salt length %u",
+ hdr.length);
+ return -1;
+ }
+ data->salt = hdr.payload;
+ pos = hdr.payload + hdr.length;
+
+ if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
+ return -1;
+ if (val != 1000) {
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected iterationCount %d", val);
+ return -1;
+ }
+
+ if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
+ return -1;
+ if (val != 32 && val != 48 && val != 64) {
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected keyLength %d", val);
+ return -1;
+ }
+ data->pbkdf2_key_len = val;
+
+ if (asn1_get_sequence(pos, e_end - pos, &hdr, NULL) < 0 ||
+ asn1_get_oid(hdr.payload, hdr.length, &oid, &pos) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not parse prf");
+ return -1;
+ }
+ if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha256_oid)) {
+ data->prf_hash_len = 32;
+ } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha384_oid)) {
+ data->prf_hash_len = 48;
+ } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha512_oid)) {
+ data->prf_hash_len = 64;
+ } else {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected PBKDF2-params.prf %s",
+ buf);
+ return -1;
+ }
+
+ pos = next;
+
+ /* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier
+ *
+ * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or
+ * id-alg-AES-SIV-CMAC-aed-512. */
+ if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
+ return -1;
+ if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
+ !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
+ !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s",
+ buf);
+ return -1;
+ }
+
+ /*
+ * encryptedKey EncryptedKey
+ *
+ * EncryptedKey ::= OCTET STRING
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected OCTETSTRING (pwri.encryptedKey) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: pwri.encryptedKey",
+ hdr.payload, hdr.length);
+ data->enc_key = hdr.payload;
+ data->enc_key_len = hdr.length;
+
+ return 0;
+}
+
+
+static int dpp_parse_encrypted_content_info(const u8 *pos, const u8 *end,
+ struct dpp_enveloped_data *data)
+{
+ struct asn1_hdr hdr;
+ struct asn1_oid oid;
+
+ /*
+ * EncryptedContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
+ */
+ if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+ return -1;
+ wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContentInfo",
+ hdr.payload, hdr.length);
+ if (pos < end) {
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Unexpected extra data after EncryptedContentInfo",
+ pos, end - pos);
+ return -1;
+ }
+
+ end = pos;
+ pos = hdr.payload;
+
+ /* ContentType ::= OBJECT IDENTIFIER */
+ if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not parse ContentType");
+ return -1;
+ }
+ if (!asn1_oid_equal(&oid, &asn1_dpp_asymmetric_key_package_oid)) {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected ContentType %s", buf);
+ return -1;
+ }
+
+ /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
+ if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
+ return -1;
+ if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
+ !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
+ !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s",
+ buf);
+ return -1;
+ }
+ /* ignore optional parameters */
+
+ /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+ * EncryptedContent ::= OCTET STRING */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected [0] IMPLICIT (EncryptedContent) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContent",
+ hdr.payload, hdr.length);
+ data->enc_cont = hdr.payload;
+ data->enc_cont_len = hdr.length;
+ return 0;
+}
+
+
+static int dpp_parse_enveloped_data(const u8 *env_data, size_t env_data_len,
+ struct dpp_enveloped_data *data)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+ int val;
+
+ os_memset(data, 0, sizeof(*data));
+
+ /*
+ * DPPEnvelopedData ::= EnvelopedData
+ *
+ * EnvelopedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * encryptedContentInfo EncryptedContentInfo,
+ * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
+ *
+ * CMSVersion ::= INTEGER
+ *
+ * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
+ *
+ * For DPP, version is 3, both originatorInfo and
+ * unprotectedAttrs are omitted, and recipientInfos contains a single
+ * RecipientInfo.
+ */
+ if (asn1_get_sequence(env_data, env_data_len, &hdr, &end) < 0)
+ return -1;
+ pos = hdr.payload;
+ if (end < env_data + env_data_len) {
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Unexpected extra data after DPPEnvelopedData",
+ end, env_data + env_data_len - end);
+ return -1;
+ }
+
+ if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+ return -1;
+ if (val != 3) {
+ wpa_printf(MSG_DEBUG, "DPP: EnvelopedData.version != 3");
+ return -1;
+ }
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected SET (RecipientInfos) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ if (dpp_parse_recipient_infos(hdr.payload, hdr.length, data) < 0)
+ return -1;
+ return dpp_parse_encrypted_content_info(hdr.payload + hdr.length, end,
+ data);
+}
+
+
+static struct dpp_asymmetric_key *
+dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos = buf, *end = buf + len, *next;
+ int val;
+ const u8 *params;
+ size_t params_len;
+ struct asn1_oid oid;
+ char txt[80];
+ struct dpp_asymmetric_key *key;
+ EC_KEY *eckey;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: OneAsymmetricKey", buf, len);
+
+ key = os_zalloc(sizeof(*key));
+ if (!key)
+ return NULL;
+
+ /*
+ * OneAsymmetricKey ::= SEQUENCE {
+ * version Version,
+ * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ * privateKey PrivateKey,
+ * attributes [0] Attributes OPTIONAL,
+ * ...,
+ * [[2: publicKey [1] BIT STRING OPTIONAL ]],
+ * ...
+ * }
+ */
+ if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
+ goto fail;
+ pos = hdr.payload;
+
+ /* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
+ if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+ goto fail;
+ if (val != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported DPPAsymmetricKeyPackage version %d",
+ val);
+ goto fail;
+ }
+
+ /* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */
+ if (asn1_get_alg_id(pos, end - pos, &oid, &params, &params_len,
+ &pos) < 0)
+ goto fail;
+ if (!asn1_oid_equal(&oid, &asn1_ec_public_key_oid)) {
+ asn1_oid_to_str(&oid, txt, sizeof(txt));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s",
+ txt);
+ goto fail;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: PrivateKeyAlgorithmIdentifier params",
+ params, params_len);
+ /*
+ * ECParameters ::= CHOICE {
+ * namedCurve OBJECT IDENTIFIER
+ * -- implicitCurve NULL
+ * -- specifiedCurve SpecifiedECDomain}
+ */
+ if (!params || asn1_get_oid(params, params_len, &oid, &next) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not parse ECParameters.namedCurve");
+ goto fail;
+ }
+ asn1_oid_to_str(&oid, txt, sizeof(txt));
+ wpa_printf(MSG_MSGDUMP, "DPP: namedCurve %s", txt);
+ /* Assume the curve is identified within ECPrivateKey, so that this
+ * separate indication is not really needed. */
+
+ /*
+ * PrivateKey ::= OCTET STRING
+ * (Contains DER encoding of ECPrivateKey)
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: PrivateKey",
+ hdr.payload, hdr.length);
+ pos = hdr.payload + hdr.length;
+ eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length);
+ if (!eckey) {
+ wpa_printf(MSG_INFO,
+ "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ key->csign = EVP_PKEY_new();
+ if (!key->csign || EVP_PKEY_assign_EC_KEY(key->csign, eckey) != 1) {
+ EC_KEY_free(eckey);
+ goto fail;
+ }
+ if (wpa_debug_show_keys)
+ dpp_debug_print_key("DPP: Received c-sign-key", key->csign);
+
+ /*
+ * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
+ *
+ * Exactly one instance of type Attribute in OneAsymmetricKey.
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected [0] Attributes - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: Attributes",
+ hdr.payload, hdr.length);
+ if (hdr.payload + hdr.length < end) {
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "DPP: Ignore additional data at the end of OneAsymmetricKey",
+ hdr.payload + hdr.length,
+ end - (hdr.payload + hdr.length));
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected SET (Attributes) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ if (hdr.payload + hdr.length < end) {
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)",
+ hdr.payload + hdr.length,
+ end - (hdr.payload + hdr.length));
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /*
+ * OneAsymmetricKeyAttributes ATTRIBUTE ::= {
+ * aa-DPPConfigurationParameters,
+ * ... -- For local profiles
+ * }
+ *
+ * aa-DPPConfigurationParameters ATTRIBUTE ::=
+ * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
+ *
+ * Attribute ::= SEQUENCE {
+ * type OBJECT IDENTIFIER,
+ * values SET SIZE(1..MAX) OF Type
+ *
+ * Exactly one instance of ATTRIBUTE in attrValues.
+ */
+ if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+ goto fail;
+ if (pos < end) {
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "DPP: Ignore additional data at the end of ATTRIBUTE",
+ pos, end - pos);
+ }
+ end = pos;
+ pos = hdr.payload;
+
+ if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0)
+ goto fail;
+ if (!asn1_oid_equal(&oid, &asn1_dpp_config_params_oid)) {
+ asn1_oid_to_str(&oid, txt, sizeof(txt));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected Attribute identifier %s", txt);
+ goto fail;
+ }
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected SET (Attribute) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /*
+ * DPPConfigurationParameters ::= SEQUENCE {
+ * configurationTemplate UTF8String,
+ * connectorTemplate UTF8String OPTIONAL}
+ */
+
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPConfigurationParameters",
+ pos, end - pos);
+ if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+ goto fail;
+ if (pos < end) {
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "DPP: Ignore additional data after DPPConfigurationParameters",
+ pos, end - pos);
+ }
+ end = pos;
+ pos = hdr.payload;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_UTF8STRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected UTF8STRING (configurationTemplate) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: configurationTemplate",
+ hdr.payload, hdr.length);
+ key->config_template = os_zalloc(hdr.length + 1);
+ if (!key->config_template)
+ goto fail;
+ os_memcpy(key->config_template, hdr.payload, hdr.length);
+
+ pos = hdr.payload + hdr.length;
+
+ if (pos < end) {
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_UTF8STRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected UTF8STRING (connectorTemplate) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: connectorTemplate",
+ hdr.payload, hdr.length);
+ key->connector_template = os_zalloc(hdr.length + 1);
+ if (!key->connector_template)
+ goto fail;
+ os_memcpy(key->connector_template, hdr.payload, hdr.length);
+ }
+
+ return key;
+fail:
+ wpa_printf(MSG_DEBUG, "DPP: Failed to parse OneAsymmetricKey");
+ dpp_free_asymmetric_key(key);
+ return NULL;
+}
+
+
+static struct dpp_asymmetric_key *
+dpp_parse_dpp_asymmetric_key_package(const u8 *key_pkg, size_t key_pkg_len)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos = key_pkg, *end = key_pkg + key_pkg_len;
+ struct dpp_asymmetric_key *first = NULL, *last = NULL, *key;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
+ key_pkg, key_pkg_len);
+
+ /*
+ * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
+ *
+ * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
+ */
+ while (pos < end) {
+ if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0 ||
+ !(key = dpp_parse_one_asymmetric_key(hdr.payload,
+ hdr.length))) {
+ dpp_free_asymmetric_key(first);
+ return NULL;
+ }
+ if (!last) {
+ first = last = key;
+ } else {
+ last->next = key;
+ last = key;
+ }
+ }
+
+ return first;
+}
+
+
+static int dpp_conf_resp_env_data(struct dpp_authentication *auth,
+ const u8 *env_data, size_t env_data_len)
+{
+ const u8 *key;
+ size_t key_len;
+ u8 kek[DPP_MAX_HASH_LEN];
+ u8 cont_encr_key[DPP_MAX_HASH_LEN];
+ size_t cont_encr_key_len;
+ int res;
+ u8 *key_pkg;
+ size_t key_pkg_len;
+ struct dpp_enveloped_data data;
+ struct dpp_asymmetric_key *keys;
+
+ wpa_hexdump(MSG_DEBUG, "DPP: DPPEnvelopedData", env_data, env_data_len);
+
+ if (dpp_parse_enveloped_data(env_data, env_data_len, &data) < 0)
+ return -1;
+
+ /* TODO: For initial testing, use ke as the key. Replace this with a
+ * new key once that has been defined. */
+ key = auth->ke;
+ key_len = auth->curve->hash_len;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
+
+ if (dpp_pbkdf2(data.prf_hash_len, key, key_len, data.salt, 64, 1000,
+ kek, data.pbkdf2_key_len)) {
+ wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
+ kek, data.pbkdf2_key_len);
+
+ if (data.enc_key_len < AES_BLOCK_SIZE ||
+ data.enc_key_len > sizeof(cont_encr_key) + AES_BLOCK_SIZE) {
+ wpa_printf(MSG_DEBUG, "DPP: Invalid encryptedKey length");
+ return -1;
+ }
+ res = aes_siv_decrypt(kek, data.pbkdf2_key_len,
+ data.enc_key, data.enc_key_len,
+ 0, NULL, NULL, cont_encr_key);
+ forced_memzero(kek, data.pbkdf2_key_len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: AES-SIV decryption of encryptedKey failed");
+ return -1;
+ }
+ cont_encr_key_len = data.enc_key_len - AES_BLOCK_SIZE;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: content-encryption key",
+ cont_encr_key, cont_encr_key_len);
+
+ if (data.enc_cont_len < AES_BLOCK_SIZE)
+ return -1;
+ key_pkg_len = data.enc_cont_len - AES_BLOCK_SIZE;
+ key_pkg = os_malloc(key_pkg_len);
+ if (!key_pkg)
+ return -1;
+ res = aes_siv_decrypt(cont_encr_key, cont_encr_key_len,
+ data.enc_cont, data.enc_cont_len,
+ 0, NULL, NULL, key_pkg);
+ forced_memzero(cont_encr_key, cont_encr_key_len);
+ if (res < 0) {
+ bin_clear_free(key_pkg, key_pkg_len);
+ wpa_printf(MSG_DEBUG,
+ "DPP: AES-SIV decryption of encryptedContent failed");
+ return -1;
+ }
+
+ keys = dpp_parse_dpp_asymmetric_key_package(key_pkg, key_pkg_len);
+ bin_clear_free(key_pkg, key_pkg_len);
+ dpp_free_asymmetric_key(auth->conf_key_pkg);
+ auth->conf_key_pkg = keys;
+
+ return keys != NULL;;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
int dpp_conf_resp_rx(struct dpp_authentication *auth,
const struct wpabuf *resp)
{
const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
+ const u8 *env_data;
+ u16 env_data_len;
const u8 *addr[1];
size_t len[1];
u8 *unwrapped = NULL;
@@ -6348,9 +7749,17 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth,
goto fail;
}
+ env_data = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_ENVELOPED_DATA, &env_data_len);
+#ifdef CONFIG_DPP2
+ if (env_data &&
+ dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
+ goto fail;
+#endif /* CONFIG_DPP2 */
+
conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
&conf_obj_len);
- if (!conf_obj) {
+ if (!conf_obj && !env_data) {
dpp_auth_fail(auth,
"Missing required Configuration Object attribute");
goto fail;
@@ -6770,15 +8179,41 @@ int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
}
-struct dpp_configurator *
-dpp_keygen_configurator(const char *curve, const u8 *privkey,
- size_t privkey_len)
+static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
{
- struct dpp_configurator *conf;
struct wpabuf *csign_pub = NULL;
u8 kid_hash[SHA256_MAC_LEN];
const u8 *addr[1];
size_t len[1];
+ int res;
+
+ csign_pub = dpp_get_pubkey_point(conf->csign, 1);
+ if (!csign_pub) {
+ wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
+ return -1;
+ }
+
+ /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
+ addr[0] = wpabuf_head(csign_pub);
+ len[0] = wpabuf_len(csign_pub);
+ res = sha256_vector(1, addr, len, kid_hash);
+ wpabuf_free(csign_pub);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to derive kid for C-sign-key");
+ return -1;
+ }
+
+ conf->kid = base64_url_encode(kid_hash, sizeof(kid_hash), NULL);
+ return conf->kid ? 0 : -1;
+}
+
+
+struct dpp_configurator *
+dpp_keygen_configurator(const char *curve, const u8 *privkey,
+ size_t privkey_len)
+{
+ struct dpp_configurator *conf;
conf = os_zalloc(sizeof(*conf));
if (!conf)
@@ -6804,31 +8239,12 @@ dpp_keygen_configurator(const char *curve, const u8 *privkey,
goto fail;
conf->own = 1;
- csign_pub = dpp_get_pubkey_point(conf->csign, 1);
- if (!csign_pub) {
- wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
- goto fail;
- }
-
- /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
- addr[0] = wpabuf_head(csign_pub);
- len[0] = wpabuf_len(csign_pub);
- if (sha256_vector(1, addr, len, kid_hash) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Failed to derive kid for C-sign-key");
+ if (dpp_configurator_gen_kid(conf) < 0)
goto fail;
- }
-
- conf->kid = base64_url_encode(kid_hash, sizeof(kid_hash), NULL);
- if (!conf->kid)
- goto fail;
-out:
- wpabuf_free(csign_pub);
return conf;
fail:
dpp_configurator_free(conf);
- conf = NULL;
- goto out;
+ return NULL;
}
@@ -8956,6 +10372,10 @@ static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
if (id && bi->id != id)
continue;
found = 1;
+#ifdef CONFIG_DPP2
+ if (dpp->remove_bi)
+ dpp->remove_bi(dpp->cb_ctx, bi);
+#endif /* CONFIG_DPP2 */
dl_list_del(&bi->list);
dpp_bootstrap_info_free(bi);
}
@@ -9006,11 +10426,10 @@ struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
{
- char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
+ char *mac = NULL, *info = NULL, *curve = NULL;
char *key = NULL;
u8 *privkey = NULL;
size_t privkey_len = 0;
- size_t len;
int ret = -1;
struct dpp_bootstrap_info *bi;
@@ -9030,7 +10449,7 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
else
goto fail;
- chan = get_param(cmd, " chan=");
+ bi->chan = get_param(cmd, " chan=");
mac = get_param(cmd, " mac=");
info = get_param(cmd, " info=");
curve = get_param(cmd, " curve=");
@@ -9044,43 +10463,19 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
goto fail;
}
- pk = dpp_keygen(bi, curve, privkey, privkey_len);
- if (!pk)
+ if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
+ dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
+ dpp_parse_uri_mac(bi, mac) < 0 ||
+ dpp_parse_uri_info(bi, info) < 0 ||
+ dpp_gen_uri(bi) < 0)
goto fail;
- len = 4; /* "DPP:" */
- if (chan) {
- if (dpp_parse_uri_chan_list(bi, chan) < 0)
- goto fail;
- len += 3 + os_strlen(chan); /* C:...; */
- }
- if (mac) {
- if (dpp_parse_uri_mac(bi, mac) < 0)
- goto fail;
- len += 3 + os_strlen(mac); /* M:...; */
- }
- if (info) {
- if (dpp_parse_uri_info(bi, info) < 0)
- goto fail;
- len += 3 + os_strlen(info); /* I:...; */
- }
- len += 4 + os_strlen(pk);
- bi->uri = os_malloc(len + 1);
- if (!bi->uri)
- goto fail;
- os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
- chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
- mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
- info ? "I:" : "", info ? info : "", info ? ";" : "",
- pk);
bi->id = dpp_next_id(dpp);
dl_list_add(&dpp->bootstrap, &bi->list);
ret = bi->id;
bi = NULL;
fail:
os_free(curve);
- os_free(pk);
- os_free(chan);
os_free(mac);
os_free(info);
str_clear_free(key);
@@ -9175,17 +10570,39 @@ int dpp_bootstrap_info(struct dpp_global *dpp, int id,
"mac_addr=" MACSTR "\n"
"info=%s\n"
"num_freq=%u\n"
+ "use_freq=%u\n"
"curve=%s\n"
"pkhash=%s\n",
dpp_bootstrap_type_txt(bi->type),
MAC2STR(bi->mac_addr),
bi->info ? bi->info : "",
bi->num_freq,
+ bi->num_freq == 1 ? bi->freq[0] : 0,
bi->curve->name,
pkhash);
}
+int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_bootstrap_get_id(dpp, id);
+ if (!bi)
+ return -1;
+
+ str_clear_free(bi->configurator_params);
+
+ if (params) {
+ bi->configurator_params = os_strdup(params);
+ return bi->configurator_params ? 0 : -1;
+ }
+
+ bi->configurator_params = NULL;
+ return 0;
+}
+
+
void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
const u8 *r_bootstrap,
struct dpp_bootstrap_info **own_bi,
@@ -9218,7 +10635,108 @@ void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
if (*own_bi && *peer_bi)
break;
}
+}
+
+
+#ifdef CONFIG_DPP2
+struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
+ const u8 *hash)
+{
+ struct dpp_bootstrap_info *bi;
+
+ if (!dpp)
+ return NULL;
+
+ dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
+ if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash,
+ SHA256_MAC_LEN) == 0)
+ return bi;
+ }
+
+ return NULL;
+}
+#endif /* CONFIG_DPP2 */
+
+
+static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
+ struct dpp_bootstrap_info *peer_bi)
+{
+ unsigned int i, freq = 0;
+ enum hostapd_hw_mode mode;
+ u8 op_class, channel;
+ char chan[20];
+
+ if (peer_bi->num_freq == 0)
+ return 0; /* no channel preference/constraint */
+
+ for (i = 0; i < peer_bi->num_freq; i++) {
+ if (own_bi->num_freq == 0 ||
+ freq_included(own_bi->freq, own_bi->num_freq,
+ peer_bi->freq[i])) {
+ freq = peer_bi->freq[i];
+ break;
+ }
+ }
+ if (!freq) {
+ wpa_printf(MSG_DEBUG, "DPP: No common channel found");
+ return -1;
+ }
+
+ mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
+ if (mode == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not determine operating class or channel number for %u MHz",
+ freq);
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
+ freq, op_class, channel);
+ os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
+ os_free(own_bi->chan);
+ own_bi->chan = os_strdup(chan);
+ own_bi->freq[0] = freq;
+ own_bi->num_freq = 1;
+ os_free(peer_bi->chan);
+ peer_bi->chan = os_strdup(chan);
+ peer_bi->freq[0] = freq;
+ peer_bi->num_freq = 1;
+ return dpp_gen_uri(own_bi);
+}
+
+
+static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
+ struct dpp_bootstrap_info *peer_bi)
+{
+ if (peer_bi->curve == own_bi->curve)
+ return 0;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Update own bootstrapping key to match peer curve from NFC handover");
+
+ EVP_PKEY_free(own_bi->pubkey);
+ own_bi->pubkey = NULL;
+
+ if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
+ dpp_gen_uri(own_bi) < 0)
+ goto fail;
+
+ return 0;
+fail:
+ dl_list_del(&own_bi->list);
+ dpp_bootstrap_info_free(own_bi);
+ return -1;
+}
+
+
+int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
+ struct dpp_bootstrap_info *peer_bi)
+{
+ if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
+ dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
+ return -1;
+ return 0;
}
@@ -9327,6 +10845,48 @@ int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
#ifdef CONFIG_DPP2
+int dpp_configurator_from_backup(struct dpp_global *dpp,
+ struct dpp_asymmetric_key *key)
+{
+ struct dpp_configurator *conf;
+ const EC_KEY *eckey;
+ const EC_GROUP *group;
+ int nid;
+ const struct dpp_curve_params *curve;
+
+ if (!key->csign)
+ return -1;
+ eckey = EVP_PKEY_get0_EC_KEY(key->csign);
+ if (!eckey)
+ return -1;
+ group = EC_KEY_get0_group(eckey);
+ if (!group)
+ return -1;
+ nid = EC_GROUP_get_curve_name(group);
+ curve = dpp_get_curve_nid(nid);
+ if (!curve) {
+ wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
+ return -1;
+ }
+
+ conf = os_zalloc(sizeof(*conf));
+ if (!conf)
+ return -1;
+ conf->curve = curve;
+ conf->csign = key->csign;
+ key->csign = NULL;
+ conf->own = 1;
+ if (dpp_configurator_gen_kid(conf) < 0) {
+ dpp_configurator_free(conf);
+ return -1;
+ }
+
+ conf->id = dpp_next_configurator_id(dpp);
+ dl_list_add(&dpp->configurator, &conf->list);
+ return conf->id;
+}
+
+
static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
void *timeout_ctx);
@@ -9405,6 +10965,7 @@ struct dpp_global * dpp_global_init(struct dpp_global_config *config)
#ifdef CONFIG_DPP2
dpp->cb_ctx = config->cb_ctx;
dpp->process_conf_obj = config->process_conf_obj;
+ dpp->remove_bi = config->remove_bi;
#endif /* CONFIG_DPP2 */
dl_list_init(&dpp->bootstrap);
@@ -9561,6 +11122,32 @@ static int dpp_tcp_send(struct dpp_connection *conn)
}
+static int dpp_tcp_send_msg(struct dpp_connection *conn,
+ const struct wpabuf *msg)
+{
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
+ if (!conn->msg_out)
+ return -1;
+ wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
+ wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
+ wpabuf_len(msg) - 1);
+
+ if (dpp_tcp_send(conn) == 1) {
+ if (!conn->write_eloop) {
+ if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
+ dpp_conn_tx_ready,
+ conn, NULL) < 0)
+ return -1;
+ conn->write_eloop = 1;
+ }
+ }
+
+ return 0;
+}
+
+
static void dpp_controller_start_gas_client(struct dpp_connection *conn)
{
struct dpp_authentication *auth = conn->auth;
@@ -9574,27 +11161,8 @@ static void dpp_controller_start_gas_client(struct dpp_connection *conn)
return;
}
- wpabuf_free(conn->msg_out);
- conn->msg_out_pos = 0;
- conn->msg_out = wpabuf_alloc(4 + wpabuf_len(buf) - 1);
- if (!conn->msg_out) {
- wpabuf_free(buf);
- return;
- }
- wpabuf_put_be32(conn->msg_out, wpabuf_len(buf) - 1);
- wpabuf_put_data(conn->msg_out, wpabuf_head_u8(buf) + 1,
- wpabuf_len(buf) - 1);
+ dpp_tcp_send_msg(conn, buf);
wpabuf_free(buf);
-
- if (dpp_tcp_send(conn) == 1) {
- if (!conn->write_eloop) {
- if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
- dpp_conn_tx_ready,
- conn, NULL) < 0)
- return;
- conn->write_eloop = 1;
- }
- }
}
@@ -9793,7 +11361,8 @@ int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
* continue that session (send this over TCP) and return 0.
*/
if (type != DPP_PA_PEER_DISCOVERY_REQ &&
- type != DPP_PA_PEER_DISCOVERY_RESP) {
+ type != DPP_PA_PEER_DISCOVERY_RESP &&
+ type != DPP_PA_PRESENCE_ANNOUNCEMENT) {
dl_list_for_each(ctrl, &dpp->controllers,
struct dpp_relay_controller, list) {
dl_list_for_each(conn, &ctrl->conn,
@@ -9808,7 +11377,14 @@ int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
if (!r_bootstrap)
return -1;
- ctrl = dpp_relay_controller_get(dpp, r_bootstrap);
+ if (type == DPP_PA_PRESENCE_ANNOUNCEMENT) {
+ /* TODO: Could send this to all configured Controllers. For now,
+ * only the first Controller is supported. */
+ ctrl = dl_list_first(&dpp->controllers,
+ struct dpp_relay_controller, list);
+ } else {
+ ctrl = dpp_relay_controller_get(dpp, r_bootstrap);
+ }
if (!ctrl)
return -1;
@@ -9940,7 +11516,8 @@ static int dpp_controller_rx_auth_req(struct dpp_connection *conn,
return 0;
}
- conn->auth = dpp_auth_req_rx(conn->ctrl->global->msg_ctx,
+ conn->auth = dpp_auth_req_rx(conn->ctrl->global,
+ conn->ctrl->global->msg_ctx,
conn->ctrl->allowed_roles,
conn->ctrl->qr_mutual,
peer_bi, own_bi, -1, hdr, buf, len);
@@ -9949,33 +11526,13 @@ static int dpp_controller_rx_auth_req(struct dpp_connection *conn,
return -1;
}
- if (dpp_set_configurator(conn->ctrl->global, conn->ctrl->global->msg_ctx,
- conn->auth,
+ if (dpp_set_configurator(conn->auth,
conn->ctrl->configurator_params) < 0) {
dpp_connection_remove(conn);
return -1;
}
- wpabuf_free(conn->msg_out);
- conn->msg_out_pos = 0;
- conn->msg_out = wpabuf_alloc(4 + wpabuf_len(conn->auth->resp_msg) - 1);
- 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_u8(conn->auth->resp_msg) + 1,
- wpabuf_len(conn->auth->resp_msg) - 1);
-
- if (dpp_tcp_send(conn) == 1) {
- if (!conn->write_eloop) {
- if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
- dpp_conn_tx_ready,
- conn, NULL) < 0)
- return -1;
- conn->write_eloop = 1;
- }
- }
-
- return 0;
+ return dpp_tcp_send_msg(conn, conn->auth->resp_msg);
}
@@ -9984,6 +11541,7 @@ static int dpp_controller_rx_auth_resp(struct dpp_connection *conn,
{
struct dpp_authentication *auth = conn->auth;
struct wpabuf *msg;
+ int res;
if (!auth)
return -1;
@@ -10002,30 +11560,10 @@ static int dpp_controller_rx_auth_resp(struct dpp_connection *conn,
return -1;
}
- wpabuf_free(conn->msg_out);
- conn->msg_out_pos = 0;
- conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
- if (!conn->msg_out) {
- wpabuf_free(msg);
- return -1;
- }
- wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
- wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
- wpabuf_len(msg) - 1);
- wpabuf_free(msg);
-
conn->on_tcp_tx_complete_auth_ok = 1;
- if (dpp_tcp_send(conn) == 1) {
- if (!conn->write_eloop) {
- if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
- dpp_conn_tx_ready,
- conn, NULL) < 0)
- return -1;
- conn->write_eloop = 1;
- }
- }
-
- return 0;
+ res = dpp_tcp_send_msg(conn, msg);
+ wpabuf_free(msg);
+ return res;
}
@@ -10142,6 +11680,56 @@ static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn,
}
+static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf,
+ size_t len)
+{
+ const u8 *r_bootstrap;
+ u16 r_bootstrap_len;
+ struct dpp_bootstrap_info *peer_bi;
+ struct dpp_authentication *auth;
+ struct dpp_global *dpp = conn->ctrl->global;
+
+ if (conn->auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Presence Announcement during ongoing Authentication");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Presence Announcement");
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(dpp->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+ peer_bi = dpp_bootstrap_find_chirp(dpp, r_bootstrap);
+ if (!peer_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching bootstrapping information found");
+ return -1;
+ }
+
+ auth = dpp_auth_init(dpp, dpp->msg_ctx, peer_bi, NULL,
+ DPP_CAPAB_CONFIGURATOR, -1, NULL, 0);
+ if (!auth)
+ return -1;
+ if (dpp_set_configurator(conn->auth,
+ conn->ctrl->configurator_params) < 0) {
+ dpp_auth_deinit(auth);
+ dpp_connection_remove(conn);
+ return -1;
+ }
+
+ conn->auth = auth;
+ return dpp_tcp_send_msg(conn, conn->auth->req_msg);
+}
+
+
static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
size_t len)
{
@@ -10192,6 +11780,9 @@ static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
case DPP_PA_CONNECTION_STATUS_RESULT:
return dpp_controller_rx_conn_status_result(conn, msg, pos,
end - pos);
+ case DPP_PA_PRESENCE_ANNOUNCEMENT:
+ return dpp_controller_rx_presence_announcement(conn, msg, pos,
+ end - pos);
default:
/* TODO: missing messages types */
wpa_printf(MSG_DEBUG,
@@ -10286,7 +11877,7 @@ static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
{
struct dpp_authentication *auth = conn->auth;
int res;
- struct wpabuf *msg, *encaps;
+ struct wpabuf *msg;
enum dpp_status_error status;
wpa_printf(MSG_DEBUG,
@@ -10308,35 +11899,19 @@ static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
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);
if (!msg)
return -1;
- encaps = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
- if (!encaps) {
- wpabuf_free(msg);
- return -1;
- }
- wpabuf_put_be32(encaps, 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);
-
- wpabuf_free(conn->msg_out);
- conn->msg_out_pos = 0;
- conn->msg_out = encaps;
conn->on_tcp_tx_complete_remove = 1;
- dpp_tcp_send(conn);
+ res = dpp_tcp_send_msg(conn, msg);
+ wpabuf_free(msg);
/* This exchange will be terminated in the TX status handler */
- return 0;
-#else /* CONFIG_DPP2 */
- return -1;
-#endif /* CONFIG_DPP2 */
+ return res;
}
@@ -10721,4 +12296,22 @@ void dpp_controller_stop(struct dpp_global *dpp)
}
}
+
+struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
+{
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame");
+
+ msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
+ if (!msg)
+ return NULL;
+
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Presence Announcement frame attributes", msg);
+ return msg;
+}
+
#endif /* CONFIG_DPP2 */
diff --git a/src/common/dpp.h b/src/common/dpp.h
index cb788ae4..ab3f9271 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -1,7 +1,7 @@
/*
* DPP functionality shared between hostapd and wpa_supplicant
* Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -36,6 +36,11 @@ enum dpp_public_action_frame_type {
DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
DPP_PA_CONFIGURATION_RESULT = 11,
DPP_PA_CONNECTION_STATUS_RESULT = 12,
+ DPP_PA_PRESENCE_ANNOUNCEMENT = 13,
+ DPP_PA_RECONFIG_ANNOUNCEMENT = 14,
+ DPP_PA_RECONFIG_AUTH_REQ = 15,
+ DPP_PA_RECONFIG_AUTH_RESP = 16,
+ DPP_PA_RECONFIG_AUTH_CONF = 17,
};
enum dpp_attribute_id {
@@ -67,6 +72,9 @@ enum dpp_attribute_id {
DPP_ATTR_ENVELOPED_DATA = 0x101A,
DPP_ATTR_SEND_CONN_STATUS = 0x101B,
DPP_ATTR_CONN_STATUS = 0x101C,
+ DPP_ATTR_RECONFIG_FLAGS = 0x101D,
+ DPP_ATTR_C_SIGN_KEY_HASH = 0x101E,
+ DPP_ATTR_CSR_ATTR_REQ = 0x101F,
};
enum dpp_status_error {
@@ -81,6 +89,9 @@ enum dpp_status_error {
DPP_STATUS_NO_MATCH = 8,
DPP_STATUS_CONFIG_REJECTED = 9,
DPP_STATUS_NO_AP = 10,
+ DPP_STATUS_CONFIGURE_PENDING = 11,
+ DPP_STATUS_CSR_NEEDED = 12,
+ DPP_STATUS_CSR_BAD = 13,
};
#define DPP_CAPAB_ENROLLEE BIT(0)
@@ -115,15 +126,19 @@ struct dpp_bootstrap_info {
enum dpp_bootstrap_type type;
char *uri;
u8 mac_addr[ETH_ALEN];
+ char *chan;
char *info;
+ char *pk;
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
unsigned int num_freq;
int own;
EVP_PKEY *pubkey;
u8 pubkey_hash[SHA256_MAC_LEN];
+ u8 pubkey_hash_chirp[SHA256_MAC_LEN];
const struct dpp_curve_params *curve;
unsigned int pkex_t; /* number of failures before dpp_pkex
* instantiation */
+ char *configurator_params;
};
#define PKEX_COUNTER_T_LIMIT 5
@@ -187,10 +202,18 @@ struct dpp_configuration {
int psk_set;
};
+struct dpp_asymmetric_key {
+ struct dpp_asymmetric_key *next;
+ EVP_PKEY *csign;
+ char *config_template;
+ char *connector_template;
+};
+
#define DPP_MAX_CONF_OBJ 10
#define DPP_MAX_CHANNELS 32
struct dpp_authentication {
+ struct dpp_global *global;
void *msg_ctx;
u8 peer_version;
const struct dpp_curve_params *curve;
@@ -246,6 +269,7 @@ struct dpp_authentication {
struct dpp_configuration *conf2_ap;
struct dpp_configuration *conf_sta;
struct dpp_configuration *conf2_sta;
+ int provision_configurator;
struct dpp_configurator *conf;
struct dpp_config_obj {
char *connector; /* received signedConnector */
@@ -259,11 +283,13 @@ struct dpp_authentication {
struct wpabuf *c_sign_key;
} conf_obj[DPP_MAX_CONF_OBJ];
unsigned int num_conf_obj;
+ struct dpp_asymmetric_key *conf_key_pkg;
struct wpabuf *net_access_key;
os_time_t net_access_key_expiry;
int send_conn_status;
int conn_status_requested;
int akm_use_selector;
+ int configurator_set;
#ifdef CONFIG_TESTING_OPTIONS
char *config_obj_override;
char *discovery_override;
@@ -414,15 +440,16 @@ extern size_t dpp_nonce_override_len;
void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info);
const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type);
-int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
const char *chan_list);
int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac);
int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info);
-char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
- const u8 *privkey, size_t privkey_len);
+int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
+ struct dpp_bootstrap_info *peer_bi);
+struct dpp_authentication *
+dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx);
struct hostapd_hw_modes;
-struct dpp_authentication * dpp_auth_init(void *msg_ctx,
+struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx,
struct dpp_bootstrap_info *peer_bi,
struct dpp_bootstrap_info *own_bi,
u8 dpp_allowed_roles,
@@ -430,8 +457,8 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx,
struct hostapd_hw_modes *own_modes,
u16 num_modes);
struct dpp_authentication *
-dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
- struct dpp_bootstrap_info *peer_bi,
+dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles,
+ int qr_mutual, struct dpp_bootstrap_info *peer_bi,
struct dpp_bootstrap_info *own_bi,
unsigned int freq, const u8 *hdr, const u8 *attr_start,
size_t attr_len);
@@ -456,9 +483,7 @@ int dpp_akm_dpp(enum dpp_akm akm);
int dpp_akm_ver2(enum dpp_akm akm);
int dpp_configuration_valid(const struct dpp_configuration *conf);
void dpp_configuration_free(struct dpp_configuration *conf);
-int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
- struct dpp_authentication *auth,
- const char *cmd);
+int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd);
void dpp_auth_deinit(struct dpp_authentication *auth);
struct wpabuf *
dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
@@ -551,14 +576,19 @@ dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id);
int dpp_bootstrap_info(struct dpp_global *dpp, int id,
char *reply, int reply_size);
+int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params);
void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
const u8 *r_bootstrap,
struct dpp_bootstrap_info **own_bi,
struct dpp_bootstrap_info **peer_bi);
+struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
+ const u8 *hash);
int dpp_configurator_add(struct dpp_global *dpp, const char *cmd);
int dpp_configurator_remove(struct dpp_global *dpp, const char *id);
int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
char *buf, size_t buflen);
+int dpp_configurator_from_backup(struct dpp_global *dpp,
+ struct dpp_asymmetric_key *key);
int dpp_relay_add_controller(struct dpp_global *dpp,
struct dpp_relay_config *config);
int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
@@ -571,11 +601,13 @@ int dpp_controller_start(struct dpp_global *dpp,
void dpp_controller_stop(struct dpp_global *dpp);
int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
const struct hostapd_ip_addr *addr, int port);
+struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi);
struct dpp_global_config {
void *msg_ctx;
void *cb_ctx;
int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
+ void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
};
struct dpp_global * dpp_global_init(struct dpp_global_config *config);
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 19593a52..f6c67a37 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -468,20 +468,53 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
data->bandwidth = (1 << (u8) bw) * 20;
data->center_freq1 = freq1;
data->center_freq2 = freq2;
- data->ht_enabled = 0;
- data->vht_enabled = 0;
}
+ data->ht_enabled = 0;
+ data->vht_enabled = 0;
return 0;
}
- if (data->vht_enabled) switch (oper_chwidth) {
+ if (data->he_enabled) switch (oper_chwidth) {
case CHANWIDTH_USE_HT:
- if (center_segment1 ||
- (center_segment0 != 0 &&
- 5000 + center_segment0 * 5 != data->center_freq1 &&
- 2407 + center_segment0 * 5 != data->center_freq1))
+ if (mode == HOSTAPD_MODE_IEEE80211G && sec_channel_offset) {
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
+ wpa_printf(MSG_ERROR,
+ "40 MHz channel width is not supported in 2.4 GHz");
+ return -1;
+ }
+ break;
+ }
+ /* fall through */
+ case CHANWIDTH_80MHZ:
+ if (mode == HOSTAPD_MODE_IEEE80211A) {
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
+ wpa_printf(MSG_ERROR,
+ "40/80 MHz channel width is not supported in 5/6 GHz");
+ return -1;
+ }
+ }
+ break;
+ case CHANWIDTH_80P80MHZ:
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) {
+ wpa_printf(MSG_ERROR,
+ "80+80 MHz channel width is not supported in 5/6 GHz");
return -1;
+ }
+ break;
+ case CHANWIDTH_160MHZ:
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)) {
+ wpa_printf(MSG_ERROR,
+ "160 MHz channel width is not supported in 5 / 6GHz");
+ return -1;
+ }
+ break;
+ } else if (data->vht_enabled) switch (oper_chwidth) {
+ case CHANWIDTH_USE_HT:
break;
case CHANWIDTH_80P80MHZ:
if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
@@ -489,6 +522,28 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
"80+80 channel width is not supported!");
return -1;
}
+ /* fall through */
+ case CHANWIDTH_80MHZ:
+ break;
+ case CHANWIDTH_160MHZ:
+ if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
+ wpa_printf(MSG_ERROR,
+ "160 MHz channel width is not supported!");
+ return -1;
+ }
+ break;
+ }
+
+ if (data->he_enabled || data->vht_enabled) switch (oper_chwidth) {
+ case CHANWIDTH_USE_HT:
+ if (center_segment1 ||
+ (center_segment0 != 0 &&
+ 5000 + center_segment0 * 5 != data->center_freq1 &&
+ 2407 + center_segment0 * 5 != data->center_freq1))
+ return -1;
+ break;
+ case CHANWIDTH_80P80MHZ:
if (center_segment1 == center_segment0 + 4 ||
center_segment1 == center_segment0 - 4)
return -1;
@@ -533,12 +588,6 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
break;
case CHANWIDTH_160MHZ:
data->bandwidth = 160;
- if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
- VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
- wpa_printf(MSG_ERROR,
- "160MHZ channel width is not supported!");
- return -1;
- }
if (center_segment1)
return -1;
if (!sec_channel_offset)
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index b3304548..42c916b5 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -130,6 +130,12 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
elems->multi_ap = pos;
elems->multi_ap_len = elen;
break;
+ case OWE_OUI_TYPE:
+ /* OWE Transition Mode element */
+ break;
+ case DPP_CC_OUI_TYPE:
+ /* DPP Configurator Connectivity element */
+ break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
@@ -206,6 +212,8 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
ext_id = *pos++;
elen--;
+ elems->frag_ies.last_eid_ext = 0;
+
switch (ext_id) {
case WLAN_EID_EXT_ASSOC_DELAY_INFO:
if (elen != 1)
@@ -245,9 +253,9 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
elems->key_delivery = pos;
elems->key_delivery_len = elen;
break;
- case WLAN_EID_EXT_FILS_WRAPPED_DATA:
- elems->fils_wrapped_data = pos;
- elems->fils_wrapped_data_len = elen;
+ case WLAN_EID_EXT_WRAPPED_DATA:
+ elems->wrapped_data = pos;
+ elems->wrapped_data_len = elen;
break;
case WLAN_EID_EXT_FILS_PUBLIC_KEY:
if (elen < 1)
@@ -286,6 +294,10 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
elems->oci = pos;
elems->oci_len = elen;
break;
+ case WLAN_EID_EXT_SHORT_SSID_LIST:
+ elems->short_ssid_list = pos;
+ elems->short_ssid_list_len = elen;
+ break;
default:
if (show_errors) {
wpa_printf(MSG_MSGDUMP,
@@ -295,10 +307,39 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
return -1;
}
+ if (elen == 254)
+ elems->frag_ies.last_eid_ext = ext_id;
+
return 0;
}
+static void ieee802_11_parse_fragment(struct frag_ies_info *frag_ies,
+ const u8 *pos, u8 elen)
+{
+ if (frag_ies->n_frags >= MAX_NUM_FRAG_IES_SUPPORTED) {
+ wpa_printf(MSG_MSGDUMP, "Too many element fragments - skip");
+ return;
+ }
+
+ /*
+ * Note: while EID == 0 is a valid ID (SSID IE), it should not be
+ * fragmented.
+ */
+ if (!frag_ies->last_eid) {
+ wpa_printf(MSG_MSGDUMP,
+ "Fragment without a valid last element - skip");
+ return;
+ }
+
+ frag_ies->frags[frag_ies->n_frags].ie = pos;
+ frag_ies->frags[frag_ies->n_frags].ie_len = elen;
+ frag_ies->frags[frag_ies->n_frags].eid = frag_ies->last_eid;
+ frag_ies->frags[frag_ies->n_frags].eid_ext = frag_ies->last_eid_ext;
+ frag_ies->n_frags++;
+}
+
+
/**
* ieee802_11_parse_elems - Parse information elements in management frames
* @start: Pointer to the start of IEs
@@ -331,6 +372,11 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elen);
break;
}
+ if (elems->ssid) {
+ wpa_printf(MSG_MSGDUMP,
+ "Ignored duplicated SSID element");
+ break;
+ }
elems->ssid = pos;
elems->ssid_len = elen;
break;
@@ -516,7 +562,7 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->dils_len = elen;
break;
case WLAN_EID_FRAGMENT:
- /* TODO */
+ ieee802_11_parse_fragment(&elems->frag_ies, pos, elen);
break;
case WLAN_EID_EXTENSION:
if (ieee802_11_parse_extension(pos, elen, elems,
@@ -532,6 +578,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
id, elen);
break;
}
+
+ if (id != WLAN_EID_FRAGMENT && elen == 255)
+ elems->frag_ies.last_eid = id;
+
+ if (id == WLAN_EID_EXTENSION && !elems->frag_ies.last_eid_ext)
+ elems->frag_ies.last_eid = 0;
}
if (!for_each_element_completed(elem, start, len)) {
@@ -2394,6 +2446,79 @@ int op_class_to_ch_width(u8 op_class)
return CHANWIDTH_USE_HT;
}
+struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
+ u8 eid, u8 eid_ext,
+ const u8 *data, u8 len)
+{
+ struct frag_ies_info *frag_ies = &elems->frag_ies;
+ struct wpabuf *buf;
+ unsigned int i;
+
+ if (!elems || !data || !len)
+ return NULL;
+
+ buf = wpabuf_alloc_copy(data, len);
+ if (!buf)
+ return NULL;
+
+ for (i = 0; i < frag_ies->n_frags; i++) {
+ int ret;
+
+ if (frag_ies->frags[i].eid != eid ||
+ frag_ies->frags[i].eid_ext != eid_ext)
+ continue;
+
+ ret = wpabuf_resize(&buf, frag_ies->frags[i].ie_len);
+ if (ret < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ /* Copy only the fragment data (without the EID and length) */
+ wpabuf_put_data(buf, frag_ies->frags[i].ie,
+ frag_ies->frags[i].ie_len);
+ }
+
+ return buf;
+}
+
+
+struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
+ u8 eid, u8 eid_ext)
+{
+ const u8 *data;
+ u8 len;
+
+ /*
+ * TODO: Defragmentation mechanism can be supported for all IEs. For now
+ * handle only those that are used (or use ieee802_11_defrag_data()).
+ */
+ switch (eid) {
+ case WLAN_EID_EXTENSION:
+ switch (eid_ext) {
+ case WLAN_EID_EXT_FILS_HLP_CONTAINER:
+ data = elems->fils_hlp;
+ len = elems->fils_hlp_len;
+ break;
+ case WLAN_EID_EXT_WRAPPED_DATA:
+ data = elems->wrapped_data;
+ len = elems->wrapped_data_len;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Defragmentation not supported. eid_ext=%u",
+ eid_ext);
+ return NULL;
+ }
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Defragmentation not supported. eid=%u", eid);
+ return NULL;
+ }
+
+ return ieee802_11_defrag_data(elems, eid, eid_ext, data, len);
+}
/* Parse HT capabilities to get maximum number of supported spatial streams */
static int parse_ht_mcs_set_for_max_nss(
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 2c66507e..e3957697 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -21,6 +21,7 @@ struct element {
struct hostapd_hw_modes;
#define MAX_NOF_MB_IES_SUPPORTED 5
+#define MAX_NUM_FRAG_IES_SUPPORTED 3
struct mb_ies_info {
struct {
@@ -30,6 +31,21 @@ struct mb_ies_info {
u8 nof_ies;
};
+struct frag_ies_info {
+ struct {
+ u8 eid;
+ u8 eid_ext;
+ const u8 *ie;
+ u8 ie_len;
+ } frags[MAX_NUM_FRAG_IES_SUPPORTED];
+
+ u8 n_frags;
+
+ /* the last parsed element ID and element extension ID */
+ u8 last_eid;
+ u8 last_eid_ext;
+};
+
/* Parsed Information Elements */
struct ieee802_11_elems {
const u8 *ssid;
@@ -85,7 +101,7 @@ struct ieee802_11_elems {
const u8 *fils_hlp;
const u8 *fils_ip_addr_assign;
const u8 *key_delivery;
- const u8 *fils_wrapped_data;
+ const u8 *wrapped_data;
const u8 *fils_pk;
const u8 *fils_nonce;
const u8 *owe_dh;
@@ -96,6 +112,7 @@ struct ieee802_11_elems {
const u8 *multi_ap;
const u8 *he_capabilities;
const u8 *he_operation;
+ const u8 *short_ssid_list;
u8 ssid_len;
u8 supp_rates_len;
@@ -137,7 +154,7 @@ struct ieee802_11_elems {
u8 fils_hlp_len;
u8 fils_ip_addr_assign_len;
u8 key_delivery_len;
- u8 fils_wrapped_data_len;
+ u8 wrapped_data_len;
u8 fils_pk_len;
u8 owe_dh_len;
u8 power_capab_len;
@@ -147,8 +164,10 @@ struct ieee802_11_elems {
u8 multi_ap_len;
u8 he_capabilities_len;
u8 he_operation_len;
+ u8 short_ssid_list_len;
struct mb_ies_info mb_ies;
+ struct frag_ies_info frag_ies;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -291,6 +310,12 @@ void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
struct ieee80211_edmg_config requested);
+struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
+ u8 eid, u8 eid_ext,
+ const u8 *data, u8 len);
+struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
+ u8 eid, u8 eid_ext);
+
int get_max_nss_capability(struct ieee802_11_elems *elems, int parse_for_rx);
struct supported_chan_width {
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index fdc51dcc..4a5eb16c 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -458,7 +458,7 @@
#define WLAN_EID_EXT_FILS_HLP_CONTAINER 5
#define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6
#define WLAN_EID_EXT_KEY_DELIVERY 7
-#define WLAN_EID_EXT_FILS_WRAPPED_DATA 8
+#define WLAN_EID_EXT_WRAPPED_DATA 8
#define WLAN_EID_EXT_FTM_SYNC_INFO 9
#define WLAN_EID_EXT_EXTENDED_REQUEST 10
#define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11
@@ -472,9 +472,11 @@
#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_SHORT_SSID_LIST 58
#define WLAN_EID_EXT_EDMG_CAPABILITIES 61
#define WLAN_EID_EXT_EDMG_OPERATION 62
#define WLAN_EID_EXT_REJECTED_GROUPS 92
+#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -556,6 +558,7 @@
#define WLAN_EXT_CAPAB_COMPLETE_NON_TX_BSSID_PROFILE 80
#define WLAN_EXT_CAPAB_SAE_PW_ID 81
#define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82
+#define WLAN_EXT_CAPAB_BEACON_PROTECTION 84
/* Extended RSN Capabilities */
/* bits 0-3: Field length (n-1) */
@@ -1319,6 +1322,8 @@ struct ieee80211_ampe_ie {
#define OWE_IE_VENDOR_TYPE 0x506f9a1c
#define OWE_OUI_TYPE 28
#define MULTI_AP_OUI_TYPE 0x1B
+#define DPP_CC_IE_VENDOR_TYPE 0x506f9a1e
+#define DPP_CC_OUI_TYPE 0x1e
#define MULTI_AP_SUB_ELEM_TYPE 0x06
#define MULTI_AP_TEAR_DOWN BIT(4)
@@ -1878,7 +1883,15 @@ enum wnm_sleep_mode_response_status {
/* WNM-Sleep Mode subelement IDs */
enum wnm_sleep_mode_subelement_id {
WNM_SLEEP_SUBELEM_GTK = 0,
- WNM_SLEEP_SUBELEM_IGTK = 1
+ WNM_SLEEP_SUBELEM_IGTK = 1,
+ WNM_SLEEP_SUBELEM_BIGTK = 2,
+};
+
+/* WNM notification type (IEEE P802.11-REVmd/D3.0, Table 9-430) */
+enum wnm_notification_Type {
+ WNM_NOTIF_TYPE_FIRMWARE_UPDATE = 0,
+ WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE = 2,
+ WNM_NOTIF_TYPE_VENDOR_SPECIFIC = 221,
};
/* Channel Switch modes (802.11h) */
@@ -2094,7 +2107,7 @@ enum phy_type {
PHY_TYPE_VHT = 9,
};
-/* IEEE P802.11-REVmc/D5.0, 9.4.2.37 - Neighbor Report element */
+/* IEEE P802.11-REVmd/D3.0, 9.4.2.36 - Neighbor Report element */
/* BSSID Information Field */
#define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0)
#define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1)
@@ -2111,6 +2124,7 @@ enum phy_type {
#define NEI_REP_BSSID_INFO_HT BIT(11)
#define NEI_REP_BSSID_INFO_VHT BIT(12)
#define NEI_REP_BSSID_INFO_FTM BIT(13)
+#define NEI_REP_BSSID_INFO_HE BIT(14)
/*
* IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information
@@ -2173,6 +2187,7 @@ struct ieee80211_6ghz_operation_info {
#define HE_CAPABILITIES_IE_MIN_LEN 21
/* HE Capabilities Information defines */
+#define HE_MACCAP_TWT_RESPONDER ((u8) BIT(2))
#define HE_PHYCAP_CHANNEL_WIDTH_SET_IDX 0
#define HE_PHYCAP_CHANNEL_WIDTH_MASK ((u8) (BIT(1) | BIT(2) | \
BIT(3) | BIT(4)))
@@ -2215,7 +2230,7 @@ struct ieee80211_6ghz_operation_info {
#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(24) | BIT(25) | \
BIT(26) | BIT(27) | \
BIT(28) | BIT(29)))
-#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(30))
+#define HE_OPERATION_BSS_COLOR_PARTIAL ((u32) BIT(30))
#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31))
#define HE_OPERATION_BSS_COLOR_OFFSET 24
diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h
index b85c6c34..d2c4bbd5 100644
--- a/src/common/privsep_commands.h
+++ b/src/common/privsep_commands.h
@@ -82,6 +82,7 @@ struct privsep_cmd_set_key {
size_t seq_len;
u8 key[32];
size_t key_len;
+ enum key_flag key_flag;
};
enum privsep_event {
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index ade7aa62..8ef666db 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -21,6 +21,10 @@
#define OUI_QCA 0x001374
+#ifndef BIT
+#define BIT(x) (1U << (x))
+#endif
+
/**
* enum qca_radiotap_vendor_ids - QCA radiotap vendor namespace IDs
*/
@@ -619,6 +623,31 @@ enum qca_radiotap_vendor_ids {
* association when in disconnected state. For AP mode, only information
* of the currently connected stations is available. This command uses
* attributes defined in enum qca_wlan_vendor_attr_get_sta_info.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_REQUEST_SAR_LIMITS_EVENT: This acts as an event.
+ * Host drivers can request the user space entity to set the SAR power
+ * limits with this event. Accordingly, the user space entity is expected
+ * to set the SAR power limits. Host drivers can retry this event to the
+ * user space for the SAR power limits configuration from user space. If
+ * the driver does not get the SAR power limits from user space for all
+ * the retried attempts, it can configure a default SAR power limit.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO: This acts as a vendor event and
+ * is used to update the information about the station from the driver to
+ * userspace. Uses attributes from enum
+ * qca_wlan_vendor_attr_update_sta_info.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON: This acts as an event.
+ * The host driver initiates the disconnection for scenarios such as beacon
+ * miss, NUD failure, peer kick out, etc. The disconnection indication
+ * through cfg80211_disconnected() expects the reason codes from enum
+ * ieee80211_reasoncode which does not signify these various reasons why
+ * the driver has triggered the disconnection. This event will be used to
+ * send the driver specific reason codes by the host driver to userspace.
+ * Host drivers should trigger this event and pass the respective reason
+ * code immediately prior to triggering cfg80211_disconnected(). The
+ * attributes used with this event are defined in enum
+ * qca_wlan_vendor_attr_driver_disconnect_reason.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -795,6 +824,9 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE = 184,
QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE = 185,
QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO = 186,
+ QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS_EVENT = 187,
+ QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO = 188,
+ QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON = 189,
};
enum qca_wlan_vendor_attr {
@@ -1191,7 +1223,9 @@ enum qca_wlan_vendor_attr_p2p_listen_offload {
*
* @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.
+ * ACS operation. The value is the index of the channel center frequency for
+ * 20 MHz, 40 MHz, and 80 MHz channels. The value is the center frequency index
+ * of the primary 80 MHz segment for 160 MHz and 80+80 MHz channels.
* 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.
@@ -1201,7 +1235,10 @@ enum qca_wlan_vendor_attr_p2p_listen_offload {
*
* @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.
+ * ACS operation. The value is zero for 20 MHz, 40 MHz, and 80 MHz channels.
+ * The value is the index of the channel center frequency for 160 MHz channels
+ * and the center frequency index of the secondary 80 MHz segment for 80+80 MHz
+ * channels.
* 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.
@@ -1244,6 +1281,15 @@ enum qca_wlan_vendor_attr_p2p_listen_offload {
* 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.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED: Flag attribute.
+ * Used with command to notify the driver of EDMG request for ACS
+ * operation.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL: Optional (u8).
+ * Used with event to notify the EDMG channel number selected in ACS
+ * operation.
+ * EDMG primary channel is indicated by QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL
*/
enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
@@ -1262,6 +1308,8 @@ enum qca_wlan_vendor_attr_acs_offload {
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,
+ QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED = 16,
+ QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL = 17,
/* keep last */
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
@@ -1320,6 +1368,11 @@ enum qca_wlan_vendor_acs_hw_mode {
* @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
+ * @QCA_WLAN_VENDOR_FEATURE_THERMAL_CONFIG: Device is capable of receiving
+ * and applying thermal configuration through
+ * %QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL and
+ * %QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW attributes from
+ * userspace.
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
@@ -1334,6 +1387,7 @@ enum qca_wlan_vendor_features {
QCA_WLAN_VENDOR_FEATURE_TWT = 8,
QCA_WLAN_VENDOR_FEATURE_11AX = 9,
QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT = 10,
+ QCA_WLAN_VENDOR_FEATURE_THERMAL_CONFIG = 11,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -1675,6 +1729,9 @@ enum qca_vendor_element_id {
* randomisation
* @QCA_WLAN_VENDOR_ATTR_SCAN_BSSID: 6-byte MAC address representing the
* specific BSSID to scan for.
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_DWELL_TIME: Unsigned 64-bit dwell time in
+ * microseconds. This is a common value which applies across all
+ * frequencies specified by QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES.
*/
enum qca_wlan_vendor_attr_scan {
QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0,
@@ -1689,6 +1746,7 @@ enum qca_wlan_vendor_attr_scan {
QCA_WLAN_VENDOR_ATTR_SCAN_MAC = 9,
QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK = 10,
QCA_WLAN_VENDOR_ATTR_SCAN_BSSID = 11,
+ QCA_WLAN_VENDOR_ATTR_SCAN_DWELL_TIME = 12,
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SCAN_MAX =
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1
@@ -2043,19 +2101,41 @@ enum qca_wlan_vendor_attr_config {
* take the union of IEs from both of these interfaces and send in
* further disassoc/deauth frames.
*/
- QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES = 58,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_DISCONNECT_IES = 58,
/* 8-bit unsigned value for ELNA bypass.
* 1-Enable, 0-Disable
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS = 59,
+ /* 8-bit unsigned value. This attribute enables/disables the host driver
+ * to send the Beacon Report Response with failure reason for the
+ * scenarios where STA cannot honor the Beacon Report Request from AP.
+ * 1-Enable, 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL = 60,
+
+ /* 8-bit unsigned value. This attribute enables/disables the host driver
+ * to send roam reason information in the Reassociation Request frame to
+ * the target AP when roaming within the same ESS.
+ * 1-Enable, 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ROAM_REASON = 61,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST - 1,
};
+/* Compatibility defines for previously used incorrect enum
+ * qca_wlan_vendor_attr_config names. These values should not be used in any
+ * new implementation. */
+#define QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES \
+ QCA_WLAN_VENDOR_ATTR_CONFIG_DISCONNECT_IES
+#define QCA_WLAN_VENDOR_ATTR_BEACON_REPORT_FAIL \
+ QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL
+
/**
* enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration
*
@@ -5656,6 +5736,39 @@ enum qca_wlan_vendor_hang_reason {
QCA_WLAN_HANG_DXE_FAILURE = 12,
/* WMI pending commands exceed the maximum count */
QCA_WLAN_HANG_WMI_EXCEED_MAX_PENDING_CMDS = 13,
+ /* Timeout for peer STA connection accept command's response from the
+ * FW in AP mode. This command is triggered when a STA (peer) connects
+ * to AP (DUT).
+ */
+ QCA_WLAN_HANG_AP_STA_CONNECT_REQ_TIMEOUT = 14,
+ /* Timeout for the AP connection accept command's response from the FW
+ * in STA mode. This command is triggered when the STA (DUT) connects
+ * to an AP (peer).
+ */
+ QCA_WLAN_HANG_STA_AP_CONNECT_REQ_TIMEOUT = 15,
+ /* Timeout waiting for the response to the MAC HW mode change command
+ * sent to FW as a part of MAC mode switch among DBS (Dual Band
+ * Simultaneous), SCC (Single Channel Concurrency), and MCC (Multi
+ * Channel Concurrency) mode.
+ */
+ QCA_WLAN_HANG_MAC_HW_MODE_CHANGE_TIMEOUT = 16,
+ /* Timeout waiting for the response from FW to configure the MAC HW's
+ * mode. This operation is to configure the single/two MACs in either
+ * SCC/MCC/DBS mode.
+ */
+ QCA_WLAN_HANG_MAC_HW_MODE_CONFIG_TIMEOUT = 17,
+ /* Timeout waiting for response of VDEV start command from the FW */
+ QCA_WLAN_HANG_VDEV_START_RESPONSE_TIMED_OUT = 18,
+ /* Timeout waiting for response of VDEV restart command from the FW */
+ QCA_WLAN_HANG_VDEV_RESTART_RESPONSE_TIMED_OUT = 19,
+ /* Timeout waiting for response of VDEV stop command from the FW */
+ QCA_WLAN_HANG_VDEV_STOP_RESPONSE_TIMED_OUT = 20,
+ /* Timeout waiting for response of VDEV delete command from the FW */
+ QCA_WLAN_HANG_VDEV_DELETE_RESPONSE_TIMED_OUT = 21,
+ /* Timeout waiting for response of peer all delete request command to
+ * the FW on a specific VDEV.
+ */
+ QCA_WLAN_HANG_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT = 22,
};
/**
@@ -5668,6 +5781,12 @@ enum qca_wlan_vendor_attr_hang {
* qca_wlan_vendor_hang_reason.
*/
QCA_WLAN_VENDOR_ATTR_HANG_REASON = 1,
+ /* The binary blob data associated with the hang reason specified by
+ * QCA_WLAN_VENDOR_ATTR_HANG_REASON. This binary data is expected to
+ * contain the required dump to analyze the reason for the hang.
+ * NLA_BINARY attribute, the max size is 1024 bytes.
+ */
+ QCA_WLAN_VENDOR_ATTR_HANG_REASON_DATA = 2,
QCA_WLAN_VENDOR_ATTR_HANG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_HANG_MAX =
@@ -5768,12 +5887,22 @@ enum qca_wlan_vendor_attr_rrop_info {
enum qca_wlan_vendor_attr_rtplinst {
QCA_WLAN_VENDOR_ATTR_RTPLINST_INVALID = 0,
- /* Primary channel number (u8) */
+ /* Primary channel number (u8).
+ * Note: If both the driver and user space application support the
+ * 6 GHz band, this attribute is deprecated and
+ * QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY_FREQUENCY should be used. To
+ * maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY is still used if either the
+ * driver or user space application or both do not support the 6 GHz
+ * band.
+ */
QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY = 1,
/* Representative Tx power in dBm (s32) with emphasis on throughput. */
QCA_WLAN_VENDOR_ATTR_RTPLINST_TXPOWER_THROUGHPUT = 2,
/* Representative Tx power in dBm (s32) with emphasis on range. */
QCA_WLAN_VENDOR_ATTR_RTPLINST_TXPOWER_RANGE = 3,
+ /* Primary channel center frequency (u32) in MHz */
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY_FREQUENCY = 4,
QCA_WLAN_VENDOR_ATTR_RTPLINST_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_RTPLINST_MAX =
@@ -6305,6 +6434,29 @@ enum qca_wlan_vendor_attr_wake_stats {
};
/**
+ * enum qca_wlan_vendor_thermal_level - Defines various thermal levels
+ * configured by userspace to the driver/firmware. The values will be
+ * encapsulated in QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL attribute.
+ * The driver/firmware takes actions requested by userspace such as throttling
+ * wifi TX etc. in order to mitigate high temperature.
+ *
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE: Stop/clear all throttling actions.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_LIGHT: Throttle TX lightly.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE: Throttle TX moderately.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_SEVERE: Throttle TX severely.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL: Critical thermal level reached.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY: Emergency thermal level reached.
+ */
+enum qca_wlan_vendor_thermal_level {
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE = 0,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_LIGHT = 1,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE = 2,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_SEVERE = 3,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL = 4,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY = 5,
+};
+
+/**
* enum qca_wlan_vendor_attr_thermal_cmd - Vendor subcmd attributes to set
* cmd value. Used for NL attributes for data used by
* QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD sub command.
@@ -6317,6 +6469,21 @@ enum qca_wlan_vendor_attr_thermal_cmd {
* u32 attribute.
*/
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE = 1,
+ /* Userspace uses this attribute to configure thermal level to the
+ * driver/firmware. Used in request, u32 attribute, possible values
+ * are defined in enum qca_wlan_vendor_thermal_level.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL = 2,
+ /* Userspace uses this attribute to configure the time in which the
+ * driver/firmware should complete applying settings it received from
+ * userspace with QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL
+ * command type. Used in request, u32 attribute, value is in
+ * milliseconds. A value of zero indicates to apply the settings
+ * immediately. The driver/firmware can delay applying the configured
+ * thermal settings within the time specified in this attribute if
+ * there is any critical ongoing operation.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_AFTER_LAST,
@@ -6340,12 +6507,15 @@ enum qca_wlan_vendor_attr_thermal_cmd {
* suspend action.
* @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME: Request to execute thermal
* resume action.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL: Configure thermal level to
+ * the driver/firmware.
*/
enum qca_wlan_vendor_attr_thermal_cmd_type {
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS,
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_TEMPERATURE,
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SUSPEND,
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL,
};
/**
@@ -7254,10 +7424,42 @@ enum qca_wlan_vendor_attr_roam_scan {
* enum qca_wlan_vendor_cfr_method - QCA vendor CFR methods used by
* attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD as part of vendor
* command QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG.
+ * @QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL: CFR method using QoS Null frame
+ * @QCA_WLAN_VENDOR_CFR_QOS_NULL_WITH_PHASE: CFR method using QoS Null frame
+ * with phase
+ * @QCA_WLAN_VENDOR_CFR_PROBE_RESPONSE: CFR method using Probe Response frame
*/
enum qca_wlan_vendor_cfr_method {
- /* CFR method using QOS Null frame */
QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL = 0,
+ QCA_WLAN_VENDOR_CFR_QOS_NULL_WITH_PHASE = 1,
+ QCA_WLAN_VENDOR_CFR_PROBE_RESPONSE = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_cfr_capture_type - QCA vendor CFR capture type used by
+ * attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE.
+ * @QCA_WLAN_VENDOR_CFR_DIRECT_FTM: Filter directed FTM ACK frames.
+ * @QCA_WLAN_VENDOR_CFR_ALL_FTM_ACK: Filter all FTM ACK frames.
+ * @QCA_WLAN_VENDOR_CFR_DIRECT_NDPA_NDP: Filter NDPA NDP directed frames.
+ * @QCA_WLAN_VENDOR_CFR_TA_RA: Filter frames based on TA/RA/Subtype which
+ * is provided by one or more of below attributes:
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER
+ * @QCA_WLAN_CFR_ALL_PACKET: Filter all packets.
+ * @QCA_WLAN_VENDOR_CFR_NDPA_NDP_ALL: Filter all NDPA NDP frames.
+ */
+enum qca_wlan_vendor_cfr_capture_type {
+ QCA_WLAN_VENDOR_CFR_DIRECT_FTM = 0,
+ QCA_WLAN_VENDOR_CFR_ALL_FTM_ACK = 1,
+ QCA_WLAN_VENDOR_CFR_DIRECT_NDPA_NDP = 2,
+ QCA_WLAN_VENDOR_CFR_TA_RA = 3,
+ QCA_WLAN_VENDOR_CFR_ALL_PACKET = 4,
+ QCA_WLAN_VENDOR_CFR_NDPA_NDP_ALL = 5,
};
/**
@@ -7265,44 +7467,177 @@ enum qca_wlan_vendor_cfr_method {
* QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG to configure peer
* Channel Frequency Response capture parameters and enable periodic CFR
* capture.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR: Optional (6-byte MAC address)
+ * MAC address of peer. This is for CFR version 1 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE: Required (flag)
+ * Enable peer CFR capture. This attribute is mandatory to enable peer CFR
+ * capture. If this attribute is not present, peer CFR capture is disabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH: Optional (u8)
+ * BW of measurement, attribute uses the values in enum nl80211_chan_width
+ * Supported values: 20, 40, 80, 80+80, 160.
+ * Note that all targets may not support all bandwidths.
+ * This attribute is mandatory for version 1 if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY: Optional (u32)
+ * Periodicity of CFR measurement in milliseconds.
+ * Periodicity should be a multiple of Base timer.
+ * Current Base timer value supported is 10 milliseconds (default).
+ * 0 for one shot capture.
+ * This attribute is mandatory for version 1 if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD: Optional (u8)
+ * Method used to capture Channel Frequency Response.
+ * Attribute uses the values defined in enum qca_wlan_vendor_cfr_method.
+ * This attribute is mandatory for version 1 if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE: Optional (flag)
+ * Enable periodic CFR capture.
+ * This attribute is mandatory for version 1 to enable Periodic CFR capture.
+ * If this attribute is not present, periodic CFR capture is disabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION: Optional (u8)
+ * Value is 1 or 2 since there are two versions of CFR capture. Two versions
+ * can't be enabled at same time. This attribute is mandatory if target
+ * support both versions and use one of them.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP: Optional (u32)
+ * This attribute is mandatory for version 2 if
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY is used.
+ * Bits 15:0 bitfield indicates which group is to be enabled.
+ * Bits 31:16 Reserved for future use.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION: Optional (u32)
+ * CFR capture duration in microsecond. This attribute is mandatory for
+ * version 2 if attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL: Optional (u32)
+ * CFR capture interval in microsecond. This attribute is mandatory for
+ * version 2 if attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE: Optional (u32)
+ * CFR capture type is defined in enum qca_wlan_vendor_cfr_capture_type.
+ * This attribute is mandatory for version 2.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK: Optional (u64)
+ * Bitfield indicating which user in the current UL MU transmissions are
+ * enabled for CFR capture. Bits 36 to 0 indicate user indexes for 37 users in
+ * a UL MU transmission. If bit 0 is set, the CFR capture will happen for user
+ * index 0 in the current UL MU transmission. If bits 0 and 2 are set, CFR
+ * capture for UL MU TX corresponds to user indices 0 and 2. Bits 63:37 are
+ * reserved for future use. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT: Optional (u32)
+ * Indicates the number of consecutive RX frames to be skipped before CFR
+ * capture is enabled again. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE: Nested attribute containing
+ * one or more %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY attributes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY: Nested attribute containing
+ * the following group attributes:
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER: Optional (u32)
+ * Target supports multiple groups for some configurations. The group number
+ * can be any value between 0 and 15. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA: Optional (6-byte MAC address)
+ * Transmitter address which is used to filter frames. This MAC address takes
+ * effect with QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA: Optional (6-byte MAC address)
+ * Receiver address which is used to filter frames. This MAC address takes
+ * effect with QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK: Optional (6-byte MAC address)
+ * Mask of transmitter address which is used to filter frames. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK: Optional (6-byte MAC address)
+ * Mask of receiver address which is used to filter frames. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS: Optional (u32)
+ * Indicates frames with a specific NSS will be filtered for CFR capture.
+ * This is for CFR version 2 only. This is a bitmask. Bits 7:0 request CFR
+ * capture to be done for frames matching the NSS specified within this bitmask.
+ * Bits 31:8 are reserved for future use. Bits 7:0 map to NSS:
+ * bit 0 : NSS 1
+ * bit 1 : NSS 2
+ * ...
+ * bit 7 : NSS 8
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW: Optional (u32)
+ * Indicates frames with a specific bandwidth will be filtered for CFR capture.
+ * This is for CFR version 2 only. This is a bitmask. Bits 4:0 request CFR
+ * capture to be done for frames matching the bandwidths specified within this
+ * bitmask. Bits 31:5 are reserved for future use. Bits 4:0 map to bandwidth
+ * numerated in enum nl80211_band (although not all bands may be supported
+ * by a given device).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER: Optional (u32)
+ * Management frames matching the subtype filter categories will be filtered in
+ * by MAC for CFR capture. This is a bitmask in which each bit represents the
+ * corresponding Management frame subtype value per IEEE Std 802.11-2016,
+ * 9.2.4.1.3 Type and Subtype subfields. For example, Beacon frame control type
+ * is 8 and its value is 1 << 8 = 0x100. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER: Optional (u32)
+ * Control frames matching the subtype filter categories will be filtered in by
+ * MAC for CFR capture. This is a bitmask in which each bit represents the
+ * corresponding Control frame subtype value per IEEE Std 802.11-2016,
+ * 9.2.4.1.3 Type and Subtype subfields. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER: Optional (u32)
+ * Data frames matching the subtype filter categories will be filtered in by
+ * MAC for CFR capture. This is a bitmask in which each bit represents the
+ * corresponding Data frame subtype value per IEEE Std 802.11-2016,
+ * 9.2.4.1.3 Type and Subtype subfields. This is for CFR version 2 only.
*/
enum qca_wlan_vendor_peer_cfr_capture_attr {
QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_INVALID = 0,
- /* 6-byte MAC address of the peer.
- * This attribute is mandatory.
- */
QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR = 1,
- /* Enable peer CFR Capture, flag attribute.
- * This attribute is mandatory to enable peer CFR capture.
- * If this attribute is not present, peer CFR capture is disabled.
- */
QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE = 2,
- /* BW of measurement, attribute uses the values in enum nl80211_chan_width
- * Supported values: 20, 40, 80, 80+80, 160.
- * Note that all targets may not support all bandwidths.
- * u8 attribute. This attribute is mandatory if attribute
- * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
- */
QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH = 3,
- /* Periodicity of CFR measurement in msec.
- * Periodicity should be a multiple of Base timer.
- * Current Base timer value supported is 10 msecs (default).
- * 0 for one shot capture. u32 attribute.
- * This attribute is mandatory if attribute
- * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
- */
QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY = 4,
- /* Method used to capture Channel Frequency Response.
- * Attribute uses the values defined in enum qca_wlan_vendor_cfr_method.
- * u8 attribute. This attribute is mandatory if attribute
- * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
- */
QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD = 5,
- /* Enable periodic CFR capture, flag attribute.
- * This attribute is mandatory to enable Periodic CFR capture.
- * If this attribute is not present, periodic CFR capture is disabled.
- */
QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE = 6,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION = 7,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP = 8,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION = 9,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL = 10,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE = 11,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK = 12,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT = 13,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE = 14,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY = 15,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER = 16,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA = 17,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA = 18,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK = 19,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK = 20,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS = 21,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW = 22,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER = 23,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER = 24,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER = 25,
/* Keep last */
QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST,
@@ -8091,10 +8426,10 @@ enum qca_vendor_wlan_sta_guard_interval {
* used by QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO vendor command.
*
* @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC:
- * Required attribute in request, 6-byte MAC address,
- * used in both STA and AP modes.
- * MAC address of the station for which information is requested (BSSID of the
- * AP in STA mode).
+ * Required attribute in request for AP mode only, 6-byte MAC address,
+ * corresponding to the station's MAC address for which information is
+ * requested. For STA mode this is not required as the info always correspond
+ * to the self STA and the current/last association.
*
* @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_FLAGS:
* Optionally used in response, u32 attribute, contains a bitmap of different
@@ -8122,7 +8457,7 @@ enum qca_vendor_wlan_sta_guard_interval {
* back to host from target.
*
* @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_EXHAUSTED:
- * Optionally used in response, u32 attribute, used in AP mode only.
+ * Optionally used in response, u32 attribute, used in both STA and AP mode.
* Value indicates the number of data frames not transmitted successfully even
* after retrying the packets for the number of times equal to the total number
* of retries allowed for that packet and for which the TX status has been
@@ -8139,10 +8474,167 @@ enum qca_vendor_wlan_sta_guard_interval {
* after retrying the packets.
*
* @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY_EXHAUSTED:
- * Optionally used in response, u32 attribute, used in AP mode only.
+ * Optionally used in response, u32 attribute, used in both STA & AP mode.
* Value indicates the number of data frames not transmitted successfully even
* after retrying the packets for the number of times equal to the total number
* of retries allowed for that packet.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_PROBE_REQ_BMISS_COUNT: u32, used in
+ * the STA mode only. Represent the number of probe requests sent by the STA
+ * while attempting to roam on missing certain number of beacons from the
+ * connected AP. If queried in the disconnected state, this represents the
+ * count for the last connected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_PROBE_RESP_BMISS_COUNT: u32, used in
+ * the STA mode. Represent the number of probe responses received by the station
+ * while attempting to roam on missing certain number of beacons from the
+ * connected AP. When queried in the disconnected state, this represents the
+ * count when in last connected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_ALL_COUNT: u32, used in the
+ * STA mode only. Represents the total number of frames sent out by STA
+ * including Data, ACK, RTS, CTS, Control Management. This data is maintained
+ * only for the connect session. Represents the count of last connected session,
+ * when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_COUNT: u32, used in the STA mode.
+ * Total number of RTS sent out by the STA. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_RETRY_FAIL_COUNT: u32, used in the
+ * STA mode.Represent the number of RTS transmission failure that reach retry
+ * limit. This data is maintained per connect session. Represents the count of
+ * last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_NON_AGGREGATED_COUNT: u32, used in
+ * the STA mode. Represent the total number of non aggregated frames transmitted
+ * by the STA. This data is maintained per connect session. Represents the count
+ * of last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_AGGREGATED_COUNT: u32, used in the
+ * STA mode. Represent the total number of aggregated frames transmitted by the
+ * STA. This data is maintained per connect session. Represents the count of
+ * last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_GOOD_PLCP_COUNT: u32, used in
+ * the STA mode. Represents the number of received frames with a good PLCP. This
+ * data is maintained per connect session. Represents the count of last
+ * connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_INVALID_DELIMITER_COUNT: u32,
+ * used in the STA mode. Represents the number of occasions that no valid
+ * delimiter is detected by A-MPDU parser. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_CRC_FAIL_COUNT: u32, used in the
+ * STA mode. Represents the number of frames for which CRC check failed in the
+ * MAC. This data is maintained per connect session. Represents the count of
+ * last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_ACKS_GOOD_FCS_COUNT: u32, used in the
+ * STA mode. Represents the number of unicast ACKs received with good FCS. This
+ * data is maintained per connect session. Represents the count of last
+ * connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BLOCKACK_COUNT: u32, used in the STA
+ * mode. Represents the number of received Block Acks. This data is maintained
+ * per connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BEACON_COUNT: u32, used in the STA
+ * mode. Represents the number of beacons received from the connected BSS. This
+ * data is maintained per connect session. Represents the count of last
+ * connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_OTHER_BEACON_COUNT: u32, used in the
+ * STA mode. Represents the number of beacons received by the other BSS when in
+ * connected state (through the probes done by the STA). This data is maintained
+ * per connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_UCAST_DATA_GOOD_FCS_COUNT: u64, used in
+ * the STA mode. Represents the number of received DATA frames with good FCS and
+ * matching Receiver Address when in connected state. This data is maintained
+ * per connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_DATA_BC_MC_DROP_COUNT: u32, used in the
+ * STA mode. Represents the number of RX Data multicast frames dropped by the HW
+ * when in the connected state. This data is maintained per connect session.
+ * Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_1MBPS: u32, used in the
+ * STA mode. This represents the target power in dBm for the transmissions done
+ * to the AP in 2.4 GHz at 1 Mbps (DSSS) rate. This data is maintained per
+ * connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_6MBPS: u32, used in the
+ * STA mode. This represents the Target power in dBm for transmissions done to
+ * the AP in 2.4 GHz at 6 Mbps (OFDM) rate. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_MCS0: u32, used in the
+ * STA mode. This represents the Target power in dBm for transmissions done to
+ * the AP in 2.4 GHz at MCS0 rate. This data is maintained per connect session.
+ * Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_6MBPS: u32, used in the
+ * STA mode. This represents the Target power in dBm for transmissions done to
+ * the AP in 5 GHz at 6 Mbps (OFDM) rate. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in
+ * the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_MCS0: u32, used in the
+ * STA mode. This represents the Target power in dBm for for transmissions done
+ * to the AP in 5 GHz at MCS0 rate. This data is maintained per connect session.
+ * Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_HW_BUFFERS_OVERFLOW_COUNT: u32, used
+ * in the STA mode. This represents the Nested attribute representing the
+ * overflow counts of each receive buffer allocated to the hardware during the
+ * STA's connection. The number of hw buffers might vary for each WLAN
+ * solution and hence this attribute represents the nested array of all such
+ * HW buffer count. This data is maintained per connect session. Represents
+ * the count of last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX_TX_POWER: u32, Max TX power (dBm)
+ * allowed as per the regulatory requirements for the current or last connected
+ * session. Used in the STA mode.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_POWER: u32, Latest TX power
+ * (dBm) used by the station in its latest unicast frame while communicating
+ * to the AP in the connected state. When queried in the disconnected state,
+ * this represents the TX power used by the STA with last AP communication
+ * when in connected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ANI_LEVEL: u32, Adaptive noise immunity
+ * level used to adjust the RX sensitivity. Represents the current ANI level
+ * when queried in the connected state. When queried in the disconnected
+ * state, this corresponds to the latest ANI level at the instance of
+ * disconnection.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_IES: Binary attribute containing
+ * the raw information elements from Beacon frames. Represents the Beacon frames
+ * of the current BSS in the connected state. When queried in the disconnected
+ * state, these IEs correspond to the last connected BSSID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PROBE_RESP_IES: Binary attribute
+ * containing the raw information elements from Probe Response frames.
+ * Represents the Probe Response frames of the current BSS in the connected
+ * state. When queried in the disconnected state, these IEs correspond to the
+ * last connected BSSID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_DRIVER_DISCONNECT_REASON: u32, Driver
+ * disconnect reason for the last disconnection if the disconnection is
+ * triggered from the host driver. The values are referred from
+ * enum qca_disconnect_reason_codes.
*/
enum qca_wlan_vendor_attr_get_sta_info {
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID = 0,
@@ -8156,6 +8648,34 @@ enum qca_wlan_vendor_attr_get_sta_info {
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_TOTAL = 8,
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY = 9,
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY_EXHAUSTED = 10,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_PROBE_REQ_BMISS_COUNT = 11,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_PROBE_RESP_BMISS_COUNT = 12,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_ALL_COUNT = 13,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_COUNT = 14,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_RETRY_FAIL_COUNT = 15,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_NON_AGGREGATED_COUNT = 16,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_AGGREGATED_COUNT = 17,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_GOOD_PLCP_COUNT = 18,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_INVALID_DELIMITER_COUNT = 19,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_CRC_FAIL_COUNT = 20,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_ACKS_GOOD_FCS_COUNT = 21,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BLOCKACK_COUNT = 22,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BEACON_COUNT = 23,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_OTHER_BEACON_COUNT = 24,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_UCAST_DATA_GOOD_FCS_COUNT = 25,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_DATA_BC_MC_DROP_COUNT = 26,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_1MBPS = 27,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_6MBPS = 28,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_MCS0 = 29,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_6MBPS = 30,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_MCS0 = 31,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_HW_BUFFERS_OVERFLOW_COUNT = 32,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX_TX_POWER = 33,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_POWER = 34,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ANI_LEVEL = 35,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_IES = 36,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PROBE_RESP_IES = 37,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_DRIVER_DISCONNECT_REASON = 38,
/* keep last */
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST,
@@ -8163,4 +8683,126 @@ enum qca_wlan_vendor_attr_get_sta_info {
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_vendor_attr_update_sta_info - Defines attributes
+ * used by QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_CONNECT_CHANNELS: Type is NLA_UNSPEC.
+ * Used in STA mode. This attribute represents the list of channel center
+ * frequencies in MHz (u32) the station has learnt during the last connection
+ * or roaming attempt. This information shall not signify the channels for
+ * an explicit scan request from the user space. Host drivers can update this
+ * information to the user space in both connected and disconnected state.
+ * In the disconnected state this information shall signify the channels
+ * scanned in the last connection/roam attempt that lead to the disconnection.
+ */
+enum qca_wlan_vendor_attr_update_sta_info {
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_CONNECT_CHANNELS = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_disconnect_reason_codes - Specifies driver disconnect reason codes.
+ * Used when the driver triggers the STA to disconnect from the AP.
+ *
+ * @QCA_DISCONNECT_REASON_UNSPECIFIED: The host driver triggered the
+ * disconnection with the AP due to unspecified reasons.
+ *
+ * @QCA_DISCONNECT_REASON_INTERNAL_ROAM_FAILURE: The host driver triggered the
+ * disconnection with the AP due to a roaming failure. This roaming is triggered
+ * internally (host driver/firmware).
+ *
+ * @QCA_DISCONNECT_REASON_EXTERNAL_ROAM_FAILURE: The driver disconnected from
+ * the AP when the user/external triggered roaming fails.
+ *
+ * @QCA_DISCONNECT_REASON_GATEWAY_REACHABILITY_FAILURE: This reason code is used
+ * by the host driver whenever gateway reachability failure is detected and the
+ * driver disconnects with AP.
+ *
+ * @QCA_DISCONNECT_REASON_UNSUPPORTED_CHANNEL_CSA: The driver disconnected from
+ * the AP on a channel switch announcement from it with an unsupported channel.
+ *
+ * @QCA_DISCONNECT_REASON_OPER_CHANNEL_DISABLED_INDOOR: On a concurrent AP start
+ * with indoor channels disabled and if the STA is connected on one of these
+ * disabled channels, the host driver disconnected the STA with this reason
+ * code.
+ *
+ * @QCA_DISCONNECT_REASON_OPER_CHANNEL_USER_DISABLED: Disconnection due to an
+ * explicit request from the user to disable the current operating channel.
+ *
+ * @QCA_DISCONNECT_REASON_DEVICE_RECOVERY: STA disconnected from the AP due to
+ * the internal host driver/firmware recovery.
+ *
+ * @QCA_DISCONNECT_REASON_KEY_TIMEOUT: The driver triggered the disconnection on
+ * a timeout for the key installations from the user space.
+ *
+ * @QCA_DISCONNECT_REASON_OPER_CHANNEL_BAND_CHANGE: The dDriver disconnected the
+ * STA on a band change request from the user space to a different band from the
+ * current operation channel/band.
+ *
+ * @QCA_DISCONNECT_REASON_IFACE_DOWN: The STA disconnected from the AP on an
+ * interface down trigger from the user space.
+ *
+ * @QCA_DISCONNECT_REASON_PEER_XRETRY_FAIL: The host driver disconnected the
+ * STA on getting continuous transmission failures for multiple Data frames.
+ *
+ * @QCA_DISCONNECT_REASON_PEER_INACTIVITY: The STA does a keep alive
+ * notification to the AP by transmitting NULL/G-ARP frames. This disconnection
+ * represents inactivity from AP on such transmissions.
+
+ * @QCA_DISCONNECT_REASON_SA_QUERY_TIMEOUT: This reason code is used on
+ * disconnection when SA Query times out (AP does not respond to SA Query).
+ *
+ * @QCA_DISCONNECT_REASON_BEACON_MISS_FAILURE: The host driver disconnected the
+ * STA on missing the beacons continuously from the AP.
+ *
+ * @QCA_DISCONNECT_REASON_CHANNEL_SWITCH_FAILURE: Disconnection due to STA not
+ * able to move to the channel mentioned by the AP in CSA.
+ *
+ * @QCA_DISCONNECT_REASON_USER_TRIGGERED: User triggered disconnection.
+ */
+enum qca_disconnect_reason_codes {
+ QCA_DISCONNECT_REASON_UNSPECIFIED = 0,
+ QCA_DISCONNECT_REASON_INTERNAL_ROAM_FAILURE = 1,
+ QCA_DISCONNECT_REASON_EXTERNAL_ROAM_FAILURE = 2,
+ QCA_DISCONNECT_REASON_GATEWAY_REACHABILITY_FAILURE = 3,
+ QCA_DISCONNECT_REASON_UNSUPPORTED_CHANNEL_CSA = 4,
+ QCA_DISCONNECT_REASON_OPER_CHANNEL_DISABLED_INDOOR = 5,
+ QCA_DISCONNECT_REASON_OPER_CHANNEL_USER_DISABLED = 6,
+ QCA_DISCONNECT_REASON_DEVICE_RECOVERY = 7,
+ QCA_DISCONNECT_REASON_KEY_TIMEOUT = 8,
+ QCA_DISCONNECT_REASON_OPER_CHANNEL_BAND_CHANGE = 9,
+ QCA_DISCONNECT_REASON_IFACE_DOWN = 10,
+ QCA_DISCONNECT_REASON_PEER_XRETRY_FAIL = 11,
+ QCA_DISCONNECT_REASON_PEER_INACTIVITY = 12,
+ QCA_DISCONNECT_REASON_SA_QUERY_TIMEOUT = 13,
+ QCA_DISCONNECT_REASON_BEACON_MISS_FAILURE = 14,
+ QCA_DISCONNECT_REASON_CHANNEL_SWITCH_FAILURE = 15,
+ QCA_DISCONNECT_REASON_USER_TRIGGERED = 16,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_driver_disconnect_reason - Defines attributes
+ * used by %QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASCON_CODE: u32 attribute.
+ * This attribute represents the driver specific reason codes (local
+ * driver/firmware initiated reasons for disconnection) defined
+ * in enum qca_disconnect_reason_codes.
+ */
+enum qca_wlan_vendor_attr_driver_disconnect_reason {
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASCON_CODE = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_MAX =
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_AFTER_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index bf8cc9de..543640de 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -123,6 +123,7 @@ void sae_clear_data(struct sae_data *sae)
return;
sae_clear_temp_data(sae);
crypto_bignum_deinit(sae->peer_commit_scalar, 0);
+ crypto_bignum_deinit(sae->peer_commit_scalar_accepted, 0);
os_memset(sae, 0, sizeof(*sae));
}
@@ -864,7 +865,7 @@ size_t sae_ecc_prime_len_2_hash_len(size_t prime_len)
}
-struct crypto_ec_point *
+static 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,
@@ -1622,38 +1623,42 @@ 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)
+int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
+ const struct wpabuf *token, const char *identifier)
{
u8 *pos;
if (sae->tmp == NULL)
- return;
+ return -1;
wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
- if (token) {
+ if (!sae->tmp->h2e && token) {
wpabuf_put_buf(buf, token);
wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
wpabuf_head(token), wpabuf_len(token));
}
pos = wpabuf_put(buf, sae->tmp->prime_len);
- crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
- sae->tmp->prime_len, sae->tmp->prime_len);
+ if (crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
+ sae->tmp->prime_len, sae->tmp->prime_len) < 0)
+ return -1;
wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
pos, sae->tmp->prime_len);
if (sae->tmp->ec) {
pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
- crypto_ec_point_to_bin(sae->tmp->ec,
- sae->tmp->own_commit_element_ecc,
- pos, pos + sae->tmp->prime_len);
+ if (crypto_ec_point_to_bin(sae->tmp->ec,
+ sae->tmp->own_commit_element_ecc,
+ pos, pos + sae->tmp->prime_len) < 0)
+ return -1;
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
pos, sae->tmp->prime_len);
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
pos + sae->tmp->prime_len, sae->tmp->prime_len);
} else {
pos = wpabuf_put(buf, sae->tmp->prime_len);
- crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
- sae->tmp->prime_len, sae->tmp->prime_len);
+ if (crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
+ sae->tmp->prime_len,
+ sae->tmp->prime_len) < 0)
+ return -1;
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
pos, sae->tmp->prime_len);
}
@@ -1677,6 +1682,18 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
wpabuf_put_u8(buf, WLAN_EID_EXT_REJECTED_GROUPS);
wpabuf_put_buf(buf, sae->tmp->own_rejected_groups);
}
+
+ if (sae->tmp->h2e && token) {
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(token));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
+ wpabuf_put_buf(buf, token);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "SAE: Anti-clogging token (in container)",
+ token);
+ }
+
+ return 0;
}
@@ -1742,32 +1759,34 @@ static int sae_is_rejected_groups_elem(const u8 *pos, const u8 *end)
}
+static int sae_is_token_container_elem(const u8 *pos, const u8 *end)
+{
+ return end - pos >= 3 &&
+ pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] >= 1 &&
+ end - pos - 2 >= pos[1] &&
+ pos[2] == WLAN_EID_EXT_ANTI_CLOGGING_TOKEN;
+}
+
+
static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
const u8 *end, const u8 **token,
size_t *token_len, int h2e)
{
size_t scalar_elem_len, tlen;
- const u8 *elem;
if (token)
*token = NULL;
if (token_len)
*token_len = 0;
+ if (h2e)
+ return; /* No Anti-Clogging Token field outside container IE */
+
scalar_elem_len = (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len;
if (scalar_elem_len >= (size_t) (end - *pos))
return; /* No extra data beyond peer scalar and element */
- /* It is a bit difficult to parse this now that there is an
- * optional variable length Anti-Clogging Token field and
- * optional variable length Password Identifier element in the
- * frame. We are sending out fixed length Anti-Clogging Token
- * 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);
if (tlen < SHA256_MAC_LEN) {
@@ -1777,36 +1796,6 @@ static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
return;
}
- elem = *pos + scalar_elem_len;
- if (sae_is_password_id_elem(elem, end)) {
- /* Password Identifier element takes out all available
- * extra octets, so there can be no Anti-Clogging token in
- * 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);
if (token)
*token = *pos;
@@ -1816,6 +1805,21 @@ static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
}
+static void sae_parse_token_container(struct sae_data *sae,
+ const u8 *pos, const u8 *end,
+ const u8 **token, size_t *token_len)
+{
+ wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
+ pos, end - pos);
+ if (!sae_is_token_container_elem(pos, end))
+ return;
+ *token = pos + 3;
+ *token_len = pos[1] - 1;
+ wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token (in container)",
+ *token, *token_len);
+}
+
+
static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
const u8 *end)
{
@@ -1836,8 +1840,9 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
* shall be dropped if the peer-scalar is identical to the one used in
* the existing protocol instance.
*/
- if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar &&
- crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) {
+ if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar_accepted &&
+ crypto_bignum_cmp(sae->peer_commit_scalar_accepted,
+ peer_scalar) == 0) {
wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous "
"peer-commit-scalar");
crypto_bignum_deinit(peer_scalar, 0);
@@ -2010,19 +2015,21 @@ static int sae_parse_password_identifier(struct sae_data *sae,
static int sae_parse_rejected_groups(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_rejected_groups_elem(pos, end))
+ *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);
+ 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);
+ 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);
+ *pos = *pos + 2 + (*pos)[1];
return WLAN_STATUS_SUCCESS;
}
@@ -2062,11 +2069,15 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
/* Conditional Rejected Groups element */
if (h2e) {
- res = sae_parse_rejected_groups(sae, pos, end);
+ res = sae_parse_rejected_groups(sae, &pos, end);
if (res != WLAN_STATUS_SUCCESS)
return res;
}
+ /* Optional Anti-Clogging Token Container element */
+ if (h2e)
+ sae_parse_token_container(sae, pos, end, token, token_len);
+
/*
* Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
* the values we sent which would be evidence of a reflection attack.
diff --git a/src/common/sae.h b/src/common/sae.h
index b3787e4f..7966d70e 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -70,6 +70,7 @@ struct sae_data {
u8 pmk[SAE_PMK_LEN];
u8 pmkid[SAE_PMKID_LEN];
struct crypto_bignum *peer_commit_scalar;
+ struct crypto_bignum *peer_commit_scalar_accepted;
int group;
unsigned int sync; /* protocol instance variable: Sync */
u16 rc; /* protocol instance variable: Rc (received send-confirm) */
@@ -87,8 +88,8 @@ 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);
+int 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,
int h2e);
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index de4b6ecd..12847430 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -355,6 +355,14 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN;
u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
size_t ptk_len;
+#ifdef CONFIG_OWE
+ int owe_ptk_workaround = 0;
+
+ if (akmp == (WPA_KEY_MGMT_OWE | WPA_KEY_MGMT_PSK_SHA256)) {
+ owe_ptk_workaround = 1;
+ akmp = WPA_KEY_MGMT_OWE;
+ }
+#endif /* CONFIG_OWE */
if (pmk_len == 0) {
wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation");
@@ -407,11 +415,33 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
#else /* CONFIG_SUITEB192 || CONFIG_FILS */
return -1;
#endif /* CONFIG_SUITEB192 || CONFIG_FILS */
- } else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) {
+ } else if (wpa_key_mgmt_sha256(akmp)) {
+ 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;
+#ifdef CONFIG_OWE
+ } else if (akmp == WPA_KEY_MGMT_OWE && (pmk_len == 32 ||
+ owe_ptk_workaround)) {
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 if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 48) {
+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
+ if (sha384_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+ } else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 64) {
+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)");
+ if (sha512_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+ } else if (akmp == WPA_KEY_MGMT_OWE) {
+ wpa_printf(MSG_INFO, "OWE: Unknown PMK length %u",
+ (unsigned int) pmk_len);
+ return -1;
+#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP
} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
@@ -904,6 +934,10 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
parse->oci_len = len;
break;
#endif /* CONFIG_OCV */
+ case FTIE_SUBELEM_BIGTK:
+ parse->bigtk = pos;
+ parse->bigtk_len = len;
+ break;
default:
wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id);
break;
@@ -1940,10 +1974,12 @@ const char * wpa_cipher_txt(int cipher)
switch (cipher) {
case WPA_CIPHER_NONE:
return "NONE";
+#ifdef CONFIG_WEP
case WPA_CIPHER_WEP40:
return "WEP-40";
case WPA_CIPHER_WEP104:
return "WEP-104";
+#endif /* CONFIG_WEP */
case WPA_CIPHER_TKIP:
return "TKIP";
case WPA_CIPHER_CCMP:
@@ -2079,8 +2115,6 @@ u32 wpa_akm_to_suite(int akm)
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;
}
@@ -2444,10 +2478,12 @@ int wpa_parse_cipher(const char *value)
val |= WPA_CIPHER_GCMP;
else if (os_strcmp(start, "TKIP") == 0)
val |= WPA_CIPHER_TKIP;
+#ifdef CONFIG_WEP
else if (os_strcmp(start, "WEP104") == 0)
val |= WPA_CIPHER_WEP104;
else if (os_strcmp(start, "WEP40") == 0)
val |= WPA_CIPHER_WEP40;
+#endif /* CONFIG_WEP */
else if (os_strcmp(start, "NONE") == 0)
val |= WPA_CIPHER_NONE;
else if (os_strcmp(start, "GTK_NOT_USED") == 0)
@@ -2645,12 +2681,10 @@ static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
/**
* 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)
+static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie)
{
if (pos[1] == 0)
return 1;
@@ -2672,8 +2706,7 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
return 0;
}
- if (1 + RSN_SELECTOR_LEN < end - pos &&
- pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
+ if (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",
@@ -2681,6 +2714,14 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
return 0;
}
+ if (pos[1] >= RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_KEYID) {
+ ie->key_id = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: KeyID 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;
@@ -2708,6 +2749,15 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
return 0;
}
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_BIGTK) {
+ ie->bigtk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->bigtk_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK 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;
@@ -2734,6 +2784,16 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
return 0;
}
+ if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_TRANSITION_DISABLE) {
+ ie->transition_disable = pos + 2 + RSN_SELECTOR_LEN;
+ ie->transition_disable_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: Transition Disable KDE in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
return 0;
}
@@ -2842,7 +2902,7 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
ie->supp_oper_classes_len = pos[1];
}
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
- ret = wpa_parse_generic(pos, end, ie);
+ ret = wpa_parse_generic(pos, ie);
if (ret < 0)
break;
if (ret > 0) {
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index beb1ecd5..da58159e 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -109,9 +109,11 @@ WPA_CIPHER_BIP_CMAC_256)
#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
#define RSN_KEY_DATA_OCI RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
+#define RSN_KEY_DATA_BIGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 14)
#define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4)
#define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5)
+#define WFA_KEY_DATA_TRANSITION_DISABLE RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x20)
#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
@@ -130,6 +132,8 @@ WPA_CIPHER_BIP_CMAC_256)
#define WPA_IGTK_LEN 16
#define WPA_IGTK_MAX_LEN 32
+#define WPA_BIGTK_LEN 16
+#define WPA_BIGTK_MAX_LEN 32
/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
@@ -227,6 +231,11 @@ struct wpa_igtk {
size_t igtk_len;
};
+struct wpa_bigtk {
+ u8 bigtk[WPA_BIGTK_MAX_LEN];
+ size_t bigtk_len;
+};
+
/* WPA IE version 1
* 00-50-f2:1 (OUI:OUI type)
* 0x01 0x00 (version; little endian)
@@ -292,6 +301,13 @@ struct wpa_igtk_kde {
u8 igtk[WPA_IGTK_MAX_LEN];
} STRUCT_PACKED;
+#define WPA_BIGTK_KDE_PREFIX_LEN (2 + 6)
+struct wpa_bigtk_kde {
+ u8 keyid[2];
+ u8 pn[6];
+ u8 bigtk[WPA_BIGTK_MAX_LEN];
+} STRUCT_PACKED;
+
struct rsn_mdie {
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 ft_capab;
@@ -321,6 +337,7 @@ struct rsn_ftie_sha384 {
#define FTIE_SUBELEM_R0KH_ID 3
#define FTIE_SUBELEM_IGTK 4
#define FTIE_SUBELEM_OCI 5
+#define FTIE_SUBELEM_BIGTK 6
struct rsn_rdie {
u8 id;
@@ -328,6 +345,12 @@ struct rsn_rdie {
le16 status_code;
} STRUCT_PACKED;
+/* WFA Transition Disable KDE (using OUI_WFA) */
+/* Transition Disable Bitmap bits */
+#define TRANSITION_DISABLE_WPA3_PERSONAL BIT(0)
+#define TRANSITION_DISABLE_SAE_PK BIT(1)
+#define TRANSITION_DISABLE_WPA3_ENTERPRISE BIT(2)
+#define TRANSITION_DISABLE_ENHANCED_OPEN BIT(3)
#ifdef _MSC_VER
#pragma pack(pop)
@@ -455,6 +478,8 @@ struct wpa_ft_ies {
size_t tie_len;
const u8 *igtk;
size_t igtk_len;
+ const u8 *bigtk;
+ size_t bigtk_len;
#ifdef CONFIG_OCV
const u8 *oci;
size_t oci_len;
@@ -476,18 +501,23 @@ struct wpa_eapol_ie_parse {
const u8 *rsn_ie;
size_t rsn_ie_len;
const u8 *pmkid;
+ const u8 *key_id;
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 *bigtk;
+ size_t bigtk_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 *transition_disable;
+ size_t transition_disable_len;
const u8 *oci;
size_t oci_len;
const u8 *osen;
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index 944b6e35..c1ce68c1 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -270,7 +270,6 @@ void wpa_ctrl_close(struct wpa_ctrl *ctrl)
void wpa_ctrl_cleanup(void)
{
DIR *dir;
- struct dirent entry;
struct dirent *result;
size_t dirnamelen;
size_t maxcopy;
@@ -288,8 +287,8 @@ void wpa_ctrl_cleanup(void)
}
namep = pathname + dirnamelen;
maxcopy = PATH_MAX - dirnamelen;
- while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
- if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
+ while ((result = readdir(dir)) != NULL) {
+ if (os_strlcpy(namep, result->d_name, maxcopy) < maxcopy)
unlink(pathname);
}
closedir(dir);
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index f03c698f..ca1c35f8 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -95,6 +95,8 @@ extern "C" {
/** SAE authentication failed due to unknown password identifier */
#define WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER \
"CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER "
+/** Unprotected Beacon frame dropped */
+#define WPA_EVENT_UNPROT_BEACON "CTRL-EVENT-UNPROT-BEACON "
/** IP subnet status change notification
*
@@ -179,6 +181,7 @@ extern "C" {
#define DPP_EVENT_NET_ACCESS_KEY "DPP-NET-ACCESS-KEY "
#define DPP_EVENT_MISSING_CONNECTOR "DPP-MISSING-CONNECTOR "
#define DPP_EVENT_NETWORK_ID "DPP-NETWORK-ID "
+#define DPP_EVENT_CONFIGURATOR_ID "DPP-CONFIGURATOR-ID "
#define DPP_EVENT_RX "DPP-RX "
#define DPP_EVENT_TX "DPP-TX "
#define DPP_EVENT_TX_STATUS "DPP-TX-STATUS "
@@ -186,6 +189,7 @@ extern "C" {
#define DPP_EVENT_PKEX_T_LIMIT "DPP-PKEX-T-LIMIT "
#define DPP_EVENT_INTRO "DPP-INTRO "
#define DPP_EVENT_CONF_REQ_RX "DPP-CONF-REQ-RX "
+#define DPP_EVENT_CHIRP_STOPPED "DPP-CHIRP-STOPPED "
/* MESH events */
#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
@@ -379,6 +383,13 @@ extern "C" {
#define WDS_STA_INTERFACE_ADDED "WDS-STA-INTERFACE-ADDED "
#define WDS_STA_INTERFACE_REMOVED "WDS-STA-INTERFACE-REMOVED "
+/* Transition mode disabled indication - followed by bitmap */
+#define TRANSITION_DISABLE "TRANSITION-DISABLE "
+
+#ifndef BIT
+#define BIT(x) (1U << (x))
+#endif
+
/* BSS command information masks */
#define WPA_BSS_MASK_ALL 0xFFFDFFFF
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index ab108daa..c40e9556 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -54,6 +54,8 @@ LIB_OBJS= \
sha384.o \
sha384-prf.o \
sha384-internal.o \
+ sha512.o \
+ sha512-prf.o \
sha512-internal.o
LIB_OBJS += crypto_internal.o
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 440da030..7c7515f6 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -916,5 +916,6 @@ struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y);
struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
const u8 *key, size_t len);
void crypto_ecdh_deinit(struct crypto_ecdh *ecdh);
+size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh);
#endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 783b293e..47b6ebbd 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -2168,4 +2168,10 @@ void crypto_ecdh_deinit(struct crypto_ecdh *ecdh)
}
}
+
+size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh)
+{
+ return crypto_ec_prime_len(ecdh->ec);
+}
+
#endif /* CONFIG_ECC */
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index 85ce565b..dc68bd65 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -1834,4 +1834,10 @@ fail:
goto done;
}
+
+size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh)
+{
+ return crypto_ec_prime_len(ecdh->ec);
+}
+
#endif /* CONFIG_ECC */
diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c
index b55e976f..17af964a 100644
--- a/src/crypto/sha256.c
+++ b/src/crypto/sha256.c
@@ -28,10 +28,10 @@ int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
{
unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
unsigned char tk[32];
- const u8 *_addr[6];
- size_t _len[6], i;
+ const u8 *_addr[11];
+ size_t _len[11], i;
- if (num_elem > 5) {
+ if (num_elem > 10) {
/*
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
diff --git a/src/crypto/sha384.c b/src/crypto/sha384.c
index ee136ce9..fd84b82b 100644
--- a/src/crypto/sha384.c
+++ b/src/crypto/sha384.c
@@ -28,10 +28,10 @@ int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
{
unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
unsigned char tk[48];
- const u8 *_addr[6];
- size_t _len[6], i;
+ const u8 *_addr[11];
+ size_t _len[11], i;
- if (num_elem > 5) {
+ if (num_elem > 10) {
/*
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
diff --git a/src/crypto/sha512.c b/src/crypto/sha512.c
index 66311c37..f60a5767 100644
--- a/src/crypto/sha512.c
+++ b/src/crypto/sha512.c
@@ -28,10 +28,10 @@ int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
{
unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
unsigned char tk[64];
- const u8 *_addr[6];
- size_t _len[6], i;
+ const u8 *_addr[11];
+ size_t _len[11], i;
- if (num_elem > 5) {
+ if (num_elem > 10) {
/*
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 84ec9854..7ee371ab 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -2208,6 +2208,7 @@ static int openssl_cert_tod(X509 *cert)
else if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.2") == 0 && !tod)
tod = 2; /* TOD-TOFU */
}
+ sk_POLICYINFO_pop_free(ext, POLICYINFO_free);
return tod;
}
@@ -4926,6 +4927,76 @@ static int ocsp_status_cb(SSL *s, void *arg)
#endif /* HAVE_OCSP */
+static size_t max_str_len(const char **lines)
+{
+ const char **p;
+ size_t max_len = 0;
+
+ for (p = lines; *p; p++) {
+ size_t len = os_strlen(*p);
+
+ if (len > max_len)
+ max_len = len;
+ }
+
+ return max_len;
+}
+
+
+static int match_lines_in_file(const char *path, const char **lines)
+{
+ FILE *f;
+ char *buf;
+ size_t bufsize;
+ int found = 0, is_linestart = 1;
+
+ bufsize = max_str_len(lines) + sizeof("\r\n");
+ buf = os_malloc(bufsize);
+ if (!buf)
+ return 0;
+
+ f = fopen(path, "r");
+ if (!f) {
+ os_free(buf);
+ return 0;
+ }
+
+ while (!found && fgets(buf, bufsize, f)) {
+ int is_lineend;
+ size_t len;
+ const char **p;
+
+ len = strcspn(buf, "\r\n");
+ is_lineend = buf[len] != '\0';
+ buf[len] = '\0';
+
+ if (is_linestart && is_lineend) {
+ for (p = lines; !found && *p; p++)
+ found = os_strcmp(buf, *p) == 0;
+ }
+ is_linestart = is_lineend;
+ }
+
+ fclose(f);
+ bin_clear_free(buf, bufsize);
+
+ return found;
+}
+
+
+static int is_tpm2_key(const char *path)
+{
+ /* Check both new and old format of TPM2 PEM guard tag */
+ static const char *tpm2_tags[] = {
+ "-----BEGIN TSS2 PRIVATE KEY-----",
+ "-----BEGIN TSS2 KEY BLOB-----",
+ NULL
+ };
+
+ return match_lines_in_file(path, tpm2_tags);
+}
+
+
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
@@ -4978,6 +5049,17 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (can_pkcs11 == 2 && !engine_id)
engine_id = "pkcs11";
+ /* If private_key points to a TPM2-wrapped key, automatically enable
+ * tpm2 engine and use it to unwrap the key. */
+ if (params->private_key &&
+ (!engine_id || os_strcmp(engine_id, "tpm2") == 0) &&
+ is_tpm2_key(params->private_key)) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Found TPM2 wrapped key %s",
+ params->private_key);
+ key_id = key_id ? key_id : params->private_key;
+ engine_id = engine_id ? engine_id : "tpm2";
+ }
+
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
if (params->flags & TLS_CONN_EAP_FAST) {
@@ -5009,7 +5091,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
}
if (engine_id) {
- wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
+ wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine %s",
+ engine_id);
ret = tls_engine_init(conn, engine_id, params->pin,
key_id, cert_id, ca_cert_id);
if (ret)
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index f0e2a6f2..032bbd89 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -182,6 +182,7 @@ struct hostapd_channel_data {
struct hostapd_wmm_rule wmm_rules[WMM_AC_NUM];
};
+#define HE_MAC_CAPAB_0 0
#define HE_MAX_MAC_CAPAB_SIZE 6
#define HE_MAX_PHY_CAPAB_SIZE 11
#define HE_MAX_MCS_CAPAB_SIZE 12
@@ -1095,6 +1096,13 @@ struct wpa_driver_associate_params {
const struct ieee80211_vht_capabilities *vhtcaps_mask;
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ /**
+ * disable_he - Disable HE for this connection
+ */
+ int disable_he;
+#endif /* CONFIG_HE_OVERRIDES */
+
/**
* req_key_mgmt_offload - Request key management offload for connection
*
@@ -1402,14 +1410,6 @@ struct wpa_driver_ap_params {
u8 p2p_go_ctwindow;
/**
- * smps_mode - SMPS mode
- *
- * SMPS mode to be used by the AP, specified as the relevant bits of
- * ht_capab (i.e. HT_CAP_INFO_SMPS_*).
- */
- unsigned int smps_mode;
-
- /**
* disable_dgaf - Whether group-addressed frames are disabled
*/
int disable_dgaf;
@@ -1487,6 +1487,26 @@ struct wpa_driver_ap_params {
* he_spr_srg_obss_pd_max_offset - Maximum TX power offset
*/
int he_spr_srg_obss_pd_max_offset;
+
+ /**
+ * he_bss_color - Whether the BSS Color is disabled
+ */
+ int he_bss_color_disabled;
+
+ /**
+ * he_bss_color_partial - The BSS Color AID equation
+ */
+ int he_bss_color_partial;
+
+ /**
+ * he_bss_color - The BSS Color of the AP
+ */
+ int he_bss_color;
+
+ /**
+ * twt_responder - Whether Target Wait Time responder is enabled
+ */
+ int twt_responder;
};
struct wpa_driver_mesh_bss_params {
@@ -1524,6 +1544,120 @@ struct wpa_driver_mesh_join_params {
unsigned int flags;
};
+struct wpa_driver_set_key_params {
+ /**
+ * ifname - Interface name (for multi-SSID/VLAN support) */
+ const char *ifname;
+
+ /**
+ * alg - Encryption algorithm
+ *
+ * (%WPA_ALG_NONE, %WPA_ALG_WEP, %WPA_ALG_TKIP, %WPA_ALG_CCMP,
+ * %WPA_ALG_IGTK, %WPA_ALG_GCMP, %WPA_ALG_GCMP_256, %WPA_ALG_CCMP_256,
+ * %WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256, %WPA_ALG_BIP_CMAC_256);
+ * %WPA_ALG_NONE clears the key. */
+ enum wpa_alg alg;
+
+ /**
+ * addr - Address of the peer STA
+ *
+ * (BSSID of the current AP when setting pairwise key in station mode),
+ * ff:ff:ff:ff:ff:ff for broadcast keys, %NULL for default keys that
+ * are used both for broadcast and unicast; when clearing keys, %NULL
+ * is used to indicate that both the broadcast-only and default key of
+ * the specified key index is to be cleared */
+ const u8 *addr;
+
+ /**
+ * key_idx - Key index
+ *
+ * (0..3), usually 0 for unicast keys; 4..5 for IGTK; 6..7 for BIGTK */
+ int key_idx;
+
+ /**
+ * set_tx - Configure this key as the default Tx key
+ *
+ * Only used when driver does not support separate unicast/individual
+ * key */
+ int set_tx;
+
+ /**
+ * seq - Sequence number/packet number
+ *
+ * seq_len octets, the next packet number to be used for in replay
+ * protection; configured for Rx keys (in most cases, this is only used
+ * with broadcast keys and set to zero for unicast keys); %NULL if not
+ * set */
+ const u8 *seq;
+
+ /**
+ * seq_len - Length of the seq, depends on the algorithm
+ *
+ * TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets */
+ size_t seq_len;
+
+ /**
+ * key - Key buffer
+ *
+ * TKIP: 16-byte temporal key, 8-byte Tx Mic key, 8-byte Rx Mic Key */
+ const u8 *key;
+
+ /**
+ * key_len - Length of the key buffer in octets
+ *
+ * WEP: 5 or 13, TKIP: 32, CCMP/GCMP: 16, IGTK: 16 */
+ size_t key_len;
+
+ /**
+ * vlan_id - VLAN index (0..4095) for VLAN offload cases */
+ int vlan_id;
+
+ /**
+ * key_flag - Additional key flags
+ *
+ * %KEY_FLAG_MODIFY
+ * Set when an already installed key must be updated.
+ * So far the only use-case is changing RX/TX status for
+ * pairwise keys. Must not be set when deleting a key.
+ * %KEY_FLAG_DEFAULT
+ * Set when the key is also a default key. Must not be set when
+ * deleting a key.
+ * %KEY_FLAG_RX
+ * The key is valid for RX. Must not be set when deleting a key.
+ * %KEY_FLAG_TX
+ * The key is valid for TX. Must not be set when deleting a key.
+ * %KEY_FLAG_GROUP
+ * The key is a broadcast or group key.
+ * %KEY_FLAG_PAIRWISE
+ * The key is a pairwise key.
+ * %KEY_FLAG_PMK
+ * The key is a Pairwise Master Key (PMK).
+ *
+ * Valid and pre-defined combinations are:
+ * %KEY_FLAG_GROUP_RX_TX
+ * WEP key not to be installed as default key.
+ * %KEY_FLAG_GROUP_RX_TX_DEFAULT
+ * Default WEP or WPA-NONE key.
+ * %KEY_FLAG_GROUP_RX
+ * GTK key valid for RX only.
+ * %KEY_FLAG_GROUP_TX_DEFAULT
+ * GTK key valid for TX only, immediately taking over TX.
+ * %KEY_FLAG_PAIRWISE_RX_TX
+ * Pairwise key immediately becoming the active pairwise key.
+ * %KEY_FLAG_PAIRWISE_RX
+ * Pairwise key not yet valid for TX. (Only usable when Extended
+ * Key ID is supported by the driver.)
+ * %KEY_FLAG_PAIRWISE_RX_TX_MODIFY
+ * Enable TX for a pairwise key installed with
+ * KEY_FLAG_PAIRWISE_RX.
+ *
+ * Not a valid standalone key type but pre-defined to be combined
+ * with other key_flags:
+ * %KEY_FLAG_RX_TX
+ * RX/TX key. */
+ enum key_flag key_flag;
+};
+
/**
* struct wpa_driver_capa - Driver capability information
*/
@@ -1577,7 +1711,7 @@ struct wpa_driver_capa {
/** Driver takes care of all DFS operations */
#define WPA_DRIVER_FLAGS_DFS_OFFLOAD 0x00000004
/** Driver takes care of RSN 4-way handshake internally; PMK is configured with
- * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
+ * struct wpa_driver_ops::set_key using key_flag = KEY_FLAG_PMK */
#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X 0x00000008
/** Driver is for a wired Ethernet interface */
#define WPA_DRIVER_FLAGS_WIRED 0x00000010
@@ -1704,15 +1838,23 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_FTM_RESPONDER 0x0100000000000000ULL
/** Driver support 4-way handshake offload for WPA-Personal */
#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK 0x0200000000000000ULL
+/** Driver supports a separate control port for EAPOL frames */
+#define WPA_DRIVER_FLAGS_CONTROL_PORT 0x0400000000000000ULL
+/** Driver supports VLAN offload */
+#define WPA_DRIVER_FLAGS_VLAN_OFFLOAD 0x0800000000000000ULL
+/** Driver supports UPDATE_FT_IES command */
+#define WPA_DRIVER_FLAGS_UPDATE_FT_IES 0x1000000000000000ULL
+/** Driver can correctly rekey PTKs without Extended Key ID */
+#define WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS 0x2000000000000000ULL
+/** Driver supports Beacon protection */
+#define WPA_DRIVER_FLAGS_BEACON_PROTECTION 0x4000000000000000ULL
+/** Driver supports Extended Key ID */
+#define WPA_DRIVER_FLAGS_EXTENDED_KEY_ID 0x8000000000000000ULL
u64 flags;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
(drv_flags & WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE)
-#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001
-#define WPA_DRIVER_SMPS_MODE_DYNAMIC 0x00000002
- unsigned int smps_modes;
-
unsigned int wmm_ac_supported:1;
unsigned int mac_addr_rand_scan_supported:1;
@@ -2194,6 +2336,9 @@ struct drv_acs_params {
/* ACS frequency list info */
const int *freq_list;
+
+ /* Indicates whether EDMG is enabled */
+ int edmg_enabled;
};
struct wpa_bss_trans_info {
@@ -2219,6 +2364,8 @@ struct wpa_pmkid_params {
const u8 *pmkid;
const u8 *pmk;
size_t pmk_len;
+ u32 pmk_lifetime;
+ u8 pmk_reauth_threshold;
};
/* Mask used to specify which connection parameters have to be updated */
@@ -2305,35 +2452,8 @@ struct wpa_driver_ops {
/**
* set_key - Configure encryption key
- * @ifname: Interface name (for multi-SSID/VLAN support)
* @priv: private driver interface data
- * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
- * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK,
- * %WPA_ALG_GCMP, %WPA_ALG_GCMP_256, %WPA_ALG_CCMP_256,
- * %WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256,
- * %WPA_ALG_BIP_CMAC_256);
- * %WPA_ALG_NONE clears the key.
- * @addr: Address of the peer STA (BSSID of the current AP when setting
- * pairwise key in station mode), ff:ff:ff:ff:ff:ff for
- * broadcast keys, %NULL for default keys that are used both for
- * broadcast and unicast; when clearing keys, %NULL is used to
- * indicate that both the broadcast-only and default key of the
- * specified key index is to be cleared
- * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for
- * IGTK
- * @set_tx: configure this key as the default Tx key (only used when
- * driver does not support separate unicast/individual key
- * @seq: sequence number/packet number, seq_len octets, the next
- * packet number to be used for in replay protection; configured
- * for Rx keys (in most cases, this is only used with broadcast
- * keys and set to zero for unicast keys); %NULL if not set
- * @seq_len: length of the seq, depends on the algorithm:
- * TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets
- * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
- * 8-byte Rx Mic Key
- * @key_len: length of the key buffer in octets (WEP: 5 or 13,
- * TKIP: 32, CCMP/GCMP: 16, IGTK: 16)
- *
+ * @params: Key parameters
* Returns: 0 on success, -1 on failure
*
* Configure the given key for the kernel driver. If the driver
@@ -2354,10 +2474,7 @@ struct wpa_driver_ops {
* in driver_*.c set_key() implementation, see driver_ndis.c for an
* example on how this can be done.
*/
- int (*set_key)(const char *ifname, void *priv, 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);
+ int (*set_key)(void *priv, struct wpa_driver_set_key_params *params);
/**
* init - Initialize driver interface
@@ -2609,11 +2726,15 @@ struct wpa_driver_ops {
* driver decide
* @csa_offs: Array of CSA offsets or %NULL
* @csa_offs_len: Number of elements in csa_offs
+ * @no_encrypt: Do not encrypt frame even if appropriate key exists
+ * (used only for testing purposes)
+ * @wait: Time to wait off-channel for a response (in ms), or zero
* Returns: 0 on success, -1 on failure
*/
int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
int noack, unsigned int freq, const u16 *csa_offs,
- size_t csa_offs_len);
+ size_t csa_offs_len, int no_encrypt,
+ unsigned int wait);
/**
* update_ft_ies - Update FT (IEEE 802.11r) IEs
@@ -2868,6 +2989,33 @@ struct wpa_driver_ops {
const u8 *addr);
/**
+ * tx_control_port - Send a frame over the 802.1X controlled port
+ * @priv: Private driver interface data
+ * @dest: Destination MAC address
+ * @proto: Ethertype in host byte order
+ * @buf: Frame payload starting from IEEE 802.1X header
+ * @len: Frame payload length
+ * @no_encrypt: Do not encrypt frame
+ *
+ * Returns 0 on success, else an error
+ *
+ * This is like a normal Ethernet send except that the driver is aware
+ * (by other means than the Ethertype) that this frame is special,
+ * and more importantly it gains an ordering between the transmission of
+ * the frame and other driver management operations such as key
+ * installations. This can be used to work around known limitations in
+ * IEEE 802.11 protocols such as race conditions between rekeying 4-way
+ * handshake message 4/4 and a PTK being overwritten.
+ *
+ * This function is only used for a given interface if the driver
+ * instance reports WPA_DRIVER_FLAGS_CONTROL_PORT capability. Otherwise,
+ * API users will fall back to sending the frame via a normal socket.
+ */
+ int (*tx_control_port)(void *priv, const u8 *dest,
+ u16 proto, const u8 *buf, size_t len,
+ int no_encrypt);
+
+ /**
* hapd_send_eapol - Send an EAPOL packet (AP only)
* @priv: private driver interface data
* @addr: Destination MAC address
@@ -3113,19 +3261,6 @@ struct wpa_driver_ops {
int (*commit)(void *priv);
/**
- * send_ether - Send an ethernet packet (AP only)
- * @priv: private driver interface data
- * @dst: Destination MAC address
- * @src: Source MAC address
- * @proto: Ethertype
- * @data: EAPOL packet starting with IEEE 802.1X header
- * @data_len: Length of the EAPOL packet in octets
- * Returns: 0 on success, -1 on failure
- */
- int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto,
- const u8 *data, size_t data_len);
-
- /**
* set_radius_acl_auth - Notification of RADIUS ACL change
* @priv: Private driver interface data
* @mac: MAC address of the station
@@ -3348,20 +3483,6 @@ struct wpa_driver_ops {
int (*signal_monitor)(void *priv, int threshold, int hysteresis);
/**
- * send_frame - Send IEEE 802.11 frame (testing use only)
- * @priv: Private driver interface data
- * @data: IEEE 802.11 frame with IEEE 802.11 header
- * @data_len: Size of the frame
- * @encrypt: Whether to encrypt the frame (if keys are set)
- * Returns: 0 on success, -1 on failure
- *
- * This function is only used for debugging purposes and is not
- * required to be implemented for normal operations.
- */
- int (*send_frame)(void *priv, const u8 *data, size_t data_len,
- int encrypt);
-
- /**
* get_noa - Get current Notice of Absence attribute payload
* @priv: Private driver interface data
* @buf: Buffer for returning NoA
@@ -3513,6 +3634,12 @@ struct wpa_driver_ops {
unsigned int val);
/**
+ * get_wowlan - Get wake-on-wireless status
+ * @priv: Private driver interface data
+ */
+ int (*get_wowlan)(void *priv);
+
+ /**
* set_wowlan - Set wake-on-wireless triggers
* @priv: Private driver interface data
* @triggers: wowlan triggers
@@ -4843,6 +4970,15 @@ enum wpa_event_type {
* EVENT_UPDATE_DH - Notification of updated DH information
*/
EVENT_UPDATE_DH,
+
+ /**
+ * EVENT_UNPROT_BEACON - Unprotected Beacon frame received
+ *
+ * This event should be called when a Beacon frame is dropped due to it
+ * not being protected correctly. union wpa_event_data::unprot_beacon
+ * is required to provide more details of the frame.
+ */
+ EVENT_UNPROT_BEACON,
};
@@ -5609,8 +5745,17 @@ union wpa_event_data {
* struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
* @pri_freq: Selected primary frequency
* @sec_freq: Selected secondary frequency
+ * @edmg_channel: Selected EDMG channel
* @vht_seg0_center_ch: VHT mode Segment0 center channel
+ * The value is the index of the channel center frequency for
+ * 20 MHz, 40 MHz, and 80 MHz channels. The value is the center
+ * frequency index of the primary 80 MHz segment for 160 MHz and
+ * 80+80 MHz channels.
* @vht_seg1_center_ch: VHT mode Segment1 center channel
+ * The value is zero for 20 MHz, 40 MHz, and 80 MHz channels. The
+ * value is the index of the channel center frequency for 160 MHz
+ * channels and the center frequency index of the secondary 80 MHz
+ * segment for 80+80 MHz channels.
* @ch_width: Selected Channel width by driver. Driver may choose to
* change hostapd configured ACS channel width due driver internal
* channel restrictions.
@@ -5619,6 +5764,7 @@ union wpa_event_data {
struct acs_selected_channels {
unsigned int pri_freq;
unsigned int sec_freq;
+ u8 edmg_channel;
u8 vht_seg0_center_ch;
u8 vht_seg1_center_ch;
u16 ch_width;
@@ -5685,6 +5831,13 @@ union wpa_event_data {
const u8 *ie;
size_t ie_len;
} update_dh;
+
+ /**
+ * struct unprot_beacon - Data for EVENT_UNPROT_BEACON
+ */
+ struct unprot_beacon {
+ const u8 *sa;
+ } unprot_beacon;
};
/**
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index eac3ae8a..d630c3dc 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -492,14 +492,18 @@ atheros_del_key(void *priv, const u8 *addr, int key_idx)
}
static int
-atheros_set_key(const char *ifname, void *priv, 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)
+atheros_set_key(void *priv, struct wpa_driver_set_key_params *params)
{
struct atheros_driver_data *drv = priv;
struct ieee80211req_key wk;
u_int8_t cipher;
int ret;
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
if (alg == WPA_ALG_NONE)
return atheros_del_key(drv, addr, key_idx);
@@ -1960,7 +1964,8 @@ static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
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)
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt, unsigned int wait)
{
struct atheros_driver_data *drv = priv;
u8 buf[1510];
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 8667ee51..b4400d7b 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -9,7 +9,6 @@
#include "includes.h"
#include <sys/ioctl.h>
-#include <sys/sysctl.h>
#include "common.h"
#include "driver.h"
@@ -51,22 +50,19 @@ struct bsd_driver_global {
void *ctx;
int sock; /* socket for 802.11 ioctls */
int route; /* routing socket for events */
- char *event_buf;
- size_t event_buf_len;
struct dl_list ifaces; /* list of interfaces */
};
struct bsd_driver_data {
struct dl_list list;
struct bsd_driver_global *global;
- struct hostapd_data *hapd; /* back pointer */
+ void *ctx;
struct l2_packet_data *sock_xmit;/* raw packet xmit socket */
char ifname[IFNAMSIZ+1]; /* interface name */
int flags;
unsigned int ifindex; /* interface index */
int if_removed; /* has the interface been removed? */
- void *ctx;
struct wpa_driver_capa capa; /* driver capability */
int is_ap; /* Access point mode */
int prev_roaming; /* roaming state to restore on deinit */
@@ -90,7 +86,6 @@ bsd_get_drvindex(void *priv, unsigned int ifindex)
return NULL;
}
-#ifndef HOSTAPD
static struct bsd_driver_data *
bsd_get_drvname(void *priv, const char *ifname)
{
@@ -103,7 +98,6 @@ bsd_get_drvname(void *priv, const char *ifname)
}
return NULL;
}
-#endif /* HOSTAPD */
static int
bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
@@ -295,9 +289,8 @@ bsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr)
}
static int
-bsd_ctrl_iface(void *priv, int enable)
+bsd_get_iface_flags(struct bsd_driver_data *drv)
{
- struct bsd_driver_data *drv = priv;
struct ifreq ifr;
os_memset(&ifr, 0, sizeof(ifr));
@@ -309,36 +302,24 @@ bsd_ctrl_iface(void *priv, int enable)
return -1;
}
drv->flags = ifr.ifr_flags;
-
- if (enable) {
- if (ifr.ifr_flags & IFF_UP)
- return 0;
- ifr.ifr_flags |= IFF_UP;
- } else {
- if (!(ifr.ifr_flags & IFF_UP))
- return 0;
- ifr.ifr_flags &= ~IFF_UP;
- }
-
- if (ioctl(drv->global->sock, SIOCSIFFLAGS, &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
- strerror(errno));
- return -1;
- }
-
- drv->flags = ifr.ifr_flags;
return 0;
}
static int
-bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
- const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
- size_t seq_len, const u8 *key, size_t key_len)
+bsd_set_key(void *priv, struct wpa_driver_set_key_params *params)
{
struct ieee80211req_key wk;
#ifdef IEEE80211_KEY_NOREPLAY
struct bsd_driver_data *drv = priv;
#endif /* IEEE80211_KEY_NOREPLAY */
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *seq = params->seq;
+ size_t seq_len = params->seq_len;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
"seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
@@ -540,7 +521,7 @@ bsd_set_ieee8021x(void *priv, struct wpa_bss_params *params)
__func__);
return -1;
}
- return bsd_ctrl_iface(priv, 1);
+ return 0;
}
static void
@@ -595,17 +576,13 @@ bsd_set_freq(void *priv, struct hostapd_freq_params *freq)
if (channel < 14) {
mode =
-#ifdef CONFIG_IEEE80211N
freq->ht_enabled ? IFM_IEEE80211_11NG :
-#endif /* CONFIG_IEEE80211N */
- IFM_IEEE80211_11G;
+ IFM_IEEE80211_11G;
} else if (channel == 14) {
mode = IFM_IEEE80211_11B;
} else {
mode =
-#ifdef CONFIG_IEEE80211N
freq->ht_enabled ? IFM_IEEE80211_11NA :
-#endif /* CONFIG_IEEE80211N */
IFM_IEEE80211_11A;
}
if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) {
@@ -636,20 +613,152 @@ bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
return 0;
}
-static size_t
-rtbuf_len(void)
+static void
+bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
{
- size_t len;
-
- int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
+ char event_buf[2048]; /* max size of a single route(4) msg */
+ struct bsd_driver_global *global = sock_ctx;
+ struct bsd_driver_data *drv;
+ struct if_announcemsghdr *ifan;
+ struct if_msghdr *ifm;
+ struct rt_msghdr *rtm;
+ union wpa_event_data event;
+ struct ieee80211_michael_event *mic;
+ struct ieee80211_leave_event *leave;
+ struct ieee80211_join_event *join;
+ int n;
- if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
- wpa_printf(MSG_WARNING, "%s failed: %s", __func__,
- strerror(errno));
- len = 2048;
+ n = read(sock, event_buf, sizeof(event_buf));
+ if (n < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ wpa_printf(MSG_ERROR, "%s read() failed: %s",
+ __func__, strerror(errno));
+ return;
}
- return len;
+ rtm = (struct rt_msghdr *) event_buf;
+ if (rtm->rtm_version != RTM_VERSION) {
+ wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
+ rtm->rtm_version);
+ return;
+ }
+ os_memset(&event, 0, sizeof(event));
+ switch (rtm->rtm_type) {
+ case RTM_IEEE80211:
+ ifan = (struct if_announcemsghdr *) rtm;
+ drv = bsd_get_drvindex(global, ifan->ifan_index);
+ if (drv == NULL)
+ return;
+ switch (ifan->ifan_what) {
+ case RTM_IEEE80211_ASSOC:
+ case RTM_IEEE80211_REASSOC:
+ if (drv->is_ap)
+ break;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+ break;
+ case RTM_IEEE80211_DISASSOC:
+ if (drv->is_ap)
+ break;
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+ break;
+ case RTM_IEEE80211_SCAN:
+ if (drv->is_ap)
+ break;
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
+ NULL);
+ break;
+ case RTM_IEEE80211_LEAVE:
+ leave = (struct ieee80211_leave_event *) &ifan[1];
+ drv_event_disassoc(drv->ctx, leave->iev_addr);
+ break;
+ case RTM_IEEE80211_JOIN:
+#ifdef RTM_IEEE80211_REJOIN
+ case RTM_IEEE80211_REJOIN:
+#endif
+ join = (struct ieee80211_join_event *) &ifan[1];
+ bsd_new_sta(drv, drv->ctx, join->iev_addr);
+ break;
+ case RTM_IEEE80211_REPLAY:
+ /* ignore */
+ break;
+ case RTM_IEEE80211_MICHAEL:
+ mic = (struct ieee80211_michael_event *) &ifan[1];
+ wpa_printf(MSG_DEBUG,
+ "Michael MIC failure wireless event: "
+ "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
+ MAC2STR(mic->iev_src));
+ os_memset(&event, 0, sizeof(event));
+ event.michael_mic_failure.unicast =
+ !IEEE80211_IS_MULTICAST(mic->iev_dst);
+ event.michael_mic_failure.src = mic->iev_src;
+ wpa_supplicant_event(drv->ctx,
+ EVENT_MICHAEL_MIC_FAILURE, &event);
+ break;
+ }
+ break;
+ case RTM_IFANNOUNCE:
+ ifan = (struct if_announcemsghdr *) rtm;
+ switch (ifan->ifan_what) {
+ case IFAN_DEPARTURE:
+ drv = bsd_get_drvindex(global, ifan->ifan_index);
+ if (drv)
+ drv->if_removed = 1;
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ break;
+ case IFAN_ARRIVAL:
+ drv = bsd_get_drvname(global, ifan->ifan_name);
+ if (drv) {
+ drv->ifindex = ifan->ifan_index;
+ drv->if_removed = 0;
+ }
+ event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action");
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
+ ifan->ifan_name,
+ ifan->ifan_what == IFAN_DEPARTURE ?
+ "removed" : "added");
+ os_strlcpy(event.interface_status.ifname, ifan->ifan_name,
+ sizeof(event.interface_status.ifname));
+ if (drv) {
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ /*
+ * Set ifindex to zero after sending the event as the
+ * event might query the driver to ensure a match.
+ */
+ if (ifan->ifan_what == IFAN_DEPARTURE)
+ drv->ifindex = 0;
+ } else {
+ wpa_supplicant_event_global(global->ctx,
+ EVENT_INTERFACE_STATUS,
+ &event);
+ }
+ break;
+ case RTM_IFINFO:
+ ifm = (struct if_msghdr *) rtm;
+ drv = bsd_get_drvindex(global, ifm->ifm_index);
+ if (drv == NULL)
+ return;
+ if ((ifm->ifm_flags & IFF_UP) == 0 &&
+ (drv->flags & IFF_UP) != 0) {
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
+ drv->ifname);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
+ NULL);
+ } else if ((ifm->ifm_flags & IFF_UP) != 0 &&
+ (drv->flags & IFF_UP) == 0) {
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
+ drv->ifname);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+ NULL);
+ }
+ drv->flags = ifm->ifm_flags;
+ break;
+ }
}
#ifdef HOSTAPD
@@ -770,80 +879,10 @@ bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
}
static void
-bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
-{
- struct bsd_driver_global *global = sock_ctx;
- struct bsd_driver_data *drv;
- struct if_announcemsghdr *ifan;
- struct rt_msghdr *rtm;
- struct ieee80211_michael_event *mic;
- struct ieee80211_join_event *join;
- struct ieee80211_leave_event *leave;
- int n;
- union wpa_event_data data;
-
- n = read(sock, global->event_buf, global->event_buf_len);
- if (n < 0) {
- if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "%s read() failed: %s",
- __func__, strerror(errno));
- return;
- }
-
- rtm = (struct rt_msghdr *) global->event_buf;
- if (rtm->rtm_version != RTM_VERSION) {
- wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
- rtm->rtm_version);
- return;
- }
- switch (rtm->rtm_type) {
- case RTM_IEEE80211:
- ifan = (struct if_announcemsghdr *) rtm;
- drv = bsd_get_drvindex(global, ifan->ifan_index);
- if (drv == NULL)
- return;
- switch (ifan->ifan_what) {
- case RTM_IEEE80211_ASSOC:
- case RTM_IEEE80211_REASSOC:
- case RTM_IEEE80211_DISASSOC:
- case RTM_IEEE80211_SCAN:
- break;
- case RTM_IEEE80211_LEAVE:
- leave = (struct ieee80211_leave_event *) &ifan[1];
- drv_event_disassoc(drv->hapd, leave->iev_addr);
- break;
- case RTM_IEEE80211_JOIN:
-#ifdef RTM_IEEE80211_REJOIN
- case RTM_IEEE80211_REJOIN:
-#endif
- join = (struct ieee80211_join_event *) &ifan[1];
- bsd_new_sta(drv, drv->hapd, join->iev_addr);
- break;
- case RTM_IEEE80211_REPLAY:
- /* ignore */
- break;
- case RTM_IEEE80211_MICHAEL:
- mic = (struct ieee80211_michael_event *) &ifan[1];
- wpa_printf(MSG_DEBUG,
- "Michael MIC failure wireless event: "
- "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
- MAC2STR(mic->iev_src));
- os_memset(&data, 0, sizeof(data));
- data.michael_mic_failure.unicast = 1;
- data.michael_mic_failure.src = mic->iev_src;
- wpa_supplicant_event(drv->hapd,
- EVENT_MICHAEL_MIC_FAILURE, &data);
- break;
- }
- break;
- }
-}
-
-static void
handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
{
struct bsd_driver_data *drv = ctx;
- drv_event_eapol_rx(drv->hapd, src_addr, buf, len);
+ drv_event_eapol_rx(drv->ctx, src_addr, buf, len);
}
static void *
@@ -864,7 +903,8 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
goto bad;
}
- drv->hapd = hapd;
+ drv->ctx = hapd;
+ drv->is_ap = 1;
drv->global = params->global_priv;
os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
@@ -875,8 +915,7 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
goto bad;
- /* mark down during setup */
- if (bsd_ctrl_iface(drv, 0) < 0)
+ if (bsd_get_iface_flags(drv) < 0)
goto bad;
if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) {
@@ -901,8 +940,6 @@ bsd_deinit(void *priv)
{
struct bsd_driver_data *drv = priv;
- if (drv->ifindex != 0)
- bsd_ctrl_iface(drv, 0);
if (drv->sock_xmit != NULL)
l2_packet_deinit(drv->sock_xmit);
os_free(drv);
@@ -910,13 +947,6 @@ bsd_deinit(void *priv)
static int
-bsd_commit(void *priv)
-{
- return bsd_ctrl_iface(priv, 1);
-}
-
-
-static int
bsd_set_sta_authorized(void *priv, const u8 *addr,
unsigned int total_flags, unsigned int flags_or,
unsigned int flags_and)
@@ -1169,8 +1199,11 @@ wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params)
}
/* NB: interface must be marked UP to do a scan */
- if (bsd_ctrl_iface(drv, 1) < 0)
+ if (!(drv->flags & IFF_UP)) {
+ wpa_printf(MSG_DEBUG, "%s: interface is not up, cannot scan",
+ __func__);
return -1;
+ }
#ifdef IEEE80211_IOC_SCAN_MAX_SSID
os_memset(&sr, 0, sizeof(sr));
@@ -1208,153 +1241,6 @@ wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params)
}
static void
-wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
-{
- struct bsd_driver_global *global = sock_ctx;
- struct bsd_driver_data *drv;
- struct if_announcemsghdr *ifan;
- struct if_msghdr *ifm;
- struct rt_msghdr *rtm;
- union wpa_event_data event;
- struct ieee80211_michael_event *mic;
- struct ieee80211_leave_event *leave;
- struct ieee80211_join_event *join;
- int n;
-
- n = read(sock, global->event_buf, global->event_buf_len);
- if (n < 0) {
- if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "%s read() failed: %s",
- __func__, strerror(errno));
- return;
- }
-
- rtm = (struct rt_msghdr *) global->event_buf;
- if (rtm->rtm_version != RTM_VERSION) {
- wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
- rtm->rtm_version);
- return;
- }
- os_memset(&event, 0, sizeof(event));
- switch (rtm->rtm_type) {
- case RTM_IFANNOUNCE:
- ifan = (struct if_announcemsghdr *) rtm;
- switch (ifan->ifan_what) {
- case IFAN_DEPARTURE:
- drv = bsd_get_drvindex(global, ifan->ifan_index);
- if (drv)
- drv->if_removed = 1;
- event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
- break;
- case IFAN_ARRIVAL:
- drv = bsd_get_drvname(global, ifan->ifan_name);
- if (drv) {
- drv->ifindex = ifan->ifan_index;
- drv->if_removed = 0;
- }
- event.interface_status.ievent = EVENT_INTERFACE_ADDED;
- break;
- default:
- wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action");
- return;
- }
- wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
- ifan->ifan_name,
- ifan->ifan_what == IFAN_DEPARTURE ?
- "removed" : "added");
- os_strlcpy(event.interface_status.ifname, ifan->ifan_name,
- sizeof(event.interface_status.ifname));
- if (drv) {
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
- &event);
- /*
- * Set ifindex to zero after sending the event as the
- * event might query the driver to ensure a match.
- */
- if (ifan->ifan_what == IFAN_DEPARTURE)
- drv->ifindex = 0;
- } else {
- wpa_supplicant_event_global(global->ctx,
- EVENT_INTERFACE_STATUS,
- &event);
- }
- break;
- case RTM_IEEE80211:
- ifan = (struct if_announcemsghdr *) rtm;
- drv = bsd_get_drvindex(global, ifan->ifan_index);
- if (drv == NULL)
- return;
- switch (ifan->ifan_what) {
- case RTM_IEEE80211_ASSOC:
- case RTM_IEEE80211_REASSOC:
- if (drv->is_ap)
- break;
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
- break;
- case RTM_IEEE80211_DISASSOC:
- if (drv->is_ap)
- break;
- wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
- break;
- case RTM_IEEE80211_SCAN:
- if (drv->is_ap)
- break;
- wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
- NULL);
- break;
- case RTM_IEEE80211_LEAVE:
- leave = (struct ieee80211_leave_event *) &ifan[1];
- drv_event_disassoc(drv->ctx, leave->iev_addr);
- break;
- case RTM_IEEE80211_JOIN:
-#ifdef RTM_IEEE80211_REJOIN
- case RTM_IEEE80211_REJOIN:
-#endif
- join = (struct ieee80211_join_event *) &ifan[1];
- bsd_new_sta(drv, drv->ctx, join->iev_addr);
- break;
- case RTM_IEEE80211_REPLAY:
- /* ignore */
- break;
- case RTM_IEEE80211_MICHAEL:
- mic = (struct ieee80211_michael_event *) &ifan[1];
- wpa_printf(MSG_DEBUG,
- "Michael MIC failure wireless event: "
- "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
- MAC2STR(mic->iev_src));
-
- os_memset(&event, 0, sizeof(event));
- event.michael_mic_failure.unicast =
- !IEEE80211_IS_MULTICAST(mic->iev_dst);
- wpa_supplicant_event(drv->ctx,
- EVENT_MICHAEL_MIC_FAILURE, &event);
- break;
- }
- break;
- case RTM_IFINFO:
- ifm = (struct if_msghdr *) rtm;
- drv = bsd_get_drvindex(global, ifm->ifm_index);
- if (drv == NULL)
- return;
- if ((ifm->ifm_flags & IFF_UP) == 0 &&
- (drv->flags & IFF_UP) != 0) {
- wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
- drv->ifname);
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
- NULL);
- } else if ((ifm->ifm_flags & IFF_UP) != 0 &&
- (drv->flags & IFF_UP) == 0) {
- wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
- drv->ifname);
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
- NULL);
- }
- drv->flags = ifm->ifm_flags;
- break;
- }
-}
-
-static void
wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
struct ieee80211req_scan_result *sr)
{
@@ -1570,12 +1456,6 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv)
if (drv == NULL)
return NULL;
- /*
- * NB: We require the interface name be mappable to an index.
- * This implies we do not support having wpa_supplicant
- * wait for an interface to appear. This seems ok; that
- * doesn't belong here; it's really the job of devd.
- */
drv->ifindex = if_nametoindex(ifname);
if (drv->ifindex == 0) {
wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
@@ -1607,7 +1487,7 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv)
goto fail;
/* Down interface during setup. */
- if (bsd_ctrl_iface(drv, 0) < 0)
+ if (bsd_get_iface_flags(drv) < 0)
goto fail;
drv->opmode = get80211opmode(drv);
@@ -1628,9 +1508,6 @@ wpa_driver_bsd_deinit(void *priv)
if (drv->ifindex != 0 && !drv->if_removed) {
wpa_driver_bsd_set_wpa(drv, 0);
- /* NB: mark interface down */
- bsd_ctrl_iface(drv, 0);
-
wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa,
drv->prev_privacy);
@@ -1664,9 +1541,7 @@ bsd_global_init(void *ctx)
#if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER)
unsigned char msgfilter[] = {
RTM_IEEE80211,
-#ifndef HOSTAPD
RTM_IFINFO, RTM_IFANNOUNCE,
-#endif
};
#endif
#ifdef ROUTE_MSGFILTER
@@ -1709,22 +1584,9 @@ bsd_global_init(void *ctx)
strerror(errno));
#endif
- global->event_buf_len = rtbuf_len();
- global->event_buf = os_malloc(global->event_buf_len);
- if (global->event_buf == NULL) {
- wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
- goto fail;
- }
-
-#ifdef HOSTAPD
eloop_register_read_sock(global->route, bsd_wireless_event_receive,
NULL, global);
-#else /* HOSTAPD */
- eloop_register_read_sock(global->route, wpa_driver_bsd_event_receive,
- NULL, global);
-#endif /* HOSTAPD */
-
return global;
fail:
@@ -1761,7 +1623,6 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = {
.sta_disassoc = bsd_sta_disassoc,
.sta_deauth = bsd_sta_deauth,
.sta_set_flags = bsd_set_sta_authorized,
- .commit = bsd_commit,
#else /* HOSTAPD */
.init2 = wpa_driver_bsd_init,
.deinit = wpa_driver_bsd_deinit,
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 731c6a3b..63846db2 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -89,6 +89,7 @@ const char * event_to_string(enum wpa_event_type event)
E2S(INTERFACE_MAC_CHANGED);
E2S(WDS_STA_INTERFACE_STATUS);
E2S(UPDATE_DH);
+ E2S(UNPROT_BEACON);
}
return "UNKNOWN";
@@ -308,6 +309,14 @@ const char * driver_flag_to_string(u64 flag)
DF2S(OCE_AP);
DF2S(OCE_STA_CFON);
DF2S(MFP_OPTIONAL);
+ DF2S(SELF_MANAGED_REGULATORY);
+ DF2S(FTM_RESPONDER);
+ DF2S(CONTROL_PORT);
+ DF2S(VLAN_OFFLOAD);
+ DF2S(UPDATE_FT_IES);
+ DF2S(SAFE_PTK0_REKEYS);
+ DF2S(BEACON_PROTECTION);
+ DF2S(EXTENDED_KEY_ID);
}
return "UNKNOWN";
#undef DF2S
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 186eccbf..b9c42e4d 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -263,7 +263,8 @@ static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr)
static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack,
unsigned int freq,
- const u16 *csa_offs, size_t csa_offs_len)
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt, unsigned int wait)
{
struct hostap_driver_data *drv = priv;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
@@ -312,7 +313,7 @@ static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data,
pos += 2;
memcpy(pos, data, data_len);
- res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0);
+ res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0, 0, 0);
if (res < 0) {
wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
"failed: %d (%s)",
@@ -395,17 +396,20 @@ static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param,
}
-static int wpa_driver_hostap_set_key(const char *ifname, void *priv,
- 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)
+static int wpa_driver_hostap_set_key(void *priv,
+ struct wpa_driver_set_key_params *params)
{
struct hostap_driver_data *drv = priv;
struct prism2_hostapd_param *param;
u8 *buf;
size_t blen;
int ret = 0;
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
blen = sizeof(*param) + key_len;
buf = os_zalloc(blen);
@@ -1051,7 +1055,7 @@ static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code = host_to_le16(reason);
return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth), 0, 0, NULL, 0);
+ sizeof(mgmt.u.deauth), 0, 0, NULL, 0, 0, 0);
}
@@ -1089,7 +1093,7 @@ static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code = host_to_le16(reason);
return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
- sizeof(mgmt.u.disassoc), 0, 0, NULL, 0);
+ sizeof(mgmt.u.disassoc), 0, 0, NULL, 0, 0, 0);
}
@@ -1169,7 +1173,7 @@ static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr,
os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
- hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0);
+ hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0, 0, 0);
}
diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c
index e922503f..5319ba2d 100644
--- a/src/drivers/driver_macsec_linux.c
+++ b/src/drivers/driver_macsec_linux.c
@@ -54,8 +54,6 @@ struct macsec_drv_data {
struct nl_sock *sk;
struct macsec_genl_ctx ctx;
- struct netlink_data *netlink;
- struct nl_handle *nl;
char ifname[IFNAMSIZ + 1];
int ifi;
int parent_ifi;
@@ -321,14 +319,14 @@ static int macsec_drv_macsec_init(void *priv, struct macsec_init_params *params)
if (err < 0) {
wpa_printf(MSG_ERROR, DRV_PREFIX
"Unable to connect NETLINK_ROUTE socket: %s",
- strerror(errno));
+ nl_geterror(err));
goto sock;
}
err = rtnl_link_alloc_cache(drv->sk, AF_UNSPEC, &drv->link_cache);
if (err < 0) {
wpa_printf(MSG_ERROR, DRV_PREFIX "Unable to get link cache: %s",
- strerror(errno));
+ nl_geterror(err));
goto sock;
}
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 5b4b9247..529fc3bc 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -1034,6 +1034,18 @@ static int wpa_driver_ndis_set_key(const char *ifname, void *priv,
static int
+wpa_driver_ndis_set_key_wrapper(void *priv,
+ struct wpa_driver_set_key_params *params)
+{
+ return wpa_driver_ndis_set_key(params->ifname, priv,
+ params->alg, params->addr,
+ params->key_idx, params->set_tx,
+ params->seq, params->seq_len,
+ params->key, params->key_len);
+}
+
+
+static int
wpa_driver_ndis_associate(void *priv,
struct wpa_driver_associate_params *params)
{
@@ -3195,7 +3207,7 @@ void driver_ndis_init_ops(void)
wpa_driver_ndis_ops.desc = ndis_drv_desc;
wpa_driver_ndis_ops.get_bssid = wpa_driver_ndis_get_bssid;
wpa_driver_ndis_ops.get_ssid = wpa_driver_ndis_get_ssid;
- wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key;
+ wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key_wrapper;
wpa_driver_ndis_ops.init = wpa_driver_ndis_init;
wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit;
wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index b7efb6a3..3b7c31c8 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -66,48 +66,6 @@ enum nlmsgerr_attrs {
#define SOL_NETLINK 270
#endif
-#ifndef CONFIG_LIBNL20
-/*
- * libnl 1.1 has a bug, it tries to allocate socket numbers densely
- * but when you free a socket again it will mess up its bitmap and
- * and use the wrong number the next time it needs a socket ID.
- * Therefore, we wrap the handle alloc/destroy and add our own pid
- * accounting.
- */
-static uint32_t port_bitmap[32] = { 0 };
-
-static struct nl_handle *nl80211_handle_alloc(void *cb)
-{
- struct nl_handle *handle;
- uint32_t pid = getpid() & 0x3FFFFF;
- int i;
-
- handle = nl_handle_alloc_cb(cb);
-
- for (i = 0; i < 1024; i++) {
- if (port_bitmap[i / 32] & (1 << (i % 32)))
- continue;
- port_bitmap[i / 32] |= 1 << (i % 32);
- pid += i << 22;
- break;
- }
-
- nl_socket_set_local_port(handle, pid);
-
- return handle;
-}
-
-static void nl80211_handle_destroy(struct nl_handle *handle)
-{
- uint32_t port = nl_socket_get_local_port(handle);
-
- port >>= 22;
- port_bitmap[port / 32] &= ~(1 << (port % 32));
-
- nl_handle_destroy(handle);
-}
-#endif /* CONFIG_LIBNL20 */
-
#ifdef ANDROID
/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
@@ -117,11 +75,11 @@ static void nl80211_handle_destroy(struct nl_handle *handle)
#endif /* ANDROID */
-static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
+static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg)
{
- struct nl_handle *handle;
+ struct nl_sock *handle;
- handle = nl80211_handle_alloc(cb);
+ handle = nl_socket_alloc_cb(cb);
if (handle == NULL) {
wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
"callbacks (%s)", dbg);
@@ -131,7 +89,7 @@ static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
if (genl_connect(handle)) {
wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
"netlink (%s)", dbg);
- nl80211_handle_destroy(handle);
+ nl_socket_free(handle);
return NULL;
}
@@ -139,11 +97,11 @@ static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
}
-static void nl_destroy_handles(struct nl_handle **handle)
+static void nl_destroy_handles(struct nl_sock **handle)
{
if (*handle == NULL)
return;
- nl80211_handle_destroy(*handle);
+ nl_socket_free(*handle);
*handle = NULL;
}
@@ -154,11 +112,10 @@ static void nl_destroy_handles(struct nl_handle **handle)
#define ELOOP_SOCKET_INVALID (intptr_t) 0x88888889ULL
#endif
-static void nl80211_register_eloop_read(struct nl_handle **handle,
+static void nl80211_register_eloop_read(struct nl_sock **handle,
eloop_sock_handler handler,
void *eloop_data, int persist)
{
-#ifdef CONFIG_LIBNL20
/*
* libnl uses a pretty small buffer (32 kB that gets converted to 64 kB)
* by default. It is possible to hit that limit in some cases where
@@ -166,13 +123,15 @@ static void nl80211_register_eloop_read(struct nl_handle **handle,
* to hostapd and STA entry deletion. Try to increase the buffer to make
* this less likely to occur.
*/
- if (nl_socket_set_buffer_size(*handle, 262144, 0) < 0) {
+ int err;
+
+ err = nl_socket_set_buffer_size(*handle, 262144, 0);
+ if (err < 0) {
wpa_printf(MSG_DEBUG,
"nl80211: Could not set nl_socket RX buffer size: %s",
- strerror(errno));
+ nl_geterror(err));
/* continue anyway with the default (smaller) buffer */
}
-#endif /* CONFIG_LIBNL20 */
nl_socket_set_nonblocking(*handle);
eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
@@ -183,7 +142,7 @@ static void nl80211_register_eloop_read(struct nl_handle **handle,
}
-static void nl80211_destroy_eloop_handle(struct nl_handle **handle, int persist)
+static void nl80211_destroy_eloop_handle(struct nl_sock **handle, int persist)
{
if (!persist)
*handle = (void *) (((intptr_t) *handle) ^
@@ -206,7 +165,8 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
const char *driver_params);
static int nl80211_send_frame_cmd(struct i802_bss *bss,
unsigned int freq, unsigned int wait,
- const u8 *buf, size_t buf_len, u64 *cookie,
+ const u8 *buf, size_t buf_len,
+ int save_cookie,
int no_cck, int no_ack, int offchanok,
const u16 *csa_offs, size_t csa_offs_len);
static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
@@ -391,7 +351,7 @@ static void nl80211_nlmsg_clear(struct nl_msg *msg)
static int send_and_recv(struct nl80211_global *global,
- struct nl_handle *nl_handle, struct nl_msg *msg,
+ struct nl_sock *nl_handle, struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
void *valid_data)
{
@@ -416,8 +376,16 @@ static int send_and_recv(struct nl80211_global *global,
NETLINK_CAP_ACK, &opt, sizeof(opt));
err = nl_send_auto_complete(nl_handle, msg);
- if (err < 0)
+ if (err < 0) {
+ wpa_printf(MSG_INFO,
+ "nl80211: nl_send_auto_complete() failed: %s",
+ nl_geterror(err));
+ /* Need to convert libnl error code to an errno value. For now,
+ * just hardcode this to EBADF; the real error reason is shown
+ * in that error print above. */
+ err = -EBADF;
goto out;
+ }
err = 1;
@@ -431,10 +399,24 @@ static int send_and_recv(struct nl80211_global *global,
while (err > 0) {
int res = nl_recvmsgs(nl_handle, cb);
- if (res < 0) {
+
+ if (res == -NLE_DUMP_INTR) {
+ /* Most likely one of the nl80211 dump routines hit a
+ * case where internal results changed while the dump
+ * was being sent. The most common known case for this
+ * is scan results fetching while associated were every
+ * received Beacon frame from the AP may end up
+ * incrementing bss_generation. This
+ * NL80211_CMD_GET_SCAN case tries again in the caller;
+ * other cases (of which there are no known common ones)
+ * will stop and return an error. */
+ wpa_printf(MSG_DEBUG, "nl80211: %s; convert to -EAGAIN",
+ nl_geterror(res));
+ err = -EAGAIN;
+ } else if (res < 0) {
wpa_printf(MSG_INFO,
- "nl80211: %s->nl_recvmsgs failed: %d",
- __func__, res);
+ "nl80211: %s->nl_recvmsgs failed: %d (%s)",
+ __func__, res, nl_geterror(res));
}
}
out:
@@ -1065,7 +1047,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
while (RTA_OK(attr, attrlen)) {
switch (attr->rta_type) {
case IFLA_IFNAME:
- if (RTA_PAYLOAD(attr) >= IFNAMSIZ)
+ if (RTA_PAYLOAD(attr) > IFNAMSIZ)
break;
os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
ifname[RTA_PAYLOAD(attr)] = '\0';
@@ -1240,7 +1222,7 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
while (RTA_OK(attr, attrlen)) {
switch (attr->rta_type) {
case IFLA_IFNAME:
- if (RTA_PAYLOAD(attr) >= IFNAMSIZ)
+ if (RTA_PAYLOAD(attr) > IFNAMSIZ)
break;
os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
ifname[RTA_PAYLOAD(attr)] = '\0';
@@ -1369,12 +1351,25 @@ int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid)
struct nl_msg *msg;
int ret;
struct nl80211_get_assoc_freq_arg arg;
+ int count = 0;
+try_again:
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
os_memset(&arg, 0, sizeof(arg));
arg.drv = drv;
ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
&arg);
+ if (ret == -EAGAIN) {
+ count++;
+ if (count >= 10) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid - try again");
+ goto try_again;
+ }
+ }
if (ret == 0) {
os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len);
return arg.assoc_ssid_len;
@@ -1390,12 +1385,25 @@ unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
struct nl_msg *msg;
int ret;
struct nl80211_get_assoc_freq_arg arg;
+ int count = 0;
+try_again:
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
os_memset(&arg, 0, sizeof(arg));
arg.drv = drv;
ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
&arg);
+ if (ret == -EAGAIN) {
+ count++;
+ if (count >= 10) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to receive consistent scan result dump for get_assoc_freq");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to receive consistent scan result dump for get_assoc_freq - try again");
+ goto try_again;
+ }
+ }
if (ret == 0) {
unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
arg.ibss_freq : arg.assoc_freq;
@@ -1733,7 +1741,7 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
if (ret < 0) {
wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
"membership for scan events: %d (%s)",
- ret, strerror(-ret));
+ ret, nl_geterror(ret));
goto err;
}
@@ -1743,7 +1751,7 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
if (ret < 0) {
wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
"membership for mlme events: %d (%s)",
- ret, strerror(-ret));
+ ret, nl_geterror(ret));
goto err;
}
@@ -1753,7 +1761,7 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
if (ret < 0) {
wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
"membership for regulatory events: %d (%s)",
- ret, strerror(-ret));
+ ret, nl_geterror(ret));
/* Continue without regulatory events */
}
@@ -1763,7 +1771,7 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
if (ret < 0) {
wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
"membership for vendor events: %d (%s)",
- ret, strerror(-ret));
+ ret, nl_geterror(ret));
/* Continue without vendor events */
}
@@ -1789,7 +1797,7 @@ err:
static void nl80211_check_global(struct nl80211_global *global)
{
- struct nl_handle *handle;
+ struct nl_sock *handle;
const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL };
int ret;
unsigned int i;
@@ -1808,7 +1816,7 @@ static void nl80211_check_global(struct nl80211_global *global)
if (ret < 0) {
wpa_printf(MSG_INFO,
"nl80211: Could not re-add multicast membership for %s events: %d (%s)",
- groups[i], ret, strerror(-ret));
+ groups[i], ret, nl_geterror(ret));
}
}
}
@@ -2087,7 +2095,7 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
static int nl80211_register_frame(struct i802_bss *bss,
- struct nl_handle *nl_handle,
+ struct nl_sock *nl_handle,
u16 type, const u8 *match, size_t match_len)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -2100,7 +2108,7 @@ static int nl80211_register_frame(struct i802_bss *bss,
wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s",
type, fc2str(type), nl_handle, buf);
- if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_ACTION)) ||
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_FRAME)) ||
nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type) ||
nla_put(msg, NL80211_ATTR_FRAME_MATCH, match_len, match)) {
nlmsg_free(msg);
@@ -2174,6 +2182,7 @@ static int nl80211_init_connect_handle(struct i802_bss *bss)
static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
+ u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
int ret = 0;
if (nl80211_alloc_mgmt_handle(bss))
@@ -2181,13 +2190,14 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
"handle %p", bss->nl_mgmt);
- if (drv->nlmode == NL80211_IFTYPE_ADHOC ||
- ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
- !(drv->capa.flags & WPA_DRIVER_FLAGS_SME))) {
- u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
-
+ if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
/* register for any AUTH message */
nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0);
+ } else if ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+ /* register for SAE Authentication frames */
+ nl80211_register_frame(bss, bss->nl_mgmt, type,
+ (u8 *) "\x03\x00", 2);
}
#ifdef CONFIG_INTERWORKING
@@ -2757,7 +2767,7 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
}
if (drv->rtnl_sk)
- nl80211_handle_destroy(drv->rtnl_sk);
+ nl_socket_free(drv->rtnl_sk);
if (bss->added_bridge) {
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
@@ -2873,7 +2883,6 @@ static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len)
case WPA_ALG_KRK:
return RSN_CIPHER_SUITE_KRK;
case WPA_ALG_NONE:
- case WPA_ALG_PMK:
wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d",
alg);
return 0;
@@ -2934,6 +2943,40 @@ static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[],
}
+static int wpa_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
+ int max_suites)
+{
+ int num_suites = 0;
+
+#define __AKM(a, b) \
+ if (num_suites < max_suites && \
+ (key_mgmt_suites & (WPA_KEY_MGMT_ ## a))) \
+ suites[num_suites++] = (RSN_AUTH_KEY_MGMT_ ## b)
+ __AKM(IEEE8021X, UNSPEC_802_1X);
+ __AKM(PSK, PSK_OVER_802_1X);
+ __AKM(FT_IEEE8021X, FT_802_1X);
+ __AKM(FT_PSK, FT_PSK);
+ __AKM(IEEE8021X_SHA256, 802_1X_SHA256);
+ __AKM(PSK_SHA256, PSK_SHA256);
+ __AKM(SAE, SAE);
+ __AKM(FT_SAE, FT_SAE);
+ __AKM(CCKM, CCKM);
+ __AKM(OSEN, OSEN);
+ __AKM(IEEE8021X_SUITE_B, 802_1X_SUITE_B);
+ __AKM(IEEE8021X_SUITE_B_192, 802_1X_SUITE_B_192);
+ __AKM(FILS_SHA256, FILS_SHA256);
+ __AKM(FILS_SHA384, FILS_SHA384);
+ __AKM(FT_FILS_SHA256, FT_FILS_SHA256);
+ __AKM(FT_FILS_SHA384, FT_FILS_SHA384);
+ __AKM(OWE, OWE);
+ __AKM(DPP, DPP);
+ __AKM(FT_IEEE8021X_SHA384, FT_802_1X_SHA384);
+#undef __AKM
+
+ return num_suites;
+}
+
+
#ifdef CONFIG_DRIVER_NL80211_QCA
static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
const u8 *key, size_t key_len)
@@ -3003,18 +3046,26 @@ static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
}
-static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
- 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)
+static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
+ struct wpa_driver_set_key_params *params)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex;
struct nl_msg *msg;
struct nl_msg *key_msg;
int ret;
- int tdls = 0;
+ int skip_set_key = 1;
+ const char *ifname = params->ifname;
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *seq = params->seq;
+ size_t seq_len = params->seq_len;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
+ int vlan_id = params->vlan_id;
+ enum key_flag key_flag = params->key_flag;
/* Ignore for P2P Device */
if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
@@ -3022,18 +3073,17 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
ifindex = if_nametoindex(ifname);
wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
- "set_tx=%d seq_len=%lu key_len=%lu",
+ "set_tx=%d seq_len=%lu key_len=%lu key_flag=0x%x",
__func__, ifindex, ifname, alg, addr, key_idx, set_tx,
- (unsigned long) seq_len, (unsigned long) key_len);
-#ifdef CONFIG_TDLS
- if (key_idx == -1) {
- key_idx = 0;
- tdls = 1;
+ (unsigned long) seq_len, (unsigned long) key_len, key_flag);
+
+ if (check_key_flag(key_flag)) {
+ wpa_printf(MSG_DEBUG, "%s: invalid key_flag", __func__);
+ return -EINVAL;
}
-#endif /* CONFIG_TDLS */
#ifdef CONFIG_DRIVER_NL80211_QCA
- if (alg == WPA_ALG_PMK &&
+ if ((key_flag & KEY_FLAG_PMK) &&
(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
__func__);
@@ -3042,15 +3092,33 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
}
#endif /* CONFIG_DRIVER_NL80211_QCA */
- if (alg == WPA_ALG_PMK &&
- (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
- return nl80211_set_pmk(drv, key, key_len, addr);
+ if (key_flag & KEY_FLAG_PMK) {
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)
+ return nl80211_set_pmk(drv, key, key_len, addr);
+ /* The driver does not have any offload mechanism for PMK, so
+ * there is no need to configure this key. */
+ return 0;
+ }
+ ret = -ENOBUFS;
key_msg = nlmsg_alloc();
if (!key_msg)
- return -ENOBUFS;
+ return ret;
- if (alg == WPA_ALG_NONE) {
+ if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+ KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: SET_KEY (pairwise RX/TX modify)");
+ msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
+ if (!msg)
+ goto fail2;
+ } else if (alg == WPA_ALG_NONE && (key_flag & KEY_FLAG_RX_TX)) {
+ wpa_printf(MSG_DEBUG, "%s: invalid key_flag to delete key",
+ __func__);
+ ret = -EINVAL;
+ goto fail2;
+ } else if (alg == WPA_ALG_NONE) {
+ wpa_printf(MSG_DEBUG, "nl80211: DEL_KEY");
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
if (!msg)
goto fail2;
@@ -3058,8 +3126,11 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
u32 suite;
suite = wpa_alg_to_cipher_suite(alg, key_len);
- if (!suite)
+ if (!suite) {
+ ret = -EINVAL;
goto fail2;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: NEW_KEY");
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
if (!msg)
goto fail2;
@@ -3067,12 +3138,13 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
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(key_msg, NL80211_KEY_SEQ, seq_len, seq))
- goto fail;
- wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len);
+ if (seq && seq_len) {
+ if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq))
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ",
+ seq, seq_len);
+ }
}
if (addr && !is_broadcast_ether_addr(addr)) {
@@ -3080,22 +3152,42 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
goto fail;
- if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
+ if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+ KEY_FLAG_PAIRWISE_RX ||
+ (key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+ KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
+ if (nla_put_u8(key_msg, NL80211_KEY_MODE,
+ key_flag == KEY_FLAG_PAIRWISE_RX ?
+ NL80211_KEY_NO_TX : NL80211_KEY_SET_TX))
+ goto fail;
+ } else if ((key_flag & KEY_FLAG_GROUP_MASK) ==
+ KEY_FLAG_GROUP_RX) {
wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
if (nla_put_u32(key_msg, NL80211_KEY_TYPE,
NL80211_KEYTYPE_GROUP))
goto fail;
+ } else if (!(key_flag & KEY_FLAG_PAIRWISE)) {
+ wpa_printf(MSG_DEBUG,
+ " key_flag missing PAIRWISE when setting a pairwise key");
+ ret = -EINVAL;
+ goto fail;
+ } else if (alg == WPA_ALG_WEP &&
+ (key_flag & KEY_FLAG_RX_TX) == KEY_FLAG_RX_TX) {
+ wpa_printf(MSG_DEBUG, " unicast WEP key");
+ skip_set_key = 0;
+ } else {
+ wpa_printf(MSG_DEBUG, " pairwise key");
}
- } else if (addr && is_broadcast_ether_addr(addr)) {
- struct nlattr *types;
-
+ } else if ((key_flag & KEY_FLAG_PAIRWISE) ||
+ !(key_flag & KEY_FLAG_GROUP)) {
+ wpa_printf(MSG_DEBUG,
+ " invalid key_flag for a broadcast key");
+ ret = -EINVAL;
+ goto fail;
+ } else {
wpa_printf(MSG_DEBUG, " broadcast key");
-
- types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
- if (!types ||
- nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
- goto fail;
- nla_nest_end(key_msg, types);
+ if (key_flag & KEY_FLAG_DEFAULT)
+ skip_set_key = 0;
}
if (nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
@@ -3104,26 +3196,31 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
nlmsg_free(key_msg);
key_msg = NULL;
+ if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
+ wpa_printf(MSG_DEBUG, "nl80211: VLAN ID %d", vlan_id);
+ if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
+ goto fail;
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
ret = 0;
if (ret)
- wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)",
+ wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s",
ret, strerror(-ret));
/*
- * If we failed or don't need to set the default TX key (below),
+ * If we failed or don't need to set the key as default (below),
* we're done here.
*/
- if (ret || !set_tx || alg == WPA_ALG_NONE || tdls)
- return ret;
- if (is_ap_interface(drv->nlmode) && addr &&
- !is_broadcast_ether_addr(addr))
+ if (ret || skip_set_key)
return ret;
+ wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_SET_KEY - default key");
+ ret = -ENOBUFS;
key_msg = nlmsg_alloc();
if (!key_msg)
- return -ENOBUFS;
+ return ret;
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
if (!msg)
@@ -3134,8 +3231,10 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
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))
+ (key_idx == 6 || key_idx == 7 ?
+ NL80211_KEY_DEFAULT_BEACON :
+ NL80211_KEY_DEFAULT_MGMT) :
+ NL80211_KEY_DEFAULT))
goto fail;
if (addr && is_broadcast_ether_addr(addr)) {
struct nlattr *types;
@@ -3161,12 +3260,18 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
nlmsg_free(key_msg);
key_msg = NULL;
+ if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
+ wpa_printf(MSG_DEBUG, "nl80211: set_key default - VLAN ID %d",
+ vlan_id);
+ if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
+ goto fail;
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- if (ret == -ENOENT)
- ret = 0;
if (ret)
- wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; "
- "err=%d %s)", ret, strerror(-ret));
+ wpa_printf(MSG_DEBUG,
+ "nl80211: set_key default failed; err=%d %s",
+ ret, strerror(-ret));
return ret;
fail:
@@ -3175,7 +3280,7 @@ fail:
fail2:
nl80211_nlmsg_clear(key_msg);
nlmsg_free(key_msg);
- return -ENOBUFS;
+ return ret;
}
@@ -3271,7 +3376,7 @@ static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
const u8 *addr, int cmd, u16 reason_code,
int local_state_change,
- struct nl_handle *nl_connect)
+ struct nl_sock *nl_connect)
{
int ret;
struct nl_msg *msg;
@@ -3300,7 +3405,7 @@ int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
u16 reason_code,
- struct nl_handle *nl_connect)
+ struct nl_sock *nl_connect)
{
int ret;
int drv_associated = drv->associated;
@@ -3332,7 +3437,7 @@ static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
return nl80211_leave_ibss(drv, 1);
}
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
- struct nl_handle *nl_connect = NULL;
+ struct nl_sock *nl_connect = NULL;
if (bss->use_nl_connect)
nl_connect = bss->nl_connect;
@@ -3450,6 +3555,7 @@ static int wpa_driver_nl80211_authenticate(
enum nl80211_iftype nlmode;
int count = 0;
int is_retry;
+ struct wpa_driver_set_key_params p;
nl80211_unmask_11b_rates(bss);
@@ -3478,14 +3584,20 @@ retry:
if (!msg)
goto fail;
+ os_memset(&p, 0, sizeof(p));
+ p.ifname = bss->ifname;
+ p.alg = WPA_ALG_WEP;
for (i = 0; i < 4; i++) {
if (!params->wep_key[i])
continue;
- wpa_driver_nl80211_set_key(bss->ifname, bss, WPA_ALG_WEP,
- NULL, i,
- i == params->wep_tx_keyidx, NULL, 0,
- params->wep_key[i],
- params->wep_key_len[i]);
+ p.key_idx = i;
+ p.set_tx = i == params->wep_tx_keyidx;
+ p.key = params->wep_key[i];
+ p.key_len = params->wep_key_len[i];
+ p.key_flag = i == params->wep_tx_keyidx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX;
+ wpa_driver_nl80211_set_key(bss, &p);
if (params->wep_tx_keyidx != i)
continue;
if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
@@ -3647,80 +3759,27 @@ int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv)
}
-static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
- const void *data, size_t len,
- int encrypt, int noack,
- unsigned int freq, int no_cck,
- int offchanok, unsigned int wait_time,
- const u16 *csa_offs,
- size_t csa_offs_len)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- u64 cookie;
- int res;
-
- if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
- freq = nl80211_get_assoc_freq(drv);
- wpa_printf(MSG_DEBUG,
- "nl80211: send_frame - Use assoc_freq=%u for IBSS",
- freq);
- }
- if (freq == 0) {
- wpa_printf(MSG_DEBUG, "nl80211: send_frame - Use bss->freq=%u",
- bss->freq);
- freq = bss->freq;
- }
-
- if (drv->use_monitor) {
- wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
- freq, bss->freq);
- return nl80211_send_monitor(drv, data, len, encrypt, noack);
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
- res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
- &cookie, no_cck, noack, offchanok,
- csa_offs, csa_offs_len);
- if (res == 0 && !noack) {
- const struct ieee80211_mgmt *mgmt;
- u16 fc;
-
- mgmt = (const struct ieee80211_mgmt *) data;
- fc = le_to_host16(mgmt->frame_control);
- if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
- WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
- wpa_printf(MSG_MSGDUMP,
- "nl80211: Update send_action_cookie from 0x%llx to 0x%llx",
- (long long unsigned int)
- drv->send_action_cookie,
- (long long unsigned int) cookie);
- drv->send_action_cookie = cookie;
- }
- }
-
- return res;
-}
-
-
static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
size_t data_len, int noack,
unsigned int freq, int no_cck,
int offchanok,
unsigned int wait_time,
const u16 *csa_offs,
- size_t csa_offs_len)
+ size_t csa_offs_len, int no_encrypt)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt *mgmt;
- int encrypt = 1;
+ int encrypt = !no_encrypt;
u16 fc;
+ int use_cookie = 1;
+ int res;
mgmt = (struct ieee80211_mgmt *) data;
fc = le_to_host16(mgmt->frame_control);
- wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da= " MACSTR
- " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x (%s) nlmode=%d",
+ wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR
+ " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u no_encrypt=%d fc=0x%x (%s) nlmode=%d",
MAC2STR(mgmt->da), noack, freq, no_cck, offchanok, wait_time,
- fc, fc2str(fc), drv->nlmode);
+ no_encrypt, fc, fc2str(fc), drv->nlmode);
if ((is_sta_interface(drv->nlmode) ||
drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
@@ -3736,9 +3795,11 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
drv->last_mgmt_freq);
freq = drv->last_mgmt_freq;
}
- return nl80211_send_frame_cmd(bss, freq, 0,
- data, data_len, NULL, 1, noack,
- 1, csa_offs, csa_offs_len);
+ wait_time = 0;
+ use_cookie = 0;
+ no_cck = 1;
+ offchanok = 1;
+ goto send_frame_cmd;
}
if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
@@ -3747,13 +3808,9 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
bss->freq);
freq = bss->freq;
}
- return nl80211_send_frame_cmd(bss, freq,
- (int) freq == bss->freq ? 0 :
- wait_time,
- data, data_len,
- &drv->send_action_cookie,
- no_cck, noack, offchanok,
- csa_offs, csa_offs_len);
+ if ((int) freq == bss->freq)
+ wait_time = 0;
+ goto send_frame_cmd;
}
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
@@ -3770,11 +3827,60 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
encrypt = 0;
}
- wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame");
- return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
- noack, freq, no_cck, offchanok,
- wait_time, csa_offs,
- csa_offs_len);
+ if (freq == 0 && drv->nlmode == NL80211_IFTYPE_STATION &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
+ freq = nl80211_get_assoc_freq(drv);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_mlme - Use assoc_freq=%u for external auth",
+ freq);
+ }
+
+ if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
+ freq = nl80211_get_assoc_freq(drv);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_mlme - Use assoc_freq=%u for IBSS",
+ freq);
+ }
+ if (freq == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: send_mlme - Use bss->freq=%u",
+ bss->freq);
+ freq = bss->freq;
+ }
+
+ if (drv->use_monitor) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
+ freq, bss->freq);
+ return nl80211_send_monitor(drv, data, data_len, encrypt,
+ noack);
+ }
+
+ if (noack || WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
+ WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
+ use_cookie = 0;
+send_frame_cmd:
+#ifdef CONFIG_TESTING_OPTIONS
+ if (no_encrypt && !encrypt && !drv->use_monitor) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Request to send an unencrypted frame - use a monitor interface for this");
+ if (nl80211_create_monitor_interface(drv) < 0)
+ return -1;
+ res = nl80211_send_monitor(drv, data, data_len, encrypt,
+ noack);
+ nl80211_remove_monitor_interface(drv);
+ return res;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame_cmd");
+ res = nl80211_send_frame_cmd(bss, freq, wait_time, data, data_len,
+ use_cookie, no_cck, noack, offchanok,
+ csa_offs, csa_offs_len);
+
+ return res;
}
@@ -4076,8 +4182,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
int ret = -ENOBUFS;
int beacon_set;
int num_suites;
- int smps_mode;
- u32 suites[10], suite;
+ u32 suites[20], suite;
u32 ver;
#ifdef CONFIG_MESH
struct wpa_driver_mesh_bss_params mesh_params;
@@ -4171,14 +4276,15 @@ static int wpa_driver_nl80211_set_ap(void *priv,
wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
params->key_mgmt_suites);
- num_suites = 0;
- if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
- suites[num_suites++] = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
- if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
- suites[num_suites++] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
- if (num_suites &&
- nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
- suites))
+ num_suites = wpa_key_mgmt_to_suites(params->key_mgmt_suites,
+ suites, ARRAY_SIZE(suites));
+ if (num_suites > NL80211_MAX_NR_AKM_SUITES)
+ wpa_printf(MSG_WARNING,
+ "nl80211: Not enough room for all AKM suites (num_suites=%d > NL80211_MAX_NR_AKM_SUITES)",
+ num_suites);
+ else if (num_suites &&
+ nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
+ suites))
goto fail;
if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
@@ -4209,27 +4315,6 @@ static int wpa_driver_nl80211_set_ap(void *priv,
nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
goto fail;
- if (params->ht_opmode != -1) {
- switch (params->smps_mode) {
- case HT_CAP_INFO_SMPS_DYNAMIC:
- wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - dynamic");
- smps_mode = NL80211_SMPS_DYNAMIC;
- break;
- case HT_CAP_INFO_SMPS_STATIC:
- wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - static");
- smps_mode = NL80211_SMPS_STATIC;
- break;
- default:
- /* invalid - fallback to smps off */
- case HT_CAP_INFO_SMPS_DISABLED:
- wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - off");
- smps_mode = NL80211_SMPS_OFF;
- break;
- }
- if (nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
- goto fail;
- }
-
if (params->beacon_ies) {
wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
params->beacon_ies);
@@ -4314,7 +4399,8 @@ static int wpa_driver_nl80211_set_ap(void *priv,
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,
+ if (!spr ||
+ 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))
@@ -4322,6 +4408,28 @@ static int wpa_driver_nl80211_set_ap(void *priv,
nla_nest_end(msg, spr);
}
+
+ if (params->freq && params->freq->he_enabled) {
+ struct nlattr *bss_color;
+
+ bss_color = nla_nest_start(msg, NL80211_ATTR_HE_BSS_COLOR);
+ if (!bss_color ||
+ (params->he_bss_color_disabled &&
+ nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_DISABLED)) ||
+ (params->he_bss_color_partial &&
+ nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_PARTIAL)) ||
+ nla_put_u8(msg, NL80211_HE_BSS_COLOR_ATTR_COLOR,
+ params->he_bss_color))
+ goto fail;
+ nla_nest_end(msg, bss_color);
+ }
+
+ if (params->twt_responder) {
+ wpa_printf(MSG_DEBUG, "nl80211: twt_responder=%d",
+ params->twt_responder);
+ if (nla_put_flag(msg, NL80211_ATTR_TWT_RESPONDER))
+ goto fail;
+ }
#endif /* CONFIG_IEEE80211AX */
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -5101,6 +5209,40 @@ static void nl80211_teardown_ap(struct i802_bss *bss)
}
+static int nl80211_tx_control_port(void *priv, const u8 *dest,
+ u16 proto, const u8 *buf, size_t len,
+ int no_encrypt)
+{
+ struct i802_bss *bss = priv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Send over control port dest=" MACSTR
+ " proto=0x%04x len=%u no_encrypt=%d",
+ MAC2STR(dest), proto, (unsigned int) len, no_encrypt);
+
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CONTROL_PORT_FRAME);
+ if (!msg ||
+ nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dest) ||
+ nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
+ (no_encrypt &&
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG,
+ "nl80211: tx_control_port failed: ret=%d (%s)",
+ ret, strerror(-ret));
+
+ return ret;
+}
+
+
static int nl80211_send_eapol_data(struct i802_bss *bss,
const u8 *addr, const u8 *data,
size_t data_len)
@@ -5143,6 +5285,10 @@ static int wpa_driver_nl80211_hapd_send_eapol(
int res;
int qos = flags & WPA_STA_WMM;
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT)
+ return nl80211_tx_control_port(bss, addr, ETH_P_EAPOL,
+ data, data_len, !encrypt);
+
if (drv->device_ap_sme || !drv->use_monitor)
return nl80211_send_eapol_data(bss, addr, data, data_len);
@@ -5183,12 +5329,11 @@ static int wpa_driver_nl80211_hapd_send_eapol(
pos += 2;
memcpy(pos, data, data_len);
- res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0,
- 0, 0, 0, 0, NULL, 0);
+ res = nl80211_send_monitor(drv, hdr, len, encrypt, 0);
if (res < 0) {
- wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
- "failed: %d (%s)",
- (unsigned long) len, errno, strerror(errno));
+ wpa_printf(MSG_ERROR,
+ "hapd_send_eapol - packet len: %lu - failed",
+ (unsigned long) len);
}
os_free(hdr);
@@ -5775,7 +5920,7 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
static int wpa_driver_nl80211_try_connect(
struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params,
- struct nl_handle *nl_connect)
+ struct nl_sock *nl_connect)
{
struct nl_msg *msg;
enum nl80211_auth_type type;
@@ -5866,7 +6011,7 @@ fail:
static int wpa_driver_nl80211_connect(
struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params,
- struct nl_handle *nl_connect)
+ struct nl_sock *nl_connect)
{
int ret;
@@ -5914,7 +6059,7 @@ static int wpa_driver_nl80211_associate(
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
enum nl80211_iftype nlmode = params->p2p ?
NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
- struct nl_handle *nl_connect = NULL;
+ struct nl_sock *nl_connect = NULL;
if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
return -1;
@@ -6646,6 +6791,8 @@ static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ ((drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) &&
+ nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) ||
nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
nlmsg_free(msg);
return -ENOBUFS;
@@ -6718,7 +6865,7 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth), 0, 0, 0, 0,
- 0, NULL, 0);
+ 0, NULL, 0, 0);
}
@@ -6745,7 +6892,7 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
- 0, NULL, 0);
+ 0, NULL, 0, 0);
}
@@ -7078,15 +7225,18 @@ static void *i802_init(struct hostapd_data *hapd,
#ifdef CONFIG_LIBNL3_ROUTE
if (bss->added_if_into_bridge || bss->already_in_bridge) {
+ int err;
+
drv->rtnl_sk = nl_socket_alloc();
if (drv->rtnl_sk == NULL) {
wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
goto failed;
}
- if (nl_connect(drv->rtnl_sk, NETLINK_ROUTE)) {
+ err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE);
+ if (err) {
wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
- strerror(errno));
+ nl_geterror(err));
goto failed;
}
}
@@ -7460,7 +7610,7 @@ static int cookie_handler(struct nl_msg *msg, void *arg)
static int nl80211_send_frame_cmd(struct i802_bss *bss,
unsigned int freq, unsigned int wait,
const u8 *buf, size_t buf_len,
- u64 *cookie_out, int no_cck, int no_ack,
+ int save_cookie, int no_cck, int no_ack,
int offchanok, const u16 *csa_offs,
size_t csa_offs_len)
{
@@ -7499,22 +7649,22 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
"cookie 0x%llx", no_ack ? " (no ACK)" : "",
(long long unsigned int) cookie);
- if (cookie_out)
- *cookie_out = no_ack ? (u64) -1 : cookie;
+ if (save_cookie)
+ drv->send_frame_cookie = no_ack ? (u64) -1 : cookie;
- if (drv->num_send_action_cookies == MAX_SEND_ACTION_COOKIES) {
+ if (drv->num_send_frame_cookies == MAX_SEND_FRAME_COOKIES) {
wpa_printf(MSG_DEBUG,
- "nl80211: Drop oldest pending send action cookie 0x%llx",
+ "nl80211: Drop oldest pending send frame cookie 0x%llx",
(long long unsigned int)
- drv->send_action_cookies[0]);
- os_memmove(&drv->send_action_cookies[0],
- &drv->send_action_cookies[1],
- (MAX_SEND_ACTION_COOKIES - 1) *
+ drv->send_frame_cookies[0]);
+ os_memmove(&drv->send_frame_cookies[0],
+ &drv->send_frame_cookies[1],
+ (MAX_SEND_FRAME_COOKIES - 1) *
sizeof(u64));
- drv->num_send_action_cookies--;
+ drv->num_send_frame_cookies--;
}
- drv->send_action_cookies[drv->num_send_action_cookies] = cookie;
- drv->num_send_action_cookies++;
+ drv->send_frame_cookies[drv->num_send_frame_cookies] = cookie;
+ drv->num_send_frame_cookies++;
}
fail:
@@ -7535,10 +7685,14 @@ static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
int ret = -1;
u8 *buf;
struct ieee80211_hdr *hdr;
+ int offchanok = 1;
+
+ if (is_ap_interface(drv->nlmode) && (int) freq == bss->freq)
+ offchanok = 0;
wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
- "freq=%u MHz wait=%d ms no_cck=%d)",
- drv->ifindex, freq, wait_time, no_cck);
+ "freq=%u MHz wait=%d ms no_cck=%d offchanok=%d)",
+ drv->ifindex, freq, wait_time, no_cck, offchanok);
buf = os_zalloc(24 + data_len);
if (buf == NULL)
@@ -7564,13 +7718,12 @@ static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
(int) freq == bss->freq || drv->device_ap_sme ||
!drv->use_monitor))
ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
- 0, freq, no_cck, 1,
- wait_time, NULL, 0);
+ 0, freq, no_cck, offchanok,
+ wait_time, NULL, 0, 0);
else
ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
24 + data_len,
- &drv->send_action_cookie,
- no_cck, 0, 1, NULL, 0);
+ 1, no_cck, 0, offchanok, NULL, 0);
os_free(buf);
return ret;
@@ -7606,19 +7759,19 @@ static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
u64 cookie;
/* Cancel the last pending TX cookie */
- nl80211_frame_wait_cancel(bss, drv->send_action_cookie);
+ nl80211_frame_wait_cancel(bss, drv->send_frame_cookie);
/*
* Cancel the other pending TX cookies, if any. This is needed since
* the driver may keep a list of all pending offchannel TX operations
* and free up the radio only once they have expired or cancelled.
*/
- for (i = drv->num_send_action_cookies; i > 0; i--) {
- cookie = drv->send_action_cookies[i - 1];
- if (cookie != drv->send_action_cookie)
+ for (i = drv->num_send_frame_cookies; i > 0; i--) {
+ cookie = drv->send_frame_cookies[i - 1];
+ if (cookie != drv->send_frame_cookie)
nl80211_frame_wait_cancel(bss, cookie);
}
- drv->num_send_action_cookies = 0;
+ drv->num_send_frame_cookies = 0;
}
@@ -7938,15 +8091,6 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
}
-static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
- int encrypt)
-{
- struct i802_bss *bss = priv;
- return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0,
- 0, 0, 0, 0, NULL, 0);
-}
-
-
static int nl80211_set_param(void *priv, const char *param)
{
struct i802_bss *bss = priv;
@@ -7981,6 +8125,12 @@ static int nl80211_set_param(void *priv, const char *param)
drv->test_use_roc_tx = 1;
}
+ if (os_strstr(param, "control_port=0"))
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
+
+ if (os_strstr(param, "full_ap_client_state=0"))
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
+
return 0;
}
@@ -8081,6 +8231,12 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd,
(params->fils_cache_id &&
nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2,
params->fils_cache_id)) ||
+ (params->pmk_lifetime &&
+ nla_put_u32(msg, NL80211_ATTR_PMK_LIFETIME,
+ params->pmk_lifetime)) ||
+ (params->pmk_reauth_threshold &&
+ nla_put_u8(msg, NL80211_ATTR_PMK_REAUTH_THRESHOLD,
+ params->pmk_reauth_threshold)) ||
(cmd != NL80211_CMD_DEL_PMKSA &&
params->pmk_len && params->pmk_len <= PMK_MAX_LEN &&
nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
@@ -8401,7 +8557,7 @@ static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
- 0, 0, NULL, 0) < 0)
+ 0, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
"send poll frame");
}
@@ -8675,15 +8831,12 @@ nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
#endif /* CONFIG TDLS */
-static int driver_nl80211_set_key(const char *ifname, void *priv,
- 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)
+static int driver_nl80211_set_key(void *priv,
+ struct wpa_driver_set_key_params *params)
{
struct i802_bss *bss = priv;
- return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx,
- set_tx, seq, seq_len, key, key_len);
+
+ return wpa_driver_nl80211_set_key(bss, params);
}
@@ -8742,12 +8895,13 @@ static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
static int driver_nl80211_send_mlme(void *priv, const u8 *data,
size_t data_len, int noack,
unsigned int freq,
- const u16 *csa_offs, size_t csa_offs_len)
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt, unsigned int wait)
{
struct i802_bss *bss = priv;
return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
- freq, 0, 0, 0, csa_offs,
- csa_offs_len);
+ freq, 0, 0, wait, csa_offs,
+ csa_offs_len, no_encrypt);
}
@@ -9398,6 +9552,46 @@ static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
}
+static int get_wowlan_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ int *wowlan_enabled = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ *wowlan_enabled = !!tb[NL80211_ATTR_WOWLAN_TRIGGERS];
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_wowlan(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int wowlan_enabled;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status");
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_WOWLAN);
+
+ ret = send_and_recv_msgs(drv, msg, get_wowlan_handler, &wowlan_enabled);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status failed");
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: wowlan is %s",
+ wowlan_enabled ? "enabled" : "disabled");
+
+ return wowlan_enabled;
+}
+
+
static int nl80211_set_wowlan(void *priv,
const struct wowlan_triggers *triggers)
{
@@ -9941,7 +10135,7 @@ static int wpa_driver_br_add_ip_neigh(void *priv, u8 version,
if (res) {
wpa_printf(MSG_DEBUG,
"nl80211: Adding bridge ip neigh failed: %s",
- strerror(errno));
+ nl_geterror(res));
}
errout:
if (nl_lladdr)
@@ -10017,7 +10211,7 @@ static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version,
if (res) {
wpa_printf(MSG_DEBUG,
"nl80211: Deleting bridge ip neigh failed: %s",
- strerror(errno));
+ nl_geterror(res));
}
errout:
if (nl_ipaddr)
@@ -10251,22 +10445,24 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
params->ch_width) ||
add_acs_ch_list(msg, params->freq_list) ||
- add_acs_freq_list(msg, params->freq_list)) {
+ add_acs_freq_list(msg, params->freq_list) ||
+ (params->edmg_enabled &&
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED))) {
nlmsg_free(msg);
return -ENOBUFS;
}
nla_nest_end(msg, data);
wpa_printf(MSG_DEBUG,
- "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d",
+ "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d EDMG: %d",
params->hw_mode, params->ht_enabled, params->ht40_enabled,
- params->vht_enabled, params->ch_width);
+ params->vht_enabled, params->ch_width, params->edmg_enabled);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Failed to invoke driver ACS function: %s",
- strerror(errno));
+ strerror(-ret));
}
return ret;
}
@@ -10313,7 +10509,7 @@ static int nl80211_set_band(void *priv, enum set_band band)
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Driver setband function failed: %s",
- strerror(errno));
+ strerror(-ret));
}
return ret;
}
@@ -11204,6 +11400,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.get_hw_feature_data = nl80211_get_hw_feature_data,
.sta_add = wpa_driver_nl80211_sta_add,
.sta_remove = driver_nl80211_sta_remove,
+ .tx_control_port = nl80211_tx_control_port,
.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
.sta_set_airtime_weight = driver_nl80211_sta_set_airtime_weight,
@@ -11234,7 +11431,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.signal_monitor = nl80211_signal_monitor,
.signal_poll = nl80211_signal_poll,
.channel_info = nl80211_channel_info,
- .send_frame = nl80211_send_frame,
.set_param = nl80211_set_param,
.get_radio_name = nl80211_get_radio_name,
.add_pmkid = nl80211_add_pmkid,
@@ -11269,6 +11465,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
#endif /* ANDROID */
.vendor_cmd = nl80211_vendor_cmd,
.set_qos_map = nl80211_set_qos_map,
+ .get_wowlan = nl80211_get_wowlan,
.set_wowlan = nl80211_set_wowlan,
.set_mac_addr = nl80211_set_mac_addr,
#ifdef CONFIG_MESH
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 716504c1..6e6c8724 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -17,12 +17,10 @@
#include "utils/list.h"
#include "driver.h"
-#ifdef CONFIG_LIBNL20
-/* libnl 2.0 compatibility code */
-#define nl_handle nl_sock
-#define nl80211_handle_alloc nl_socket_alloc_cb
-#define nl80211_handle_destroy nl_socket_free
-#endif /* CONFIG_LIBNL20 */
+#ifndef NL_CAPABILITY_VERSION_3_5_0
+#define nla_nest_start(msg, attrtype) \
+ nla_nest_start(msg, NLA_F_NESTED | (attrtype))
+#endif
struct nl80211_global {
void *ctx;
@@ -32,11 +30,11 @@ struct nl80211_global {
int if_add_wdevid_set;
struct netlink_data *netlink;
struct nl_cb *nl_cb;
- struct nl_handle *nl;
+ struct nl_sock *nl;
int nl80211_id;
int ioctl_sock; /* socket for ioctl() use */
- struct nl_handle *nl_event;
+ struct nl_sock *nl_event;
};
struct nl80211_wiphy_data {
@@ -44,7 +42,7 @@ struct nl80211_wiphy_data {
struct dl_list bsss;
struct dl_list drvs;
- struct nl_handle *nl_beacons;
+ struct nl_sock *nl_beacons;
struct nl_cb *nl_cb;
int wiphy_idx;
@@ -75,7 +73,7 @@ struct i802_bss {
int if_dynamic;
void *ctx;
- struct nl_handle *nl_preq, *nl_mgmt, *nl_connect;
+ struct nl_sock *nl_preq, *nl_mgmt, *nl_connect;
struct nl_cb *nl_cb;
struct nl80211_wiphy_data *wiphy_data;
@@ -176,10 +174,10 @@ struct wpa_driver_nl80211_data {
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
- u64 send_action_cookie;
-#define MAX_SEND_ACTION_COOKIES 20
- u64 send_action_cookies[MAX_SEND_ACTION_COOKIES];
- unsigned int num_send_action_cookies;
+ u64 send_frame_cookie;
+#define MAX_SEND_FRAME_COOKIES 20
+ u64 send_frame_cookies[MAX_SEND_FRAME_COOKIES];
+ unsigned int num_send_frame_cookies;
unsigned int last_mgmt_freq;
@@ -192,7 +190,7 @@ struct wpa_driver_nl80211_data {
int eapol_sock; /* socket for EAPOL frames */
- struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
+ struct nl_sock *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
struct drv_nl80211_if_info default_if_indices[16];
struct drv_nl80211_if_info *if_indices;
@@ -256,7 +254,7 @@ int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
const u8 *addr, int cmd, u16 reason_code,
int local_state_change,
- struct nl_handle *nl_connect);
+ struct nl_sock *nl_connect);
int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv);
void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv);
@@ -275,7 +273,7 @@ int process_bss_event(struct nl_msg *msg, void *arg);
const char * nl80211_iftype_str(enum nl80211_iftype mode);
#ifdef ANDROID
-int android_nl_socket_set_nonblocking(struct nl_handle *handle);
+int android_nl_socket_set_nonblocking(struct nl_sock *handle);
int android_pno_start(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
int android_pno_stop(struct i802_bss *bss);
diff --git a/src/drivers/driver_nl80211_android.c b/src/drivers/driver_nl80211_android.c
index ba478888..9431a12d 100644
--- a/src/drivers/driver_nl80211_android.c
+++ b/src/drivers/driver_nl80211_android.c
@@ -182,9 +182,7 @@ int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
#endif /* ANDROID_P2P */
-int android_nl_socket_set_nonblocking(struct nl_handle *handle)
+int android_nl_socket_set_nonblocking(struct nl_sock *handle)
{
return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
}
-
-
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 9a82cd1e..b4fed9ea 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -78,6 +78,7 @@ struct wiphy_info_data {
unsigned int wmm_ac_supported:1;
unsigned int mac_addr_rand_scan_supported:1;
unsigned int mac_addr_rand_sched_scan_supported:1;
+ unsigned int update_ft_ies_supported:1;
};
@@ -243,6 +244,9 @@ static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
case NL80211_CMD_SET_QOS_MAP:
info->set_qos_map_supported = 1;
break;
+ case NL80211_CMD_UPDATE_FT_IES:
+ info->update_ft_ies_supported = 1;
+ break;
}
}
}
@@ -433,6 +437,26 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER))
capa->flags |= WPA_DRIVER_FLAGS_FTM_RESPONDER;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
+ capa->flags |= WPA_DRIVER_FLAGS_CONTROL_PORT;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_VLAN_OFFLOAD))
+ capa->flags |= WPA_DRIVER_FLAGS_VLAN_OFFLOAD;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_CAN_REPLACE_PTK0))
+ capa->flags |= WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION))
+ capa->flags |= WPA_DRIVER_FLAGS_BEACON_PROTECTION;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_EXT_KEY_ID))
+ capa->flags |= WPA_DRIVER_FLAGS_EXTENDED_KEY_ID;
}
@@ -479,12 +503,6 @@ static void wiphy_info_feature_flags(struct wiphy_info_data *info,
if (flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR)
info->mac_addr_rand_sched_scan_supported = 1;
- if (flags & NL80211_FEATURE_STATIC_SMPS)
- capa->smps_modes |= WPA_DRIVER_SMPS_MODE_STATIC;
-
- if (flags & NL80211_FEATURE_DYNAMIC_SMPS)
- capa->smps_modes |= WPA_DRIVER_SMPS_MODE_DYNAMIC;
-
if (flags & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
info->wmm_ac_supported = 1;
@@ -904,6 +922,9 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
drv->capa.max_sched_scan_plan_iterations = 0;
}
+ if (info->update_ft_ies_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_UPDATE_FT_IES;
+
return 0;
}
@@ -1294,6 +1315,12 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
#endif /* CONFIG_DRIVER_NL80211_QCA */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: key_mgmt=0x%x enc=0x%x auth=0x%x flags=0x%llx rrm_flags=0x%x probe_resp_offloads=0x%x max_stations=%u max_remain_on_chan=%u max_scan_ssids=%d",
+ drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth,
+ (unsigned long long) drv->capa.flags, drv->capa.rrm_flags,
+ drv->capa.probe_resp_offloads, drv->capa.max_stations,
+ drv->capa.max_remain_on_chan, drv->capa.max_scan_ssids);
return 0;
}
@@ -1360,6 +1387,20 @@ static int phy_info_edmg_capa(struct hostapd_hw_modes *mode,
}
+static int cw2ecw(unsigned int cw)
+{
+ int bit;
+
+ if (cw == 0)
+ return 0;
+
+ for (bit = 1; cw != 1; bit++)
+ cw >>= 1;
+
+ return bit;
+}
+
+
static void phy_info_freq(struct hostapd_hw_modes *mode,
struct hostapd_channel_data *chan,
struct nlattr *tb_freq[])
@@ -1432,6 +1473,12 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
[NL80211_WMMR_AIFSN] = { .type = NLA_U8 },
[NL80211_WMMR_TXOP] = { .type = NLA_U16 },
};
+ static const u8 wmm_map[4] = {
+ [NL80211_AC_BE] = WMM_AC_BE,
+ [NL80211_AC_BK] = WMM_AC_BK,
+ [NL80211_AC_VI] = WMM_AC_VI,
+ [NL80211_AC_VO] = WMM_AC_VO,
+ };
struct nlattr *nl_wmm;
struct nlattr *tb_wmm[NL80211_WMMR_MAX + 1];
int rem_wmm, ac, count = 0;
@@ -1453,16 +1500,19 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
return;
}
ac = nl_wmm->nla_type;
- if (ac < 0 || ac >= WMM_AC_NUM) {
+ if ((unsigned int) ac >= ARRAY_SIZE(wmm_map)) {
wpa_printf(MSG_DEBUG,
"nl80211: Invalid AC value %d", ac);
return;
}
+ ac = wmm_map[ac];
chan->wmm_rules[ac].min_cwmin =
- nla_get_u16(tb_wmm[NL80211_WMMR_CW_MIN]);
+ cw2ecw(nla_get_u16(
+ tb_wmm[NL80211_WMMR_CW_MIN]));
chan->wmm_rules[ac].min_cwmax =
- nla_get_u16(tb_wmm[NL80211_WMMR_CW_MAX]);
+ cw2ecw(nla_get_u16(
+ tb_wmm[NL80211_WMMR_CW_MAX]));
chan->wmm_rules[ac].min_aifs =
nla_get_u8(tb_wmm[NL80211_WMMR_AIFSN]);
chan->wmm_rules[ac].max_txop =
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 2aecc749..d4ca2eb2 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -683,29 +683,42 @@ static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
size_t len, struct nlattr *ack)
{
union wpa_event_data event;
- const struct ieee80211_hdr *hdr;
- u16 fc;
+ const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame;
+ u16 fc = le_to_host16(hdr->frame_control);
+ u64 cookie_val = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
- if (!is_ap_interface(drv->nlmode)) {
- u64 cookie_val;
+ if (cookie)
+ cookie_val = nla_get_u64(cookie);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Frame TX status event A1=" MACSTR
+ " %sstype=%d cookie=0x%llx%s ack=%d",
+ MAC2STR(hdr->addr1),
+ WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ? "not-mgmt " : "",
+ WLAN_FC_GET_STYPE(fc), (long long unsigned int) cookie_val,
+ cookie ? "" : "(N/A)", ack != NULL);
+
+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
+ return;
+ if (!is_ap_interface(drv->nlmode) &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
if (!cookie)
return;
- cookie_val = nla_get_u64(cookie);
- wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
- " cookie=0x%llx%s (ack=%d)",
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Frame TX status: cookie=0x%llx%s (ack=%d)",
(long long unsigned int) cookie_val,
- cookie_val == drv->send_action_cookie ?
+ cookie_val == drv->send_frame_cookie ?
" (match)" : " (unknown)", ack != NULL);
- if (cookie_val != drv->send_action_cookie)
+ if (cookie_val != drv->send_frame_cookie)
return;
+ } else if (!is_ap_interface(drv->nlmode) &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Authentication frame TX status: ack=%d",
+ !!ack);
}
- hdr = (const struct ieee80211_hdr *) frame;
- fc = le_to_host16(hdr->frame_control);
-
os_memset(&event, 0, sizeof(event));
event.tx_status.type = WLAN_FC_GET_TYPE(fc);
event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
@@ -1740,8 +1753,41 @@ static enum hostapd_hw_mode get_qca_hw_mode(u8 hw_mode)
}
-static unsigned int chan_2ghz_or_5ghz_to_freq(u8 chan)
+static unsigned int chan_to_freq(struct wpa_driver_nl80211_data *drv,
+ u8 chan, enum hostapd_hw_mode hw_mode)
{
+ if (hw_mode == NUM_HOSTAPD_MODES) {
+ /* For drivers that do not report ACS_HW_MODE */
+ u16 num_modes, flags;
+ struct hostapd_hw_modes *modes;
+ u8 dfs_domain;
+ int i;
+
+ modes = nl80211_get_hw_feature_data(drv->first_bss, &num_modes,
+ &flags, &dfs_domain);
+ if (!modes) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Fetching hardware mode failed");
+ goto try_2_4_or_5;
+ }
+ if (num_modes == 1)
+ hw_mode = modes[0].mode;
+
+ for (i = 0; i < num_modes; i++) {
+ os_free(modes[i].channels);
+ os_free(modes[i].rates);
+ }
+
+ os_free(modes);
+ }
+
+ if (hw_mode == HOSTAPD_MODE_IEEE80211AD) {
+ if (chan >= 1 && chan <= 6)
+ return 56160 + (2160 * chan);
+ return 0;
+ }
+
+try_2_4_or_5:
if (chan >= 1 && chan <= 13)
return 2407 + 5 * chan;
if (chan == 14)
@@ -1772,13 +1818,30 @@ static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
return;
os_memset(&event, 0, sizeof(event));
+ event.acs_selected_channels.hw_mode = NUM_HOSTAPD_MODES;
+
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) {
+ u8 hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]);
+
+ event.acs_selected_channels.hw_mode = get_qca_hw_mode(hw_mode);
+ if (event.acs_selected_channels.hw_mode == NUM_HOSTAPD_MODES ||
+ event.acs_selected_channels.hw_mode ==
+ HOSTAPD_MODE_IEEE80211ANY) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Invalid hw_mode %d in ACS selection event",
+ hw_mode);
+ return;
+ }
+ }
+
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY]) {
event.acs_selected_channels.pri_freq = nla_get_u32(
tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY]);
} else {
chan = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
event.acs_selected_channels.pri_freq =
- chan_2ghz_or_5ghz_to_freq(chan);
+ chan_to_freq(drv, chan,
+ event.acs_selected_channels.hw_mode);
}
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY]) {
@@ -1788,40 +1851,31 @@ static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
chan = nla_get_u8(
tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
event.acs_selected_channels.sec_freq =
- chan_2ghz_or_5ghz_to_freq(chan);
+ chan_to_freq(drv, chan,
+ event.acs_selected_channels.hw_mode);
}
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL])
+ event.acs_selected_channels.edmg_channel =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL]);
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
event.acs_selected_channels.vht_seg0_center_ch =
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
- if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL])
event.acs_selected_channels.vht_seg1_center_ch =
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH])
event.acs_selected_channels.ch_width =
nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
- if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) {
- u8 hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]);
-
- event.acs_selected_channels.hw_mode = get_qca_hw_mode(hw_mode);
- if (event.acs_selected_channels.hw_mode == NUM_HOSTAPD_MODES ||
- event.acs_selected_channels.hw_mode ==
- HOSTAPD_MODE_IEEE80211ANY) {
- wpa_printf(MSG_DEBUG,
- "nl80211: Invalid hw_mode %d in ACS selection event",
- hw_mode);
- return;
- }
- }
-
wpa_printf(MSG_INFO,
- "nl80211: ACS Results: PFreq: %d SFreq: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d",
+ "nl80211: ACS Results: PFreq: %d SFreq: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d EDMGCH: %d",
event.acs_selected_channels.pri_freq,
event.acs_selected_channels.sec_freq,
event.acs_selected_channels.ch_width,
event.acs_selected_channels.vht_seg0_center_ch,
event.acs_selected_channels.vht_seg1_center_ch,
- event.acs_selected_channels.hw_mode);
+ event.acs_selected_channels.hw_mode,
+ event.acs_selected_channels.edmg_channel);
/* Ignore ACS channel list check for backwards compatibility */
@@ -2448,6 +2502,18 @@ static void nl80211_sta_opmode_change_event(struct wpa_driver_nl80211_data *drv,
}
+static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_FRAME])
+ return;
+
+ drv_event_eapol_rx(drv->ctx, nla_data(tb[NL80211_ATTR_MAC]),
+ nla_data(tb[NL80211_ATTR_FRAME]),
+ nla_len(tb[NL80211_ATTR_FRAME]));
+}
+
+
static void do_process_drv_event(struct i802_bss *bss, int cmd,
struct nlattr **tb)
{
@@ -2663,6 +2729,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
case NL80211_CMD_UPDATE_OWE_INFO:
mlme_event_dh_event(drv, bss, tb);
break;
+ case NL80211_CMD_CONTROL_PORT_FRAME:
+ nl80211_control_port_frame(drv, tb);
+ break;
default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
diff --git a/src/drivers/driver_nl80211_monitor.c b/src/drivers/driver_nl80211_monitor.c
index f25cd792..7ff55f14 100644
--- a/src/drivers/driver_nl80211_monitor.c
+++ b/src/drivers/driver_nl80211_monitor.c
@@ -71,6 +71,9 @@ static void handle_frame(struct wpa_driver_nl80211_data *drv,
u16 fc;
union wpa_event_data event;
+ if (!drv->use_monitor)
+ return;
+
hdr = (struct ieee80211_hdr *) buf;
fc = le_to_host16(hdr->frame_control);
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 9afa5b30..04f6bb87 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -236,6 +236,11 @@ nl80211_scan_common(struct i802_bss *bss, u8 cmd,
params->filter_ssids = NULL;
drv->num_filter_ssids = params->num_filter_ssids;
+ if (!drv->hostapd && is_ap_interface(drv->nlmode)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_AP");
+ scan_flags |= NL80211_SCAN_FLAG_AP;
+ }
+
if (params->only_new_results) {
wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
scan_flags |= NL80211_SCAN_FLAG_FLUSH;
@@ -928,7 +933,9 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
struct wpa_scan_results *res;
int ret;
struct nl80211_bss_info_arg arg;
+ int count = 0;
+try_again:
res = os_zalloc(sizeof(*res));
if (res == NULL)
return NULL;
@@ -941,6 +948,18 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
arg.drv = drv;
arg.res = res;
ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+ if (ret == -EAGAIN) {
+ count++;
+ if (count >= 10) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to receive consistent scan result dump");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to receive consistent scan result dump - try again");
+ wpa_scan_results_free(res);
+ goto try_again;
+ }
+ }
if (ret == 0) {
struct nl80211_noise_info info;
diff --git a/src/drivers/driver_none.c b/src/drivers/driver_none.c
index 6ff3eae6..ccd2d9da 100644
--- a/src/drivers/driver_none.c
+++ b/src/drivers/driver_none.c
@@ -43,13 +43,6 @@ static void none_driver_hapd_deinit(void *priv)
}
-static int none_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
- u16 proto, const u8 *data, size_t data_len)
-{
- return 0;
-}
-
-
static void * none_driver_init(void *ctx, const char *ifname)
{
struct none_driver_data *drv;
@@ -79,7 +72,6 @@ const struct wpa_driver_ops wpa_driver_none_ops = {
.desc = "no driver (RADIUS server/WPS ER)",
.hapd_init = none_driver_hapd_init,
.hapd_deinit = none_driver_hapd_deinit,
- .send_ether = none_driver_send_ether,
.init = none_driver_init,
.deinit = none_driver_deinit,
};
diff --git a/src/drivers/driver_openbsd.c b/src/drivers/driver_openbsd.c
index c06e75c0..bfc23117 100644
--- a/src/drivers/driver_openbsd.c
+++ b/src/drivers/driver_openbsd.c
@@ -69,14 +69,16 @@ wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa)
static int
-wpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
- const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
- size_t seq_len, const u8 *key, size_t key_len)
+wpa_driver_openbsd_set_key(void *priv, struct wpa_driver_set_key_params *params)
{
struct openbsd_driver_data *drv = priv;
struct ieee80211_keyavail keyavail;
+ enum key_flag key_flag = params->key_flag;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
- if (alg != WPA_ALG_PMK || key_len > IEEE80211_PMK_LEN)
+ if (key_len > IEEE80211_PMK_LEN ||
+ (key_flag & KEY_FLAG_PMK_MASK) != KEY_FLAG_PMK) {
return -1;
memset(&keyavail, 0, sizeof(keyavail));
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index 55cf6188..d6735b49 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -205,14 +205,19 @@ wpa_driver_privsep_get_scan_results2(void *priv)
}
-static int wpa_driver_privsep_set_key(const char *ifname, void *priv,
- 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)
+static int wpa_driver_privsep_set_key(void *priv,
+ struct wpa_driver_set_key_params *params)
{
struct wpa_driver_privsep_data *drv = priv;
struct privsep_cmd_set_key cmd;
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *seq = params->seq;
+ size_t seq_len = params->seq_len;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
__func__, priv, alg, key_idx, set_tx);
@@ -225,6 +230,7 @@ static int wpa_driver_privsep_set_key(const char *ifname, void *priv,
os_memset(cmd.addr, 0xff, ETH_ALEN);
cmd.key_idx = key_idx;
cmd.set_tx = set_tx;
+ cmd.key_flag = params->key_flag;
if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) {
os_memcpy(cmd.seq, seq, seq_len);
cmd.seq_len = seq_len;
@@ -791,6 +797,8 @@ static int wpa_driver_privsep_get_capa(void *priv,
capa->extended_capa = NULL;
capa->extended_capa_mask = NULL;
capa->extended_capa_len = 0;
+ /* Control port is not yet supported */
+ capa->flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
return 0;
}
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 32c29713..978e1cf4 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1712,7 +1712,8 @@ static int wpa_driver_wext_set_key_ext(void *priv, 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)
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
struct wpa_driver_wext_data *drv = priv;
struct iwreq iwr;
@@ -1751,30 +1752,31 @@ static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg,
os_memcpy(ext + 1, key, key_len);
ext->key_len = key_len;
}
- switch (alg) {
- case WPA_ALG_NONE:
- ext->alg = IW_ENCODE_ALG_NONE;
- break;
- case WPA_ALG_WEP:
- ext->alg = IW_ENCODE_ALG_WEP;
- break;
- case WPA_ALG_TKIP:
- ext->alg = IW_ENCODE_ALG_TKIP;
- break;
- case WPA_ALG_CCMP:
- ext->alg = IW_ENCODE_ALG_CCMP;
- break;
- case WPA_ALG_PMK:
+ if (key_flag & KEY_FLAG_PMK) {
ext->alg = IW_ENCODE_ALG_PMK;
- break;
- case WPA_ALG_IGTK:
- ext->alg = IW_ENCODE_ALG_AES_CMAC;
- break;
- default:
- wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
- __FUNCTION__, alg);
- os_free(ext);
- return -1;
+ } else {
+ switch (alg) {
+ case WPA_ALG_NONE:
+ ext->alg = IW_ENCODE_ALG_NONE;
+ break;
+ case WPA_ALG_WEP:
+ ext->alg = IW_ENCODE_ALG_WEP;
+ break;
+ case WPA_ALG_TKIP:
+ ext->alg = IW_ENCODE_ALG_TKIP;
+ break;
+ case WPA_ALG_CCMP:
+ ext->alg = IW_ENCODE_ALG_CCMP;
+ break;
+ case WPA_ALG_IGTK:
+ ext->alg = IW_ENCODE_ALG_AES_CMAC;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
+ __FUNCTION__, alg);
+ os_free(ext);
+ return -1;
+ }
}
if (seq && seq_len) {
@@ -1803,37 +1805,27 @@ static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg,
/**
* wpa_driver_wext_set_key - Configure encryption key
* @priv: Pointer to private wext data from wpa_driver_wext_init()
- * @priv: Private driver interface data
- * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
- * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key.
- * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for
- * broadcast/default keys
- * @key_idx: key index (0..3), usually 0 for unicast keys
- * @set_tx: Configure this key as the default Tx key (only used when
- * driver does not support separate unicast/individual key
- * @seq: Sequence number/packet number, seq_len octets, the next
- * packet number to be used for in replay protection; configured
- * for Rx keys (in most cases, this is only used with broadcast
- * keys and set to zero for unicast keys)
- * @seq_len: Length of the seq, depends on the algorithm:
- * TKIP: 6 octets, CCMP: 6 octets
- * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
- * 8-byte Rx Mic Key
- * @key_len: Length of the key buffer in octets (WEP: 5 or 13,
- * TKIP: 32, CCMP: 16)
+ * @params: Key parameters
* Returns: 0 on success, -1 on failure
*
* This function uses SIOCSIWENCODEEXT by default, but tries to use
* SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key.
*/
-int wpa_driver_wext_set_key(const char *ifname, void *priv, 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)
+static int wpa_driver_wext_set_key(void *priv,
+ struct wpa_driver_set_key_params *params)
{
struct wpa_driver_wext_data *drv = priv;
struct iwreq iwr;
int ret = 0;
+ enum wpa_alg alg = params->alg;
+ enum key_flag key_flag = params->key_flag;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *seq = params->seq;
+ size_t seq_len = params->seq_len;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
"key_len=%lu",
@@ -1841,7 +1833,7 @@ int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
(unsigned long) seq_len, (unsigned long) key_len);
ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx,
- seq, seq_len, key, key_len);
+ seq, seq_len, key, key_len, key_flag);
if (ret == 0)
return 0;
diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h
index b4b5960a..6214cdf4 100644
--- a/src/drivers/driver_wext.h
+++ b/src/drivers/driver_wext.h
@@ -52,10 +52,6 @@ int wpa_driver_wext_get_ssid(void *priv, u8 *ssid);
int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len);
int wpa_driver_wext_set_freq(void *priv, int freq);
int wpa_driver_wext_set_mode(void *priv, int mode);
-int wpa_driver_wext_set_key(const char *ifname, void *priv, 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);
int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params);
struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv);
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index bc2e87e0..55a98ef8 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -176,7 +176,6 @@ endif
ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
- DRV_CFLAGS += -DCONFIG_LIBNL20
ifdef LIBNL_INC
DRV_CFLAGS += -I$(LIBNL_INC)
else
@@ -193,14 +192,8 @@ else
else
ifndef CONFIG_OSX
DRV_LIBS += -lnl
- endif
- endif
-
- ifdef CONFIG_LIBNL20
- ifndef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-genl
endif
- DRV_CFLAGS += -DCONFIG_LIBNL20
endif
endif
endif
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index c3c2c0fe..5a32a242 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -160,7 +160,7 @@ ifdef NEED_LIBNL
ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
- DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
+ DRV_CFLAGS += -I/usr/include/libnl3
ifdef CONFIG_LIBNL3_ROUTE
DRV_LIBS += -lnl-route-3
DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
@@ -170,13 +170,7 @@ else
DRV_LIBS += -lnl-tiny
else
DRV_LIBS += -lnl
- endif
-
- ifdef CONFIG_LIBNL20
- ifndef CONFIG_LIBNL_TINY
- DRV_LIBS += -lnl-genl
- endif
- DRV_CFLAGS += -DCONFIG_LIBNL20
+ DRV_LIBS += -lnl-genl
endif
endif
endif
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 341e0e8c..38835b58 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -11,7 +11,7 @@
* Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
* Copyright 2008 Colin McCabe <colin@cozybit.com>
* Copyright 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2019 Intel Corporation
+ * Copyright (C) 2018-2020 Intel Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -265,6 +265,29 @@
*/
/**
+ * DOC: TID configuration
+ *
+ * TID config support can be checked in the %NL80211_ATTR_TID_CONFIG
+ * attribute given in wiphy capabilities.
+ *
+ * The necessary configuration parameters are mentioned in
+ * &enum nl80211_tid_config_attr and it will be passed to the
+ * %NL80211_CMD_SET_TID_CONFIG command in %NL80211_ATTR_TID_CONFIG.
+ *
+ * If the configuration needs to be applied for specific peer then the MAC
+ * address of the peer needs to be passed in %NL80211_ATTR_MAC, otherwise the
+ * configuration will be applied for all the connected peers in the vif except
+ * any peers that have peer specific configuration for the TID by default; if
+ * the %NL80211_TID_CONFIG_ATTR_OVERRIDE flag is set, peer specific values
+ * will be overwritten.
+ *
+ * All this configuration is valid only for STA's current connection
+ * i.e. the configuration will be reset to default when the STA connects back
+ * after disconnection/roaming, and this configuration will be cleared when
+ * the interface goes down.
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -1125,6 +1148,9 @@
* peer MAC address and %NL80211_ATTR_FRAME is used to specify the frame
* content. The frame is ethernet data.
*
+ * @NL80211_CMD_SET_TID_CONFIG: Data frame TID specific configuration
+ * is passed using %NL80211_ATTR_TID_CONFIG attribute.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1349,6 +1375,8 @@ enum nl80211_commands {
NL80211_CMD_PROBE_MESH_LINK,
+ NL80211_CMD_SET_TID_CONFIG,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1604,7 +1632,8 @@ enum nl80211_commands {
* flag is included, then control port frames are sent over NL80211 instead
* using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is
* to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER
- * flag.
+ * flag. When used with %NL80211_ATTR_CONTROL_PORT_NO_PREAUTH, pre-auth
+ * frames are not forwared over the control port.
*
* @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
* We recommend using nested, driver-specific attributes within this.
@@ -2400,6 +2429,47 @@ enum nl80211_commands {
* @NL80211_ATTR_VLAN_ID: VLAN ID (1..4094) for the station and VLAN group key
* (u16).
*
+ * @NL80211_ATTR_HE_BSS_COLOR: nested attribute for BSS Color Settings.
+ *
+ * @NL80211_ATTR_IFTYPE_AKM_SUITES: nested array attribute, with each entry
+ * using attributes from &enum nl80211_iftype_akm_attributes. This
+ * attribute is sent in a response to %NL80211_CMD_GET_WIPHY indicating
+ * supported AKM suites capability per interface. AKMs advertised in
+ * %NL80211_ATTR_AKM_SUITES are default capabilities if AKM suites not
+ * advertised for a specific interface type.
+ *
+ * @NL80211_ATTR_TID_CONFIG: TID specific configuration in a
+ * nested attribute with &enum nl80211_tid_config_attr sub-attributes;
+ * on output (in wiphy attributes) it contains only the feature sub-
+ * attributes.
+ *
+ * @NL80211_ATTR_CONTROL_PORT_NO_PREAUTH: disable preauth frame rx on control
+ * port in order to forward/receive them as ordinary data frames.
+ *
+ * @NL80211_ATTR_PMK_LIFETIME: Maximum lifetime for PMKSA in seconds (u32,
+ * dot11RSNAConfigPMKReauthThreshold; 0 is not a valid value).
+ * An optional parameter configured through %NL80211_CMD_SET_PMKSA.
+ * Drivers that trigger roaming need to know the lifetime of the
+ * configured PMKSA for triggering the full vs. PMKSA caching based
+ * authentication. This timeout helps authentication methods like SAE,
+ * where PMK gets updated only by going through a full (new SAE)
+ * authentication instead of getting updated during an association for EAP
+ * authentication. No new full authentication within the PMK expiry shall
+ * result in a disassociation at the end of the lifetime.
+ *
+ * @NL80211_ATTR_PMK_REAUTH_THRESHOLD: Reauthentication threshold time, in
+ * terms of percentage of %NL80211_ATTR_PMK_LIFETIME
+ * (u8, dot11RSNAConfigPMKReauthThreshold, 1..100). This is an optional
+ * parameter configured through %NL80211_CMD_SET_PMKSA. Requests the
+ * driver to trigger a full authentication roam (without PMKSA caching)
+ * after the reauthentication threshold time, but before the PMK lifetime
+ * has expired.
+ *
+ * Authentication methods like SAE need to be able to generate a new PMKSA
+ * entry without having to force a disconnection after the PMK timeout. If
+ * no roaming occurs between the reauth threshold and PMK expiration,
+ * disassociation is still forced.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2864,6 +2934,17 @@ enum nl80211_attrs {
NL80211_ATTR_VLAN_ID,
+ NL80211_ATTR_HE_BSS_COLOR,
+
+ NL80211_ATTR_IFTYPE_AKM_SUITES,
+
+ NL80211_ATTR_TID_CONFIG,
+
+ NL80211_ATTR_CONTROL_PORT_NO_PREAUTH,
+
+ NL80211_ATTR_PMK_LIFETIME,
+ NL80211_ATTR_PMK_REAUTH_THRESHOLD,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3583,6 +3664,8 @@ enum nl80211_wmm_rule {
* @NL80211_FREQUENCY_ATTR_WMM: this channel has wmm limitations.
* This is a nested attribute that contains the wmm limitation per AC.
* (see &enum nl80211_wmm_rule)
+ * @NL80211_FREQUENCY_ATTR_NO_HE: HE operation is not allowed on this channel
+ * in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -3612,6 +3695,7 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_NO_20MHZ,
NL80211_FREQUENCY_ATTR_NO_10MHZ,
NL80211_FREQUENCY_ATTR_WMM,
+ NL80211_FREQUENCY_ATTR_NO_HE,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -3809,6 +3893,7 @@ enum nl80211_sched_scan_match_attr {
* @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
* @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
* @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed
+ * @NL80211_RRF_NO_HE: HE operation not allowed
*/
enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0,
@@ -3826,6 +3911,7 @@ enum nl80211_reg_rule_flags {
NL80211_RRF_NO_HT40PLUS = 1<<14,
NL80211_RRF_NO_80MHZ = 1<<15,
NL80211_RRF_NO_160MHZ = 1<<16,
+ NL80211_RRF_NO_HE = 1<<17,
};
#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
@@ -4532,6 +4618,7 @@ enum nl80211_key_default_types {
* See &enum nl80211_key_default_types.
* @NL80211_KEY_MODE: the mode from enum nl80211_key_mode.
* Defaults to @NL80211_KEY_RX_TX.
+ * @NL80211_KEY_DEFAULT_BEACON: flag indicating default Beacon frame key
*
* @__NL80211_KEY_AFTER_LAST: internal
* @NL80211_KEY_MAX: highest key attribute
@@ -4547,6 +4634,7 @@ enum nl80211_key_attributes {
NL80211_KEY_TYPE,
NL80211_KEY_DEFAULT_TYPES,
NL80211_KEY_MODE,
+ NL80211_KEY_DEFAULT_BEACON,
/* keep last */
__NL80211_KEY_AFTER_LAST,
@@ -4703,6 +4791,69 @@ enum nl80211_tx_power_setting {
};
/**
+ * enum nl80211_tid_config - TID config state
+ * @NL80211_TID_CONFIG_ENABLE: Enable config for the TID
+ * @NL80211_TID_CONFIG_DISABLE: Disable config for the TID
+ */
+enum nl80211_tid_config {
+ NL80211_TID_CONFIG_ENABLE,
+ NL80211_TID_CONFIG_DISABLE,
+};
+
+/* enum nl80211_tid_config_attr - TID specific configuration.
+ * @NL80211_TID_CONFIG_ATTR_PAD: pad attribute for 64-bit values
+ * @NL80211_TID_CONFIG_ATTR_VIF_SUPP: a bitmap (u64) of attributes supported
+ * for per-vif configuration; doesn't list the ones that are generic
+ * (%NL80211_TID_CONFIG_ATTR_TIDS, %NL80211_TID_CONFIG_ATTR_OVERRIDE).
+ * @NL80211_TID_CONFIG_ATTR_PEER_SUPP: same as the previous per-vif one, but
+ * per peer instead.
+ * @NL80211_TID_CONFIG_ATTR_OVERRIDE: flag attribute, if no peer
+ * is selected, if set indicates that the new configuration overrides
+ * all previous peer configurations, otherwise previous peer specific
+ * configurations should be left untouched. If peer is selected then
+ * it will reset particular TID configuration of that peer and it will
+ * not accept other TID config attributes along with peer.
+ * @NL80211_TID_CONFIG_ATTR_TIDS: a bitmask value of TIDs (bit 0 to 7)
+ * Its type is u16.
+ * @NL80211_TID_CONFIG_ATTR_NOACK: Configure ack policy for the TID.
+ * specified in %NL80211_TID_CONFIG_ATTR_TID. see %enum nl80211_tid_config.
+ * Its type is u8.
+ * @NL80211_TID_CONFIG_ATTR_RETRY_SHORT: Number of retries used with data frame
+ * transmission, user-space sets this configuration in
+ * &NL80211_CMD_SET_TID_CONFIG. It is u8 type, min value is 1 and
+ * the max value is advertised by the driver in this attribute on
+ * output in wiphy capabilities.
+ * @NL80211_TID_CONFIG_ATTR_RETRY_LONG: Number of retries used with data frame
+ * transmission, user-space sets this configuration in
+ * &NL80211_CMD_SET_TID_CONFIG. Its type is u8, min value is 1 and
+ * the max value is advertised by the driver in this attribute on
+ * output in wiphy capabilities.
+ * @NL80211_TID_CONFIG_ATTR_AMPDU_CTRL: Enable/Disable aggregation for the TIDs
+ * specified in %NL80211_TID_CONFIG_ATTR_TIDS. Its type is u8, using
+ * the values from &nl80211_tid_config.
+ * @NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL: Enable/Disable RTS_CTS for the TIDs
+ * specified in %NL80211_TID_CONFIG_ATTR_TIDS. It is u8 type, using
+ * the values from &nl80211_tid_config.
+ */
+enum nl80211_tid_config_attr {
+ __NL80211_TID_CONFIG_ATTR_INVALID,
+ NL80211_TID_CONFIG_ATTR_PAD,
+ NL80211_TID_CONFIG_ATTR_VIF_SUPP,
+ NL80211_TID_CONFIG_ATTR_PEER_SUPP,
+ NL80211_TID_CONFIG_ATTR_OVERRIDE,
+ NL80211_TID_CONFIG_ATTR_TIDS,
+ NL80211_TID_CONFIG_ATTR_NOACK,
+ NL80211_TID_CONFIG_ATTR_RETRY_SHORT,
+ NL80211_TID_CONFIG_ATTR_RETRY_LONG,
+ NL80211_TID_CONFIG_ATTR_AMPDU_CTRL,
+ NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL,
+
+ /* keep last */
+ __NL80211_TID_CONFIG_ATTR_AFTER_LAST,
+ NL80211_TID_CONFIG_ATTR_MAX = __NL80211_TID_CONFIG_ATTR_AFTER_LAST - 1
+};
+
+/**
* enum nl80211_packet_pattern_attr - packet pattern attribute
* @__NL80211_PKTPAT_INVALID: invalid number for nested attribute
* @NL80211_PKTPAT_PATTERN: the pattern, values where the mask has
@@ -5517,6 +5668,22 @@ enum nl80211_feature_flags {
* with VLAN tagged frames and separate VLAN-specific netdevs added using
* vconfig similarly to the Ethernet case.
*
+ * @NL80211_EXT_FEATURE_AQL: The driver supports the Airtime Queue Limit (AQL)
+ * feature, which prevents bufferbloat by using the expected transmission
+ * time to limit the amount of data buffered in the hardware.
+ *
+ * @NL80211_EXT_FEATURE_BEACON_PROTECTION: The driver supports Beacon protection
+ * and can receive key configuration for BIGTK using key indexes 6 and 7.
+ *
+ * @NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH: The driver can disable the
+ * forwarding of preauth frames over the control port. They are then
+ * handled as ordinary data frames.
+ *
+ * @NL80211_EXT_FEATURE_PROTECTED_TWT: Driver supports protected TWT frames
+ *
+ * @NL80211_EXT_FEATURE_DEL_IBSS_STA: The driver supports removing stations
+ * in IBSS mode, essentially by dropping their state.
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -5563,6 +5730,11 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_STA_TX_PWR,
NL80211_EXT_FEATURE_SAE_OFFLOAD,
NL80211_EXT_FEATURE_VLAN_OFFLOAD,
+ NL80211_EXT_FEATURE_AQL,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION,
+ NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH,
+ NL80211_EXT_FEATURE_PROTECTED_TWT,
+ NL80211_EXT_FEATURE_DEL_IBSS_STA,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -6185,12 +6357,14 @@ enum nl80211_ftm_responder_stats {
* @NL80211_PREAMBLE_HT: HT preamble
* @NL80211_PREAMBLE_VHT: VHT preamble
* @NL80211_PREAMBLE_DMG: DMG preamble
+ * @NL80211_PREAMBLE_HE: HE preamble
*/
enum nl80211_preamble {
NL80211_PREAMBLE_LEGACY,
NL80211_PREAMBLE_HT,
NL80211_PREAMBLE_VHT,
NL80211_PREAMBLE_DMG,
+ NL80211_PREAMBLE_HE,
};
/**
@@ -6383,6 +6557,10 @@ enum nl80211_peer_measurement_attrs {
* is valid)
* @NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST: u32 attribute indicating
* the maximum FTMs per burst (if not present anything is valid)
+ * @NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED: flag attribute indicating if
+ * trigger based ranging measurement is supported
+ * @NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED: flag attribute indicating
+ * if non trigger based ranging measurement is supported
*
* @NUM_NL80211_PMSR_FTM_CAPA_ATTR: internal
* @NL80211_PMSR_FTM_CAPA_ATTR_MAX: highest attribute number
@@ -6398,6 +6576,8 @@ enum nl80211_peer_measurement_ftm_capa {
NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS,
NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT,
NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST,
+ NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED,
+ NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED,
/* keep last */
NUM_NL80211_PMSR_FTM_CAPA_ATTR,
@@ -6427,6 +6607,20 @@ enum nl80211_peer_measurement_ftm_capa {
* @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI: request LCI data (flag)
* @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC: request civic location data
* (flag)
+ * @NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED: request trigger based ranging
+ * measurement (flag).
+ * This attribute and %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED are
+ * mutually exclusive.
+ * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor
+ * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based
+ * ranging will be used.
+ * @NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED: request non trigger based
+ * ranging measurement (flag)
+ * This attribute and %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED are
+ * mutually exclusive.
+ * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor
+ * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based
+ * ranging will be used.
*
* @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal
* @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number
@@ -6443,6 +6637,8 @@ enum nl80211_peer_measurement_ftm_req {
NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES,
NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI,
NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC,
+ NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED,
+ NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED,
/* keep last */
NUM_NL80211_PMSR_FTM_REQ_ATTR,
@@ -6582,5 +6778,51 @@ enum nl80211_obss_pd_attributes {
NL80211_HE_OBSS_PD_ATTR_MAX = __NL80211_HE_OBSS_PD_ATTR_LAST - 1,
};
+/**
+ * enum nl80211_bss_color_attributes - BSS Color attributes
+ * @__NL80211_HE_BSS_COLOR_ATTR_INVALID: Invalid
+ *
+ * @NL80211_HE_BSS_COLOR_ATTR_COLOR: the current BSS Color.
+ * @NL80211_HE_BSS_COLOR_ATTR_DISABLED: is BSS coloring disabled.
+ * @NL80211_HE_BSS_COLOR_ATTR_PARTIAL: the AID equation to be used..
+ *
+ * @__NL80211_HE_BSS_COLOR_ATTR_LAST: Internal
+ * @NL80211_HE_BSS_COLOR_ATTR_MAX: highest BSS Color attribute.
+ */
+enum nl80211_bss_color_attributes {
+ __NL80211_HE_BSS_COLOR_ATTR_INVALID,
+
+ NL80211_HE_BSS_COLOR_ATTR_COLOR,
+ NL80211_HE_BSS_COLOR_ATTR_DISABLED,
+ NL80211_HE_BSS_COLOR_ATTR_PARTIAL,
+
+ /* keep last */
+ __NL80211_HE_BSS_COLOR_ATTR_LAST,
+ NL80211_HE_BSS_COLOR_ATTR_MAX = __NL80211_HE_BSS_COLOR_ATTR_LAST - 1,
+};
+
+/**
+ * enum nl80211_iftype_akm_attributes - interface type AKM attributes
+ * @__NL80211_IFTYPE_AKM_ATTR_INVALID: Invalid
+ *
+ * @NL80211_IFTYPE_AKM_ATTR_IFTYPES: nested attribute containing a flag
+ * attribute for each interface type that supports AKM suites specified in
+ * %NL80211_IFTYPE_AKM_ATTR_SUITES
+ * @NL80211_IFTYPE_AKM_ATTR_SUITES: an array of u32. Used to indicate supported
+ * AKM suites for the specified interface types.
+ *
+ * @__NL80211_IFTYPE_AKM_ATTR_LAST: Internal
+ * @NL80211_IFTYPE_AKM_ATTR_MAX: highest interface type AKM attribute.
+ */
+enum nl80211_iftype_akm_attributes {
+ __NL80211_IFTYPE_AKM_ATTR_INVALID,
+
+ NL80211_IFTYPE_AKM_ATTR_IFTYPES,
+ NL80211_IFTYPE_AKM_ATTR_SUITES,
+
+ /* keep last */
+ __NL80211_IFTYPE_AKM_ATTR_LAST,
+ NL80211_IFTYPE_AKM_ATTR_MAX = __NL80211_IFTYPE_AKM_ATTR_LAST - 1,
+};
#endif /* __LINUX_NL80211_H */
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index 5a2ba261..2e79614f 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -648,6 +648,8 @@ SM_STEP(REAUTH_TIMER)
+#ifdef CONFIG_WEP
+
/* Authenticator Key Transmit state machine */
SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
@@ -726,6 +728,8 @@ SM_STEP(KEY_RX)
}
}
+#endif /* CONFIG_WEP */
+
/* Controlled Directions state machine */
@@ -813,10 +817,12 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
sm->portControl = Auto;
+#ifdef CONFIG_WEP
if (!eapol->conf.wpa &&
(eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0))
sm->keyTxEnabled = TRUE;
else
+#endif /* CONFIG_WEP */
sm->keyTxEnabled = FALSE;
if (eapol->conf.wpa)
sm->portValid = FALSE;
@@ -910,10 +916,12 @@ restart:
SM_STEP_RUN(BE_AUTH);
if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
SM_STEP_RUN(REAUTH_TIMER);
+#ifdef CONFIG_WEP
if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
SM_STEP_RUN(AUTH_KEY_TX);
if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
SM_STEP_RUN(KEY_RX);
+#endif /* CONFIG_WEP */
if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
SM_STEP_RUN(CTRL_DIR);
@@ -1167,7 +1175,9 @@ static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
dst->ctx = src->ctx;
dst->eap_reauth_period = src->eap_reauth_period;
dst->wpa = src->wpa;
+#ifdef CONFIG_WEP
dst->individual_wep_key_len = src->individual_wep_key_len;
+#endif /* CONFIG_WEP */
os_free(dst->eap_req_id_text);
if (src->eap_req_id_text) {
dst->eap_req_id_text = os_memdup(src->eap_req_id_text,
@@ -1221,10 +1231,12 @@ struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
return NULL;
}
+#ifdef CONFIG_WEP
if (conf->individual_wep_key_len > 0) {
/* use key0 in individual key and key1 in broadcast key */
eapol->default_wep_key_idx = 1;
}
+#endif /* CONFIG_WEP */
eapol->cb.eapol_send = cb->eapol_send;
eapol->cb.aaa_send = cb->aaa_send;
@@ -1249,6 +1261,8 @@ void eapol_auth_deinit(struct eapol_authenticator *eapol)
return;
eapol_auth_conf_free(&eapol->conf);
+#ifdef CONFIG_WEP
os_free(eapol->default_wep_key);
+#endif /* CONFIG_WEP */
os_free(eapol);
}
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index f1ca0a85..7f04b010 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -200,6 +200,15 @@ static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
}
+static int eapol_sm_confirm_auth(struct eapol_sm *sm)
+{
+ if (!sm->ctx->confirm_auth_cb)
+ return 0;
+
+ return sm->ctx->confirm_auth_cb(sm->ctx->ctx);
+}
+
+
static void eapol_enable_timer_tick(struct eapol_sm *sm)
{
if (sm->timer_tick_enabled)
@@ -316,6 +325,11 @@ SM_STATE(SUPP_PAE, AUTHENTICATED)
SM_STATE(SUPP_PAE, RESTART)
{
+ if (eapol_sm_confirm_auth(sm)) {
+ /* Don't process restart, we are already reconnecting */
+ return;
+ }
+
SM_ENTRY(SUPP_PAE, RESTART);
sm->eapRestart = TRUE;
if (sm->altAccept) {
@@ -678,6 +692,7 @@ struct eap_key_data {
static void eapol_sm_processKey(struct eapol_sm *sm)
{
+#ifdef CONFIG_WEP
#ifndef CONFIG_FIPS
struct ieee802_1x_hdr *hdr;
struct ieee802_1x_eapol_key *key;
@@ -828,7 +843,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
if (sm->ctx->set_wep_key &&
sm->ctx->set_wep_key(sm->ctx->ctx,
- key->key_index & IEEE8021X_KEY_INDEX_FLAG,
+ !!(key->key_index & IEEE8021X_KEY_INDEX_FLAG),
key->key_index & IEEE8021X_KEY_INDEX_MASK,
datakey, key_len) < 0) {
wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
@@ -852,6 +867,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
}
}
#endif /* CONFIG_FIPS */
+#endif /* CONFIG_WEP */
}
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index c9d7522d..67f82c60 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -298,6 +298,15 @@ struct eapol_ctx {
* @len: Length of anonymous identity in octets
*/
void (*set_anon_id)(void *ctx, const u8 *id, size_t len);
+
+ /**
+ * confirm_auth_cb - Callback confirming if we can install a new PTK
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * Returns: 0 when authentication can continue, -1 when reconnecting
+ *
+ * Automatically triggers a reconnect when not.
+ */
+ int (*confirm_auth_cb)(void *ctx);
};
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 79de09ce..2dae6c6e 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -36,7 +36,7 @@
/**
* P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class
*/
-#define P2P_MAX_REG_CLASS_CHANNELS 20
+#define P2P_MAX_REG_CLASS_CHANNELS 60
/**
* struct p2p_channels - List of supported channels
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 07240ea2..be16e27b 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -609,7 +609,7 @@ static int radius_msg_add_attr_to_array(struct radius_msg *msg,
{
if (msg->attr_used >= msg->attr_size) {
size_t *nattr_pos;
- int nlen = msg->attr_size * 2;
+ size_t nlen = msg->attr_size * 2;
nattr_pos = os_realloc_array(msg->attr_pos, nlen,
sizeof(*msg->attr_pos));
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index a3db4048..2b7a604e 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -457,7 +457,7 @@ static int radius_client_retransmit(struct radius_client_data *radius,
}
/* retransmit; remove entry if too many attempts */
- if (entry->accu_attempts > RADIUS_CLIENT_MAX_FAILOVER *
+ if (entry->accu_attempts >= RADIUS_CLIENT_MAX_FAILOVER *
RADIUS_CLIENT_NUM_FAILOVER * num_servers) {
wpa_printf(MSG_INFO,
"RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
@@ -507,7 +507,7 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
if (now.sec >= entry->next_try) {
s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
radius->acct_sock;
- if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
+ if (entry->attempts >= RADIUS_CLIENT_NUM_FAILOVER ||
(s < 0 && entry->attempts > 0)) {
if (entry->msg_type == RADIUS_ACCT ||
entry->msg_type == RADIUS_ACCT_INTERIM)
@@ -1116,7 +1116,7 @@ radius_change_server(struct radius_client_data *radius,
(!auth && entry->msg_type != RADIUS_ACCT))
continue;
entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
- entry->attempts = 1;
+ entry->attempts = 0;
entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
}
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index fa5215ca..e46c89a6 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -270,7 +270,9 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
wpas_notify_pmk_cache_added((struct wpa_supplicant *)pmksa->sm->ctx->ctx, entry);
wpa_sm_add_pmkid(pmksa->sm, entry->network_ctx, entry->aa, entry->pmkid,
entry->fils_cache_id_set ? entry->fils_cache_id : NULL,
- entry->pmk, entry->pmk_len);
+ entry->pmk, entry->pmk_len,
+ pmksa->sm->dot11RSNAConfigPMKLifetime,
+ pmksa->sm->dot11RSNAConfigPMKReauthThreshold);
return entry;
}
@@ -374,9 +376,12 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
{
struct rsn_pmksa_cache_entry *new_entry;
os_time_t old_expiration = old_entry->expiration;
+ const u8 *pmkid = NULL;
+ if (wpa_key_mgmt_sae(old_entry->akmp))
+ pmkid = old_entry->pmkid;
new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
- NULL, NULL, 0,
+ pmkid, NULL, 0,
aa, pmksa->sm->own_addr,
old_entry->network_ctx, old_entry->akmp,
old_entry->fils_cache_id_set ?
@@ -416,6 +421,20 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
while (entry) {
if (entry->network_ctx == network_ctx &&
(!akmp || entry->akmp == akmp)) {
+ struct os_reltime now;
+
+ if (wpa_key_mgmt_sae(entry->akmp) &&
+ os_get_reltime(&now) == 0 &&
+ entry->reauth_time < now.sec) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Do not clone PMKSA cache entry for "
+ MACSTR
+ " since its reauth threshold has passed",
+ MAC2STR(entry->aa));
+ entry = entry->next;
+ continue;
+ }
+
entry = pmksa_cache_clone_entry(pmksa, entry, aa);
if (entry) {
wpa_printf(MSG_DEBUG, "RSN: added "
@@ -519,6 +538,20 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
network_ctx,
fils_cache_id);
if (sm->cur_pmksa) {
+ struct os_reltime now;
+
+ if (wpa_key_mgmt_sae(sm->cur_pmksa->akmp) &&
+ os_get_reltime(&now) == 0 &&
+ sm->cur_pmksa->reauth_time < now.sec) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Do not allow PMKSA cache entry for "
+ MACSTR
+ " to be used for SAE since its reauth threshold has passed",
+ MAC2STR(sm->cur_pmksa->aa));
+ sm->cur_pmksa = NULL;
+ return -1;
+ }
+
wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID",
sm->cur_pmksa->pmkid, PMKID_LEN);
return 0;
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index d0c43f46..a1019217 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -49,6 +49,15 @@ void pmksa_candidate_free(struct wpa_sm *sm)
}
+static int rsn_preauth_key_mgmt(int akmp)
+{
+ return !!(akmp & (WPA_KEY_MGMT_IEEE8021X |
+ WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
+}
+
+
static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -311,10 +320,7 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
if (sm->preauth_eapol ||
sm->proto != WPA_PROTO_RSN ||
wpa_sm_get_state(sm) != WPA_COMPLETED ||
- (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256 &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)) {
+ !rsn_preauth_key_mgmt(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
"state for new pre-authentication");
return; /* invalid state for new pre-auth */
@@ -343,7 +349,7 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
* PMKIDs again, so report the existing data now. */
if (p) {
wpa_sm_add_pmkid(sm, NULL, candidate->bssid, p->pmkid,
- NULL, p->pmk, p->pmk_len);
+ NULL, p->pmk, p->pmk_len, 0, 0);
}
dl_list_del(&candidate->list);
@@ -488,6 +494,9 @@ void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
!(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
return;
+ if (!rsn_preauth_key_mgmt(ie.key_mgmt))
+ return;
+
/* Give less priority to candidates found from normal scan results. */
pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN,
ie.capabilities & WPA_CAPABILITY_PREAUTH);
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 704c95e6..7b47e3ac 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -178,7 +178,7 @@ static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
{
if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr,
- 0, 0, NULL, 0, NULL, 0) < 0) {
+ 0, 0, NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE) < 0) {
wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from "
"the driver");
return -1;
@@ -227,8 +227,9 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR,
MAC2STR(peer->addr));
- if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1,
- rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
+ if (wpa_sm_set_key(sm, alg, peer->addr, 0, 1, rsc, sizeof(rsc),
+ peer->tpk.tk, key_len,
+ KEY_FLAG_PAIRWISE_RX_TX) < 0) {
wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the "
"driver");
return -1;
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 892eece7..166d6eeb 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -183,6 +183,14 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
int key_info, ver;
u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic;
+ if (pairwise && sm->wpa_deny_ptk0_rekey && !sm->use_ext_key_id &&
+ wpa_sm_get_state(sm) == WPA_COMPLETED) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: PTK0 rekey not allowed, reconnecting");
+ wpa_sm_reconnect(sm);
+ return;
+ }
+
if (wpa_use_akm_defined(sm->key_mgmt))
ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
@@ -570,6 +578,7 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
{
const u8 *z = NULL;
size_t z_len = 0;
+ int akmp;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt))
@@ -583,13 +592,67 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
}
#endif /* CONFIG_DPP2 */
+ akmp = sm->key_mgmt;
+#ifdef CONFIG_OWE
+ if (sm->owe_ptk_workaround && akmp == WPA_KEY_MGMT_OWE &&
+ sm->pmk_len > 32) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Force SHA256 for PTK derivation");
+ akmp |= WPA_KEY_MGMT_PSK_SHA256;
+ }
+#endif /* CONFIG_OWE */
return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
sm->own_addr, sm->bssid, sm->snonce,
- key->key_nonce, ptk, sm->key_mgmt,
+ key->key_nonce, ptk, akmp,
sm->pairwise_cipher, z, z_len);
}
+static int wpa_handle_ext_key_id(struct wpa_sm *sm,
+ struct wpa_eapol_ie_parse *kde)
+{
+ if (sm->ext_key_id) {
+ u16 key_id;
+
+ if (!kde->key_id) {
+ wpa_msg(sm->ctx->msg_ctx,
+ sm->use_ext_key_id ? MSG_INFO : MSG_DEBUG,
+ "RSN: No Key ID in Extended Key ID handshake");
+ sm->keyidx_active = 0;
+ return sm->use_ext_key_id ? -1 : 0;
+ }
+
+ key_id = kde->key_id[0] & 0x03;
+ if (key_id > 1) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Invalid Extended Key ID: %d", key_id);
+ return -1;
+ }
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Using Extended Key ID %d", key_id);
+ sm->keyidx_active = key_id;
+ sm->use_ext_key_id = 1;
+ } else {
+ if (kde->key_id && (kde->key_id[0] & 0x03)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Non-zero Extended Key ID Key ID in PTK0 handshake");
+ return -1;
+ }
+
+ if (kde->key_id) {
+ /* This is not supposed to be included here, but ignore
+ * the case of matching Key ID 0 just in case. */
+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Extended Key ID Key ID 0 in PTK0 handshake");
+ }
+ sm->keyidx_active = 0;
+ sm->use_ext_key_id = 0;
+ }
+
+ return 0;
+}
+
+
static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
const unsigned char *src_addr,
const struct wpa_eapol_key *key,
@@ -608,6 +671,14 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
return;
}
+ if (sm->wpa_deny_ptk0_rekey && !sm->use_ext_key_id &&
+ wpa_sm_get_state(sm) == WPA_COMPLETED) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: PTK0 rekey not allowed, reconnecting");
+ wpa_sm_reconnect(sm);
+ return;
+ }
+
wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
wpa_dbg(sm->ctx->msg_ctx, MSG_INFO, "WPA: RX message 1 of 4-Way "
"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
@@ -789,7 +860,8 @@ static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
- const struct wpa_eapol_key *key)
+ const struct wpa_eapol_key *key,
+ enum key_flag key_flag)
{
int keylen, rsclen;
enum wpa_alg alg;
@@ -833,12 +905,14 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
}
- if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
- sm->ptk.tk, keylen) < 0) {
+ if (wpa_sm_set_key(sm, alg, sm->bssid, sm->keyidx_active, 1, key_rsc,
+ rsclen, sm->ptk.tk, keylen,
+ KEY_FLAG_PAIRWISE | key_flag) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Failed to set PTK to the "
- "driver (alg=%d keylen=%d bssid=" MACSTR ")",
- alg, keylen, MAC2STR(sm->bssid));
+ "WPA: Failed to set PTK to the driver (alg=%d keylen=%d bssid="
+ MACSTR " idx=%d key_flag=0x%x)",
+ alg, keylen, MAC2STR(sm->bssid),
+ sm->keyidx_active, key_flag);
return -1;
}
@@ -852,7 +926,23 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
sm, NULL);
}
+ return 0;
+}
+
+static int wpa_supplicant_activate_ptk(struct wpa_sm *sm)
+{
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Activate PTK (idx=%d bssid=" MACSTR ")",
+ sm->keyidx_active, MAC2STR(sm->bssid));
+
+ if (wpa_sm_set_key(sm, 0, sm->bssid, sm->keyidx_active, 0, NULL, 0,
+ NULL, 0, KEY_FLAG_PAIRWISE_RX_TX_MODIFY) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Failed to activate PTK for TX (idx=%d bssid="
+ MACSTR ")", sm->keyidx_active, MAC2STR(sm->bssid));
+ return -1;
+ }
return 0;
}
@@ -927,7 +1017,8 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
if (wpa_sm_set_key(sm, gd->alg, NULL,
gd->keyidx, 1, key_rsc, gd->key_rsc_len,
- _gtk, gd->gtk_len) < 0) {
+ _gtk, gd->gtk_len,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set GTK to the driver "
"(Group only)");
@@ -936,7 +1027,7 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
}
} else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
- _gtk, gd->gtk_len) < 0) {
+ _gtk, gd->gtk_len, KEY_FLAG_GROUP_RX) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set GTK to "
"the driver (alg=%d keylen=%d keyidx=%d)",
@@ -1090,7 +1181,7 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
broadcast_ether_addr,
keyidx, 0, igtk->pn, sizeof(igtk->pn),
- igtk->igtk, len) < 0) {
+ igtk->igtk, len, KEY_FLAG_GROUP_RX) < 0) {
if (keyidx == 0x0400 || keyidx == 0x0500) {
/* Assume the AP has broken PMF implementation since it
* seems to have swapped the KeyID bytes. The AP cannot
@@ -1127,14 +1218,66 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
}
+static int wpa_supplicant_install_bigtk(struct wpa_sm *sm,
+ const struct wpa_bigtk_kde *bigtk,
+ int wnm_sleep)
+{
+ size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ u16 keyidx = WPA_GET_LE16(bigtk->keyid);
+
+ /* Detect possible key reinstallation */
+ if ((sm->bigtk.bigtk_len == len &&
+ os_memcmp(sm->bigtk.bigtk, bigtk->bigtk,
+ sm->bigtk.bigtk_len) == 0) ||
+ (sm->bigtk_wnm_sleep.bigtk_len == len &&
+ os_memcmp(sm->bigtk_wnm_sleep.bigtk, bigtk->bigtk,
+ sm->bigtk_wnm_sleep.bigtk_len) == 0)) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Not reinstalling already in-use BIGTK to the driver (keyidx=%d)",
+ keyidx);
+ return 0;
+ }
+
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: BIGTK keyid %d pn " COMPACT_MACSTR,
+ keyidx, MAC2STR(bigtk->pn));
+ wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK", bigtk->bigtk, len);
+ if (keyidx < 6 || keyidx > 7) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Invalid BIGTK KeyID %d", keyidx);
+ return -1;
+ }
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr,
+ keyidx, 0, bigtk->pn, sizeof(bigtk->pn),
+ bigtk->bigtk, len, KEY_FLAG_GROUP_RX) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Failed to configure BIGTK to the driver");
+ return -1;
+ }
+
+ if (wnm_sleep) {
+ sm->bigtk_wnm_sleep.bigtk_len = len;
+ os_memcpy(sm->bigtk_wnm_sleep.bigtk, bigtk->bigtk,
+ sm->bigtk_wnm_sleep.bigtk_len);
+ } else {
+ sm->bigtk.bigtk_len = len;
+ os_memcpy(sm->bigtk.bigtk, bigtk->bigtk, sm->bigtk.bigtk_len);
+ }
+
+ return 0;
+}
+
+
static int ieee80211w_set_keys(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *ie)
{
+ size_t len;
+
if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
return 0;
if (ie->igtk) {
- size_t len;
const struct wpa_igtk_kde *igtk;
len = wpa_cipher_key_len(sm->mgmt_group_cipher);
@@ -1146,6 +1289,18 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
return -1;
}
+ if (ie->bigtk && sm->beacon_prot) {
+ const struct wpa_bigtk_kde *bigtk;
+
+ len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ if (ie->bigtk_len != WPA_BIGTK_KDE_PREFIX_LEN + len)
+ return -1;
+
+ bigtk = (const struct wpa_bigtk_kde *) ie->bigtk;
+ if (wpa_supplicant_install_bigtk(sm, bigtk, 0) < 0)
+ return -1;
+ }
+
return 0;
}
@@ -1332,11 +1487,10 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Could not find AP from "
"the scan results");
- } else {
- wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
- "WPA: Found the current AP from "
- "updated scan results");
+ return -1;
}
+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Found the current AP from updated scan results");
}
if (ie->wpa_ie == NULL && ie->rsn_ie == NULL &&
@@ -1380,6 +1534,11 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
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");
+ wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp",
+ sm->ap_rsnxe, sm->ap_rsnxe_len);
+ wpa_hexdump(MSG_INFO, "RSNXE in EAPOL-Key msg 3/4",
+ ie->rsnxe, ie->rsnxe_len);
+ wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
return -1;
}
@@ -1486,6 +1645,9 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
goto failed;
+ if (wpa_handle_ext_key_id(sm, &ie))
+ goto failed;
+
if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: ANonce from message 1 of 4-Way Handshake "
@@ -1531,6 +1693,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
}
#endif /* CONFIG_OCV */
+ if (sm->use_ext_key_id &&
+ wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX))
+ goto failed;
+
if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
&sm->ptk) < 0) {
goto failed;
@@ -1542,7 +1708,14 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
sm->renew_snonce = 1;
if (key_info & WPA_KEY_INFO_INSTALL) {
- if (wpa_supplicant_install_ptk(sm, key))
+ int res;
+
+ if (sm->use_ext_key_id)
+ res = wpa_supplicant_activate_ptk(sm);
+ else
+ res = wpa_supplicant_install_ptk(sm, key,
+ KEY_FLAG_RX_TX);
+ if (res)
goto failed;
}
@@ -1598,6 +1771,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
sm->cur_pmksa = sa;
}
+ if (ie.transition_disable)
+ wpa_sm_transition_disable(sm, ie.transition_disable[0]);
sm->msg_3_of_4_ok = 1;
return;
@@ -2784,6 +2959,8 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
#ifdef CONFIG_P2P
os_memset(sm->p2p_ip_addr, 0, sizeof(sm->p2p_ip_addr));
#endif /* CONFIG_P2P */
+
+ sm->keyidx_active = 0;
}
@@ -2815,6 +2992,7 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
/* Keys are not needed in the WPA state machine anymore */
wpa_sm_drop_sa(sm);
+ sm->keyidx_active = 0;
sm->msg_3_of_4_ok = 0;
os_memset(sm->bssid, 0, ETH_ALEN);
@@ -2910,7 +3088,7 @@ void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx)
/**
- * wpa_sm_set_config - Notification of current configration change
+ * wpa_sm_set_config - Notification of current configuration change
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @config: Pointer to current network configuration
*
@@ -2937,6 +3115,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
sm->p2p = config->p2p;
sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation;
+ sm->owe_ptk_workaround = config->owe_ptk_workaround;
#ifdef CONFIG_FILS
if (config->fils_cache_id) {
sm->fils_cache_id_set = 1;
@@ -2946,6 +3125,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->fils_cache_id_set = 0;
}
#endif /* CONFIG_FILS */
+ sm->beacon_prot = config->beacon_prot;
} else {
sm->network_ctx = NULL;
sm->allowed_pairwise_cipher = 0;
@@ -2956,6 +3136,8 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->wpa_ptk_rekey = 0;
sm->p2p = 0;
sm->wpa_rsc_relaxation = 0;
+ sm->owe_ptk_workaround = 0;
+ sm->beacon_prot = 0;
}
}
@@ -3061,6 +3243,15 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_SAE_PWE:
sm->sae_pwe = value;
break;
+ case WPA_PARAM_DENY_PTK0_REKEY:
+ sm->wpa_deny_ptk0_rekey = value;
+ break;
+ case WPA_PARAM_EXT_KEY_ID:
+ sm->ext_key_id = value;
+ break;
+ case WPA_PARAM_USE_EXT_KEY_ID:
+ sm->use_ext_key_id = value;
+ break;
default:
break;
}
@@ -3135,6 +3326,18 @@ int wpa_sm_pmf_enabled(struct wpa_sm *sm)
}
+int wpa_sm_ext_key_id(struct wpa_sm *sm)
+{
+ return sm ? sm->ext_key_id : 0;
+}
+
+
+int wpa_sm_ext_key_id_active(struct wpa_sm *sm)
+{
+ return sm ? sm->use_ext_key_id : 0;
+}
+
+
int wpa_sm_ocv_enabled(struct wpa_sm *sm)
{
struct wpa_ie_data rsn;
@@ -3510,6 +3713,14 @@ int wpa_sm_has_ptk(struct wpa_sm *sm)
}
+int wpa_sm_has_ptk_installed(struct wpa_sm *sm)
+{
+ if (!sm)
+ return 0;
+ return sm->ptk.installed;
+}
+
+
void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
{
os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
@@ -3570,6 +3781,13 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
igtk = (const struct wpa_igtk_kde *) (buf + 2);
if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0)
return -1;
+ } else if (subelem_id == WNM_SLEEP_SUBELEM_BIGTK) {
+ const struct wpa_bigtk_kde *bigtk;
+
+ bigtk = (const struct wpa_bigtk_kde *) (buf + 2);
+ if (sm->beacon_prot &&
+ wpa_supplicant_install_bigtk(sm, bigtk, 1) < 0)
+ return -1;
} else {
wpa_printf(MSG_DEBUG, "Unknown element id");
return -1;
@@ -3753,13 +3971,13 @@ struct wpabuf * fils_build_auth(struct wpa_sm *sm, int dh_group, const u8 *md)
wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
wpabuf_put_data(buf, sm->fils_session, FILS_SESSION_LEN);
- /* FILS Wrapped Data */
+ /* Wrapped Data */
sm->fils_erp_pmkid_set = 0;
if (erp_msg) {
wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg)); /* Length */
/* Element ID Extension */
- wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_WRAPPED_DATA);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
wpabuf_put_buf(buf, erp_msg);
/* Calculate pending PMKID here so that we do not need to
* maintain a copy of the EAP-Initiate/Reauth message. */
@@ -3964,16 +4182,16 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
goto fail;
}
- /* FILS Wrapped Data */
- if (!sm->cur_pmksa && elems.fils_wrapped_data) {
+ /* Wrapped Data */
+ if (!sm->cur_pmksa && elems.wrapped_data) {
u8 rmsk[ERP_MAX_KEY_LEN];
size_t rmsk_len;
wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
- elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
- eapol_sm_process_erp_finish(sm->eapol, elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
+ elems.wrapped_data,
+ elems.wrapped_data_len);
+ eapol_sm_process_erp_finish(sm->eapol, elems.wrapped_data,
+ elems.wrapped_data_len);
if (eapol_sm_failed(sm->eapol))
goto fail;
@@ -4135,6 +4353,8 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
capab |= WPA_CAPABILITY_MFPR;
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
+ if (sm->ext_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
wpabuf_put_le16(buf, capab);
/* PMKID Count */
@@ -4562,11 +4782,12 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
keylen, (long unsigned int) sm->ptk.tk_len);
goto fail;
}
+
rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
wpa_hexdump_key(MSG_DEBUG, "FILS: Set TK to driver",
sm->ptk.tk, keylen);
if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, null_rsc, rsclen,
- sm->ptk.tk, keylen) < 0) {
+ sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE_RX_TX) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"FILS: Failed to set PTK to the driver (alg=%d keylen=%d bssid="
MACSTR ")",
@@ -4590,6 +4811,9 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
sm->fils_completed = 1;
forced_memzero(&gd, sizeof(gd));
+ if (kde.transition_disable)
+ wpa_sm_transition_disable(sm, kde.transition_disable[0]);
+
return 0;
fail:
forced_memzero(&gd, sizeof(gd));
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index f1fbb1bb..796f3920 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -27,10 +27,11 @@ struct wpa_sm_ctx {
void (*set_state)(void *ctx, enum wpa_states state);
enum wpa_states (*get_state)(void *ctx);
void (*deauthenticate)(void * ctx, u16 reason_code);
+ void (*reconnect)(void *ctx);
int (*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);
+ const u8 *key, size_t key_len, enum key_flag key_flag);
void * (*get_network_ctx)(void *ctx);
int (*get_bssid)(void *ctx, u8 *bssid);
int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
@@ -41,7 +42,8 @@ struct wpa_sm_ctx {
size_t *msg_len, void **data_pos);
int (*add_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
const u8 *pmkid, const u8 *fils_cache_id,
- const u8 *pmk, size_t pmk_len);
+ const u8 *pmk, size_t pmk_len, u32 pmk_lifetime,
+ u8 pmk_reauth_threshold);
int (*remove_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
const u8 *pmkid, const u8 *fils_cache_id);
void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
@@ -84,6 +86,7 @@ struct wpa_sm_ctx {
void (*fils_hlp_rx)(void *ctx, const u8 *dst, const u8 *src,
const u8 *pkt, size_t pkt_len);
int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
+ void (*transition_disable)(void *ctx, u8 bitmap);
};
@@ -100,6 +103,9 @@ enum wpa_sm_conf_params {
WPA_PARAM_MFP,
WPA_PARAM_OCV,
WPA_PARAM_SAE_PWE,
+ WPA_PARAM_DENY_PTK0_REKEY,
+ WPA_PARAM_EXT_KEY_ID,
+ WPA_PARAM_USE_EXT_KEY_ID,
};
struct rsn_supp_config {
@@ -111,9 +117,12 @@ struct rsn_supp_config {
const u8 *ssid;
size_t ssid_len;
int wpa_ptk_rekey;
+ int wpa_deny_ptk0_rekey;
int p2p;
int wpa_rsc_relaxation;
+ int owe_ptk_workaround;
const u8 *fils_cache_id;
+ int beacon_prot;
};
#ifndef CONFIG_NO_WPA
@@ -149,6 +158,8 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose);
int wpa_sm_pmf_enabled(struct wpa_sm *sm);
+int wpa_sm_ext_key_id(struct wpa_sm *sm);
+int wpa_sm_ext_key_id_active(struct wpa_sm *sm);
int wpa_sm_ocv_enabled(struct wpa_sm *sm);
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
@@ -172,6 +183,7 @@ int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
const void *network_ctx);
void wpa_sm_drop_sa(struct wpa_sm *sm);
int wpa_sm_has_ptk(struct wpa_sm *sm);
+int wpa_sm_has_ptk_installed(struct wpa_sm *sm);
void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
@@ -294,6 +306,16 @@ static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm)
return 0;
}
+static inline int wpa_sm_ext_key_id(struct wpa_sm *sm)
+{
+ return 0;
+}
+
+static inline int wpa_sm_ext_key_id_active(struct wpa_sm *sm)
+{
+ return 0;
+}
+
static inline int wpa_sm_ocv_enabled(struct wpa_sm *sm)
{
return 0;
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 2b8b41fa..203a61c7 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -82,23 +82,30 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
if (sm == NULL)
return 0;
+ if (!get_ie(ies, ies_len, WLAN_EID_MOBILITY_DOMAIN)) {
+ os_free(sm->assoc_resp_ies);
+ sm->assoc_resp_ies = NULL;
+ sm->assoc_resp_ies_len = 0;
+ os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
+ os_memset(sm->r0kh_id, 0, FT_R0KH_ID_MAX_LEN);
+ sm->r0kh_id_len = 0;
+ os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN);
+ return 0;
+ }
+
use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
if (wpa_ft_parse_ies(ies, ies_len, &ft, use_sha384) < 0)
return -1;
- if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
+ if (ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
return -1;
- if (ft.mdie) {
- wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
- ft.mdie, MOBILITY_DOMAIN_ID_LEN);
- os_memcpy(sm->mobility_domain, ft.mdie,
- MOBILITY_DOMAIN_ID_LEN);
- sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
- wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
- sm->mdie_ft_capab);
- } else
- os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
+ ft.mdie, MOBILITY_DOMAIN_ID_LEN);
+ os_memcpy(sm->mobility_domain, ft.mdie, MOBILITY_DOMAIN_ID_LEN);
+ sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
+ wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
+ sm->mdie_ft_capab);
if (ft.r0kh_id) {
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID",
@@ -125,10 +132,10 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2);
if (sm->assoc_resp_ies) {
u8 *pos = sm->assoc_resp_ies;
- if (ft.mdie) {
- os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
- pos += ft.mdie_len + 2;
- }
+
+ os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
+ pos += ft.mdie_len + 2;
+
if (ft.ftie) {
os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2);
pos += ft.ftie_len + 2;
@@ -155,6 +162,7 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
* @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
* @ric_ies_len: Length of ric_ies buffer in octets
* @ap_mdie: Mobility Domain IE from the target AP
+ * @omit_rsnxe: Whether RSNXE is omitted from Reassociation Request frame
* Returns: Pointer to buffer with IEs or %NULL on failure
*
* Caller is responsible for freeing the returned buffer with os_free();
@@ -164,16 +172,16 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
const u8 *kck, size_t kck_len,
const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len,
- const u8 *ap_mdie)
+ const u8 *ap_mdie, int omit_rsnxe)
{
size_t buf_len;
u8 *buf, *pos, *ftie_len, *ftie_pos, *fte_mic, *elem_count;
struct rsn_mdie *mdie;
struct rsn_ie_hdr *rsnie;
- u16 capab;
int mdie_len;
u8 rsnxe[10];
size_t rsnxe_len;
+ int rsnxe_used;
int res;
sm->ft_completed = 0;
@@ -249,14 +257,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
pos += RSN_SELECTOR_LEN;
/* RSN Capabilities */
- capab = 0;
- if (sm->mfp)
- capab |= WPA_CAPABILITY_MFPC;
- if (sm->mfp == 2)
- capab |= WPA_CAPABILITY_MFPR;
- if (sm->ocv)
- capab |= WPA_CAPABILITY_OCVC;
- WPA_PUT_LE16(pos, capab);
+ WPA_PUT_LE16(pos, rsn_supp_capab(sm));
pos += 2;
/* PMKID Count */
@@ -302,10 +303,13 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
ftie_pos = pos;
*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
ftie_len = pos++;
+ rsnxe_used = wpa_key_mgmt_sae(sm->key_mgmt) && anonce &&
+ (sm->sae_pwe == 1 || sm->sae_pwe == 2);
if (wpa_key_mgmt_sha384(sm->key_mgmt)) {
struct rsn_ftie_sha384 *ftie;
ftie = (struct rsn_ftie_sha384 *) pos;
+ ftie->mic_control[0] = !!rsnxe_used;
fte_mic = ftie->mic;
elem_count = &ftie->mic_control[1];
pos += sizeof(*ftie);
@@ -316,6 +320,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
struct rsn_ftie *ftie;
ftie = (struct rsn_ftie *) pos;
+ ftie->mic_control[0] = !!rsnxe_used;
fte_mic = ftie->mic;
elem_count = &ftie->mic_control[1];
pos += sizeof(*ftie);
@@ -363,12 +368,16 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
pos += ric_ies_len;
}
- res = wpa_gen_rsnxe(sm, rsnxe, sizeof(rsnxe));
- if (res < 0) {
- os_free(buf);
- return NULL;
+ if (omit_rsnxe) {
+ rsnxe_len = 0;
+ } else {
+ res = wpa_gen_rsnxe(sm, rsnxe, sizeof(rsnxe));
+ if (res < 0) {
+ os_free(buf);
+ return NULL;
+ }
+ rsnxe_len = res;
}
- rsnxe_len = res;
if (kck) {
/*
@@ -422,8 +431,9 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
alg = wpa_cipher_to_alg(sm->pairwise_cipher);
keylen = wpa_cipher_key_len(sm->pairwise_cipher);
- if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
- sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen) < 0) {
+ if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, sizeof(null_rsc),
+ (u8 *) sm->ptk.tk, keylen,
+ KEY_FLAG_PAIRWISE_RX_TX) < 0) {
wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
return -1;
}
@@ -450,7 +460,7 @@ int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie)
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, 0, sm->bssid, NULL, 0, mdie);
+ NULL, 0, sm->bssid, NULL, 0, mdie, 0);
if (ft_ies) {
wpa_sm_update_ft_ies(sm, sm->mobility_domain,
ft_ies, ft_ies_len);
@@ -646,7 +656,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
sm->pmk_r1_name,
kck, kck_len, bssid,
ric_ies, ric_ies_len,
- parse.mdie ? parse.mdie - 2 : NULL);
+ parse.mdie ? parse.mdie - 2 : NULL,
+ !sm->ap_rsnxe);
if (ft_ies) {
wpa_sm_update_ft_ies(sm, sm->mobility_domain,
ft_ies, ft_ies_len);
@@ -773,7 +784,8 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
os_memcpy(gtk + 24, tmp, 8);
}
if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
- gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
+ gtk_elem + 3, rsc_len, gtk, keylen,
+ KEY_FLAG_GROUP_RX) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
"driver.");
return -1;
@@ -840,7 +852,8 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
igtk_len);
if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
broadcast_ether_addr, keyidx, 0,
- igtk_elem + 2, 6, igtk, igtk_len) < 0) {
+ igtk_elem + 2, 6, igtk, igtk_len,
+ KEY_FLAG_GROUP_RX) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
"driver.");
forced_memzero(igtk, sizeof(igtk));
@@ -852,6 +865,74 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
}
+static int wpa_ft_process_bigtk_subelem(struct wpa_sm *sm, const u8 *bigtk_elem,
+ size_t bigtk_elem_len)
+{
+ u8 bigtk[WPA_BIGTK_MAX_LEN];
+ size_t bigtk_len;
+ u16 keyidx;
+ const u8 *kek;
+ size_t kek_len;
+
+ if (!sm->beacon_prot || !bigtk_elem ||
+ (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))
+ return 0;
+
+ if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+ kek = sm->ptk.kek2;
+ kek_len = sm->ptk.kek2_len;
+ } else {
+ kek = sm->ptk.kek;
+ kek_len = sm->ptk.kek_len;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: Received BIGTK in Reassoc Resp",
+ bigtk_elem, bigtk_elem_len);
+
+ bigtk_len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ if (bigtk_elem_len != 2 + 6 + 1 + bigtk_len + 8) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Invalid BIGTK sub-elem length %lu",
+ (unsigned long) bigtk_elem_len);
+ return -1;
+ }
+ if (bigtk_elem[8] != bigtk_len) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Invalid BIGTK sub-elem Key Length %d",
+ bigtk_elem[8]);
+ return -1;
+ }
+
+ if (aes_unwrap(kek, kek_len, bigtk_len / 8, bigtk_elem + 9, bigtk)) {
+ wpa_printf(MSG_WARNING,
+ "FT: AES unwrap failed - could not decrypt BIGTK");
+ return -1;
+ }
+
+ /* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */
+
+ keyidx = WPA_GET_LE16(bigtk_elem);
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: BIGTK from Reassoc Resp", bigtk,
+ bigtk_len);
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr, keyidx, 0,
+ bigtk_elem + 2, 6, bigtk, bigtk_len,
+ KEY_FLAG_GROUP_RX) < 0) {
+ wpa_printf(MSG_WARNING,
+ "WPA: Failed to set BIGTK to the driver");
+ forced_memzero(bigtk, sizeof(bigtk));
+ return -1;
+ }
+ forced_memzero(bigtk, sizeof(bigtk));
+
+ return 0;
+}
+
+
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
size_t ies_len, const u8 *src_addr)
{
@@ -864,6 +945,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
const u8 *anonce, *snonce, *fte_mic;
u8 fte_elem_count;
+ int own_rsnxe_used, rsnxe_used;
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
@@ -902,6 +984,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
} else {
@@ -915,6 +998,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
}
@@ -1012,6 +1096,58 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1;
}
+ if (rsnxe_used && !sm->ap_rsnxe) {
+ wpa_printf(MSG_INFO,
+ "FT: FTE indicated that AP uses RSNXE, but RSNXE was not included in Beacon/Probe Response frames");
+ return -1;
+ }
+
+ if (!sm->ap_rsn_ie) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "FT: No RSNE for this AP known - trying to get from scan results");
+ if (wpa_sm_get_beacon_ie(sm) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "FT: Could not find AP from the scan results");
+ return -1;
+ }
+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "FT: Found the current AP from updated scan results");
+ }
+
+ if (sm->ap_rsn_ie &&
+ wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
+ sm->ap_rsn_ie, sm->ap_rsn_ie_len,
+ parse.rsn - 2, parse.rsn_len + 2)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "FT: RSNE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame");
+ wpa_hexdump(MSG_INFO, "RSNE in Beacon/ProbeResp",
+ sm->ap_rsn_ie, sm->ap_rsn_ie_len);
+ wpa_hexdump(MSG_INFO,
+ "RSNE in FT protocol Reassociation Response frame",
+ parse.rsn ? parse.rsn - 2 : NULL,
+ parse.rsn ? parse.rsn_len + 2 : 0);
+ return -1;
+ }
+
+ own_rsnxe_used = wpa_key_mgmt_sae(sm->key_mgmt) &&
+ (sm->sae_pwe == 1 || sm->sae_pwe == 2);
+ if ((sm->ap_rsnxe && !parse.rsnxe && own_rsnxe_used) ||
+ (!sm->ap_rsnxe && parse.rsnxe) ||
+ (sm->ap_rsnxe && parse.rsnxe &&
+ (sm->ap_rsnxe_len != 2 + parse.rsnxe_len ||
+ os_memcmp(sm->ap_rsnxe, parse.rsnxe - 2,
+ sm->ap_rsnxe_len) != 0))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "FT: RSNXE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame");
+ wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp",
+ sm->ap_rsnxe, sm->ap_rsnxe_len);
+ wpa_hexdump(MSG_INFO,
+ "RSNXE in FT protocol Reassociation Response frame",
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0);
+ return -1;
+ }
+
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm)) {
struct wpa_channel_info ci;
@@ -1033,10 +1169,9 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
sm->ft_reassoc_completed = 1;
- if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
- return -1;
-
- if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
+ if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0 ||
+ wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0 ||
+ wpa_ft_process_bigtk_subelem(sm, parse.bigtk, parse.bigtk_len) < 0)
return -1;
if (sm->set_ptk_after_assoc) {
@@ -1083,7 +1218,7 @@ int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, 0, target_ap, NULL, 0, mdie);
+ NULL, 0, target_ap, NULL, 0, mdie, 0);
if (ft_ies) {
sm->over_the_ds_in_progress = 1;
os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 2a433425..1ad75dcf 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -33,6 +33,8 @@ struct wpa_sm {
struct wpa_gtk gtk_wnm_sleep;
struct wpa_igtk igtk;
struct wpa_igtk igtk_wnm_sleep;
+ struct wpa_bigtk bigtk;
+ struct wpa_bigtk bigtk_wnm_sleep;
struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
@@ -61,8 +63,15 @@ struct wpa_sm {
u8 ssid[32];
size_t ssid_len;
int wpa_ptk_rekey;
+ int wpa_deny_ptk0_rekey:1;
int p2p;
int wpa_rsc_relaxation;
+ int owe_ptk_workaround;
+ int beacon_prot;
+ int ext_key_id; /* whether Extended Key ID is enabled */
+ int use_ext_key_id; /* whether Extended Key ID has been detected
+ * to be used */
+ int keyidx_active; /* Key ID for the active TK */
u8 own_addr[ETH_ALEN];
const char *ifname;
@@ -198,11 +207,18 @@ static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, u16 reason_code)
static inline int wpa_sm_set_key(struct wpa_sm *sm, 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)
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
WPA_ASSERT(sm->ctx->set_key);
return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx,
- seq, seq_len, key, key_len);
+ seq, seq_len, key, key_len, key_flag);
+}
+
+static inline void wpa_sm_reconnect(struct wpa_sm *sm)
+{
+ WPA_ASSERT(sm->ctx->reconnect);
+ sm->ctx->reconnect(sm->ctx->ctx);
}
static inline void * wpa_sm_get_network_ctx(struct wpa_sm *sm)
@@ -248,11 +264,13 @@ static inline u8 * wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type,
static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *cache_id, const u8 *pmk,
- size_t pmk_len)
+ size_t pmk_len, u32 pmk_lifetime,
+ u8 pmk_reauth_threshold)
{
WPA_ASSERT(sm->ctx->add_pmkid);
return sm->ctx->add_pmkid(sm->ctx->ctx, network_ctx, bssid, pmkid,
- cache_id, pmk, pmk_len);
+ cache_id, pmk, pmk_len, pmk_lifetime,
+ pmk_reauth_threshold);
}
static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, void *network_ctx,
@@ -410,6 +428,12 @@ static inline int wpa_sm_channel_info(struct wpa_sm *sm,
return sm->ctx->channel_info(sm->ctx->ctx, ci);
}
+static inline void wpa_sm_transition_disable(struct wpa_sm *sm, u8 bitmap)
+{
+ if (sm->ctx->transition_disable)
+ sm->ctx->transition_disable(sm->ctx->ctx, bitmap);
+}
+
int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
int ver, const u8 *dest, u16 proto,
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 03c0d7e8..9068781b 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -105,6 +105,23 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
}
+u16 rsn_supp_capab(struct wpa_sm *sm)
+{
+ u16 capab = 0;
+
+ if (sm->mfp)
+ capab |= WPA_CAPABILITY_MFPC;
+ if (sm->mfp == 2)
+ capab |= WPA_CAPABILITY_MFPR;
+ if (sm->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+ if (sm->ext_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
+
+ return capab;
+}
+
+
static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
int pairwise_cipher, int group_cipher,
int key_mgmt, int mgmt_group_cipher,
@@ -112,7 +129,6 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
{
u8 *pos;
struct rsn_ie_hdr *hdr;
- u16 capab;
u32 suite;
if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
@@ -214,14 +230,7 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
pos += RSN_SELECTOR_LEN;
/* RSN Capabilities */
- capab = 0;
- if (sm->mfp)
- capab |= WPA_CAPABILITY_MFPC;
- if (sm->mfp == 2)
- capab |= WPA_CAPABILITY_MFPR;
- if (sm->ocv)
- capab |= WPA_CAPABILITY_OCVC;
- WPA_PUT_LE16(pos, capab);
+ WPA_PUT_LE16(pos, rsn_supp_capab(sm));
pos += 2;
if (sm->cur_pmksa) {
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 6dc6cf56..83a6727f 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -13,5 +13,6 @@ struct wpa_sm;
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);
+u16 rsn_supp_capab(struct wpa_sm *sm);
#endif /* WPA_IE_H */
diff --git a/src/tls/asn1.c b/src/tls/asn1.c
index a08c2e1e..2da7b4a3 100644
--- a/src/tls/asn1.c
+++ b/src/tls/asn1.c
@@ -9,18 +9,99 @@
#include "includes.h"
#include "common.h"
+#include "utils/wpabuf.h"
#include "asn1.h"
-struct asn1_oid asn1_sha1_oid = {
+const struct asn1_oid asn1_sha1_oid = {
.oid = { 1, 3, 14, 3, 2, 26 },
.len = 6
};
-struct asn1_oid asn1_sha256_oid = {
+const struct asn1_oid asn1_sha256_oid = {
.oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 },
.len = 9
};
+const struct asn1_oid asn1_ec_public_key_oid = {
+ .oid = { 1, 2, 840, 10045, 2, 1 },
+ .len = 6
+};
+
+const struct asn1_oid asn1_prime256v1_oid = {
+ .oid = { 1, 2, 840, 10045, 3, 1, 7 },
+ .len = 7
+};
+
+const struct asn1_oid asn1_secp384r1_oid = {
+ .oid = { 1, 3, 132, 0, 34 },
+ .len = 5
+};
+
+const struct asn1_oid asn1_secp521r1_oid = {
+ .oid = { 1, 3, 132, 0, 35 },
+ .len = 5
+};
+
+const struct asn1_oid asn1_brainpoolP256r1_oid = {
+ .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 7 },
+ .len = 10
+};
+
+const struct asn1_oid asn1_brainpoolP384r1_oid = {
+ .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 11 },
+ .len = 10
+};
+
+const struct asn1_oid asn1_brainpoolP512r1_oid = {
+ .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 13 },
+ .len = 10
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid = {
+ .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 22 },
+ .len = 9
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid = {
+ .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 23 },
+ .len = 9
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid = {
+ .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 24 },
+ .len = 9
+};
+
+const struct asn1_oid asn1_pbkdf2_oid = {
+ .oid = { 1, 2, 840, 113549, 1, 5, 12 },
+ .len = 7
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid = {
+ .oid = { 1, 2, 840, 113549, 2, 9 },
+ .len = 6
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid = {
+ .oid = { 1, 2, 840, 113549, 2, 10 },
+ .len = 6
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid = {
+ .oid = { 1, 2, 840, 113549, 2, 11 },
+ .len = 6
+};
+
+const struct asn1_oid asn1_dpp_config_params_oid = {
+ .oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 1 },
+ .len = 10
+};
+
+const struct asn1_oid asn1_dpp_asymmetric_key_package_oid = {
+ .oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 2 },
+ .len = 10
+};
+
static int asn1_valid_der_boolean(struct asn1_hdr *hdr)
{
@@ -270,3 +351,231 @@ int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b)
return 1;
}
+
+
+int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next)
+{
+ struct asn1_hdr hdr;
+ size_t left;
+ const u8 *pos;
+ int value;
+
+ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
+ return -1;
+
+ if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG,
+ "ASN.1: Expected INTEGER - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ *next = hdr.payload + hdr.length;
+ pos = hdr.payload;
+ left = hdr.length;
+ if (left > sizeof(value)) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Too large INTEGER (len %u)",
+ hdr.length);
+ return -1;
+ }
+ value = 0;
+ while (left) {
+ value <<= 8;
+ value |= *pos++;
+ left--;
+ }
+
+ *integer = value;
+ return 0;
+}
+
+
+int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr,
+ const u8 **next)
+{
+ if (asn1_get_next(buf, len, hdr) < 0 ||
+ hdr->class != ASN1_CLASS_UNIVERSAL ||
+ hdr->tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "ASN.1: Expected SEQUENCE - found class %d tag 0x%x",
+ hdr->class, hdr->tag);
+ return -1;
+ }
+
+ if (next)
+ *next = hdr->payload + hdr->length;
+ return 0;
+}
+
+
+int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid,
+ const u8 **params, size_t *params_len, const u8 **next)
+{
+ const u8 *pos = buf, *end = buf + len;
+ struct asn1_hdr hdr;
+
+ /*
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL}
+ */
+ if (asn1_get_sequence(pos, end - pos, &hdr, next) < 0 ||
+ asn1_get_oid(hdr.payload, hdr.length, oid, &pos) < 0)
+ return -1;
+
+ if (params && params_len) {
+ *params = pos;
+ *params_len = hdr.payload + hdr.length - pos;
+ }
+
+ return 0;
+}
+
+
+void asn1_put_integer(struct wpabuf *buf, int val)
+{
+ u8 bin[4];
+ int zeros;
+
+ WPA_PUT_BE32(bin, val);
+ zeros = 0;
+ while (zeros < 3 && bin[zeros] == 0)
+ zeros++;
+ wpabuf_put_u8(buf, ASN1_TAG_INTEGER);
+ wpabuf_put_u8(buf, 4 - zeros);
+ wpabuf_put_data(buf, &bin[zeros], 4 - zeros);
+}
+
+
+static void asn1_put_len(struct wpabuf *buf, size_t len)
+{
+ if (len <= 0x7f) {
+ wpabuf_put_u8(buf, len);
+ } else if (len <= 0xff) {
+ wpabuf_put_u8(buf, 0x80 | 1);
+ wpabuf_put_u8(buf, len);
+ } else if (len <= 0xffff) {
+ wpabuf_put_u8(buf, 0x80 | 2);
+ wpabuf_put_be16(buf, len);
+ } else if (len <= 0xffffff) {
+ wpabuf_put_u8(buf, 0x80 | 3);
+ wpabuf_put_be24(buf, len);
+ } else {
+ wpabuf_put_u8(buf, 0x80 | 4);
+ wpabuf_put_be32(buf, len);
+ }
+}
+
+
+void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val)
+{
+ wpabuf_put_u8(buf, ASN1_TAG_OCTETSTRING);
+ asn1_put_len(buf, wpabuf_len(val));
+ wpabuf_put_buf(buf, val);
+}
+
+
+void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid)
+{
+ u8 *len;
+ size_t i;
+
+ if (oid->len < 2)
+ return;
+ wpabuf_put_u8(buf, ASN1_TAG_OID);
+ len = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, 40 * oid->oid[0] + oid->oid[1]);
+ for (i = 2; i < oid->len; i++) {
+ unsigned long val = oid->oid[i];
+ u8 bytes[8];
+ int idx = 0;
+
+ while (val) {
+ bytes[idx] = (idx ? 0x80 : 0x00) | (val & 0x7f);
+ idx++;
+ val >>= 7;
+ }
+ if (idx == 0) {
+ bytes[idx] = 0;
+ idx = 1;
+ }
+ while (idx > 0) {
+ idx--;
+ wpabuf_put_u8(buf, bytes[idx]);
+ }
+ }
+ *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
+}
+
+
+void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag,
+ size_t len)
+{
+ wpabuf_put_u8(buf, class << 6 | (constructed ? 0x20 : 0x00) | tag);
+ asn1_put_len(buf, len);
+}
+
+
+void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload)
+{
+ asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SEQUENCE,
+ wpabuf_len(payload));
+ wpabuf_put_buf(buf, payload);
+}
+
+
+void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload)
+{
+ asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SET,
+ wpabuf_len(payload));
+ wpabuf_put_buf(buf, payload);
+}
+
+
+void asn1_put_utf8string(struct wpabuf *buf, const char *val)
+{
+ asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 0, ASN1_TAG_UTF8STRING,
+ os_strlen(val));
+ wpabuf_put_str(buf, val);
+}
+
+
+struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid,
+ const struct wpabuf *params)
+{
+ struct wpabuf *buf;
+ size_t len;
+
+ /*
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL}
+ */
+
+ len = 100;
+ if (params)
+ len += wpabuf_len(params);
+ buf = wpabuf_alloc(len);
+ if (!buf)
+ return NULL;
+ asn1_put_oid(buf, oid);
+ if (params)
+ wpabuf_put_buf(buf, params);
+ return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag)
+{
+ struct wpabuf *res;
+
+ if (!buf)
+ return NULL;
+ res = wpabuf_alloc(10 + wpabuf_len(buf));
+ if (res) {
+ asn1_put_hdr(res, class, 1, tag, wpabuf_len(buf));
+ wpabuf_put_buf(res, buf);
+ }
+ wpabuf_clear_free(buf);
+ return res;
+}
diff --git a/src/tls/asn1.h b/src/tls/asn1.h
index 6bd7df56..6878a4f2 100644
--- a/src/tls/asn1.h
+++ b/src/tls/asn1.h
@@ -65,8 +65,43 @@ int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len);
unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len);
int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b);
+int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next);
+int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr,
+ const u8 **next);
+int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid,
+ const u8 **params, size_t *params_len, const u8 **next);
+void asn1_put_integer(struct wpabuf *buf, int val);
+void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val);
+void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid);
+void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag,
+ size_t len);
+void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload);
+void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload);
+void asn1_put_utf8string(struct wpabuf *buf, const char *val);
+struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid,
+ const struct wpabuf *params);
+struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag);
-extern struct asn1_oid asn1_sha1_oid;
-extern struct asn1_oid asn1_sha256_oid;
+extern const struct asn1_oid asn1_sha1_oid;
+extern const struct asn1_oid asn1_sha256_oid;
+extern const struct asn1_oid asn1_ec_public_key_oid;
+extern const struct asn1_oid asn1_prime256v1_oid;
+extern const struct asn1_oid asn1_secp384r1_oid;
+extern const struct asn1_oid asn1_secp521r1_oid;
+extern const struct asn1_oid asn1_brainpoolP256r1_oid;
+extern const struct asn1_oid asn1_brainpoolP384r1_oid;
+extern const struct asn1_oid asn1_brainpoolP512r1_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid;
+extern const struct asn1_oid asn1_pbkdf2_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid;
+extern const struct asn1_oid asn1_dpp_config_params_oid;
+extern const struct asn1_oid asn1_dpp_asymmetric_key_package_oid;
#endif /* ASN1_H */
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index 80874e59..3825a738 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -312,6 +312,14 @@ static void tls_peer_cert_event(struct tlsv1_client *conn, int depth,
x509_name_string(&cert->subject, subject, sizeof(subject));
ev.peer_cert.subject = subject;
+ if (cert->extensions_present & X509_EXT_CERTIFICATE_POLICY) {
+ if (cert->certificate_policy & X509_EXT_CERT_POLICY_TOD_STRICT)
+ ev.peer_cert.tod = 1;
+ else if (cert->certificate_policy &
+ X509_EXT_CERT_POLICY_TOD_TOFU)
+ ev.peer_cert.tod = 2;
+ }
+
conn->event_cb(conn->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
wpabuf_free(cert_buf);
}
@@ -532,7 +540,7 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
}
} else if (conn->cred && conn->cred->cert_probe) {
wpa_printf(MSG_DEBUG,
- "TLSv1: Reject server certificate on probe-only rune");
+ "TLSv1: Reject server certificate on probe-only run");
if (conn->event_cb) {
union tls_event_data ev;
char buf[128];
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index 1bd5aa00..5c8ac567 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -1120,6 +1120,133 @@ static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
}
+static int x509_id_cert_policy_any_oid(struct asn1_oid *oid)
+{
+ return oid->len == 5 &&
+ oid->oid[0] == 2 /* iso/itu-t */ &&
+ oid->oid[1] == 5 /* X.500 Directory Services */ &&
+ oid->oid[2] == 29 /* id-ce */ &&
+ oid->oid[3] == 32 /* id-ce-certificate-policies */ &&
+ oid->oid[4] == 0 /* anyPolicy */;
+}
+
+
+static int x509_id_wfa_oid(struct asn1_oid *oid)
+{
+ return oid->len >= 7 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 3 /* identified-organization */ &&
+ oid->oid[2] == 6 /* dod */ &&
+ oid->oid[3] == 1 /* internet */ &&
+ oid->oid[4] == 4 /* private */ &&
+ oid->oid[5] == 1 /* enterprise */ &&
+ oid->oid[6] == 40808 /* WFA */;
+}
+
+
+static int x509_id_wfa_tod_oid(struct asn1_oid *oid)
+{
+ return oid->len >= 9 &&
+ x509_id_wfa_oid(oid) &&
+ oid->oid[7] == 1 &&
+ oid->oid[8] == 3;
+}
+
+
+static int x509_id_wfa_tod_strict_oid(struct asn1_oid *oid)
+{
+ return oid->len == 10 &&
+ x509_id_wfa_tod_oid(oid) &&
+ oid->oid[9] == 1;
+}
+
+
+static int x509_id_wfa_tod_tofu_oid(struct asn1_oid *oid)
+{
+ return oid->len == 10 &&
+ x509_id_wfa_tod_oid(oid) &&
+ oid->oid[9] == 2;
+}
+
+
+static int x509_parse_ext_certificate_policies(struct x509_certificate *cert,
+ const u8 *pos, size_t len)
+{
+ struct asn1_hdr hdr;
+ const u8 *end;
+
+ /*
+ * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+ *
+ * PolicyInformation ::= SEQUENCE {
+ * policyIdentifier CertPolicyId,
+ * policyQualifiers SEQUENCE SIZE (1..MAX) OF
+ * PolicyQualifierInfo OPTIONAL }
+ *
+ * CertPolicyId ::= OBJECT IDENTIFIER
+ */
+
+ if (asn1_get_next(pos, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE (certificatePolicies) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (hdr.length > pos + len - hdr.payload)
+ return -1;
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ wpa_hexdump(MSG_MSGDUMP, "X509: certificatePolicies", pos, end - pos);
+
+ while (pos < end) {
+ const u8 *pol_end;
+ struct asn1_oid oid;
+ char buf[80];
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE (PolicyInformation) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (hdr.length > end - hdr.payload)
+ return -1;
+ pos = hdr.payload;
+ pol_end = pos + hdr.length;
+ wpa_hexdump(MSG_MSGDUMP, "X509: PolicyInformation",
+ pos, pol_end - pos);
+
+ if (asn1_get_oid(pos, pol_end - pos, &oid, &pos))
+ return -1;
+ if (x509_id_cert_policy_any_oid(&oid)) {
+ os_strlcpy(buf, "anyPolicy-STRICT", sizeof(buf));
+ cert->certificate_policy |=
+ X509_EXT_CERT_POLICY_ANY;
+ } else if (x509_id_wfa_tod_strict_oid(&oid)) {
+ os_strlcpy(buf, "TOD-STRICT", sizeof(buf));
+ cert->certificate_policy |=
+ X509_EXT_CERT_POLICY_TOD_STRICT;
+ } else if (x509_id_wfa_tod_tofu_oid(&oid)) {
+ os_strlcpy(buf, "TOD-TOFU", sizeof(buf));
+ cert->certificate_policy |=
+ X509_EXT_CERT_POLICY_TOD_TOFU;
+ } else {
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ }
+ wpa_printf(MSG_DEBUG, "policyIdentifier: %s", buf);
+
+ pos = pol_end;
+ }
+
+ cert->extensions_present |= X509_EXT_CERTIFICATE_POLICY;
+
+ return 0;
+}
+
+
static int x509_id_pkix_oid(struct asn1_oid *oid)
{
return oid->len >= 7 &&
@@ -1234,7 +1361,6 @@ static int x509_parse_extension_data(struct x509_certificate *cert,
return 1;
/* TODO: add other extensions required by RFC 3280, Ch 4.2:
- * certificate policies (section 4.2.1.5)
* name constraints (section 4.2.1.11)
* policy constraints (section 4.2.1.12)
* inhibit any-policy (section 4.2.1.15)
@@ -1248,6 +1374,8 @@ static int x509_parse_extension_data(struct x509_certificate *cert,
return x509_parse_ext_issuer_alt_name(cert, pos, len);
case 19: /* id-ce-basicConstraints */
return x509_parse_ext_basic_constraints(cert, pos, len);
+ case 32: /* id-ce-certificatePolicies */
+ return x509_parse_ext_certificate_policies(cert, pos, len);
case 37: /* id-ce-extKeyUsage */
return x509_parse_ext_ext_key_usage(cert, pos, len);
default:
diff --git a/src/tls/x509v3.h b/src/tls/x509v3.h
index 7df8e2ab..e3b108ff 100644
--- a/src/tls/x509v3.h
+++ b/src/tls/x509v3.h
@@ -74,6 +74,7 @@ struct x509_certificate {
#define X509_EXT_SUBJECT_ALT_NAME (1 << 3)
#define X509_EXT_ISSUER_ALT_NAME (1 << 4)
#define X509_EXT_EXT_KEY_USAGE (1 << 5)
+#define X509_EXT_CERTIFICATE_POLICY (1 << 6)
/* BasicConstraints */
int ca; /* cA */
@@ -98,6 +99,12 @@ struct x509_certificate {
#define X509_EXT_KEY_USAGE_CLIENT_AUTH (1 << 2)
#define X509_EXT_KEY_USAGE_OCSP (1 << 3)
+ /* CertificatePolicy */
+ unsigned long certificate_policy;
+#define X509_EXT_CERT_POLICY_ANY (1 << 0)
+#define X509_EXT_CERT_POLICY_TOD_STRICT (1 << 1)
+#define X509_EXT_CERT_POLICY_TOD_TOFU (1 << 2)
+
/*
* The DER format certificate follows struct x509_certificate. These
* pointers point to that buffer.
diff --git a/src/utils/browser-android.c b/src/utils/browser-android.c
index 71a16526..26c83d63 100644
--- a/src/utils/browser-android.c
+++ b/src/utils/browser-android.c
@@ -62,7 +62,7 @@ static void http_req(void *ctx, struct http_request *req)
}
-int hs20_web_browser(const char *url)
+int hs20_web_browser(const char *url, int ignore_tls)
{
struct http_server *http;
struct in_addr addr;
diff --git a/src/utils/browser-system.c b/src/utils/browser-system.c
index aed39706..d87d97b5 100644
--- a/src/utils/browser-system.c
+++ b/src/utils/browser-system.c
@@ -62,7 +62,7 @@ static void http_req(void *ctx, struct http_request *req)
}
-int hs20_web_browser(const char *url)
+int hs20_web_browser(const char *url, int ignore_tls)
{
struct http_server *http;
struct in_addr addr;
diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c
index dfb4b679..d32a85bd 100644
--- a/src/utils/browser-wpadebug.c
+++ b/src/utils/browser-wpadebug.c
@@ -63,7 +63,7 @@ static void http_req(void *ctx, struct http_request *req)
}
-int hs20_web_browser(const char *url)
+int hs20_web_browser(const char *url, int ignore_tls)
{
struct http_server *http;
struct in_addr addr;
diff --git a/src/utils/browser.c b/src/utils/browser.c
index ad0b382f..c0f4380c 100644
--- a/src/utils/browser.c
+++ b/src/utils/browser.c
@@ -7,7 +7,11 @@
*/
#include "includes.h"
+#ifdef USE_WEBKIT2
+#include <webkit2/webkit2.h>
+#else /* USE_WEBKIT2 */
#include <webkit/webkit.h>
+#endif /* USE_WEBKIT2 */
#include "common.h"
#include "browser.h"
@@ -15,16 +19,20 @@
struct browser_context {
GtkWidget *win;
+ WebKitWebView *view;
int success;
int progress;
char *hover_link;
char *title;
+ int gtk_main_started;
+ int quit_gtk_main;
};
static void win_cb_destroy(GtkWidget *win, struct browser_context *ctx)
{
wpa_printf(MSG_DEBUG, "BROWSER:%s", __func__);
- gtk_main_quit();
+ if (ctx->gtk_main_started)
+ gtk_main_quit();
}
@@ -50,6 +58,142 @@ static void browser_update_title(struct browser_context *ctx)
}
+static void process_request_starting_uri(struct browser_context *ctx,
+ const char *uri)
+{
+ int quit = 0;
+
+ if (g_str_has_prefix(uri, "osu://")) {
+ ctx->success = atoi(uri + 6);
+ quit = 1;
+ } else if (g_str_has_prefix(uri, "http://localhost:12345")) {
+ /*
+ * This is used as a special trigger to indicate that the
+ * user exchange has been completed.
+ */
+ ctx->success = 1;
+ quit = 1;
+ }
+
+ if (quit) {
+ if (ctx->gtk_main_started) {
+ gtk_main_quit();
+ ctx->gtk_main_started = 0;
+ } else {
+ ctx->quit_gtk_main = 1;
+ }
+ }
+}
+
+
+#ifdef USE_WEBKIT2
+
+static void view_cb_notify_estimated_load_progress(WebKitWebView *view,
+ GParamSpec *pspec,
+ struct browser_context *ctx)
+{
+ ctx->progress = 100 * webkit_web_view_get_estimated_load_progress(view);
+ wpa_printf(MSG_DEBUG, "BROWSER:%s progress=%d", __func__,
+ ctx->progress);
+ browser_update_title(ctx);
+}
+
+
+static void view_cb_resource_load_starting(WebKitWebView *view,
+ WebKitWebResource *res,
+ WebKitURIRequest *req,
+ struct browser_context *ctx)
+{
+ const gchar *uri = webkit_uri_request_get_uri(req);
+
+ wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
+ process_request_starting_uri(ctx, uri);
+}
+
+
+static gboolean view_cb_decide_policy(WebKitWebView *view,
+ WebKitPolicyDecision *policy,
+ WebKitPolicyDecisionType type,
+ struct browser_context *ctx)
+{
+ wpa_printf(MSG_DEBUG, "BROWSER:%s type=%d", __func__, type);
+ switch (type) {
+ case WEBKIT_POLICY_DECISION_TYPE_RESPONSE: {
+ /* This function makes webkit send a download signal for all
+ * unknown mime types. */
+ WebKitResponsePolicyDecision *response;
+
+ response = WEBKIT_RESPONSE_POLICY_DECISION(policy);
+ if (!webkit_response_policy_decision_is_mime_type_supported(
+ response)) {
+ webkit_policy_decision_download(policy);
+ return TRUE;
+ }
+ break;
+ }
+ case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION: {
+ WebKitNavigationPolicyDecision *d;
+ WebKitNavigationAction *a;
+ WebKitURIRequest *req;
+ const gchar *uri;
+
+ d = WEBKIT_NAVIGATION_POLICY_DECISION(policy);
+ a = webkit_navigation_policy_decision_get_navigation_action(d);
+ req = webkit_navigation_action_get_request(a);
+ uri = webkit_uri_request_get_uri(req);
+ wpa_printf(MSG_DEBUG, "BROWSER:%s navigation action: uri=%s",
+ __func__, uri);
+ process_request_starting_uri(ctx, uri);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
+static void view_cb_mouse_target_changed(WebKitWebView *view,
+ WebKitHitTestResult *h,
+ guint modifiers,
+ struct browser_context *ctx)
+{
+ WebKitHitTestResultContext hc = webkit_hit_test_result_get_context(h);
+ const char *uri = NULL;
+
+ if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
+ uri = webkit_hit_test_result_get_link_uri(h);
+ else if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE)
+ uri = webkit_hit_test_result_get_image_uri(h);
+ else if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA)
+ uri = webkit_hit_test_result_get_media_uri(h);
+
+ wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri ? uri : "N/A");
+ os_free(ctx->hover_link);
+ if (uri)
+ ctx->hover_link = os_strdup(uri);
+ else
+ ctx->hover_link = NULL;
+
+ browser_update_title(ctx);
+}
+
+
+static void view_cb_notify_title(WebKitWebView *view, GParamSpec *ps,
+ struct browser_context *ctx)
+{
+ const char *title;
+
+ title = webkit_web_view_get_title(ctx->view);
+ wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s", __func__, title);
+ os_free(ctx->title);
+ ctx->title = os_strdup(title);
+ browser_update_title(ctx);
+}
+
+#else /* USE_WEBKIT2 */
+
static void view_cb_notify_progress(WebKitWebView *view, GParamSpec *pspec,
struct browser_context *ctx)
{
@@ -66,6 +210,10 @@ static void view_cb_notify_load_status(WebKitWebView *view, GParamSpec *pspec,
int status = webkit_web_view_get_load_status(view);
wpa_printf(MSG_DEBUG, "BROWSER:%s load-status=%d uri=%s",
__func__, status, webkit_web_view_get_uri(view));
+ if (ctx->quit_gtk_main) {
+ gtk_main_quit();
+ ctx->gtk_main_started = 0;
+ }
}
@@ -77,21 +225,12 @@ static void view_cb_resource_request_starting(WebKitWebView *view,
struct browser_context *ctx)
{
const gchar *uri = webkit_network_request_get_uri(req);
+
wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
if (g_str_has_suffix(uri, "/favicon.ico"))
webkit_network_request_set_uri(req, "about:blank");
- if (g_str_has_prefix(uri, "osu://")) {
- ctx->success = atoi(uri + 6);
- gtk_main_quit();
- }
- if (g_str_has_prefix(uri, "http://localhost:12345")) {
- /*
- * This is used as a special trigger to indicate that the
- * user exchange has been completed.
- */
- ctx->success = 1;
- gtk_main_quit();
- }
+
+ process_request_starting_uri(ctx, uri);
}
@@ -147,23 +286,32 @@ static void view_cb_title_changed(WebKitWebView *view, WebKitWebFrame *frame,
browser_update_title(ctx);
}
+#endif /* USE_WEBKIT2 */
+
-int hs20_web_browser(const char *url)
+int hs20_web_browser(const char *url, int ignore_tls)
{
GtkWidget *scroll;
- SoupSession *s;
WebKitWebView *view;
+#ifdef USE_WEBKIT2
+ WebKitSettings *settings;
+#else /* USE_WEBKIT2 */
WebKitWebSettings *settings;
+ SoupSession *s;
+#endif /* USE_WEBKIT2 */
struct browser_context ctx;
memset(&ctx, 0, sizeof(ctx));
if (!gtk_init_check(NULL, NULL))
return -1;
+#ifndef USE_WEBKIT2
s = webkit_get_default_session();
g_object_set(G_OBJECT(s), "ssl-ca-file",
"/etc/ssl/certs/ca-certificates.crt", NULL);
- g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
+ if (ignore_tls)
+ g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
+#endif /* USE_WEBKIT2 */
ctx.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_role(GTK_WINDOW(ctx.win), "Hotspot 2.0 client");
@@ -177,10 +325,24 @@ int hs20_web_browser(const char *url)
G_CALLBACK(win_cb_destroy), &ctx);
view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_signal_connect(G_OBJECT(view), "notify::progress",
- G_CALLBACK(view_cb_notify_progress), &ctx);
+ ctx.view = view;
+#ifdef USE_WEBKIT2
+ g_signal_connect(G_OBJECT(view), "notify::estimated-load-progress",
+ G_CALLBACK(view_cb_notify_estimated_load_progress),
+ &ctx);
+ g_signal_connect(G_OBJECT(view), "resource-load-started",
+ G_CALLBACK(view_cb_resource_load_starting), &ctx);
+ g_signal_connect(G_OBJECT(view), "decide-policy",
+ G_CALLBACK(view_cb_decide_policy), &ctx);
+ g_signal_connect(G_OBJECT(view), "mouse-target-changed",
+ G_CALLBACK(view_cb_mouse_target_changed), &ctx);
+ g_signal_connect(G_OBJECT(view), "notify::title",
+ G_CALLBACK(view_cb_notify_title), &ctx);
+#else /* USE_WEBKIT2 */
g_signal_connect(G_OBJECT(view), "notify::load-status",
G_CALLBACK(view_cb_notify_load_status), &ctx);
+ g_signal_connect(G_OBJECT(view), "notify::progress",
+ G_CALLBACK(view_cb_notify_progress), &ctx);
g_signal_connect(G_OBJECT(view), "resource-request-starting",
G_CALLBACK(view_cb_resource_request_starting), &ctx);
g_signal_connect(G_OBJECT(view), "mime-type-policy-decision-requested",
@@ -191,6 +353,7 @@ int hs20_web_browser(const char *url)
G_CALLBACK(view_cb_hovering_over_link), &ctx);
g_signal_connect(G_OBJECT(view), "title-changed",
G_CALLBACK(view_cb_title_changed), &ctx);
+#endif /* USE_WEBKIT2 */
gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(view));
gtk_container_add(GTK_CONTAINER(ctx.win), GTK_WIDGET(scroll));
@@ -205,8 +368,19 @@ int hs20_web_browser(const char *url)
"hs20-client/1.0", NULL);
g_object_set(G_OBJECT(settings), "auto-load-images", TRUE, NULL);
+#ifdef USE_WEBKIT2
+ if (ignore_tls) {
+ WebKitWebContext *wkctx;
+
+ wkctx = webkit_web_context_get_default();
+ webkit_web_context_set_tls_errors_policy(
+ wkctx, WEBKIT_TLS_ERRORS_POLICY_IGNORE);
+ }
+#endif /* USE_WEBKIT2 */
+
webkit_web_view_load_uri(view, url);
+ ctx.gtk_main_started = 1;
gtk_main();
gtk_widget_destroy(ctx.win);
while (gtk_events_pending())
diff --git a/src/utils/browser.h b/src/utils/browser.h
index aaa0eed2..3af13b9a 100644
--- a/src/utils/browser.h
+++ b/src/utils/browser.h
@@ -10,12 +10,12 @@
#define BROWSER_H
#ifdef CONFIG_NO_BROWSER
-static inline int hs20_web_browser(const char *url)
+static inline int hs20_web_browser(const char *url, int ignore_tls)
{
return -1;
}
#else /* CONFIG_NO_BROWSER */
-int hs20_web_browser(const char *url);
+int hs20_web_browser(const char *url, int ignore_tls);
#endif /* CONFIG_NO_BROWSER */
#endif /* BROWSER_H */
diff --git a/src/utils/common.c b/src/utils/common.c
index 27bf435d..2c127519 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -7,6 +7,7 @@
*/
#include "includes.h"
+#include <limits.h>
#include "common/ieee802_11_defs.h"
#include "common.h"
@@ -790,6 +791,10 @@ int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value)
*/
pos = value;
while (pos && pos[0]) {
+ if (count == UINT_MAX) {
+ os_free(freq);
+ return -1;
+ }
n = os_realloc_array(freq, count + 1,
sizeof(struct wpa_freq_range));
if (n == NULL) {
@@ -874,9 +879,10 @@ char * freq_range_list_str(const struct wpa_freq_range_list *list)
}
-int int_array_len(const int *a)
+size_t int_array_len(const int *a)
{
- int i;
+ size_t i;
+
for (i = 0; a && a[i]; i++)
;
return i;
@@ -885,12 +891,21 @@ int int_array_len(const int *a)
void int_array_concat(int **res, const int *a)
{
- int reslen, alen, i;
+ size_t reslen, alen, i, max_size;
int *n;
reslen = int_array_len(*res);
alen = int_array_len(a);
-
+ max_size = (size_t) -1;
+ if (alen >= max_size - reslen) {
+ /* This should not really happen, but if it did, something
+ * would overflow. Do not try to merge the arrays; instead, make
+ * this behave like memory allocation failure to avoid messing
+ * up memory. */
+ os_free(*res);
+ *res = NULL;
+ return;
+ }
n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
if (n == NULL) {
os_free(*res);
@@ -918,8 +933,7 @@ static int freq_cmp(const void *a, const void *b)
void int_array_sort_unique(int *a)
{
- int alen;
- int i, j;
+ size_t alen, i, j;
if (a == NULL)
return;
@@ -944,7 +958,7 @@ void int_array_sort_unique(int *a)
void int_array_add_unique(int **res, int a)
{
- int reslen;
+ size_t reslen, max_size;
int *n;
for (reslen = 0; *res && (*res)[reslen]; reslen++) {
@@ -952,6 +966,16 @@ void int_array_add_unique(int **res, int a)
return; /* already in the list */
}
+ max_size = (size_t) -1;
+ if (reslen > max_size - 2) {
+ /* This should not really happen in practice, but if it did,
+ * something would overflow. Do not try to add the new value;
+ * instead, make this behave like memory allocation failure to
+ * avoid messing up memory. */
+ os_free(*res);
+ *res = NULL;
+ return;
+ }
n = os_realloc_array(*res, reslen + 2, sizeof(int));
if (n == NULL) {
os_free(*res);
diff --git a/src/utils/common.h b/src/utils/common.h
index 833469a5..8e5cfe16 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -547,7 +547,7 @@ int freq_range_list_includes(const struct wpa_freq_range_list *list,
unsigned int freq);
char * freq_range_list_str(const struct wpa_freq_range_list *list);
-int int_array_len(const int *a);
+size_t int_array_len(const int *a);
void int_array_concat(int **res, const int *a);
void int_array_sort_unique(int *a);
void int_array_add_unique(int **res, int a);
diff --git a/src/utils/crc32.c b/src/utils/crc32.c
new file mode 100644
index 00000000..12d9e2a7
--- /dev/null
+++ b/src/utils/crc32.c
@@ -0,0 +1,85 @@
+/*
+ * 32-bit CRC for FCS calculation
+ * Copyright (c) 2010, 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/crc32.h"
+
+/*
+ * IEEE 802.11 FCS CRC32
+ * G(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 +
+ * x^5 + x^4 + x^2 + x + 1
+ */
+static const u32 crc32_table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+};
+
+
+u32 crc32(const u8 *frame, size_t frame_len)
+{
+ size_t i;
+ u32 crc;
+
+ crc = 0xFFFFFFFF;
+ for (i = 0; i < frame_len; i++)
+ crc = crc32_table[(crc ^ frame[i]) & 0xff] ^ (crc >> 8);
+
+ return ~crc;
+}
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index bb375be1..b353ab0e 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -68,7 +68,7 @@ struct eloop_signal {
};
struct eloop_sock_table {
- int count;
+ size_t count;
struct eloop_sock *table;
eloop_event_type type;
int changed;
@@ -77,10 +77,10 @@ struct eloop_sock_table {
struct eloop_data {
int max_sock;
- int count; /* sum of all table counts */
+ size_t count; /* sum of all table counts */
#ifdef CONFIG_ELOOP_POLL
- int max_pollfd_map; /* number of pollfds_map currently allocated */
- int max_poll_fds; /* number of pollfds currently allocated */
+ size_t max_pollfd_map; /* number of pollfds_map currently allocated */
+ size_t max_poll_fds; /* number of pollfds currently allocated */
struct pollfd *pollfds;
struct pollfd **pollfds_map;
#endif /* CONFIG_ELOOP_POLL */
@@ -90,12 +90,12 @@ struct eloop_data {
#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
#ifdef CONFIG_ELOOP_EPOLL
int epollfd;
- int epoll_max_event_num;
+ size_t epoll_max_event_num;
struct epoll_event *epoll_events;
#endif /* CONFIG_ELOOP_EPOLL */
#ifdef CONFIG_ELOOP_KQUEUE
int kqueuefd;
- int kqueue_nevents;
+ size_t kqueue_nevents;
struct kevent *kqueue_events;
#endif /* CONFIG_ELOOP_KQUEUE */
struct eloop_sock_table readers;
@@ -104,7 +104,7 @@ struct eloop_data {
struct dl_list timeout;
- int signal_count;
+ size_t signal_count;
struct eloop_signal *signals;
int signaled;
int pending_terminate;
@@ -125,7 +125,8 @@ static void eloop_sigsegv_handler(int sig)
static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
{
- int i;
+ size_t i;
+
if (table == NULL || table->table == NULL)
return;
for (i = 0; i < table->count; i++) {
@@ -139,7 +140,8 @@ static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
{
- int i;
+ size_t i;
+
if (table == NULL || table->table == NULL)
return;
for (i = 0; i < table->count; i++) {
@@ -266,7 +268,7 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
#endif /* CONFIG_ELOOP_EPOLL */
#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
struct eloop_sock *temp_table;
- int next;
+ size_t next;
#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
struct eloop_sock *tmp;
int new_max_sock;
@@ -280,7 +282,7 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
return -1;
#ifdef CONFIG_ELOOP_POLL
- if (new_max_sock >= eloop.max_pollfd_map) {
+ if ((size_t) new_max_sock >= eloop.max_pollfd_map) {
struct pollfd **nmap;
nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
sizeof(struct pollfd *));
@@ -293,7 +295,8 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
if (eloop.count + 1 > eloop.max_poll_fds) {
struct pollfd *n;
- int nmax = eloop.count + 1 + 50;
+ size_t nmax = eloop.count + 1 + 50;
+
n = os_realloc_array(eloop.pollfds, nmax,
sizeof(struct pollfd));
if (n == NULL)
@@ -385,7 +388,7 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
#ifdef CONFIG_ELOOP_KQUEUE
struct kevent ke;
#endif /* CONFIG_ELOOP_KQUEUE */
- int i;
+ size_t i;
if (table == NULL || table->table == NULL || table->count == 0)
return;
@@ -444,7 +447,7 @@ static int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
struct pollfd **pollfds_map,
int max_pollfd_map)
{
- int i;
+ size_t i;
int nxt = 0;
int fd;
struct pollfd *pfd;
@@ -519,7 +522,7 @@ static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
int max_pollfd_map,
short int revents)
{
- int i;
+ size_t i;
struct pollfd *pfd;
if (!table || !table->table)
@@ -572,7 +575,7 @@ static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
fd_set *fds)
{
- int i;
+ size_t i;
FD_ZERO(fds);
@@ -589,7 +592,7 @@ static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
fd_set *fds)
{
- int i;
+ size_t i;
if (table == NULL || table->table == NULL)
return;
@@ -653,7 +656,8 @@ static void eloop_sock_table_dispatch(struct kevent *events, int nfds)
static int eloop_sock_table_requeue(struct eloop_sock_table *table)
{
- int i, r;
+ size_t i;
+ int r;
r = 0;
for (i = 0; i < table->count && table->table; i++) {
@@ -694,7 +698,8 @@ int eloop_sock_requeue(void)
static void eloop_sock_table_destroy(struct eloop_sock_table *table)
{
if (table) {
- int i;
+ size_t i;
+
for (i = 0; i < table->count && table->table; i++) {
wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
"sock=%d eloop_data=%p user_data=%p "
@@ -968,7 +973,7 @@ static void eloop_handle_alarm(int sig)
static void eloop_handle_signal(int sig)
{
- int i;
+ size_t i;
#ifndef CONFIG_NATIVE_WINDOWS
if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
@@ -992,7 +997,7 @@ static void eloop_handle_signal(int sig)
static void eloop_process_pending_signals(void)
{
- int i;
+ size_t i;
if (eloop.signaled == 0)
return;
diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c
index 9c8b12be..74eaa33e 100644
--- a/src/utils/eloop_win.c
+++ b/src/utils/eloop_win.c
@@ -54,7 +54,7 @@ struct eloop_data {
struct dl_list timeout;
- int signal_count;
+ size_t signal_count;
struct eloop_signal *signals;
int signaled;
int pending_terminate;
@@ -422,7 +422,7 @@ int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
#if 0
static void eloop_handle_signal(int sig)
{
- int i;
+ size_t i;
eloop.signaled++;
for (i = 0; i < eloop.signal_count; i++) {
@@ -437,7 +437,7 @@ static void eloop_handle_signal(int sig)
static void eloop_process_pending_signals(void)
{
- int i;
+ size_t i;
if (eloop.signaled == 0)
return;
@@ -517,7 +517,7 @@ int eloop_register_signal_terminate(eloop_signal_handler handler,
eloop.term_signal.handler = handler;
eloop.term_signal.user_data = user_data;
-
+
return 0;
}
diff --git a/src/utils/http-utils.h b/src/utils/http-utils.h
index 8d4399a3..d9fc925a 100644
--- a/src/utils/http-utils.h
+++ b/src/utils/http-utils.h
@@ -28,11 +28,11 @@ struct http_logo {
struct http_cert {
char **dnsname;
- unsigned int num_dnsname;
+ size_t num_dnsname;
struct http_othername *othername;
- unsigned int num_othername;
+ size_t num_othername;
struct http_logo *logo;
- unsigned int num_logo;
+ size_t num_logo;
};
int soap_init_client(struct http_ctx *ctx, const char *address,
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 494bf4cc..ae2f8029 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -339,6 +339,8 @@ char * os_rel2abs_path(const char *rel_path)
int os_program_init(void)
{
+ unsigned int seed;
+
#ifdef ANDROID
struct __user_cap_header_struct header;
struct __user_cap_data_struct cap;
@@ -391,6 +393,9 @@ int os_program_init(void)
capset(&header, &cap);
#endif /* ANDROID */
+ if (os_get_random((unsigned char *) &seed, sizeof(seed)) == 0)
+ srandom(seed);
+
return 0;
}
diff --git a/src/utils/trace.c b/src/utils/trace.c
index 40843432..8f12da87 100644
--- a/src/utils/trace.c
+++ b/src/utils/trace.c
@@ -146,6 +146,17 @@ struct bfd_data {
unsigned int line;
};
+/*
+ * binutils removed the bfd parameter and renamed things but
+ * those were macros so we can detect their absence.
+ * Cf. https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commitdiff;h=fd3619828e94a24a92cddec42cbc0ab33352eeb4;hp=5dfda3562a69686c43aad4fb0269cc9d5ec010d5
+ */
+#ifndef bfd_get_section_vma
+#define bfd_get_section_vma(bfd, section) bfd_section_vma(section)
+#endif
+#ifndef bfd_get_section_size
+#define bfd_get_section_size bfd_section_size
+#endif
static void find_addr_sect(bfd *abfd, asection *section, void *obj)
{
diff --git a/src/utils/utils_module_tests.c b/src/utils/utils_module_tests.c
index b09225de..365f21fb 100644
--- a/src/utils/utils_module_tests.c
+++ b/src/utils/utils_module_tests.c
@@ -226,7 +226,7 @@ static int int_array_tests(void)
int test3[] = { 1, 1, 1, -1, 2, 3, 4, 1, 2, 0 };
int test3_res[] = { -1, 1, 2, 3, 4, 0 };
int errors = 0;
- int len;
+ size_t len;
wpa_printf(MSG_INFO, "int_array tests");
@@ -930,7 +930,7 @@ static int const_time_tests(void)
{ 0, 0 },
{ 1, 0 },
{ 2, 0 },
- { 1 << (sizeof(unsigned int) * 8 - 1), ~0 },
+ { 1U << (sizeof(unsigned int) * 8 - 1), ~0 },
{ ~0 - 1, ~0 },
{ ~0, ~0 }
};
@@ -941,7 +941,7 @@ static int const_time_tests(void)
{ 0, ~0 },
{ 1, 0 },
{ 2, 0 },
- { 1 << (sizeof(unsigned int) * 8 - 1), 0 },
+ { 1U << (sizeof(unsigned int) * 8 - 1), 0 },
{ ~0 - 1, 0 },
{ ~0, 0 }
};
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index c336e538..a338a203 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -12,8 +12,6 @@
#ifdef CONFIG_DEBUG_SYSLOG
#include <syslog.h>
-
-int wpa_debug_syslog = 0;
#endif /* CONFIG_DEBUG_SYSLOG */
#ifdef CONFIG_DEBUG_LINUX_TRACING
@@ -32,6 +30,10 @@ static FILE *wpa_debug_tracing_file = NULL;
int wpa_debug_level = MSG_INFO;
int wpa_debug_show_keys = 0;
int wpa_debug_timestamp = 0;
+int wpa_debug_syslog = 0;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static FILE *out_file = NULL;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
#ifdef CONFIG_ANDROID_LOG
@@ -61,8 +63,6 @@ static int wpa_to_android_level(int level)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
-
-static FILE *out_file = NULL;
#endif /* CONFIG_DEBUG_FILE */
@@ -76,12 +76,12 @@ void wpa_debug_print_timestamp(void)
os_get_time(&tv);
#ifdef CONFIG_DEBUG_FILE
- if (out_file) {
+ if (out_file)
fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
(unsigned int) tv.usec);
- } else
#endif /* CONFIG_DEBUG_FILE */
- printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
+ if (!out_file && !wpa_debug_syslog)
+ printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
#endif /* CONFIG_ANDROID_LOG */
}
@@ -210,35 +210,37 @@ void wpa_printf(int level, const char *fmt, ...)
{
va_list ap;
- va_start(ap, fmt);
if (level >= wpa_debug_level) {
#ifdef CONFIG_ANDROID_LOG
+ va_start(ap, fmt);
__android_log_vprint(wpa_to_android_level(level),
ANDROID_LOG_NAME, fmt, ap);
+ va_end(ap);
#else /* CONFIG_ANDROID_LOG */
#ifdef CONFIG_DEBUG_SYSLOG
if (wpa_debug_syslog) {
+ va_start(ap, fmt);
vsyslog(syslog_priority(level), fmt, ap);
- } else {
+ va_end(ap);
+ }
#endif /* CONFIG_DEBUG_SYSLOG */
wpa_debug_print_timestamp();
#ifdef CONFIG_DEBUG_FILE
if (out_file) {
+ va_start(ap, fmt);
vfprintf(out_file, fmt, ap);
fprintf(out_file, "\n");
- } else {
-#endif /* CONFIG_DEBUG_FILE */
- vprintf(fmt, ap);
- printf("\n");
-#ifdef CONFIG_DEBUG_FILE
+ va_end(ap);
}
#endif /* CONFIG_DEBUG_FILE */
-#ifdef CONFIG_DEBUG_SYSLOG
+ if (!wpa_debug_syslog && !out_file) {
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ printf("\n");
+ va_end(ap);
}
-#endif /* CONFIG_DEBUG_SYSLOG */
#endif /* CONFIG_ANDROID_LOG */
}
- va_end(ap);
#ifdef CONFIG_DEBUG_LINUX_TRACING
if (wpa_debug_tracing_file != NULL) {
@@ -254,7 +256,7 @@ void wpa_printf(int level, const char *fmt, ...)
static void _wpa_hexdump(int level, const char *title, const u8 *buf,
- size_t len, int show)
+ size_t len, int show, int only_syslog)
{
size_t i;
@@ -345,7 +347,8 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
title, (unsigned long) len, display);
bin_clear_free(strbuf, 1 + 3 * len);
- return;
+ if (only_syslog)
+ return;
}
#endif /* CONFIG_DEBUG_SYSLOG */
wpa_debug_print_timestamp();
@@ -362,33 +365,32 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
fprintf(out_file, " [REMOVED]");
}
fprintf(out_file, "\n");
- } else {
-#endif /* CONFIG_DEBUG_FILE */
- printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
- if (buf == NULL) {
- printf(" [NULL]");
- } else if (show) {
- for (i = 0; i < len; i++)
- printf(" %02x", buf[i]);
- } else {
- printf(" [REMOVED]");
- }
- printf("\n");
-#ifdef CONFIG_DEBUG_FILE
}
#endif /* CONFIG_DEBUG_FILE */
+ if (!wpa_debug_syslog && !out_file) {
+ printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
+ if (buf == NULL) {
+ printf(" [NULL]");
+ } else if (show) {
+ for (i = 0; i < len; i++)
+ printf(" %02x", buf[i]);
+ } else {
+ printf(" [REMOVED]");
+ }
+ printf("\n");
+ }
#endif /* CONFIG_ANDROID_LOG */
}
void wpa_hexdump(int level, const char *title, const void *buf, size_t len)
{
- _wpa_hexdump(level, title, buf, len, 1);
+ _wpa_hexdump(level, title, buf, len, 1, 0);
}
void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len)
{
- _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
+ _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys, 0);
}
@@ -421,13 +423,11 @@ static void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
if (level < wpa_debug_level)
return;
#ifdef CONFIG_ANDROID_LOG
- _wpa_hexdump(level, title, buf, len, show);
+ _wpa_hexdump(level, title, buf, len, show, 0);
#else /* CONFIG_ANDROID_LOG */
#ifdef CONFIG_DEBUG_SYSLOG
- if (wpa_debug_syslog) {
- _wpa_hexdump(level, title, buf, len, show);
- return;
- }
+ if (wpa_debug_syslog)
+ _wpa_hexdump(level, title, buf, len, show, 1);
#endif /* CONFIG_DEBUG_SYSLOG */
wpa_debug_print_timestamp();
#ifdef CONFIG_DEBUG_FILE
@@ -436,13 +436,13 @@ static void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
fprintf(out_file,
"%s - hexdump_ascii(len=%lu): [REMOVED]\n",
title, (unsigned long) len);
- return;
+ goto file_done;
}
if (buf == NULL) {
fprintf(out_file,
"%s - hexdump_ascii(len=%lu): [NULL]\n",
title, (unsigned long) len);
- return;
+ goto file_done;
}
fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
title, (unsigned long) len);
@@ -466,42 +466,43 @@ static void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
pos += llen;
len -= llen;
}
- } else {
-#endif /* CONFIG_DEBUG_FILE */
- if (!show) {
- printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
- title, (unsigned long) len);
- return;
}
- if (buf == NULL) {
- printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
- title, (unsigned long) len);
- return;
- }
- printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
- while (len) {
- llen = len > line_len ? line_len : len;
- printf(" ");
- for (i = 0; i < llen; i++)
- printf(" %02x", pos[i]);
- for (i = llen; i < line_len; i++)
+file_done:
+#endif /* CONFIG_DEBUG_FILE */
+ if (!wpa_debug_syslog && !out_file) {
+ if (!show) {
+ printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
+ title, (unsigned long) len);
+ return;
+ }
+ if (buf == NULL) {
+ printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
+ title, (unsigned long) len);
+ return;
+ }
+ printf("%s - hexdump_ascii(len=%lu):\n", title,
+ (unsigned long) len);
+ while (len) {
+ llen = len > line_len ? line_len : len;
+ printf(" ");
+ for (i = 0; i < llen; i++)
+ printf(" %02x", pos[i]);
+ for (i = llen; i < line_len; i++)
+ printf(" ");
printf(" ");
- printf(" ");
- for (i = 0; i < llen; i++) {
- if (isprint(pos[i]))
- printf("%c", pos[i]);
- else
- printf("_");
+ for (i = 0; i < llen; i++) {
+ if (isprint(pos[i]))
+ printf("%c", pos[i]);
+ else
+ printf("_");
+ }
+ for (i = llen; i < line_len; i++)
+ printf(" ");
+ printf("\n");
+ pos += llen;
+ len -= llen;
}
- for (i = llen; i < line_len; i++)
- printf(" ");
- printf("\n");
- pos += llen;
- len -= llen;
- }
-#ifdef CONFIG_DEBUG_FILE
}
-#endif /* CONFIG_DEBUG_FILE */
#endif /* CONFIG_ANDROID_LOG */
}
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index c94c4391..c6d5cc64 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -14,9 +14,7 @@
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
extern int wpa_debug_timestamp;
-#ifdef CONFIG_DEBUG_SYSLOG
extern int wpa_debug_syslog;
-#endif /* CONFIG_DEBUG_SYSLOG */
/* Debugging function - conditional printf and hex dump. Driver wrappers can
* use these for debugging purposes. */
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 9963c468..93888b01 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -98,6 +98,7 @@ struct wps_device_data {
u16 config_methods;
struct wpabuf *vendor_ext_m1;
struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+ struct wpabuf *application_ext;
int p2p;
u8 multi_ap_ext;
@@ -344,6 +345,14 @@ struct wps_registrar_config {
const char *dev_name);
/**
+ * lookup_pskfile_cb - Callback for searching for PSK in wpa_psk_file
+ * @ctx: Higher layer context data (cb_ctx)
+ * @addr: Enrollee's MAC address
+ * @psk: Pointer to found PSK (output arg)
+ */
+ int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk);
+
+ /**
* cb_ctx: Higher layer context data for Registrar callbacks
*/
void *cb_ctx;
@@ -386,11 +395,6 @@ struct wps_registrar_config {
int disable_auto_conf;
/**
- * static_wep_only - Whether the BSS supports only static WEP
- */
- int static_wep_only;
-
- /**
* dualband - Whether this is a concurrent dualband AP
*/
int dualband;
diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c
index b209fea8..c2e949cb 100644
--- a/src/wps/wps_dev_attr.c
+++ b/src/wps/wps_dev_attr.c
@@ -242,6 +242,21 @@ int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg)
}
+int wps_build_application_ext(struct wps_device_data *dev, struct wpabuf *msg)
+{
+ if (!dev->application_ext)
+ return 0;
+
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: * Application Extension",
+ dev->application_ext);
+ wpabuf_put_be16(msg, ATTR_APPLICATION_EXT);
+ wpabuf_put_be16(msg, wpabuf_len(dev->application_ext));
+ wpabuf_put_buf(msg, dev->application_ext);
+
+ return 0;
+}
+
+
static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str,
size_t str_len)
{
@@ -424,4 +439,6 @@ void wps_device_data_free(struct wps_device_data *dev)
dev->model_number = NULL;
os_free(dev->serial_number);
dev->serial_number = NULL;
+ wpabuf_free(dev->application_ext);
+ dev->application_ext = NULL;
}
diff --git a/src/wps/wps_dev_attr.h b/src/wps/wps_dev_attr.h
index a4b4173c..81fdd5f4 100644
--- a/src/wps/wps_dev_attr.h
+++ b/src/wps/wps_dev_attr.h
@@ -33,6 +33,7 @@ void wps_process_vendor_ext_m1(struct wps_device_data *dev, const u8 ext);
int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands);
void wps_device_data_free(struct wps_device_data *dev);
int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_application_ext(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,
unsigned int num_req_dev_types,
const u8 *req_dev_types);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 671f5fed..9ee89ae3 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -17,6 +17,7 @@
#include "crypto/sha256.h"
#include "crypto/random.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_common.h"
#include "wps_i.h"
#include "wps_dev_attr.h"
#include "wps_upnp.h"
@@ -159,6 +160,7 @@ struct wps_registrar {
const u8 *pri_dev_type, u16 config_methods,
u16 dev_password_id, u8 request_type,
const char *dev_name);
+ int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk);
void *cb_ctx;
struct dl_list pins;
@@ -171,7 +173,6 @@ struct wps_registrar {
int sel_reg_union;
int sel_reg_dev_password_id_override;
int sel_reg_config_methods_override;
- int static_wep_only;
int dualband;
int force_per_enrollee_psk;
@@ -681,6 +682,7 @@ wps_registrar_init(struct wps_context *wps,
reg->reg_success_cb = cfg->reg_success_cb;
reg->set_sel_reg_cb = cfg->set_sel_reg_cb;
reg->enrollee_seen_cb = cfg->enrollee_seen_cb;
+ reg->lookup_pskfile_cb = cfg->lookup_pskfile_cb;
reg->cb_ctx = cfg->cb_ctx;
reg->skip_cred_build = cfg->skip_cred_build;
if (cfg->extra_cred) {
@@ -694,7 +696,6 @@ wps_registrar_init(struct wps_context *wps,
reg->disable_auto_conf = cfg->disable_auto_conf;
reg->sel_reg_dev_password_id_override = -1;
reg->sel_reg_config_methods_override = -1;
- reg->static_wep_only = cfg->static_wep_only;
reg->dualband = cfg->dualband;
reg->force_per_enrollee_psk = cfg->force_per_enrollee_psk;
@@ -1290,6 +1291,15 @@ static void wps_cb_set_sel_reg(struct wps_registrar *reg)
}
+static int wps_cp_lookup_pskfile(struct wps_registrar *reg, const u8 *mac_addr,
+ const u8 **psk)
+{
+ if (!reg->lookup_pskfile_cb)
+ return 0;
+ return reg->lookup_pskfile_cb(reg->cb_ctx, mac_addr, psk);
+}
+
+
static int wps_set_ie(struct wps_registrar *reg)
{
struct wpabuf *beacon;
@@ -1331,7 +1341,8 @@ static int wps_set_ie(struct wps_registrar *reg)
wps_build_sel_pbc_reg_uuid_e(reg, beacon) ||
(reg->dualband && wps_build_rf_bands(&reg->wps->dev, beacon, 0)) ||
wps_build_wfa_ext(beacon, 0, auth_macs, count, 0) ||
- wps_build_vendor_ext(&reg->wps->dev, beacon)) {
+ wps_build_vendor_ext(&reg->wps->dev, beacon) ||
+ wps_build_application_ext(&reg->wps->dev, beacon)) {
wpabuf_free(beacon);
wpabuf_free(probe);
return -1;
@@ -1361,7 +1372,8 @@ static int wps_set_ie(struct wps_registrar *reg)
wps_build_probe_config_methods(reg, probe) ||
(reg->dualband && wps_build_rf_bands(&reg->wps->dev, probe, 0)) ||
wps_build_wfa_ext(probe, 0, auth_macs, count, 0) ||
- wps_build_vendor_ext(&reg->wps->dev, probe)) {
+ wps_build_vendor_ext(&reg->wps->dev, probe) ||
+ wps_build_application_ext(&reg->wps->dev, probe)) {
wpabuf_free(beacon);
wpabuf_free(probe);
return -1;
@@ -1376,28 +1388,6 @@ static int wps_set_ie(struct wps_registrar *reg)
return -1;
}
- if (reg->static_wep_only) {
- /*
- * Windows XP and Vista clients can get confused about
- * EAP-Identity/Request when they probe the network with
- * EAPOL-Start. In such a case, they may assume the network is
- * using IEEE 802.1X and prompt user for a certificate while
- * the correct (non-WPS) behavior would be to ask for the
- * static WEP key. As a workaround, use Microsoft Provisioning
- * IE to advertise that legacy 802.1X is not supported.
- */
- const u8 ms_wps[7] = {
- WLAN_EID_VENDOR_SPECIFIC, 5,
- /* Microsoft Provisioning IE (00:50:f2:5) */
- 0x00, 0x50, 0xf2, 5,
- 0x00 /* no legacy 802.1X or MS WPS */
- };
- wpa_printf(MSG_DEBUG, "WPS: Add Microsoft Provisioning IE "
- "into Beacon/Probe Response frames");
- wpabuf_put_data(beacon, ms_wps, sizeof(ms_wps));
- wpabuf_put_data(probe, ms_wps, sizeof(ms_wps));
- }
-
return wps_cb_set_ie(reg, beacon, probe);
}
@@ -1642,6 +1632,8 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
{
struct wpabuf *cred;
struct wps_registrar *reg = wps->wps->registrar;
+ const u8 *pskfile_psk;
+ char hex[65];
if (wps->wps->registrar->skip_cred_build)
goto skip_cred_build;
@@ -1757,23 +1749,27 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
wps->new_psk, wps->new_psk_len);
os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len);
wps->cred.key_len = wps->new_psk_len;
+ } else if (wps_cp_lookup_pskfile(reg, wps->mac_addr_e, &pskfile_psk)) {
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Use PSK from wpa_psk_file",
+ pskfile_psk, PMK_LEN);
+ wpa_snprintf_hex(hex, sizeof(hex), pskfile_psk, PMK_LEN);
+ os_memcpy(wps->cred.key, hex, PMK_LEN * 2);
+ wps->cred.key_len = PMK_LEN * 2;
} else if (!wps->wps->registrar->force_per_enrollee_psk &&
wps->use_psk_key && wps->wps->psk_set) {
- char hex[65];
wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key");
- wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, 32);
- os_memcpy(wps->cred.key, hex, 32 * 2);
- wps->cred.key_len = 32 * 2;
+ wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, PMK_LEN);
+ os_memcpy(wps->cred.key, hex, PMK_LEN * 2);
+ wps->cred.key_len = PMK_LEN * 2;
} else if (!wps->wps->registrar->force_per_enrollee_psk &&
wps->wps->network_key) {
os_memcpy(wps->cred.key, wps->wps->network_key,
wps->wps->network_key_len);
wps->cred.key_len = wps->wps->network_key_len;
} else if (wps->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
- char hex[65];
/* Generate a random per-device PSK */
os_free(wps->new_psk);
- wps->new_psk_len = 32;
+ wps->new_psk_len = PMK_LEN;
wps->new_psk = os_malloc(wps->new_psk_len);
if (wps->new_psk == NULL)
return -1;
@@ -3482,6 +3478,7 @@ static void wps_registrar_set_selected_timeout(void *eloop_ctx,
"unselect internal Registrar");
reg->selected_registrar = 0;
reg->pbc = 0;
+ wps_registrar_expire_pins(reg);
wps_registrar_selected_registrar_changed(reg, 0);
}
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 309127ec..65c639b6 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -124,6 +124,7 @@ OBJS += src/utils/wpa_debug.c
OBJS += src/utils/wpabuf.c
OBJS += src/utils/bitfield.c
OBJS += src/utils/ip_addr.c
+OBJS += src/utils/crc32.c
OBJS += wmm_ac.c
OBJS += op_classes.c
OBJS += rrm.c
@@ -195,6 +196,10 @@ ifdef CONFIG_VHT_OVERRIDES
L_CFLAGS += -DCONFIG_VHT_OVERRIDES
endif
+ifdef CONFIG_HE_OVERRIDES
+L_CFLAGS += -DCONFIG_HE_OVERRIDES
+endif
+
ifndef CONFIG_BACKEND
CONFIG_BACKEND=file
endif
@@ -282,6 +287,7 @@ NEED_ECC=y
NEED_JSON=y
NEED_GAS_SERVER=y
NEED_BASE64=y
+NEED_ASN1=y
ifdef CONFIG_DPP2
L_CFLAGS += -DCONFIG_DPP2
endif
@@ -410,6 +416,10 @@ OBJS += src/fst/fst_ctrl_iface.c
endif
endif
+ifdef CONFIG_WEP
+L_CFLAGS += -DCONFIG_WEP
+endif
+
include $(LOCAL_PATH)/src/drivers/drivers.mk
@@ -890,7 +900,6 @@ OBJS += src/ap/bss_load.c
OBJS += src/ap/eap_user_db.c
OBJS += src/ap/neighbor_db.c
OBJS += src/ap/rrm.c
-ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c
ifdef CONFIG_IEEE80211AC
OBJS += src/ap/ieee802_11_vht.c
@@ -898,7 +907,6 @@ endif
ifdef CONFIG_IEEE80211AX
OBJS += src/ap/ieee802_11_he.c
endif
-endif
ifdef CONFIG_WNM_AP
L_CFLAGS += -DCONFIG_WNM_AP
OBJS += src/ap/wnm_ap.c
@@ -918,15 +926,12 @@ OBJS += src/eap_server/eap_server.c
OBJS += src/eap_server/eap_server_identity.c
OBJS += src/eap_server/eap_server_methods.c
-ifdef CONFIG_IEEE80211N
-L_CFLAGS += -DCONFIG_IEEE80211N
ifdef CONFIG_IEEE80211AC
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
ifdef CONFIG_IEEE80211AX
L_CFLAGS += -DCONFIG_IEEE80211AX
endif
-endif
ifdef NEED_AP_MLME
OBJS += src/ap/wmm.c
@@ -1123,7 +1128,7 @@ OBJS += src/tls/tlsv1_client.c
OBJS += src/tls/tlsv1_client_write.c
OBJS += src/tls/tlsv1_client_read.c
OBJS += src/tls/tlsv1_client_ocsp.c
-OBJS += src/tls/asn1.c
+NEED_ASN1=y
OBJS += src/tls/rsa.c
OBJS += src/tls/x509v3.c
OBJS += src/tls/pkcs1.c
@@ -1413,6 +1418,10 @@ endif
OBJS += src/crypto/sha512-prf.c
endif
+ifdef NEED_ASN1
+OBJS += src/tls/asn1.c
+endif
+
ifdef NEED_DH_GROUPS
OBJS += src/crypto/dh_groups.c
endif
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 68ef5a2f..45f673ee 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -104,6 +104,7 @@ OBJS += ../src/utils/wpa_debug.o
OBJS += ../src/utils/wpabuf.o
OBJS += ../src/utils/bitfield.o
OBJS += ../src/utils/ip_addr.o
+OBJS += ../src/utils/crc32.o
OBJS += op_classes.o
OBJS += rrm.o
OBJS_p = wpa_passphrase.o
@@ -197,6 +198,10 @@ ifdef CONFIG_VHT_OVERRIDES
CFLAGS += -DCONFIG_VHT_OVERRIDES
endif
+ifdef CONFIG_HE_OVERRIDES
+CFLAGS += -DCONFIG_HE_OVERRIDES
+endif
+
ifndef CONFIG_BACKEND
CONFIG_BACKEND=file
endif
@@ -284,6 +289,7 @@ NEED_ECC=y
NEED_JSON=y
NEED_GAS_SERVER=y
NEED_BASE64=y
+NEED_ASN1=y
ifdef CONFIG_DPP2
CFLAGS += -DCONFIG_DPP2
endif
@@ -906,7 +912,6 @@ OBJS += ../src/ap/bss_load.o
OBJS += ../src/ap/eap_user_db.o
OBJS += ../src/ap/neighbor_db.o
OBJS += ../src/ap/rrm.o
-ifdef CONFIG_IEEE80211N
OBJS += ../src/ap/ieee802_11_ht.o
ifdef CONFIG_IEEE80211AC
OBJS += ../src/ap/ieee802_11_vht.o
@@ -914,7 +919,6 @@ endif
ifdef CONFIG_IEEE80211AX
OBJS += ../src/ap/ieee802_11_he.o
endif
-endif
ifdef CONFIG_WNM_AP
CFLAGS += -DCONFIG_WNM_AP
OBJS += ../src/ap/wnm_ap.o
@@ -934,15 +938,12 @@ OBJS += ../src/eap_server/eap_server.o
OBJS += ../src/eap_server/eap_server_identity.o
OBJS += ../src/eap_server/eap_server_methods.o
-ifdef CONFIG_IEEE80211N
-CFLAGS += -DCONFIG_IEEE80211N
ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC
endif
ifdef CONFIG_IEEE80211AX
CFLAGS += -DCONFIG_IEEE80211AX
endif
-endif
ifdef NEED_AP_MLME
OBJS += ../src/ap/wmm.o
@@ -1156,12 +1157,12 @@ OBJS += ../src/tls/tlsv1_client.o
OBJS += ../src/tls/tlsv1_client_write.o
OBJS += ../src/tls/tlsv1_client_read.o
OBJS += ../src/tls/tlsv1_client_ocsp.o
-OBJS += ../src/tls/asn1.o
OBJS += ../src/tls/rsa.o
OBJS += ../src/tls/x509v3.o
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
+NEED_ASN1=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -1235,12 +1236,12 @@ OBJS += ../src/tls/tlsv1_client.o
OBJS += ../src/tls/tlsv1_client_write.o
OBJS += ../src/tls/tlsv1_client_read.o
OBJS += ../src/tls/tlsv1_client_ocsp.o
-OBJS += ../src/tls/asn1.o
OBJS += ../src/tls/rsa.o
OBJS += ../src/tls/x509v3.o
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
+NEED_ASN1=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -1523,6 +1524,10 @@ CFLAGS += -DCONFIG_SHA512
OBJS += ../src/crypto/sha512-prf.o
endif
+ifdef NEED_ASN1
+OBJS += ../src/tls/asn1.o
+endif
+
ifdef NEED_DH_GROUPS
OBJS += ../src/crypto/dh_groups.o
endif
@@ -1846,6 +1851,10 @@ OBJS_t2 += $(FST_OBJS)
OBJS_nfc += $(FST_OBJS)
endif
+ifdef CONFIG_WEP
+CFLAGS += -DCONFIG_WEP
+endif
+
ifndef LDO
LDO=$(CC)
endif
diff --git a/wpa_supplicant/README-DPP b/wpa_supplicant/README-DPP
index 457e32ee..d378245c 100644
--- a/wpa_supplicant/README-DPP
+++ b/wpa_supplicant/README-DPP
@@ -9,40 +9,44 @@ Connector mechanism.
Introduction to DPP
-------------------
-Device provisioning Protocol allows enrolling of interface-less devices
-in a secure Wi-Fi network using many methods like QR code based
-authentication( detailed below ), PKEX based authentication etc. In DPP
-a Configurator is used to provide network credentials to the devices.
-The three phases of DPP connection are authentication, configuration and
+Device Provisioning Protocol (also known as Wi-Fi Easy Connect) allows
+enrolling of interface-less devices in a secure Wi-Fi network using many
+methods like QR code based authentication (detailed below), PKEX based
+authentication (password with in-band provisioning), etc. In DPP a
+Configurator is used to provide network credentials to the devices. The
+three phases of DPP connection are authentication, configuration and
network introduction.
+More information about Wi-Fi Easy Connect is available from this Wi-Fi
+Alliance web page:
+https://www.wi-fi.org/discover-wi-fi/wi-fi-easy-connect
+
Build config setup
------------------
-The following changes must go in the config file used to compile hostapd
-and wpa_supplicant.
+The following parameters must be included in the config file used to
+compile hostapd and wpa_supplicant.
wpa_supplicant build config
---------------------------
-Enable DPP and protected management frame in wpa_supplicant build config
-file
+Enable DPP in wpa_supplicant build config file
CONFIG_DPP=y
hostapd build config
--------------------
-Enable DPP and protected management frame in hostapd build config file
+Enable DPP in hostapd build config file
CONFIG_DPP=y
Configurator build config
-------------------------
-Any STA or AP device can act as a Configurator. Enable DPP and protected
-managment frames in build config. For an AP to act as Configurator,
-Interworking needs to be enabled. For wpa_supplicant it is not required.
+Any STA or AP device can act as a Configurator. Enable DPP in build
+config. For an AP to act as a Configurator, Interworking needs to be
+enabled for GAS. For wpa_supplicant it is not required.
CONFIG_INTERWORKING=y
@@ -90,41 +94,46 @@ To get key of Configurator
> dpp_configurator_get_key <id>
-How to configure an enrollee using Configurator
+How to configure an Enrollee using Configurator
-----------------------------------------------
-On enrollee side:
+On Enrollee side:
-Generate QR code for the device. Store the qr code id returned by the
+Generate QR code for the device. Store the QR code id returned by the
command.
-> dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-class/operating-channel> key=<key of the device>
-(returns bootstrapping info id)
+> dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-class/channel> key=<key of the device>
+(Returns bootstrapping info id. If the key parameter is not included, a new key
+is generated automatically. The MAC address is specified without octet
+separating colons. The channel list includes the possible channels on which the
+device is waiting. This uses global operating classes; e.g., 81/1 is the 2.4
+GHz channel 1 on 2412 MHz.)
-Get QR Code of device using the bootstrap info id.
+Get URI for the QR Code of device using the bootstrap info id.
> dpp_bootstrap_get_uri <bootstrap-id>
-Make device listen to DPP request (The central frequency of channel 1 is
-2412) in case if enrollee is a client device.
+Make device listen to DPP request. The central frequency of the 2.4 GHz
+band channel 1 is 2412 MHz) in case the Enrollee is a client device. An
+AP as an Enrollee is listening on its operating channel.
> dpp_listen <frequency>
On Configurator side:
Enter the QR Code in the Configurator.
-> dpp_qr_code "<QR-Code-read-from-enrollee>"
+> dpp_qr_code "<URI-from-QR-Code-read-from-enrollee>"
On successfully adding QR Code, a bootstrapping info id is returned.
-Send provisioning request to enrollee. (conf is ap-dpp if enrollee is an
-AP. conf is sta-dpp if enrollee is a client)
+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> 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
-values to the hostapd config file. If the enrollee is a client device,
+The DPP values will be printed in the console. Save these values into the
+config file. If the Enrollee is an AP, we need to manually write these
+values to the hostapd config file. If the Enrollee is a client device,
these details can be automatically saved to config file using the
following command.
@@ -156,7 +165,7 @@ command to get DPP credentials.
> dpp_configurator_add
(returns configurator id)
-> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id>
+> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id> ssid=<SSID hexdump>
Sample AP configuration files after provisioning
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index acefc926..5f8c8f6c 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -435,11 +435,7 @@ CONFIG_ANDROID_LOG=y
# either wpa_supplicant or hostapd are run.
CONFIG_NO_RANDOM_POOL=y
-# IEEE 802.11n (High Throughput) support (mainly for AP mode)
-CONFIG_IEEE80211N=y
-
# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
-# (depends on CONFIG_IEEE80211N)
#CONFIG_IEEE80211AC=y
# Wireless Network Management (IEEE Std 802.11v-2011)
@@ -552,4 +548,12 @@ CONFIG_SUITEB192=y
# Note: does not configure WAPI implementation itself.
#CONFIG_WAPI_INTERFACE=y
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current wpa_supplicant
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+CONFIG_WEP=y
+
include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index e552306d..62416820 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -44,7 +44,6 @@ static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
#endif /* CONFIG_WPS */
-#ifdef CONFIG_IEEE80211N
static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct hostapd_config *conf,
@@ -130,7 +129,6 @@ no_vht:
conf->channel + conf->secondary_channel * 2;
conf->vht_oper_chwidth = CHANWIDTH_USE_HT;
}
-#endif /* CONFIG_IEEE80211N */
int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
@@ -149,7 +147,6 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
/* TODO: enable HT40 if driver supports it;
* drop to 11b if driver does not support 11g */
-#ifdef CONFIG_IEEE80211N
/*
* Enable HT20 if the driver supports it, by setting conf->ieee80211n
* and a mask of allowed capabilities within conf->ht_capab.
@@ -269,7 +266,6 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
conf->no_pri_sec_switch = 1;
}
}
-#endif /* CONFIG_IEEE80211N */
return 0;
}
@@ -348,7 +344,9 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_IEEE80211AX */
bss->isolate = !wpa_s->conf->p2p_intra_bss;
+ bss->extended_key_id = wpa_s->conf->extended_key_id;
bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk;
+ bss->wpa_deny_ptk0_rekey = ssid->wpa_deny_ptk0_rekey;
if (ssid->p2p_group) {
os_memcpy(bss->ip_addr_go, wpa_s->p2pdev->conf->ip_addr_go, 4);
@@ -393,6 +391,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->ssid.wpa_psk_set = 1;
} else if (ssid->passphrase) {
bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
+#ifdef CONFIG_WEP
} else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
ssid->wep_key_len[2] || ssid->wep_key_len[3]) {
struct hostapd_wep_keys *wep = &bss->ssid.wep;
@@ -408,6 +407,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
}
wep->idx = ssid->wep_tx_keyidx;
wep->keys_set = 1;
+#endif /* CONFIG_WEP */
}
#ifdef CONFIG_SAE
if (ssid->sae_password) {
@@ -489,11 +489,12 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
bss->rsn_pairwise);
- if (bss->wpa && bss->ieee802_1x)
+ if (bss->wpa && bss->ieee802_1x) {
bss->ssid.security_policy = SECURITY_WPA;
- else if (bss->wpa)
+ } else if (bss->wpa) {
bss->ssid.security_policy = SECURITY_WPA_PSK;
- else if (bss->ieee802_1x) {
+#ifdef CONFIG_WEP
+ } else if (bss->ieee802_1x) {
int cipher = WPA_CIPHER_NONE;
bss->ssid.security_policy = SECURITY_IEEE_802_1X;
bss->ssid.wep.default_len = bss->default_wep_key_len;
@@ -511,6 +512,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->wpa_group = cipher;
bss->wpa_pairwise = cipher;
bss->rsn_pairwise = cipher;
+#endif /* CONFIG_WEP */
} else {
bss->ssid.security_policy = SECURITY_PLAINTEXT;
bss->wpa_group = WPA_CIPHER_NONE;
@@ -605,6 +607,8 @@ no_wps:
bss->ftm_responder = wpa_s->conf->ftm_responder;
bss->ftm_initiator = wpa_s->conf->ftm_initiator;
+ bss->transition_disable = ssid->transition_disable;
+
return 0;
}
@@ -839,7 +843,6 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
return -1;
hapd_iface->owner = wpa_s;
hapd_iface->drv_flags = wpa_s->drv_flags;
- hapd_iface->smps_modes = wpa_s->drv_smps_modes;
hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
hapd_iface->extended_capa = wpa_s->extended_capa;
hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 943a3408..127f43e5 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -906,7 +906,7 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
}
}
- wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
+ wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%zu/%zu",
wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
}
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 3ce8cd3f..07167617 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -18,6 +18,7 @@ struct wpa_scan_res;
#define WPA_BSS_AUTHENTICATED BIT(4)
#define WPA_BSS_ASSOCIATED BIT(5)
#define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
+#define WPA_BSS_OWE_TRANSITION BIT(7)
struct wpa_bss_anqp_elem {
struct dl_list list;
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 2d1c126e..e1d98249 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1856,6 +1856,8 @@ static char * wpa_config_write_machine_password(const struct parse_data *data,
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
+
static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
const char *value, int idx)
{
@@ -1966,6 +1968,8 @@ static char * wpa_config_write_wep_key3(const struct parse_data *data,
}
#endif /* NO_CONFIG_WRITE */
+#endif /* CONFIG_WEP */
+
#ifdef CONFIG_P2P
@@ -2451,11 +2455,13 @@ static const struct parse_data ssid_fields[] = {
{ STRe(openssl_ciphers, openssl_ciphers) },
{ INTe(erp, erp) },
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
{ FUNC_KEY(wep_key0) },
{ FUNC_KEY(wep_key1) },
{ FUNC_KEY(wep_key2) },
{ FUNC_KEY(wep_key3) },
{ INT(wep_tx_keyidx) },
+#endif /* CONFIG_WEP */
{ INT(priority) },
#ifdef IEEE8021X_EAPOL
{ INT(eap_workaround) },
@@ -2495,6 +2501,7 @@ static const struct parse_data ssid_fields[] = {
{ INT(dot11MeshHoldingTimeout) },
#endif /* CONFIG_MESH */
{ INT(wpa_ptk_rekey) },
+ { INT_RANGE(wpa_deny_ptk0_rekey, 0, 2) },
{ INT(group_rekey) },
{ STR(bgscan) },
{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
@@ -2537,6 +2544,9 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(vht_tx_mcs_nss_7, -1, 3) },
{ INT_RANGE(vht_tx_mcs_nss_8, -1, 3) },
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ { INT_RANGE(disable_he, 0, 1)},
+#endif /* CONFIG_HE_OVERRIDES */
{ INT(ap_max_inactivity) },
{ INT(dtim_period) },
{ INT(beacon_int) },
@@ -2563,11 +2573,15 @@ static const struct parse_data ssid_fields[] = {
{ STR_LEN(dpp_netaccesskey) },
{ INT(dpp_netaccesskey_expiry) },
{ STR_LEN(dpp_csign) },
+ { INT_RANGE(dpp_pfs, 0, 2) },
#endif /* CONFIG_DPP */
{ INT_RANGE(owe_group, 0, 65535) },
{ INT_RANGE(owe_only, 0, 1) },
+ { INT_RANGE(owe_ptk_workaround, 0, 1) },
{ INT_RANGE(multi_ap_backhaul_sta, 0, 1) },
{ INT_RANGE(ft_eap_pmksa_caching, 0, 1) },
+ { INT_RANGE(beacon_prot, 0, 1) },
+ { INT_RANGE(transition_disable, 0, 255) },
};
#undef OFFSET
@@ -2603,7 +2617,7 @@ static const struct parse_data ssid_fields[] = {
int wpa_config_add_prio_network(struct wpa_config *config,
struct wpa_ssid *ssid)
{
- int prio;
+ size_t prio;
struct wpa_ssid *prev, **nlist;
/*
@@ -3018,6 +3032,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
ssid->pairwise_cipher = DEFAULT_PAIRWISE;
ssid->group_cipher = DEFAULT_GROUP;
ssid->key_mgmt = DEFAULT_KEY_MGMT;
+ ssid->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
ssid->ht = 1;
#ifdef IEEE8021X_EAPOL
@@ -4283,6 +4298,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
config->cert_in_cb = DEFAULT_CERT_IN_CB;
config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
+ config->extended_key_id = DEFAULT_EXTENDED_KEY_ID;
#ifdef CONFIG_MBO
config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA;
@@ -4308,7 +4324,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
*/
void wpa_config_debug_dump_networks(struct wpa_config *config)
{
- int prio;
+ size_t prio;
struct wpa_ssid *ssid;
for (prio = 0; prio < config->num_prio; prio++) {
@@ -4639,7 +4655,7 @@ static int wpa_config_process_p2p_pref_chan(
struct wpa_config *config, int line, const char *pos)
{
struct p2p_channel *pref = NULL, *n;
- unsigned int num = 0;
+ size_t num = 0;
const char *pos2;
u8 op_class, chan;
@@ -4997,7 +5013,7 @@ static const struct global_parse_data global_fields[] = {
{ INT(okc), 0 },
{ INT(pmf), 0 },
{ FUNC(sae_groups), 0 },
- { INT_RANGE(sae_pwe, 0, 2), 0 },
+ { INT_RANGE(sae_pwe, 0, 3), 0 },
{ INT_RANGE(sae_pmkid_in_assoc, 0, 1), 0 },
{ INT(dtim_period), 0 },
{ INT(beacon_int), 0 },
@@ -5047,6 +5063,7 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(bss_no_flush_when_down, 0, 1), 0 },
#ifdef CONFIG_WNM
{ INT_RANGE(disable_btm, 0, 1), CFG_CHANGED_DISABLE_BTM },
+ { INT_RANGE(extended_key_id, 0, 1), 0 },
#endif /* CONFIG_WNM */
};
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index d00c4ec0..0ca27cb3 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -44,6 +44,7 @@
#define DEFAULT_MBO_CELL_CAPA MBO_CELL_CAPA_NOT_SUPPORTED
#define DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD -75
#define DEFAULT_OCE_SUPPORT OCE_STA
+#define DEFAULT_EXTENDED_KEY_ID 0
#include "config_ssid.h"
#include "wps/wps.h"
@@ -332,7 +333,7 @@ struct wpa_cred {
*/
unsigned int max_bss_load;
- unsigned int num_req_conn_capab;
+ size_t num_req_conn_capab;
u8 *req_conn_capab_proto;
int **req_conn_capab_port;
@@ -403,7 +404,7 @@ struct wpa_config {
* This indicates how many per-priority network lists are included in
* pssid.
*/
- int num_prio;
+ size_t num_prio;
/**
* cred - Head of the credential list
@@ -1578,6 +1579,17 @@ struct wpa_config {
* By default BSS transition management is enabled
*/
int disable_btm;
+
+ /**
+ * extended_key_id - Extended Key ID support
+ *
+ * IEEE Std 802.11-2016 optionally allows to use Key ID 0 and 1 for PTK
+ * keys with Extended Key ID.
+ *
+ * 0 = don't use Extended Key ID
+ * 1 = use Extended Key ID when possible
+ */
+ int extended_key_id;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 305291eb..52e1372e 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -213,8 +213,22 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
}
}
- if (wpa_config_set(ssid, pos, pos2, *line) < 0)
+ if (wpa_config_set(ssid, pos, pos2, *line) < 0) {
+#ifndef CONFIG_WEP
+ if (os_strcmp(pos, "wep_key0") == 0 ||
+ os_strcmp(pos, "wep_key1") == 0 ||
+ os_strcmp(pos, "wep_key2") == 0 ||
+ os_strcmp(pos, "wep_key3") == 0 ||
+ os_strcmp(pos, "wep_tx_keyidx") == 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: unsupported WEP parameter",
+ *line);
+ ssid->disabled = 1;
+ continue;
+ }
+#endif /* CONFIG_WEP */
errors++;
+ }
}
if (!end) {
@@ -653,6 +667,7 @@ static void write_eap(FILE *f, struct wpa_ssid *ssid)
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
{
char field[20], *value;
@@ -667,6 +682,7 @@ static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
os_free(value);
}
}
+#endif /* CONFIG_WEP */
#ifdef CONFIG_P2P
@@ -741,8 +757,6 @@ static void write_mka_ckn(FILE *f, struct wpa_ssid *ssid)
static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
{
- int i;
-
#define STR(t) write_str(f, #t, ssid)
#define INT(t) write_int(f, #t, ssid->t, 0)
#define INTe(t, m) write_int(f, #t, ssid->eap.m, 0)
@@ -831,9 +845,15 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(openssl_ciphers);
INTe(erp, erp);
#endif /* IEEE8021X_EAPOL */
- for (i = 0; i < 4; i++)
- write_wep_key(f, i, ssid);
- INT(wep_tx_keyidx);
+#ifdef CONFIG_WEP
+ {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ write_wep_key(f, i, ssid);
+ INT(wep_tx_keyidx);
+ }
+#endif /* CONFIG_WEP */
INT(priority);
#ifdef IEEE8021X_EAPOL
INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
@@ -900,6 +920,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT_DEF(mesh_rssi_threshold, DEFAULT_MESH_RSSI_THRESHOLD);
#endif /* CONFIG_MESH */
INT(wpa_ptk_rekey);
+ INT(wpa_deny_ptk0_rekey);
INT(group_rekey);
INT(ignore_broadcast_ssid);
#ifdef CONFIG_DPP
@@ -907,11 +928,15 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(dpp_netaccesskey);
INT(dpp_netaccesskey_expiry);
STR(dpp_csign);
+ INT(dpp_pfs);
#endif /* CONFIG_DPP */
INT(owe_group);
INT(owe_only);
+ INT(owe_ptk_workaround);
INT(multi_ap_backhaul_sta);
INT(ft_eap_pmksa_caching);
+ INT(beacon_prot);
+ INT(transition_disable);
#ifdef CONFIG_HT_OVERRIDES
INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40);
@@ -946,6 +971,9 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT_DEF(vht_tx_mcs_nss_7, -1);
INT_DEF(vht_tx_mcs_nss_8, -1);
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ INT(disable_he);
+#endif /* CONFIG_HE_OVERRIDES */
#undef STR
#undef INT
@@ -1576,6 +1604,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
config->bss_no_flush_when_down);
if (config->disable_btm)
fprintf(f, "disable_btm=1\n");
+ if (config->extended_key_id != DEFAULT_EXTENDED_KEY_ID)
+ fprintf(f, "extended_key_id=%d\n",
+ config->extended_key_id);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
@@ -1592,9 +1623,16 @@ int wpa_config_write(const char *name, struct wpa_config *config)
#endif /* CONFIG_NO_CONFIG_BLOBS */
int ret = 0;
const char *orig_name = name;
- int tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */
- char *tmp_name = os_malloc(tmp_len);
+ int tmp_len;
+ char *tmp_name;
+
+ if (!name) {
+ wpa_printf(MSG_ERROR, "No configuration file for writing");
+ return -1;
+ }
+ tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */
+ tmp_name = os_malloc(tmp_len);
if (tmp_name) {
os_snprintf(tmp_name, tmp_len, "%s.tmp", name);
name = tmp_name;
@@ -1622,8 +1660,11 @@ int wpa_config_write(const char *name, struct wpa_config *config)
for (ssid = config->ssid; ssid; ssid = ssid->next) {
if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary)
continue; /* do not save temporary networks */
- if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
- !ssid->passphrase)
+ if (wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt) &&
+ !ssid->psk_set && !ssid->passphrase)
+ continue; /* do not save invalid network */
+ if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ !ssid->passphrase && !ssid->sae_password)
continue; /* do not save invalid network */
fprintf(f, "\nnetwork={\n");
wpa_config_write_network(f, ssid);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index af8317bd..a186ab9f 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -299,6 +299,7 @@ struct wpa_ssid {
struct eap_peer_config eap;
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
#define NUM_WEP_KEYS 4
#define MAX_WEP_KEY_LEN 16
/**
@@ -315,6 +316,7 @@ struct wpa_ssid {
* wep_tx_keyidx - Default key index for TX frames using WEP
*/
int wep_tx_keyidx;
+#endif /* CONFIG_WEP */
/**
* proactive_key_caching - Enable proactive key caching
@@ -552,6 +554,19 @@ struct wpa_ssid {
*/
int wpa_ptk_rekey;
+ /** wpa_deny_ptk0_rekey - Control PTK0 rekeying
+ *
+ * Rekeying a pairwise key using only keyid 0 (PTK0 rekey) has many
+ * broken implementations and should be avoided when using or
+ * interacting with one.
+ *
+ * 0 = always rekey when configured/instructed
+ * 1 = only rekey when the local driver is explicitly indicating it can
+ * perform this operation without issues
+ * 2 = never allow PTK0 rekeys
+ */
+ enum ptk0_rekey_handling wpa_deny_ptk0_rekey;
+
/**
* group_rekey - Group rekeying time in seconds
*
@@ -763,6 +778,16 @@ struct wpa_ssid {
vht_tx_mcs_nss_7, vht_tx_mcs_nss_8;
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ /**
+ * disable_he - Disable HE (IEEE 802.11ax) for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_he;
+#endif /* CONFIG_HE_OVERRIDES */
+
/**
* ap_max_inactivity - Timeout in seconds to detect STA's inactivity
*
@@ -987,6 +1012,22 @@ struct wpa_ssid {
size_t dpp_csign_len;
/**
+ * dpp_pfs - DPP PFS
+ * 0: allow PFS to be used or not used
+ * 1: require PFS to be used (note: not compatible with DPP R1)
+ * 2: do not allow PFS to be used
+ */
+ int dpp_pfs;
+
+ /**
+ * dpp_pfs_fallback - DPP PFS fallback selection
+ *
+ * This is an internally used variable (i.e., not used in external
+ * configuration) to track state of the DPP PFS fallback mechanism.
+ */
+ int dpp_pfs_fallback;
+
+ /**
* owe_group - OWE DH Group
*
* 0 = use default (19) first and then try all supported groups one by
@@ -1008,6 +1049,19 @@ struct wpa_ssid {
int owe_only;
/**
+ * owe_ptk_workaround - OWE PTK derivation workaround
+ *
+ * Initial OWE implementation used SHA256 when deriving the PTK for all
+ * OWE groups. This was supposed to change to SHA384 for group 20 and
+ * SHA512 for group 21. This parameter can be used to enable older
+ * behavior mainly for testing purposes. There is no impact to group 19
+ * behavior, but if enabled, this will make group 20 and 21 cases use
+ * SHA256-based PTK derivation which will not work with the updated
+ * OWE implementation on the AP side.
+ */
+ int owe_ptk_workaround;
+
+ /**
* owe_transition_bss_select_count - OWE transition BSS select count
*
* This is an internally used variable (i.e., not used in external
@@ -1033,6 +1087,34 @@ struct wpa_ssid {
* FT initial mobility domain association.
*/
int ft_eap_pmksa_caching;
+
+ /**
+ * beacon_prot - Whether Beacon protection is enabled
+ *
+ * This depends on management frame protection (ieee80211w) being
+ * enabled.
+ */
+ int beacon_prot;
+
+ /**
+ * transition_disable - Transition Disable indication
+ * The AP can notify authenticated stations to disable transition mode
+ * in their network profiles when the network has completed transition
+ * steps, i.e., once sufficiently large number of APs in the ESS have
+ * been updated to support the more secure alternative. When this
+ * indication is used, the stations are expected to automatically
+ * disable transition mode and less secure security options. This
+ * includes use of WEP, TKIP (including use of TKIP as the group
+ * cipher), and connections without PMF.
+ * Bitmap bits:
+ * bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK
+ * and only allow SAE to be used)
+ * bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK)
+ * bit 2 (0x04): WPA3-Enterprise (move to requiring PMF)
+ * bit 3 (0x08): Enhanced Open (disable use of open network; require
+ * OWE)
+ */
+ u8 transition_disable;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 0f2a30a4..1b7f96ed 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -277,6 +277,15 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc);
wpa_config_read_reg_dword(hk, TEXT("pmf"), &val);
config->pmf = val;
+ if (wpa_config_read_reg_dword(hk, TEXT("extended_key_id"),
+ &val) == 0) {
+ if (val < 0 || val > 1) {
+ wpa_printf(MSG_ERROR,
+ "Invalid Extended Key ID setting (%d)", val);
+ errors++;
+ }
+ config->extended_key_id = val;
+ }
return errors ? -1 : 0;
}
@@ -823,6 +832,7 @@ static void write_eap(HKEY hk, struct wpa_ssid *ssid)
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid)
{
char field[20], *value;
@@ -834,11 +844,12 @@ static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid)
os_free(value);
}
}
+#endif /* CONFIG_WEP */
static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
{
- int i, errors = 0;
+ int errors = 0;
HKEY nhk, netw;
LONG ret;
TCHAR name[5];
@@ -924,9 +935,15 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
INTe(engine2, phase2_cert.engine);
INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
#endif /* IEEE8021X_EAPOL */
- for (i = 0; i < 4; i++)
- write_wep_key(netw, i, ssid);
- INT(wep_tx_keyidx);
+#ifdef CONFIG_WEP
+ {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ write_wep_key(netw, i, ssid);
+ INT(wep_tx_keyidx);
+ }
+#endif /* CONFIG_WEP */
INT(priority);
#ifdef IEEE8021X_EAPOL
INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index be5ea17b..7301d50f 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -419,6 +419,64 @@ static int wpas_ctrl_iface_set_ric_ies(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_TESTING_OPTIONS
+static int wpas_ctrl_iface_set_dso(struct wpa_supplicant *wpa_s,
+ const char *val)
+{
+ u8 bssid[ETH_ALEN];
+ const char *pos = val;
+ struct driver_signal_override *dso = NULL, *tmp, parsed;
+
+ if (hwaddr_aton(pos, bssid))
+ return -1;
+ pos = os_strchr(pos, ' ');
+
+ dl_list_for_each(tmp, &wpa_s->drv_signal_override,
+ struct driver_signal_override, list) {
+ if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) {
+ dso = tmp;
+ break;
+ }
+ }
+
+ if (!pos) {
+ /* Remove existing entry */
+ if (dso) {
+ dl_list_del(&dso->list);
+ os_free(dso);
+ }
+ return 0;
+ }
+ pos++;
+
+ /* Update an existing entry or add a new one */
+ os_memset(&parsed, 0, sizeof(parsed));
+ if (sscanf(pos, "%d %d %d %d %d",
+ &parsed.si_current_signal,
+ &parsed.si_avg_signal,
+ &parsed.si_avg_beacon_signal,
+ &parsed.si_current_noise,
+ &parsed.scan_level) != 5)
+ return -1;
+
+ if (!dso) {
+ dso = os_zalloc(sizeof(*dso));
+ if (!dso)
+ return -1;
+ os_memcpy(dso->bssid, bssid, ETH_ALEN);
+ dl_list_add(&wpa_s->drv_signal_override, &dso->list);
+ }
+ dso->si_current_signal = parsed.si_current_signal;
+ dso->si_avg_signal = parsed.si_avg_signal;
+ dso->si_avg_beacon_signal = parsed.si_avg_beacon_signal;
+ dso->si_current_noise = parsed.si_current_noise;
+ dso->scan_level = parsed.scan_level;
+
+ return 0;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *cmd)
{
@@ -663,6 +721,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wpa_s->ignore_assoc_disallow = !!atoi(value);
wpa_drv_ignore_assoc_disallow(wpa_s,
wpa_s->ignore_assoc_disallow);
+ } else if (os_strcasecmp(cmd, "disable_sa_query") == 0) {
+ wpa_s->disable_sa_query = !!atoi(value);
} else if (os_strcasecmp(cmd, "ignore_sae_h2e_only") == 0) {
wpa_s->ignore_sae_h2e_only = !!atoi(value);
} else if (os_strcasecmp(cmd, "extra_sae_rejected_groups") == 0) {
@@ -687,6 +747,12 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
break;
pos++;
}
+ } else if (os_strcasecmp(cmd, "rsne_override_eapol") == 0) {
+ wpabuf_free(wpa_s->rsne_override_eapol);
+ if (os_strcmp(value, "NULL") == 0)
+ wpa_s->rsne_override_eapol = NULL;
+ else
+ wpa_s->rsne_override_eapol = wpabuf_parse_bin(value);
} else if (os_strcasecmp(cmd, "rsnxe_override_assoc") == 0) {
wpabuf_free(wpa_s->rsnxe_override_assoc);
if (os_strcmp(value, "NULL") == 0)
@@ -713,6 +779,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wpa_s->sae_commit_override = NULL;
else
wpa_s->sae_commit_override = wpabuf_parse_bin(value);
+ } else if (os_strcasecmp(cmd, "driver_signal_override") == 0) {
+ ret = wpas_ctrl_iface_set_dso(wpa_s, value);
#ifdef CONFIG_DPP
} else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
os_free(wpa_s->dpp_config_obj_override);
@@ -851,6 +919,8 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
return wpa_snprintf_hex(buf, buflen,
wpa_sm_get_anonce(wpa_s->wpa),
WPA_NONCE_LEN);
+ } else if (os_strcasecmp(cmd, "last_tk_key_idx") == 0) {
+ res = os_snprintf(buf, buflen, "%d", wpa_s->last_tk_key_idx);
#endif /* CONFIG_TESTING_OPTIONS */
} else {
res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen);
@@ -3889,8 +3959,10 @@ static const struct cipher_info ciphers[] = {
{ WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
{ WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
{ WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 },
+#ifdef CONFIG_WEP
{ WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 },
{ WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
+#endif /* CONFIG_WEP */
};
static const struct cipher_info ciphers_group_mgmt[] = {
@@ -3952,7 +4024,11 @@ static int ctrl_iface_get_capability_group(int res, char *strict,
if (res < 0) {
if (strict)
return 0;
+#ifdef CONFIG_WEP
len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
+#else /* CONFIG_WEP */
+ len = os_strlcpy(buf, "CCMP TKIP", buflen);
+#endif /* CONFIG_WEP */
if (len >= buflen)
return -1;
return len;
@@ -5285,15 +5361,24 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
/* MLME-DELETEKEYS.request */
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
- 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);
- 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);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
- 0);
+ 0, KEY_FLAG_PAIRWISE);
+ if (wpa_sm_ext_key_id(wpa_s->wpa))
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 1, 0,
+ NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
/* MLME-SETPROTECTION.request(None) */
wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
MLME_SETPROTECTION_PROTECT_TYPE_NONE,
@@ -7130,7 +7215,7 @@ static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst,
return -1;
}
- bss = wpa_bss_get_bssid(wpa_s, bssid);
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
if (bss == NULL) {
wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
MAC2STR(bssid));
@@ -8019,6 +8104,10 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->dpp_resp_wait_time = 0;
wpa_s->dpp_resp_max_tries = 0;
wpa_s->dpp_resp_retry_time = 0;
+#ifdef CONFIG_DPP2
+ wpas_dpp_chirp_stop(wpa_s);
+ wpa_s->dpp_pfs_fallback = 0;
+#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN);
os_memset(dpp_pkex_peer_mac_override, 0, ETH_ALEN);
@@ -8038,9 +8127,12 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
wpa_supplicant_stop_countermeasures(wpa_s, NULL);
+ wpa_s->last_michael_mic_error.sec = 0;
wpa_s->no_keep_alive = 0;
wpa_s->own_disconnect_req = 0;
+ wpa_s->own_reconnect_req = 0;
+ wpa_s->deny_ptk0_rekey = 0;
os_free(wpa_s->disallow_aps_bssid);
wpa_s->disallow_aps_bssid = NULL;
@@ -8089,6 +8181,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->p2p_go_csa_on_inv = 0;
wpa_s->ignore_auth_resp = 0;
wpa_s->ignore_assoc_disallow = 0;
+ wpa_s->disable_sa_query = 0;
wpa_s->testing_resend_assoc = 0;
wpa_s->ignore_sae_h2e_only = 0;
wpa_s->reject_btm_req_reason = 0;
@@ -8099,10 +8192,13 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->sae_commit_override = NULL;
os_free(wpa_s->extra_sae_rejected_groups);
wpa_s->extra_sae_rejected_groups = NULL;
+ wpabuf_free(wpa_s->rsne_override_eapol);
+ wpa_s->rsne_override_eapol = NULL;
wpabuf_free(wpa_s->rsnxe_override_assoc);
wpa_s->rsnxe_override_assoc = NULL;
wpabuf_free(wpa_s->rsnxe_override_eapol);
wpa_s->rsnxe_override_eapol = NULL;
+ wpas_clear_driver_signal_override(wpa_s);
#ifdef CONFIG_DPP
os_free(wpa_s->dpp_config_obj_override);
wpa_s->dpp_config_obj_override = NULL;
@@ -8117,6 +8213,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->disconnected = 0;
os_free(wpa_s->next_scan_freqs);
wpa_s->next_scan_freqs = NULL;
+ os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN);
+ wpa_s->next_scan_bssid_wildcard_ssid = 0;
os_free(wpa_s->select_network_scan_freqs);
wpa_s->select_network_scan_freqs = NULL;
@@ -8135,6 +8233,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_SME
wpa_s->sme.last_unprot_disconnect.sec = 0;
+ wpa_s->sme.auth_alg = 0;
#endif /* CONFIG_SME */
wpabuf_free(wpa_s->ric_ies);
@@ -8451,6 +8550,9 @@ static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
goto done;
}
os_memcpy(wpa_s->next_scan_bssid, bssid, ETH_ALEN);
+
+ wpa_s->next_scan_bssid_wildcard_ssid =
+ os_strstr(params, "wildcard_ssid=1") != NULL;
}
pos = params;
@@ -8962,7 +9064,7 @@ static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
{
struct wpa_supplicant *wpa_s = ctx;
const struct ether_header *eth;
- struct iphdr ip;
+ struct ip ip;
const u8 *pos;
unsigned int i;
char extra[30];
@@ -8978,14 +9080,13 @@ static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
os_memcpy(&ip, eth + 1, sizeof(ip));
pos = &buf[sizeof(*eth) + sizeof(ip)];
- if (ip.ihl != 5 || ip.version != 4 ||
- ntohs(ip.tot_len) > HWSIM_IP_LEN) {
+ if (ip.ip_hl != 5 || ip.ip_v != 4 || ntohs(ip.ip_len) > HWSIM_IP_LEN) {
wpa_printf(MSG_DEBUG,
"test data: RX - ignore unexpect IP header");
return;
}
- for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) {
+ for (i = 0; i < ntohs(ip.ip_len) - sizeof(ip); i++) {
if (*pos != (u8) i) {
wpa_printf(MSG_DEBUG,
"test data: RX - ignore mismatching payload");
@@ -8994,8 +9095,8 @@ static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
pos++;
}
extra[0] = '\0';
- if (ntohs(ip.tot_len) != HWSIM_IP_LEN)
- os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len));
+ if (ntohs(ip.ip_len) != HWSIM_IP_LEN)
+ os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.ip_len));
wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
}
@@ -9047,7 +9148,7 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
u8 tos;
u8 buf[2 + HWSIM_PACKETLEN];
struct ether_header *eth;
- struct iphdr *ip;
+ struct ip *ip;
u8 *dpos;
unsigned int i;
size_t send_len = HWSIM_IP_LEN;
@@ -9086,17 +9187,17 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
os_memcpy(eth->ether_shost, src, ETH_ALEN);
eth->ether_type = htons(ETHERTYPE_IP);
- ip = (struct iphdr *) (eth + 1);
+ ip = (struct ip *) (eth + 1);
os_memset(ip, 0, sizeof(*ip));
- ip->ihl = 5;
- ip->version = 4;
- ip->ttl = 64;
- ip->tos = tos;
- ip->tot_len = htons(send_len);
- ip->protocol = 1;
- ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
- ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
- ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
+ ip->ip_hl = 5;
+ ip->ip_v = 4;
+ ip->ip_ttl = 64;
+ ip->ip_tos = tos;
+ ip->ip_len = htons(send_len);
+ ip->ip_p = 1;
+ ip->ip_src.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
+ ip->ip_dst.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
+ ip->ip_sum = ipv4_hdr_checksum(ip, sizeof(*ip));
dpos = (u8 *) (ip + 1);
for (i = 0; i < send_len - sizeof(*ip); i++)
*dpos++ = i;
@@ -9289,13 +9390,15 @@ static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s)
* in the driver. */
if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
wpa_s->last_tk_key_idx, 1, zero, 6,
- zero, wpa_s->last_tk_len) < 0)
+ zero, wpa_s->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX) < 0)
return -1;
/* Set the previously configured key to reset its TSC/RSC */
return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
wpa_s->last_tk_key_idx, 1, zero, 6,
- wpa_s->last_tk, wpa_s->last_tk_len);
+ wpa_s->last_tk, wpa_s->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX);
}
@@ -10741,6 +10844,28 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (os_snprintf_error(reply_size, reply_len))
reply_len = -1;
}
+ } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) {
+ int res;
+
+ res = wpas_dpp_nfc_handover_req(wpa_s, buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) {
+ int res;
+
+ res = wpas_dpp_nfc_handover_sel(wpa_s, buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
int res;
@@ -10769,6 +10894,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
reply_len = dpp_bootstrap_info(wpa_s->dpp, atoi(buf + 19),
reply, reply_size);
+ } else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) {
+ if (dpp_bootstrap_set(wpa_s->dpp, atoi(buf + 18),
+ os_strchr(buf + 18, ' ')) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
if (wpas_dpp_auth_init(wpa_s, buf + 13) < 0)
reply_len = -1;
@@ -10822,6 +10951,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = -1;
} else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) {
dpp_controller_stop(wpa_s->dpp);
+ } else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) {
+ if (wpas_dpp_chirp(wpa_s, buf + 9) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
+ wpas_dpp_chirp_stop(wpa_s);
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
} else {
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 8a6057a8..1e92b975 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -516,7 +516,7 @@ static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
return;
if (ifname)
- os_snprintf(levelstr, sizeof(levelstr), "IFACE=%s <%d>",
+ os_snprintf(levelstr, sizeof(levelstr), "IFNAME=%s <%d>",
ifname, level);
else
os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 4b6dabcc..4e17e31a 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -991,20 +991,25 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(
const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
- const char *capabilities[11];
+ const char *capabilities[12];
size_t num_items = 0;
-#ifdef CONFIG_FILS
struct wpa_global *global = user_data;
struct wpa_supplicant *wpa_s;
+#ifdef CONFIG_FILS
int fils_supported = 0, fils_sk_pfs_supported = 0;
+#endif /* CONFIG_FILS */
+ int ext_key_id_supported = 0;
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+#ifdef CONFIG_FILS
if (wpa_is_fils_supported(wpa_s))
fils_supported = 1;
if (wpa_is_fils_sk_pfs_supported(wpa_s))
fils_sk_pfs_supported = 1;
- }
#endif /* CONFIG_FILS */
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)
+ ext_key_id_supported = 1;
+ }
#ifdef CONFIG_AP
capabilities[num_items++] = "ap";
@@ -1037,6 +1042,8 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(
#ifdef CONFIG_OWE
capabilities[num_items++] = "owe";
#endif /* CONFIG_OWE */
+ if (ext_key_id_supported)
+ capabilities[num_items++] = "extended_key_id";
return wpas_dbus_simple_array_property_getter(iter,
DBUS_TYPE_STRING,
@@ -1146,7 +1153,7 @@ static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
DBusMessage **reply)
{
u8 *ies = NULL, *nies;
- int ies_len = 0;
+ size_t ies_len = 0;
DBusMessageIter array_iter, sub_array_iter;
char *val;
int len;
@@ -1177,7 +1184,7 @@ static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
dbus_message_iter_recurse(&array_iter, &sub_array_iter);
dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
- if (len == 0) {
+ if (len <= 0) {
dbus_message_iter_next(&array_iter);
continue;
}
@@ -1208,7 +1215,7 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
{
DBusMessageIter array_iter, sub_array_iter;
int *freqs = NULL, *nfreqs;
- int freqs_num = 0;
+ size_t freqs_num = 0;
if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
wpa_printf(MSG_DEBUG,
@@ -2664,7 +2671,10 @@ dbus_bool_t wpas_dbus_getter_capabilities(
/***** group cipher */
if (res < 0) {
const char *args[] = {
- "ccmp", "tkip", "wep104", "wep40"
+ "ccmp", "tkip",
+#ifdef CONFIG_WEP
+ "wep104", "wep40"
+#endif /* CONFIG_WEP */
};
if (!wpa_dbus_dict_append_string_array(
@@ -2691,12 +2701,14 @@ dbus_bool_t wpas_dbus_getter_capabilities(
((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "tkip")) ||
+#ifdef CONFIG_WEP
((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "wep104")) ||
((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "wep40")) ||
+#endif /* CONFIG_WEP */
!wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
@@ -2793,6 +2805,12 @@ dbus_bool_t wpas_dbus_getter_capabilities(
goto nomem;
#endif /* CONFIG_WPS */
+#ifdef CONFIG_SAE
+ if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
+ !wpa_dbus_dict_string_array_add_element(&iter_array, "sae"))
+ goto nomem;
+#endif /* CONFIG_SAE */
+
if (!wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
@@ -4733,9 +4751,14 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(
/* Group */
switch (ie_data->group_cipher) {
+#ifdef CONFIG_WEP
case WPA_CIPHER_WEP40:
group = "wep40";
break;
+ case WPA_CIPHER_WEP104:
+ group = "wep104";
+ break;
+#endif /* CONFIG_WEP */
case WPA_CIPHER_TKIP:
group = "tkip";
break;
@@ -4745,9 +4768,6 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(
case WPA_CIPHER_GCMP:
group = "gcmp";
break;
- case WPA_CIPHER_WEP104:
- group = "wep104";
- break;
case WPA_CIPHER_CCMP_256:
group = "ccmp-256";
break;
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index db76c6ad..ef2339f2 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -77,7 +77,7 @@ CONFIG_DRIVER_WIRED=y
#CONFIG_DRIVER_MACSEC_QCA=y
# Driver interface for Linux MACsec drivers
-#CONFIG_DRIVER_MACSEC_LINUX=y
+CONFIG_DRIVER_MACSEC_LINUX=y
# Driver interface for the Broadcom RoboSwitch family
#CONFIG_DRIVER_ROBOSWITCH=y
@@ -183,7 +183,7 @@ CONFIG_EAP_IKEV2=y
#CONFIG_EAP_EKE=y
# MACsec
-#CONFIG_MACSEC=y
+CONFIG_MACSEC=y
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
@@ -248,7 +248,7 @@ CONFIG_CTRL_IFACE=y
# Simultaneous Authentication of Equals (SAE), WPA3-Personal
CONFIG_SAE=y
-# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# Disable scan result processing (ap_scan=1) to save code size by about 1 kB.
# This can be used if ap_scan=1 mode is never enabled.
#CONFIG_NO_SCAN_PROCESSING=y
@@ -471,11 +471,7 @@ CONFIG_DEBUG_SYSLOG=y
# Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
#CONFIG_GETRANDOM=y
-# IEEE 802.11n (High Throughput) support (mainly for AP mode)
-CONFIG_IEEE80211N=y
-
# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
-# (depends on CONFIG_IEEE80211N)
CONFIG_IEEE80211AC=y
# Wireless Network Management (IEEE Std 802.11v-2011)
@@ -612,3 +608,12 @@ CONFIG_DPP=y
# Configure the building of the interface which allows WAPI configuration.
# Note: does not configure WAPI implementation itself.
#CONFIG_WAPI_INTERFACE=y
+
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current wpa_supplicant
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+#CONFIG_WEP=y
+
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 73649c23..c75ab47c 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -1,7 +1,7 @@
/*
* wpa_supplicant - DPP
* Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -107,6 +107,71 @@ int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd)
}
+int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
+
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Request");
+ return -1;
+ }
+
+ if (dpp_nfc_update_bi(own_bi, peer_bi) < 0)
+ return -1;
+
+ return peer_bi->id;
+}
+
+
+int wpas_dpp_nfc_handover_sel(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
+
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Select");
+ return -1;
+ }
+
+ if (peer_bi->curve != own_bi->curve) {
+ wpa_printf(MSG_INFO,
+ "DPP: Peer (NFC Handover Selector) used different curve");
+ return -1;
+ }
+
+ return peer_bi->id;
+}
+
+
static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
@@ -689,6 +754,8 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
else
wpa_s->dpp_netrole = DPP_NETROLE_STA;
+ } else {
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
}
pos = os_strstr(cmd, " neg_freq=");
@@ -705,12 +772,12 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
wpa_s->dpp_auth = NULL;
}
- auth = dpp_auth_init(wpa_s, peer_bi, own_bi, allowed_roles, neg_freq,
- wpa_s->hw.modes, wpa_s->hw.num_modes);
+ auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, own_bi, allowed_roles,
+ neg_freq, wpa_s->hw.modes, wpa_s->hw.num_modes);
if (!auth)
goto fail;
wpas_dpp_set_testing_options(wpa_s, auth);
- if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) < 0) {
+ if (dpp_set_configurator(auth, cmd) < 0) {
dpp_auth_deinit(auth);
goto fail;
}
@@ -911,6 +978,10 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
MAC2STR(src));
+#ifdef CONFIG_DPP2
+ wpas_dpp_chirp_stop(wpa_s);
+#endif /* CONFIG_DPP2 */
+
r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
&r_bootstrap_len);
if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
@@ -949,7 +1020,8 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
wpa_s->dpp_gas_client = 0;
wpa_s->dpp_auth_ok_on_ack = 0;
- wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s, wpa_s->dpp_allowed_roles,
+ wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s->dpp, wpa_s,
+ wpa_s->dpp_allowed_roles,
wpa_s->dpp_qr_mutual,
peer_bi, own_bi, freq, hdr, buf, len);
if (!wpa_s->dpp_auth) {
@@ -957,7 +1029,7 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
return;
}
wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
- if (dpp_set_configurator(wpa_s->dpp, wpa_s, wpa_s->dpp_auth,
+ if (dpp_set_configurator(wpa_s->dpp_auth,
wpa_s->dpp_configurator_params) < 0) {
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
@@ -1031,8 +1103,10 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
ssid->ssid_len = conf->ssid_len;
if (conf->connector) {
- ssid->key_mgmt = WPA_KEY_MGMT_DPP;
- ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+ if (dpp_akm_dpp(conf->akm)) {
+ ssid->key_mgmt = WPA_KEY_MGMT_DPP;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+ }
ssid->dpp_connector = os_strdup(conf->connector);
if (!ssid->dpp_connector)
goto fail;
@@ -1061,7 +1135,7 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
if (!conf->connector || dpp_akm_psk(conf->akm) ||
dpp_akm_sae(conf->akm)) {
- if (!conf->connector)
+ if (!conf->connector || !dpp_akm_dpp(conf->akm))
ssid->key_mgmt = 0;
if (dpp_akm_psk(conf->akm))
ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
@@ -1203,6 +1277,32 @@ static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
}
+static int wpas_dpp_handle_key_pkg(struct wpa_supplicant *wpa_s,
+ struct dpp_asymmetric_key *key)
+{
+#ifdef CONFIG_DPP2
+ int res;
+
+ if (!key)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+
+ while (key) {
+ res = dpp_configurator_from_backup(wpa_s->dpp, key);
+ if (res < 0)
+ return -1;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFIGURATOR_ID "%d",
+ res);
+ key = key->next;
+ }
+#endif /* CONFIG_DPP2 */
+
+ return 0;
+}
+
+
static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
@@ -1259,6 +1359,8 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
}
if (auth->num_conf_obj)
wpas_dpp_post_process_config(wpa_s, auth);
+ if (wpas_dpp_handle_key_pkg(wpa_s, auth->conf_key_pkg) < 0)
+ goto fail;
status = DPP_STATUS_OK;
#ifdef CONFIG_TESTING_OPTIONS
@@ -1605,6 +1707,76 @@ static int wpas_dpp_process_conf_obj(void *ctx,
return res;
}
+
+static void wpas_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (bi == wpa_s->dpp_chirp_bi)
+ wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void
+wpas_dpp_rx_presence_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *r_bootstrap;
+ u16 r_bootstrap_len;
+ struct dpp_bootstrap_info *peer_bi;
+ struct dpp_authentication *auth;
+
+ if (!wpa_s->dpp)
+ return;
+
+ if (wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Presence Announcement during ongoing Authentication");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR,
+ MAC2STR(src));
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+ peer_bi = dpp_bootstrap_find_chirp(wpa_s->dpp, r_bootstrap);
+ if (!peer_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching bootstrapping information found");
+ return;
+ }
+
+ auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, NULL,
+ DPP_CAPAB_CONFIGURATOR, freq, NULL, 0);
+ if (!auth)
+ return;
+ wpas_dpp_set_testing_options(wpa_s, auth);
+ if (dpp_set_configurator(auth, wpa_s->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(auth);
+ return;
+ }
+
+ auth->neg_freq = freq;
+
+ if (!is_zero_ether_addr(peer_bi->mac_addr))
+ os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+
+ wpa_s->dpp_auth = auth;
+ if (wpas_dpp_auth_init_next(wpa_s) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ }
+}
+
#endif /* CONFIG_DPP2 */
@@ -2069,6 +2241,7 @@ wpas_dpp_rx_pkex_commit_reveal_resp(struct wpa_supplicant *wpa_s, const u8 *src,
if (wpas_dpp_auth_init(wpa_s, cmd) < 0) {
wpa_printf(MSG_DEBUG,
"DPP: Authentication initialization failed");
+ offchannel_send_action_done(wpa_s);
return;
}
}
@@ -2149,6 +2322,10 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
case DPP_PA_CONNECTION_STATUS_RESULT:
wpas_dpp_rx_conn_status_result(wpa_s, src, hdr, buf, len);
break;
+ case DPP_PA_PRESENCE_ANNOUNCEMENT:
+ wpas_dpp_rx_presence_announcement(wpa_s, src, hdr, buf, len,
+ freq);
+ break;
#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
@@ -2271,13 +2448,13 @@ int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd)
int ret = -1;
char *curve = NULL;
- auth = os_zalloc(sizeof(*auth));
+ auth = dpp_alloc_auth(wpa_s->dpp, wpa_s);
if (!auth)
return -1;
curve = get_param(cmd, " curve=");
wpas_dpp_set_testing_options(wpa_s, auth);
- if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) == 0 &&
+ if (dpp_set_configurator(auth, cmd) == 0 &&
dpp_configurator_own_config(auth, curve, 0) == 0)
ret = wpas_dpp_handle_config_obj(wpa_s, auth,
&auth->conf_obj[0]);
@@ -2549,6 +2726,8 @@ int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id)
void wpas_dpp_stop(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->dpp_auth || wpa_s->dpp_pkex)
+ offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
dpp_pkex_free(wpa_s->dpp_pkex);
@@ -2579,6 +2758,7 @@ int wpas_dpp_init(struct wpa_supplicant *wpa_s)
config.cb_ctx = wpa_s;
#ifdef CONFIG_DPP2
config.process_conf_obj = wpas_dpp_process_conf_obj;
+ config.remove_bi = wpas_dpp_remove_bi;
#endif /* CONFIG_DPP2 */
wpa_s->dpp = dpp_global_init(&config);
return wpa_s->dpp ? 0 : -1;
@@ -2610,6 +2790,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = NULL;
+ wpas_dpp_chirp_stop(wpa_s);
#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
@@ -2622,6 +2803,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_DPP2
+
int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
{
struct dpp_controller_config config;
@@ -2638,4 +2820,270 @@ int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
config.configurator_params = wpa_s->dpp_configurator_params;
return dpp_controller_start(wpa_s->dpp, &config);
}
+
+
+static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx);
+
+static void wpas_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "DPP: No chirp response received");
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_chirp_next(wpa_s, NULL);
+}
+
+
+static void wpas_dpp_chirp_tx_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result)
+{
+ if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to send chirp on %d MHz",
+ wpa_s->dpp_chirp_freq);
+ if (eloop_register_timeout(0, 0, wpas_dpp_chirp_next,
+ wpa_s, NULL) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Chirp send completed - wait for response");
+ if (eloop_register_timeout(2, 0, wpas_dpp_chirp_timeout,
+ wpa_s, NULL) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", wpa_s->dpp_chirp_freq);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(broadcast), wpa_s->dpp_chirp_freq,
+ DPP_PA_PRESENCE_ANNOUNCEMENT);
+ if (offchannel_send_action(
+ wpa_s, wpa_s->dpp_chirp_freq, broadcast,
+ wpa_s->own_addr, broadcast,
+ wpabuf_head(wpa_s->dpp_presence_announcement),
+ wpabuf_len(wpa_s->dpp_presence_announcement),
+ 2000, wpas_dpp_chirp_tx_status, 0) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ struct dpp_bootstrap_info *bi = wpa_s->dpp_chirp_bi;
+ unsigned int i;
+ struct hostapd_hw_modes *mode;
+ int c;
+ struct wpa_bss *bss;
+
+ if (!bi)
+ return;
+
+ wpa_s->dpp_chirp_scan_done = 1;
+
+ os_free(wpa_s->dpp_chirp_freqs);
+ wpa_s->dpp_chirp_freqs = NULL;
+
+ /* Channels from own bootstrapping info */
+ for (i = 0; i < bi->num_freq; i++)
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, bi->freq[i]);
+
+ /* Preferred chirping channels */
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437);
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211A, 0);
+ if (mode) {
+ int chan44 = 0, chan149 = 0;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR))
+ continue;
+ if (chan->freq == 5220)
+ chan44 = 1;
+ if (chan->freq == 5745)
+ chan149 = 1;
+ }
+ if (chan149)
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5745);
+ else if (chan44)
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5220);
+ }
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211AD, 0);
+ if (mode) {
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if ((chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR)) ||
+ chan->freq != 60480)
+ continue;
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 60480);
+ break;
+ }
+ }
+
+ /* Add channels from scan results for APs that advertise Configurator
+ * Connectivity element */
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (wpa_bss_get_vendor_ie(bss, DPP_CC_IE_VENDOR_TYPE))
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs,
+ bss->freq);
+ }
+
+ if (!wpa_s->dpp_chirp_freqs ||
+ eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ int i;
+
+ if (wpa_s->dpp_chirp_listen)
+ wpas_dpp_listen_stop(wpa_s);
+
+ if (wpa_s->dpp_chirp_freq == 0) {
+ if (wpa_s->dpp_chirp_round % 4 == 0 &&
+ !wpa_s->dpp_chirp_scan_done) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Update channel list for chirping");
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_s->scan_res_handler =
+ wpas_dpp_chirp_scan_res_handler;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ return;
+ }
+ wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[0];
+ wpa_s->dpp_chirp_round++;
+ wpa_printf(MSG_DEBUG, "DPP: Start chirping round %d",
+ wpa_s->dpp_chirp_round);
+ } else {
+ for (i = 0; wpa_s->dpp_chirp_freqs[i]; i++)
+ if (wpa_s->dpp_chirp_freqs[i] == wpa_s->dpp_chirp_freq)
+ break;
+ if (!wpa_s->dpp_chirp_freqs[i]) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Previous chirp freq %d not found",
+ wpa_s->dpp_chirp_freq);
+ return;
+ }
+ i++;
+ if (wpa_s->dpp_chirp_freqs[i]) {
+ wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[i];
+ } else {
+ wpa_s->dpp_chirp_iter--;
+ if (wpa_s->dpp_chirp_iter <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Chirping iterations completed");
+ wpas_dpp_chirp_stop(wpa_s);
+ return;
+ }
+ wpa_s->dpp_chirp_freq = 0;
+ wpa_s->dpp_chirp_scan_done = 0;
+ if (eloop_register_timeout(30, 0, wpas_dpp_chirp_next,
+ wpa_s, NULL) < 0) {
+ wpas_dpp_chirp_stop(wpa_s);
+ return;
+ }
+ if (wpa_s->dpp_chirp_listen) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Listen on %d MHz during chirp 30 second wait",
+ wpa_s->dpp_chirp_listen);
+ wpas_dpp_listen_start(wpa_s,
+ wpa_s->dpp_chirp_listen);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Wait 30 seconds before starting the next chirping round");
+ }
+ return;
+ }
+ }
+
+ wpas_dpp_chirp_start(wpa_s);
+}
+
+
+int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos;
+ int iter = 1, listen_freq = 0;
+ struct dpp_bootstrap_info *bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Identified bootstrap info not found");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " iter=");
+ if (pos) {
+ iter = atoi(pos + 6);
+ if (iter <= 0)
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " listen=");
+ if (pos) {
+ listen_freq = atoi(pos + 8);
+ if (iter <= 0)
+ return -1;
+ }
+
+ wpas_dpp_chirp_stop(wpa_s);
+ wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ wpa_s->dpp_qr_mutual = 0;
+ wpa_s->dpp_chirp_bi = bi;
+ wpa_s->dpp_presence_announcement = dpp_build_presence_announcement(bi);
+ if (!wpa_s->dpp_presence_announcement)
+ return -1;
+ wpa_s->dpp_chirp_iter = iter;
+ wpa_s->dpp_chirp_round = 0;
+ wpa_s->dpp_chirp_scan_done = 0;
+ wpa_s->dpp_chirp_listen = listen_freq;
+
+ return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
+}
+
+
+void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->dpp_presence_announcement) {
+ offchannel_send_action_done(wpa_s);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CHIRP_STOPPED);
+ }
+ wpa_s->dpp_chirp_bi = NULL;
+ wpabuf_free(wpa_s->dpp_presence_announcement);
+ wpa_s->dpp_presence_announcement = NULL;
+ if (wpa_s->dpp_chirp_listen)
+ wpas_dpp_listen_stop(wpa_s);
+ wpa_s->dpp_chirp_listen = 0;
+ wpa_s->dpp_chirp_freq = 0;
+ os_free(wpa_s->dpp_chirp_freqs);
+ wpa_s->dpp_chirp_freqs = NULL;
+ eloop_cancel_timeout(wpas_dpp_chirp_next, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_chirp_timeout, wpa_s, NULL);
+ if (wpa_s->scan_res_handler == wpas_dpp_chirp_scan_res_handler) {
+ wpas_abort_ongoing_scan(wpa_s);
+ wpa_s->scan_res_handler = NULL;
+ }
+}
+
#endif /* CONFIG_DPP2 */
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index 607036a3..2ce378dc 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -1,7 +1,7 @@
/*
* wpa_supplicant - DPP
* Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,6 +14,8 @@ enum dpp_status_error;
int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_nfc_handover_sel(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);
void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s);
@@ -33,5 +35,7 @@ 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);
+int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd);
+void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s);
#endif /* DPP_SUPPLICANT_H */
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index cf9972a6..6a03d8e9 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -124,13 +124,8 @@ static inline int wpa_drv_stop_sched_scan(struct wpa_supplicant *wpa_s)
return -1;
}
-static inline struct wpa_scan_results * wpa_drv_get_scan_results2(
- struct wpa_supplicant *wpa_s)
-{
- if (wpa_s->driver->get_scan_results2)
- return wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
- return NULL;
-}
+struct wpa_scan_results *
+wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s);
static inline int wpa_drv_get_bssid(struct wpa_supplicant *wpa_s, u8 *bssid)
{
@@ -152,18 +147,38 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
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)
-{
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
+{
+ struct wpa_driver_set_key_params params;
+
+ os_memset(&params, 0, sizeof(params));
+ params.ifname = wpa_s->ifname;
+ params.alg = alg;
+ params.addr = addr;
+ params.key_idx = key_idx;
+ params.set_tx = set_tx;
+ params.seq = seq;
+ params.seq_len = seq_len;
+ params.key = key;
+ params.key_len = key_len;
+ params.key_flag = key_flag;
+
if (alg != WPA_ALG_NONE) {
- if (key_idx >= 0 && key_idx <= 6)
+ /* keyidx = 1 can be either a broadcast or--with
+ * Extended Key ID--a unicast key. Use bit 15 for
+ * the pairwise keyidx 1 which is hopefully high enough
+ * to not clash with future extensions.
+ */
+ if (key_idx == 1 && (key_flag & KEY_FLAG_PAIRWISE))
+ wpa_s->keys_cleared &= ~BIT(15);
+ else if (key_idx >= 0 && key_idx <= 5)
wpa_s->keys_cleared &= ~BIT(key_idx);
else
wpa_s->keys_cleared = 0;
}
if (wpa_s->driver->set_key) {
- return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv,
- alg, addr, key_idx, set_tx,
- seq, seq_len, key, key_len);
+ return wpa_s->driver->set_key(wpa_s->drv_priv, &params);
}
return -1;
}
@@ -304,12 +319,12 @@ static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s,
static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
const u8 *data, size_t data_len, int noack,
- unsigned int freq)
+ unsigned int freq, unsigned int wait)
{
if (wpa_s->driver->send_mlme)
return wpa_s->driver->send_mlme(wpa_s->drv_priv,
data, data_len, noack,
- freq, NULL, 0);
+ freq, NULL, 0, 0, wait);
return -1;
}
@@ -347,6 +362,17 @@ static inline int wpa_drv_sta_remove(struct wpa_supplicant *wpa_s,
return -1;
}
+static inline int wpa_drv_tx_control_port(struct wpa_supplicant *wpa_s,
+ const u8 *dest, u16 proto,
+ const u8 *buf, size_t len,
+ int no_encrypt)
+{
+ if (!wpa_s->driver->tx_control_port)
+ return -1;
+ return wpa_s->driver->tx_control_port(wpa_s->drv_priv, dest, proto,
+ buf, len, no_encrypt);
+}
+
static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s,
const u8 *addr, const u8 *data,
size_t data_len, int encrypt,
@@ -494,13 +520,8 @@ static inline int wpa_drv_signal_monitor(struct wpa_supplicant *wpa_s,
return -1;
}
-static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
- struct wpa_signal_info *si)
-{
- if (wpa_s->driver->signal_poll)
- return wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
- return -1;
-}
+int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
+ struct wpa_signal_info *si);
static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s,
struct wpa_channel_info *ci)
@@ -681,6 +702,13 @@ static inline int wpa_drv_set_qos_map(struct wpa_supplicant *wpa_s,
qos_map_set_len);
}
+static inline int wpa_drv_get_wowlan(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->driver->get_wowlan)
+ return 0;
+ return wpa_s->driver->get_wowlan(wpa_s->drv_priv);
+}
+
static inline int wpa_drv_wowlan(struct wpa_supplicant *wpa_s,
const struct wowlan_triggers *triggers)
{
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 53d75853..2fa49681 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -1390,7 +1390,7 @@ int main(int argc, char *argv[])
eapol_test.ctrl_iface = 1;
break;
case 'v':
- printf("eapol_test v" VERSION_STR "\n");
+ printf("eapol_test v%s\n", VERSION_STR);
return 0;
case 'W':
wait_for_monitor++;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 4c459cfe..cf561083 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -188,6 +188,16 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
drv_ssid_len) == 0)
return 0; /* current profile still in use */
+#ifdef CONFIG_OWE
+ if ((wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ wpa_s->current_bss &&
+ (wpa_s->current_bss->flags & WPA_BSS_OWE_TRANSITION) &&
+ drv_ssid_len == wpa_s->current_bss->ssid_len &&
+ os_memcmp(drv_ssid, wpa_s->current_bss->ssid,
+ drv_ssid_len) == 0)
+ return 0; /* current profile still in use */
+#endif /* CONFIG_OWE */
+
wpa_msg(wpa_s, MSG_DEBUG,
"Driver-initiated BSS selection changed the SSID to %s",
wpa_ssid_txt(drv_ssid, drv_ssid_len));
@@ -479,6 +489,7 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
#ifndef CONFIG_NO_SCAN_PROCESSING
+#ifdef CONFIG_WEP
static int has_wep_key(struct wpa_ssid *ssid)
{
int i;
@@ -490,6 +501,7 @@ static int has_wep_key(struct wpa_ssid *ssid)
return 0;
}
+#endif /* CONFIG_WEP */
static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
@@ -510,8 +522,10 @@ static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
return 1;
#endif /* CONFIG_OWE */
+#ifdef CONFIG_WEP
if (has_wep_key(ssid))
privacy = 1;
+#endif /* CONFIG_WEP */
#ifdef IEEE8021X_EAPOL
if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
@@ -540,17 +554,21 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
int proto_match = 0;
const u8 *rsn_ie, *wpa_ie;
int ret;
+#ifdef CONFIG_WEP
int wep_ok;
+#endif /* CONFIG_WEP */
ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
if (ret >= 0)
return ret;
+#ifdef CONFIG_WEP
/* Allow TSN if local configuration accepts WEP use without WPA/WPA2 */
wep_ok = !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
(((ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
ssid->wep_key_len[ssid->wep_tx_keyidx] > 0) ||
(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
+#endif /* CONFIG_WEP */
rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
while ((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) && rsn_ie) {
@@ -567,6 +585,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
if (!ie.has_group)
ie.group_cipher = wpa_default_rsn_cipher(bss->freq);
+#ifdef CONFIG_WEP
if (wep_ok &&
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
{
@@ -575,6 +594,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
" selected based on TSN in RSN IE");
return 1;
}
+#endif /* CONFIG_WEP */
if (!(ie.proto & ssid->proto) &&
!(ssid->proto & WPA_PROTO_OSEN)) {
@@ -655,6 +675,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
break;
}
+#ifdef CONFIG_WEP
if (wep_ok &&
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
{
@@ -663,6 +684,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
" selected based on TSN in WPA IE");
return 1;
}
+#endif /* CONFIG_WEP */
if (!(ie.proto & ssid->proto)) {
if (debug_print)
@@ -772,8 +794,8 @@ static int freq_allowed(int *freqs, int freq)
}
-static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- int debug_print)
+static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_bss *bss, int debug_print)
{
const struct hostapd_hw_modes *mode = NULL, *modes;
const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES };
@@ -853,7 +875,9 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
#ifdef CONFIG_SAE
if (flagged && ((rate_ie[j] & 0x7f) ==
BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY)) {
- if (wpa_s->conf->sae_pwe == 0) {
+ if (wpa_s->conf->sae_pwe == 0 &&
+ !ssid->sae_password_id &&
+ wpa_key_mgmt_sae(ssid->key_mgmt)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
" SAE H2E disabled");
@@ -971,6 +995,24 @@ static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
*ret_ssid = pos;
*ret_ssid_len = ssid_len;
+ if (!(bss->flags & WPA_BSS_OWE_TRANSITION)) {
+ struct wpa_ssid *ssid;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (wpas_network_disabled(wpa_s, ssid))
+ continue;
+ if (ssid->ssid_len == ssid_len &&
+ os_memcmp(ssid->ssid, pos, ssid_len) == 0) {
+ /* OWE BSS in transition mode for a currently
+ * enabled OWE network. */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "OWE: transition mode OWE SSID for active OWE profile");
+ bss->flags |= WPA_BSS_OWE_TRANSITION;
+ break;
+ }
+ }
+ }
+
if (bss->ssid_len > 0)
return;
@@ -1011,10 +1053,33 @@ static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
wpa_ssid_txt(pos, ssid_len));
os_memcpy(bss->ssid, pos, ssid_len);
bss->ssid_len = ssid_len;
+ bss->flags |= WPA_BSS_OWE_TRANSITION;
#endif /* CONFIG_OWE */
}
+static int disabled_freq(struct wpa_supplicant *wpa_s, int freq)
+{
+ int i, j;
+
+ if (!wpa_s->hw.modes || !wpa_s->hw.num_modes)
+ return 0;
+
+ for (j = 0; j < wpa_s->hw.num_modes; j++) {
+ struct hostapd_hw_modes *mode = &wpa_s->hw.modes[j];
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *chan = &mode->channels[i];
+
+ if (chan->freq == freq)
+ return !!(chan->flag & HOSTAPD_CHAN_DISABLED);
+ }
+ }
+
+ return 1;
+}
+
+
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
@@ -1106,6 +1171,12 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
return NULL;
}
+ if (disabled_freq(wpa_s, bss->freq)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - channel disabled");
+ return NULL;
+ }
+
wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) {
@@ -1206,6 +1277,7 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
continue;
}
+#ifdef CONFIG_WEP
if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
has_wep_key(ssid)) {
if (debug_print)
@@ -1213,6 +1285,7 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
" skip - ignore WPA/WPA2 AP for WEP network block");
continue;
}
+#endif /* CONFIG_WEP */
if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen &&
!rsn_osen) {
@@ -1262,7 +1335,7 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_MESH */
- if (!rate_match(wpa_s, bss, debug_print)) {
+ if (!rate_match(wpa_s, ssid, bss, debug_print)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
" skip - rate sets do not match");
@@ -1270,7 +1343,8 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
}
#ifdef CONFIG_SAE
- if (wpa_s->conf->sae_pwe == 1 &&
+ if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
+ wpa_s->conf->sae_pwe != 3 &&
wpa_key_mgmt_sae(ssid->key_mgmt) &&
(!(ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX)) ||
ie[1] < 1 ||
@@ -1446,8 +1520,9 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
wpa_s->owe_transition_select = 0;
if (!*selected_ssid)
continue;
- wpa_dbg(wpa_s, MSG_DEBUG, " selected BSS " MACSTR
+ wpa_dbg(wpa_s, MSG_DEBUG, " selected %sBSS " MACSTR
" ssid='%s'",
+ bss == wpa_s->current_bss ? "current ": "",
MAC2STR(bss->bssid),
wpa_ssid_txt(bss->ssid, bss->ssid_len));
return bss;
@@ -1461,7 +1536,7 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid **selected_ssid)
{
struct wpa_bss *selected = NULL;
- int prio;
+ size_t prio;
struct wpa_ssid *next_ssid = NULL;
struct wpa_ssid *ssid;
@@ -1616,7 +1691,7 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
static struct wpa_ssid *
wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
{
- int prio;
+ size_t prio;
struct wpa_ssid *ssid;
for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
@@ -1672,6 +1747,31 @@ static void wpa_supplicant_rsn_preauth_scan_results(
}
+#ifndef CONFIG_NO_ROAMING
+
+static int wpas_get_snr_signal_info(u32 frequency, int avg_signal, int noise)
+{
+ if (noise == WPA_INVALID_NOISE)
+ noise = IS_5GHZ(frequency) ? DEFAULT_NOISE_FLOOR_5GHZ :
+ DEFAULT_NOISE_FLOOR_2GHZ;
+ return avg_signal - noise;
+}
+
+
+static unsigned int
+wpas_get_est_throughput_from_bss_snr(const struct wpa_supplicant *wpa_s,
+ const struct wpa_bss *bss, int snr)
+{
+ int rate = wpa_bss_get_max_rate(bss);
+ const u8 *ies = (const void *) (bss + 1);
+ size_t ie_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+
+ return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr);
+}
+
+#endif /* CONFIG_NO_ROAMING */
+
+
static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
struct wpa_bss *selected,
struct wpa_ssid *ssid)
@@ -1680,7 +1780,10 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
#ifndef CONFIG_NO_ROAMING
int min_diff, diff;
int to_5ghz;
- int cur_est, sel_est;
+ int cur_level;
+ unsigned int cur_est, sel_est;
+ struct wpa_signal_info si;
+ int cur_snr = 0;
#endif /* CONFIG_NO_ROAMING */
if (wpa_s->reassociate)
@@ -1731,7 +1834,41 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
return 1;
}
- if (selected->est_throughput > current_bss->est_throughput + 5000) {
+ cur_level = current_bss->level;
+ cur_est = current_bss->est_throughput;
+ sel_est = selected->est_throughput;
+
+ /*
+ * Try to poll the signal from the driver since this will allow to get
+ * more accurate values. In some cases, there can be big differences
+ * between the RSSI of the Probe Response frames of the AP we are
+ * associated with and the Beacon frames we hear from the same AP after
+ * association. This can happen, e.g., when there are two antennas that
+ * hear the AP very differently. If the driver chooses to hear the
+ * Probe Response frames during the scan on the "bad" antenna because
+ * it wants to save power, but knows to choose the other antenna after
+ * association, we will hear our AP with a low RSSI as part of the
+ * scan even when we can hear it decently on the other antenna. To cope
+ * with this, ask the driver to teach us how it hears the AP. Also, the
+ * scan results may be a bit old, since we can very quickly get fresh
+ * information about our currently associated AP.
+ */
+ if (wpa_drv_signal_poll(wpa_s, &si) == 0 &&
+ (si.avg_beacon_signal || si.avg_signal)) {
+ cur_level = si.avg_beacon_signal ? si.avg_beacon_signal :
+ si.avg_signal;
+ cur_snr = wpas_get_snr_signal_info(si.frequency, cur_level,
+ si.current_noise);
+
+ cur_est = wpas_get_est_throughput_from_bss_snr(wpa_s,
+ current_bss,
+ cur_snr);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Using signal poll values for the current BSS: level=%d snr=%d est_throughput=%u",
+ cur_level, cur_snr, cur_est);
+ }
+
+ if (sel_est > cur_est + 5000) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Allow reassociation - selected BSS has better estimated throughput");
return 1;
@@ -1739,59 +1876,59 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
to_5ghz = selected->freq > 4000 && current_bss->freq < 4000;
- if (current_bss->level < 0 &&
- current_bss->level > selected->level + to_5ghz * 2) {
+ if (cur_level < 0 && cur_level > selected->level + to_5ghz * 2 &&
+ sel_est < cur_est * 1.2) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
"signal level");
return 0;
}
- if (current_bss->est_throughput > selected->est_throughput + 5000) {
+ if (cur_est > sel_est + 5000) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Skip roam - Current BSS has better estimated throughput");
return 0;
}
- cur_est = current_bss->est_throughput;
- sel_est = selected->est_throughput;
- min_diff = 2;
- if (current_bss->level < 0) {
- if (current_bss->level < -85)
- min_diff = 1;
- else if (current_bss->level < -80)
- min_diff = 2;
- else if (current_bss->level < -75)
- min_diff = 3;
- else if (current_bss->level < -70)
- min_diff = 4;
- else
- min_diff = 5;
- if (cur_est > sel_est * 1.5)
- min_diff += 10;
- else if (cur_est > sel_est * 1.2)
- min_diff += 5;
- else if (cur_est > sel_est * 1.1)
- min_diff += 2;
- else if (cur_est > sel_est)
- min_diff++;
- }
- if (to_5ghz) {
- int reduce = 2;
-
- /* Make it easier to move to 5 GHz band */
- if (sel_est > cur_est * 1.5)
- reduce = 5;
- else if (sel_est > cur_est * 1.2)
- reduce = 4;
- else if (sel_est > cur_est * 1.1)
- reduce = 3;
-
- if (min_diff > reduce)
- min_diff -= reduce;
- else
- min_diff = 0;
+ if (cur_snr > GREAT_SNR) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Skip roam - Current BSS has good SNR (%u > %u)",
+ cur_snr, GREAT_SNR);
+ return 0;
}
- diff = abs(current_bss->level - selected->level);
+
+ if (cur_level < -85) /* ..-86 dBm */
+ min_diff = 1;
+ else if (cur_level < -80) /* -85..-81 dBm */
+ min_diff = 2;
+ else if (cur_level < -75) /* -80..-76 dBm */
+ min_diff = 3;
+ else if (cur_level < -70) /* -75..-71 dBm */
+ min_diff = 4;
+ else if (cur_level < 0) /* -70..-1 dBm */
+ min_diff = 5;
+ else /* unspecified units (not in dBm) */
+ min_diff = 2;
+
+ if (cur_est > sel_est * 1.5)
+ min_diff += 10;
+ else if (cur_est > sel_est * 1.2)
+ min_diff += 5;
+ else if (cur_est > sel_est * 1.1)
+ min_diff += 2;
+ else if (cur_est > sel_est)
+ min_diff++;
+ else if (sel_est > cur_est * 1.5)
+ min_diff -= 10;
+ else if (sel_est > cur_est * 1.2)
+ min_diff -= 5;
+ else if (sel_est > cur_est * 1.1)
+ min_diff -= 2;
+ else if (sel_est > cur_est)
+ min_diff--;
+
+ if (to_5ghz)
+ min_diff -= 2;
+ diff = selected->level - cur_level;
if (diff < min_diff) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Skip roam - too small difference in signal level (%d < %d)",
@@ -1887,15 +2024,6 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
goto scan_work_done;
}
- if (ap) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode");
-#ifdef CONFIG_AP
- if (wpa_s->ap_iface->scan_cb)
- wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
-#endif /* CONFIG_AP */
- goto scan_work_done;
- }
-
wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)",
wpa_s->own_scan_running,
data ? data->scan_info.external_scan : 0);
@@ -1912,6 +2040,15 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
wpas_notify_scan_done(wpa_s, 1);
+ if (ap) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode");
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface->scan_cb)
+ wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
+#endif /* CONFIG_AP */
+ goto scan_work_done;
+ }
+
if (data && data->scan_info.external_scan) {
wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection");
wpa_scan_results_free(scan_res);
@@ -2194,7 +2331,8 @@ int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
return -1;
os_get_reltime(&now);
- if (os_reltime_expired(&now, &wpa_s->last_scan, 5)) {
+ if (os_reltime_expired(&now, &wpa_s->last_scan,
+ SCAN_RES_VALID_FOR_CONNECT)) {
wpa_printf(MSG_DEBUG, "Fast associate: Old scan results");
return -1;
}
@@ -2327,28 +2465,41 @@ static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s,
const u8 *map_sub_elem, *pos;
size_t len;
- if (!wpa_s->current_ssid ||
- !wpa_s->current_ssid->multi_ap_backhaul_sta ||
- !ies ||
- ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
- return;
+ wpa_s->multi_ap_ie = 0;
- if (!elems.multi_ap || elems.multi_ap_len < 7) {
- wpa_printf(MSG_INFO, "AP doesn't support Multi-AP protocol");
- goto fail;
- }
+ if (!ies ||
+ ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed ||
+ !elems.multi_ap || elems.multi_ap_len < 7)
+ return;
pos = elems.multi_ap + 4;
len = elems.multi_ap_len - 4;
map_sub_elem = get_ie(pos, len, MULTI_AP_SUB_ELEM_TYPE);
- if (!map_sub_elem || map_sub_elem[1] < 1) {
- wpa_printf(MSG_INFO, "invalid Multi-AP sub elem type");
+ if (!map_sub_elem || map_sub_elem[1] < 1)
+ return;
+
+ wpa_s->multi_ap_backhaul = !!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS);
+ wpa_s->multi_ap_fronthaul = !!(map_sub_elem[2] &
+ MULTI_AP_FRONTHAUL_BSS);
+ wpa_s->multi_ap_ie = 1;
+}
+
+
+static void multi_ap_set_4addr_mode(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->current_ssid ||
+ !wpa_s->current_ssid->multi_ap_backhaul_sta)
+ return;
+
+ if (!wpa_s->multi_ap_ie) {
+ wpa_printf(MSG_INFO,
+ "AP does not include valid Multi-AP element");
goto fail;
}
- if (!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS)) {
- if ((map_sub_elem[2] & MULTI_AP_FRONTHAUL_BSS) &&
+ if (!wpa_s->multi_ap_backhaul) {
+ if (wpa_s->multi_ap_fronthaul &&
wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
wpa_printf(MSG_INFO,
"WPS active, accepting fronthaul-only BSS");
@@ -2472,8 +2623,14 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
wpa_s->connection_set = 1;
wpa_s->connection_ht = req_elems.ht_capabilities &&
resp_elems.ht_capabilities;
+ /* Do not include subset of VHT on 2.4 GHz vendor
+ * extension in consideration for reporting VHT
+ * association. */
wpa_s->connection_vht = req_elems.vht_capabilities &&
- resp_elems.vht_capabilities;
+ resp_elems.vht_capabilities &&
+ (!data->assoc_info.freq ||
+ wpas_freq_to_band(data->assoc_info.freq) !=
+ BAND_2_4_GHZ);
wpa_s->connection_he = req_elems.he_capabilities &&
resp_elems.he_capabilities;
@@ -2818,6 +2975,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_AP */
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ wpa_s->own_reconnect_req = 0;
ft_completed = wpa_ft_is_completed(wpa_s->wpa);
if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
@@ -2867,6 +3025,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
}
}
+ multi_ap_set_4addr_mode(wpa_s);
+
if (wpa_s->conf->ap_scan == 1 &&
wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION) {
if (wpa_supplicant_assoc_update_ie(wpa_s) < 0 && new_bss)
@@ -2971,6 +3131,13 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wpa_s->last_eapol_matches_bssid = 0;
#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->rsne_override_eapol) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: RSNE EAPOL-Key msg 2/4 override");
+ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa,
+ wpabuf_head(wpa_s->rsne_override_eapol),
+ wpabuf_len(wpa_s->rsne_override_eapol));
+ }
if (wpa_s->rsnxe_override_eapol) {
wpa_printf(MSG_DEBUG,
"TESTING: RSNXE EAPOL-Key msg 2/4 override");
@@ -2999,6 +3166,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wpa_s->pending_eapol_rx = NULL;
}
+#ifdef CONFIG_WEP
if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
wpa_s->current_ssid &&
@@ -3006,6 +3174,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
/* Set static WEP keys again */
wpa_set_wep_keys(wpa_s, wpa_s->current_ssid);
}
+#endif /* CONFIG_WEP */
#ifdef CONFIG_IBSS_RSN
if (wpa_s->current_ssid &&
@@ -3051,6 +3220,10 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_MBO
wpas_mbo_check_pmf(wpa_s, bss, wpa_s->current_ssid);
#endif /* CONFIG_MBO */
+
+#ifdef CONFIG_DPP2
+ wpa_s->dpp_pfs_fallback = 0;
+#endif /* CONFIG_DPP2 */
}
@@ -3178,21 +3351,25 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
if (wpa_s->wpa_state == WPA_COMPLETED &&
wpa_s->current_ssid &&
wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
- !locally_generated &&
- disconnect_reason_recoverable(reason_code)) {
+ (wpa_s->own_reconnect_req ||
+ (!locally_generated &&
+ disconnect_reason_recoverable(reason_code)))) {
/*
* It looks like the AP has dropped association with
- * us, but could allow us to get back in. Try to
- * reconnect to the same BSS without full scan to save
- * time for some common cases.
+ * us, but could allow us to get back in. This is also
+ * triggered for cases where local reconnection request
+ * is used to force reassociation with the same BSS.
+ * Try to reconnect to the same BSS without a full scan
+ * to save time for some common cases.
*/
fast_reconnect = wpa_s->current_bss;
fast_reconnect_ssid = wpa_s->current_ssid;
- } else if (wpa_s->wpa_state >= WPA_ASSOCIATING)
+ } else if (wpa_s->wpa_state >= WPA_ASSOCIATING) {
wpa_supplicant_req_scan(wpa_s, 0, 100000);
- else
+ } else {
wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new "
"immediate scan");
+ }
} else {
wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect disabled: do not "
"try to re-connect");
@@ -4216,6 +4393,39 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ /* Try to follow AP's PFS policy. WLAN_STATUS_ASSOC_DENIED_UNSPEC is
+ * the status code defined in the DPP R2 tech spec.
+ * WLAN_STATUS_AKMP_NOT_VALID is addressed in the same manner as an
+ * interoperability workaround with older hostapd implementation. */
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP &&
+ wpa_s->current_ssid->dpp_pfs == 0 &&
+ (data->assoc_reject.status_code ==
+ WLAN_STATUS_ASSOC_DENIED_UNSPEC ||
+ data->assoc_reject.status_code == WLAN_STATUS_AKMP_NOT_VALID)) {
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct wpa_bss *bss = wpa_s->current_bss;
+
+ wpa_s->current_ssid->dpp_pfs_fallback ^= 1;
+ if (!bss)
+ bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+ if (!bss || wpa_s->dpp_pfs_fallback) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Updated PFS policy for next try");
+ wpas_connection_failed(wpa_s, bssid);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Try again with updated PFS policy");
+ wpa_s->dpp_pfs_fallback = 1;
+ wpas_connect_work_done(wpa_s);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+
#ifdef CONFIG_MBO
if (data->assoc_reject.status_code ==
WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
@@ -4282,11 +4492,44 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
}
+static void wpas_event_unprot_beacon(struct wpa_supplicant *wpa_s,
+ struct unprot_beacon *data)
+{
+ struct wpabuf *buf;
+ int res;
+
+ if (!data || wpa_s->wpa_state != WPA_COMPLETED ||
+ os_memcmp(data->sa, wpa_s->bssid, ETH_ALEN) != 0)
+ return;
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_UNPROT_BEACON MACSTR,
+ MAC2STR(data->sa));
+
+ buf = wpabuf_alloc(4);
+ if (!buf)
+ return;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+ wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
+ wpabuf_put_u8(buf, 1); /* Dialog Token */
+ wpabuf_put_u8(buf, WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE);
+
+ res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (res < 0)
+ wpa_printf(MSG_DEBUG,
+ "Failed to send WNM-Notification Request frame");
+
+ wpabuf_free(buf);
+}
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
struct wpa_supplicant *wpa_s = ctx;
int resched;
+ struct os_reltime age, clear_at;
#ifndef CONFIG_NO_STDOUT_DEBUG
int level = MSG_DEBUG;
#endif /* CONFIG_NO_STDOUT_DEBUG */
@@ -4589,6 +4832,20 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_s->assoc_freq = data->ch_switch.freq;
wpa_s->current_ssid->frequency = data->ch_switch.freq;
+#ifdef CONFIG_SME
+ switch (data->ch_switch.ch_offset) {
+ case 1:
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_ABOVE;
+ break;
+ case -1:
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_BELOW;
+ break;
+ default:
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_UNKNOWN;
+ break;
+ }
+#endif /* CONFIG_SME */
+
#ifdef CONFIG_AP
if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO ||
@@ -4811,6 +5068,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
case EVENT_INTERFACE_ENABLED:
wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ eloop_cancel_timeout(wpas_clear_disabled_interface,
+ wpa_s, NULL);
wpa_supplicant_update_mac_addr(wpa_s);
wpa_supplicant_set_default_scan_ies(wpa_s);
if (wpa_s->p2p_mgmt) {
@@ -4879,8 +5138,20 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1);
}
wpa_supplicant_mark_disassoc(wpa_s);
- if (!wpa_s->conf->bss_no_flush_when_down)
- wpa_bss_flush(wpa_s);
+ os_reltime_age(&wpa_s->last_scan, &age);
+ if (age.sec >= SCAN_RES_VALID_FOR_CONNECT) {
+ clear_at.sec = SCAN_RES_VALID_FOR_CONNECT;
+ clear_at.usec = 0;
+ } else {
+ struct os_reltime tmp;
+
+ tmp.sec = SCAN_RES_VALID_FOR_CONNECT;
+ tmp.usec = 0;
+ os_reltime_sub(&tmp, &age, &clear_at);
+ }
+ eloop_register_timeout(clear_at.sec, clear_at.usec,
+ wpas_clear_disabled_interface,
+ wpa_s, NULL);
radio_remove_works(wpa_s, NULL, 0);
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
@@ -5057,6 +5328,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->sta_opmode.rx_nss);
#endif /* CONFIG_AP */
break;
+ case EVENT_UNPROT_BEACON:
+ wpas_event_unprot_beacon(wpa_s, &data->unprot_beacon);
+ break;
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break;
diff --git a/wpa_supplicant/examples/dpp-nfc.py b/wpa_supplicant/examples/dpp-nfc.py
new file mode 100755
index 00000000..f49da34f
--- /dev/null
+++ b/wpa_supplicant/examples/dpp-nfc.py
@@ -0,0 +1,692 @@
+#!/usr/bin/python3
+#
+# Example nfcpy to wpa_supplicant wrapper for DPP NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2019-2020, The Linux Foundation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+import threading
+import argparse
+
+import nfc
+import ndef
+
+import logging
+
+scriptsdir = os.path.dirname(os.path.realpath("dpp-nfc.py"))
+sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy'))
+import wpaspy
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+ifname = None
+init_on_touch = False
+in_raw_mode = False
+prev_tcgetattr = 0
+no_input = False
+srv = None
+continue_loop = True
+terminate_now = False
+summary_file = None
+success_file = None
+
+def summary(txt):
+ print(txt)
+ if summary_file:
+ with open(summary_file, 'a') as f:
+ f.write(txt + "\n")
+
+def success_report(txt):
+ summary(txt)
+ if success_file:
+ with open(success_file, 'a') as f:
+ f.write(txt + "\n")
+
+def wpas_connect():
+ ifaces = []
+ if os.path.isdir(wpas_ctrl):
+ try:
+ ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+ except OSError as error:
+ print("Could not find wpa_supplicant: ", error)
+ return None
+
+ if len(ifaces) < 1:
+ print("No wpa_supplicant control interface found")
+ return None
+
+ for ctrl in ifaces:
+ if ifname:
+ if ifname not in ctrl:
+ continue
+ try:
+ print("Trying to use control interface " + ctrl)
+ wpas = wpaspy.Ctrl(ctrl)
+ return wpas
+ except Exception as e:
+ pass
+ return None
+
+def dpp_nfc_uri_process(uri):
+ wpas = wpas_connect()
+ if wpas is None:
+ return False
+ peer_id = wpas.request("DPP_NFC_URI " + uri)
+ if "FAIL" in peer_id:
+ print("Could not parse DPP URI from NFC URI record")
+ return False
+ peer_id = int(peer_id)
+ print("peer_id=%d" % peer_id)
+ cmd = "DPP_AUTH_INIT peer=%d" % peer_id
+ res = wpas.request(cmd)
+ if "OK" not in res:
+ print("Failed to initiate DPP Authentication")
+ return False
+ print("DPP Authentication initiated")
+ return True
+
+def dpp_hs_tag_read(record):
+ wpas = wpas_connect()
+ if wpas is None:
+ return False
+ print(record)
+ if len(record.data) < 5:
+ print("Too short DPP HS")
+ return False
+ if record.data[0] != 0:
+ print("Unexpected URI Identifier Code")
+ return False
+ uribuf = record.data[1:]
+ try:
+ uri = uribuf.decode()
+ except:
+ print("Invalid URI payload")
+ return False
+ print("URI: " + uri)
+ if not uri.startswith("DPP:"):
+ print("Not a DPP URI")
+ return False
+ return dpp_nfc_uri_process(uri)
+
+def get_status(wpas, extra=None):
+ if extra:
+ extra = "-" + extra
+ else:
+ extra = ""
+ res = wpas.request("STATUS" + extra)
+ lines = res.splitlines()
+ vals = dict()
+ for l in lines:
+ try:
+ [name, value] = l.split('=', 1)
+ except ValueError:
+ logger.info("Ignore unexpected status line: " + l)
+ continue
+ vals[name] = value
+ return vals
+
+def get_status_field(wpas, field, extra=None):
+ vals = get_status(wpas, extra)
+ if field in vals:
+ return vals[field]
+ return None
+
+def own_addr(wpas):
+ return get_status_field(wpas, "address")
+
+def dpp_bootstrap_gen(wpas, type="qrcode", chan=None, mac=None, info=None,
+ curve=None, key=None):
+ cmd = "DPP_BOOTSTRAP_GEN type=" + type
+ if chan:
+ cmd += " chan=" + chan
+ if mac:
+ if mac is True:
+ mac = own_addr(wpas)
+ cmd += " mac=" + mac.replace(':', '')
+ if info:
+ cmd += " info=" + info
+ if curve:
+ cmd += " curve=" + curve
+ if key:
+ cmd += " key=" + key
+ res = wpas.request(cmd)
+ if "FAIL" in res:
+ raise Exception("Failed to generate bootstrapping info")
+ return int(res)
+
+def wpas_get_nfc_uri(start_listen=True):
+ wpas = wpas_connect()
+ if wpas is None:
+ return None
+ global own_id, chanlist
+ own_id = dpp_bootstrap_gen(wpas, type="nfc-uri", chan=chanlist, mac=True)
+ res = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
+ if "FAIL" in res:
+ return None
+ if start_listen:
+ wpas.request("DPP_LISTEN 2412 netrole=configurator")
+ return res
+
+def wpas_report_handover_req(uri):
+ wpas = wpas_connect()
+ if wpas is None:
+ return None
+ global own_id
+ cmd = "DPP_NFC_HANDOVER_REQ own=%d uri=%s" % (own_id, uri)
+ return wpas.request(cmd)
+
+def wpas_report_handover_sel(uri):
+ wpas = wpas_connect()
+ if wpas is None:
+ return None
+ global own_id
+ cmd = "DPP_NFC_HANDOVER_SEL own=%d uri=%s" % (own_id, uri)
+ return wpas.request(cmd)
+
+def dpp_handover_client(llc):
+ uri = wpas_get_nfc_uri(start_listen=False)
+ uri = ndef.UriRecord(uri)
+ print("NFC URI record for DPP: " + str(uri))
+ carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+ hr = ndef.HandoverRequestRecord(version="1.4", crn=os.urandom(2))
+ hr.add_alternative_carrier('active', carrier.name)
+ message = [hr, carrier]
+ print("NFC Handover Request message for DPP: " + str(message))
+
+ client = nfc.handover.HandoverClient(llc)
+ try:
+ summary("Trying to initiate NFC connection handover")
+ client.connect()
+ summary("Connected for handover")
+ except nfc.llcp.ConnectRefused:
+ summary("Handover connection refused")
+ client.close()
+ return
+ except Exception as e:
+ summary("Other exception: " + str(e))
+ client.close()
+ return
+
+ summary("Sending handover request")
+
+ if not client.send_records(message):
+ summary("Failed to send handover request")
+ client.close()
+ return
+
+ summary("Receiving handover response")
+ message = client.recv_records(timeout=3.0)
+ if message is None:
+ summary("No response received")
+ client.close()
+ return
+ print("Received message: " + str(message))
+ if len(message) < 1 or \
+ not isinstance(message[0], ndef.HandoverSelectRecord):
+ summary("Response was not Hs - received: " + message.type)
+ client.close()
+ return
+
+ print("Received message")
+ print("alternative carriers: " + str(message[0].alternative_carriers))
+
+ dpp_found = False
+ for carrier in message:
+ if isinstance(carrier, ndef.HandoverSelectRecord):
+ continue
+ print("Remote carrier type: " + carrier.type)
+ if carrier.type == "application/vnd.wfa.dpp":
+ if len(carrier.data) == 0 or carrier.data[0] != 0:
+ print("URI Identifier Code 'None' not seen")
+ continue
+ print("DPP carrier type match - send to wpa_supplicant")
+ dpp_found = True
+ uri = carrier.data[1:].decode("utf-8")
+ print("DPP URI: " + uri)
+ res = wpas_report_handover_sel(uri)
+ if res is None or "FAIL" in res:
+ summary("DPP handover report rejected")
+ break
+
+ success_report("DPP handover reported successfully (initiator)")
+ print("peer_id=" + res)
+ peer_id = int(res)
+ # TODO: Single Configurator instance
+ wpas = wpas_connect()
+ if wpas is None:
+ break
+ res = wpas.request("DPP_CONFIGURATOR_ADD")
+ if "FAIL" in res:
+ print("Failed to initiate Configurator")
+ break
+ conf_id = int(res)
+ global own_id
+ print("Initiate DPP authentication")
+ cmd = "DPP_AUTH_INIT peer=%d own=%d conf=sta-dpp configurator=%d" % (peer_id, own_id, conf_id)
+ res = wpas.request(cmd)
+ if "FAIL" in res:
+ print("Failed to initiate DPP authentication")
+ break
+
+ if not dpp_found:
+ print("DPP carrier not seen in response - allow peer to initiate a new handover with different parameters")
+ client.close()
+ print("Returning from dpp_handover_client")
+ return
+
+ print("Remove peer")
+ client.close()
+ print("Done with handover")
+ global only_one
+ if only_one:
+ print("only_one -> stop loop")
+ global continue_loop
+ continue_loop = False
+
+ global no_wait
+ if no_wait:
+ print("Trying to exit..")
+ global terminate_now
+ terminate_now = True
+
+ print("Returning from dpp_handover_client")
+
+class HandoverServer(nfc.handover.HandoverServer):
+ def __init__(self, llc):
+ super(HandoverServer, self).__init__(llc)
+ self.sent_carrier = None
+ self.ho_server_processing = False
+ self.success = False
+ self.try_own = False
+
+ def process_handover_request_message(self, records):
+ self.ho_server_processing = True
+ clear_raw_mode()
+ print("\nHandoverServer - request received: " + str(records))
+
+ carrier = None
+ hs = ndef.HandoverSelectRecord('1.4')
+ sel = [hs]
+
+ found = False
+
+ for carrier in records:
+ if isinstance(carrier, ndef.HandoverRequestRecord):
+ continue
+ print("Remote carrier type: " + carrier.type)
+ if carrier.type == "application/vnd.wfa.dpp":
+ print("DPP carrier type match - add DPP carrier record")
+ if len(carrier.data) == 0 or carrier.data[0] != 0:
+ print("URI Identifier Code 'None' not seen")
+ continue
+ uri = carrier.data[1:].decode("utf-8")
+ print("Received DPP URI: " + uri)
+
+ data = wpas_get_nfc_uri(start_listen=False)
+ print("Own URI (pre-processing): %s" % data)
+
+ res = wpas_report_handover_req(uri)
+ if res is None or "FAIL" in res:
+ print("DPP handover request processing failed")
+ continue
+
+ found = True
+ self.received_carrier = carrier
+
+ wpas = wpas_connect()
+ if wpas is None:
+ continue
+ global own_id
+ data = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
+ if "FAIL" in data:
+ continue
+ print("Own URI (post-processing): %s" % data)
+ uri = ndef.UriRecord(data)
+ print("Own bootstrapping NFC URI record: " + str(uri))
+
+ info = wpas.request("DPP_BOOTSTRAP_INFO %d" % own_id)
+ freq = None
+ for line in info.splitlines():
+ if line.startswith("use_freq="):
+ freq = int(line.split('=')[1])
+ if freq is None:
+ print("No channel negotiated over NFC - use channel 1")
+ freq = 2412
+ res = wpas.request("DPP_LISTEN %d" % freq)
+ if "OK" not in res:
+ print("Failed to start DPP listen")
+ break
+
+ carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+ print("Own DPP carrier record: " + str(carrier))
+ hs.add_alternative_carrier('active', carrier.name)
+ sel = [hs, carrier]
+ break
+
+ summary("Sending handover select: " + str(sel))
+ if found:
+ self.success = True
+ else:
+ self.try_own = True
+ return sel
+
+def clear_raw_mode():
+ import sys, tty, termios
+ global prev_tcgetattr, in_raw_mode
+ if not in_raw_mode:
+ return
+ fd = sys.stdin.fileno()
+ termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
+ in_raw_mode = False
+
+def getch():
+ import sys, tty, termios, select
+ global prev_tcgetattr, in_raw_mode
+ fd = sys.stdin.fileno()
+ prev_tcgetattr = termios.tcgetattr(fd)
+ ch = None
+ try:
+ tty.setraw(fd)
+ in_raw_mode = True
+ [i, o, e] = select.select([fd], [], [], 0.05)
+ if i:
+ ch = sys.stdin.read(1)
+ finally:
+ termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
+ in_raw_mode = False
+ return ch
+
+def dpp_tag_read(tag):
+ success = False
+ for record in tag.ndef.records:
+ print(record)
+ print("record type " + record.type)
+ if record.type == "application/vnd.wfa.dpp":
+ summary("DPP HS tag - send to wpa_supplicant")
+ success = dpp_hs_tag_read(record)
+ break
+ if isinstance(record, ndef.UriRecord):
+ print("URI record: uri=" + record.uri)
+ print("URI record: iri=" + record.iri)
+ if record.iri.startswith("DPP:"):
+ print("DPP URI")
+ if not dpp_nfc_uri_process(record.iri):
+ break
+ success = True
+ else:
+ print("Ignore unknown URI")
+ break
+
+ if success:
+ success_report("Tag read succeeded")
+
+ return success
+
+def rdwr_connected_write_tag(tag):
+ summary("Tag found - writing - " + str(tag))
+ if not tag.ndef.is_writeable:
+ print("Not a writable tag")
+ return
+ global dpp_tag_data
+ if tag.ndef.capacity < len(dpp_tag_data):
+ print("Not enough room for the message")
+ return
+ tag.ndef.records = dpp_tag_data
+ success_report("Tag write succeeded")
+ print("Done - remove tag")
+ global only_one
+ if only_one:
+ global continue_loop
+ continue_loop = False
+ global dpp_sel_wait_remove
+ return dpp_sel_wait_remove
+
+def write_nfc_uri(clf, wait_remove=True):
+ print("Write NFC URI record")
+ data = wpas_get_nfc_uri()
+ if data is None:
+ summary("Could not get NFC URI from wpa_supplicant")
+ return
+
+ global dpp_sel_wait_remove
+ dpp_sel_wait_remove = wait_remove
+ print("URI: %s" % data)
+ uri = ndef.UriRecord(data)
+ print(uri)
+
+ print("Touch an NFC tag")
+ global dpp_tag_data
+ dpp_tag_data = [uri]
+ clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
+
+def write_nfc_hs(clf, wait_remove=True):
+ print("Write NFC Handover Select record on a tag")
+ data = wpas_get_nfc_uri()
+ if data is None:
+ summary("Could not get NFC URI from wpa_supplicant")
+ return
+
+ global dpp_sel_wait_remove
+ dpp_sel_wait_remove = wait_remove
+ print("URI: %s" % data)
+ uri = ndef.UriRecord(data)
+ print(uri)
+ carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+ hs = ndef.HandoverSelectRecord('1.4')
+ hs.add_alternative_carrier('active', carrier.name)
+ print(hs)
+ print(carrier)
+
+ print("Touch an NFC tag")
+ global dpp_tag_data
+ dpp_tag_data = [hs, carrier]
+ print(dpp_tag_data)
+ clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
+
+def rdwr_connected(tag):
+ global only_one, no_wait
+ summary("Tag connected: " + str(tag))
+
+ if tag.ndef:
+ print("NDEF tag: " + tag.type)
+ print(tag.ndef.records)
+ success = dpp_tag_read(tag)
+ if only_one and success:
+ global continue_loop
+ continue_loop = False
+ else:
+ summary("Not an NDEF tag - remove tag")
+ return True
+
+ return not no_wait
+
+def llcp_worker(llc):
+ global init_on_touch
+ if init_on_touch:
+ print("Starting handover client")
+ dpp_handover_client(llc)
+ print("Exiting llcp_worker thread (init_in_touch)")
+ return
+
+ global no_input
+ if no_input:
+ print("Wait for handover to complete")
+ else:
+ print("Wait for handover to complete - press 'i' to initiate")
+ global srv
+ global wait_connection
+ while not wait_connection and srv.sent_carrier is None:
+ if srv.try_own:
+ srv.try_own = False
+ print("Try to initiate another handover with own parameters")
+ dpp_handover_client(llc)
+ print("Exiting llcp_worker thread (retry with own parameters)")
+ return
+ if srv.ho_server_processing:
+ time.sleep(0.025)
+ elif no_input:
+ time.sleep(0.5)
+ else:
+ res = getch()
+ if res != 'i':
+ continue
+ clear_raw_mode()
+ print("Starting handover client")
+ dpp_handover_client(llc)
+ print("Exiting llcp_worker thread (manual init)")
+ return
+
+ clear_raw_mode()
+ print("\rExiting llcp_worker thread")
+
+def llcp_startup(llc):
+ print("Start LLCP server")
+ global srv
+ srv = HandoverServer(llc)
+ return llc
+
+def llcp_connected(llc):
+ print("P2P LLCP connected")
+ global wait_connection
+ wait_connection = False
+ global init_on_touch
+ if not init_on_touch:
+ global srv
+ srv.start()
+ if init_on_touch or not no_input:
+ threading.Thread(target=llcp_worker, args=(llc,)).start()
+ return True
+
+def llcp_release(llc):
+ print("LLCP release")
+ return True
+
+def terminate_loop():
+ global terminate_now
+ return terminate_now
+
+def main():
+ clf = nfc.ContactlessFrontend()
+
+ parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for DPP NFC operations')
+ parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+ action='store_const', dest='loglevel',
+ help='verbose debug output')
+ parser.add_argument('-q', const=logging.WARNING, action='store_const',
+ dest='loglevel', help='be quiet')
+ parser.add_argument('--only-one', '-1', action='store_true',
+ help='run only one operation and exit')
+ parser.add_argument('--init-on-touch', '-I', action='store_true',
+ help='initiate handover on touch')
+ parser.add_argument('--no-wait', action='store_true',
+ help='do not wait for tag to be removed before exiting')
+ parser.add_argument('--ifname', '-i',
+ help='network interface name')
+ parser.add_argument('--no-input', '-a', action='store_true',
+ help='do not use stdout input to initiate handover')
+ parser.add_argument('--tag-read-only', '-t', action='store_true',
+ help='tag read only (do not allow connection handover)')
+ parser.add_argument('--handover-only', action='store_true',
+ help='connection handover only (do not allow tag read)')
+ parser.add_argument('--summary',
+ help='summary file for writing status updates')
+ parser.add_argument('--success',
+ help='success file for writing success update')
+ parser.add_argument('--device', default='usb', help='NFC device to open')
+ parser.add_argument('--chan', default='81/1', help='channel list')
+ parser.add_argument('command', choices=['write-nfc-uri',
+ 'write-nfc-hs'],
+ nargs='?')
+ args = parser.parse_args()
+ print(args)
+
+ global only_one
+ only_one = args.only_one
+
+ global no_wait
+ no_wait = args.no_wait
+
+ global chanlist
+ chanlist = args.chan
+
+ logging.basicConfig(level=args.loglevel)
+
+ global init_on_touch
+ init_on_touch = args.init_on_touch
+
+ if args.ifname:
+ global ifname
+ ifname = args.ifname
+ print("Selected ifname " + ifname)
+
+ if args.summary:
+ global summary_file
+ summary_file = args.summary
+
+ if args.success:
+ global success_file
+ success_file = args.success
+
+ if args.no_input:
+ global no_input
+ no_input = True
+
+ clf = nfc.ContactlessFrontend()
+ global wait_connection
+
+ try:
+ if not clf.open(args.device):
+ print("Could not open connection with an NFC device")
+ raise SystemExit
+
+ if args.command == "write-nfc-uri":
+ write_nfc_uri(clf, wait_remove=not args.no_wait)
+ raise SystemExit
+
+ if args.command == "write-nfc-hs":
+ write_nfc_hs(clf, wait_remove=not args.no_wait)
+ raise SystemExit
+
+ global continue_loop
+ while continue_loop:
+ clear_raw_mode()
+ print("\rWaiting for a tag or peer to be touched")
+ wait_connection = True
+ try:
+ if args.tag_read_only:
+ if not clf.connect(rdwr={'on-connect': rdwr_connected}):
+ break
+ elif args.handover_only:
+ if not clf.connect(llcp={'on-startup': llcp_startup,
+ 'on-connect': llcp_connected,
+ 'on-release': llcp_release},
+ terminate=terminate_loop):
+ break
+ else:
+ if not clf.connect(rdwr={'on-connect': rdwr_connected},
+ llcp={'on-startup': llcp_startup,
+ 'on-connect': llcp_connected,
+ 'on-release': llcp_release},
+ terminate=terminate_loop):
+ break
+ except Exception as e:
+ print("clf.connect failed: " + str(e))
+ break
+
+ global srv
+ if only_one and srv and srv.success:
+ raise SystemExit
+
+ except KeyboardInterrupt:
+ raise SystemExit
+ finally:
+ clf.close()
+
+ raise SystemExit
+
+if __name__ == '__main__':
+ main()
diff --git a/wpa_supplicant/examples/p2p/p2p_connect.py b/wpa_supplicant/examples/p2p/p2p_connect.py
index 6e3d94e2..2f62e9c9 100644
--- a/wpa_supplicant/examples/p2p/p2p_connect.py
+++ b/wpa_supplicant/examples/p2p/p2p_connect.py
@@ -108,7 +108,7 @@ class P2P_Connect():
self.path = None
try:
self.path = self.wpas.GetInterface(ifname)
- except:
+ except dbus.DBusException as exc:
if not str(exc).startswith(
self.wpas_dbus_interface + \
".InterfaceUnknown:"):
diff --git a/wpa_supplicant/hidl/1.3/p2p_iface.cpp b/wpa_supplicant/hidl/1.3/p2p_iface.cpp
index bd893a34..ffa9b6a6 100644
--- a/wpa_supplicant/hidl/1.3/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/1.3/p2p_iface.cpp
@@ -100,7 +100,7 @@ void setBandScanFreqsList(
struct hostapd_hw_modes *mode;
int count, i;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, 0);
if (mode == NULL) {
/* No channels supported in this band. */
return;
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 36c0aff1..02e63904 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -64,10 +64,16 @@ static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
{
struct ibss_rsn_peer *peer = ctx;
struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s;
+ int encrypt = peer->authentication_status & IBSS_RSN_REPORTED_PTK;
- wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
- "len=%lu)",
- __func__, MAC2STR(dest), proto, (unsigned long) len);
+ wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR
+ " proto=0x%04x len=%lu no_encrypt=%d)",
+ __func__, MAC2STR(dest), proto, (unsigned long) len,
+ !encrypt);
+
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT)
+ return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len,
+ !encrypt);
if (wpa_s->l2)
return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
@@ -140,7 +146,7 @@ static void ibss_check_rsn_completed(struct ibss_rsn_peer *peer)
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)
+ const u8 *key, size_t key_len, enum key_flag key_flag)
{
struct ibss_rsn_peer *peer = ctx;
@@ -167,7 +173,7 @@ static int supp_set_key(void *ctx, enum wpa_alg alg,
if (is_broadcast_ether_addr(addr))
addr = peer->addr;
return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx,
- set_tx, seq, seq_len, key, key_len);
+ set_tx, seq, seq_len, key, key_len, key_flag);
}
@@ -194,7 +200,13 @@ static void supp_cancel_auth_timeout(void *ctx)
}
-static void supp_deauthenticate(void * ctx, u16 reason_code)
+static void supp_deauthenticate(void *ctx, u16 reason_code)
+{
+ wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__);
+}
+
+
+static void supp_reconnect(void *ctx)
{
wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__);
}
@@ -219,6 +231,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
ctx->mlme_setprotection = supp_mlme_setprotection;
ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
ctx->deauthenticate = supp_deauthenticate;
+ ctx->reconnect = supp_reconnect;
peer->supp = wpa_sm_init(ctx);
if (peer->supp == NULL) {
wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
@@ -287,6 +300,10 @@ static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
"encrypt=%d)",
__func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT)
+ return wpa_drv_tx_control_port(wpa_s, addr, ETH_P_EAPOL,
+ data, data_len, !encrypt);
+
if (wpa_s->l2)
return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data,
data_len);
@@ -296,7 +313,8 @@ static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
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)
+ const u8 *addr, int idx, u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
struct ibss_rsn *ibss_rsn = ctx;
u8 seq[6];
@@ -335,7 +353,7 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
}
return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx,
- 1, seq, 6, key, key_len);
+ 1, seq, 6, key, key_len, key_flag);
}
@@ -487,9 +505,6 @@ static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq)
const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth);
struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s;
- if (wpa_s->driver->send_frame == NULL)
- return -1;
-
os_memset(&auth, 0, sizeof(auth));
auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -505,8 +520,7 @@ static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq)
wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR,
seq, MAC2STR(da));
- return wpa_s->driver->send_frame(wpa_s->drv_priv, (u8 *) &auth,
- auth_length, 0);
+ return wpa_drv_send_mlme(wpa_s, (u8 *) &auth, auth_length, 0, 0, 0);
}
@@ -852,7 +866,7 @@ static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn,
wpa_printf(MSG_DEBUG, "RSN: Clear pairwise key for peer "
MACSTR, MAC2STR(addr));
wpa_drv_set_key(ibss_rsn->wpa_s, WPA_ALG_NONE, addr, 0, 0,
- NULL, 0, NULL, 0);
+ NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
}
if (peer &&
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 308366f6..4925b5cd 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -233,12 +233,10 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
2 + 24 + /* peering management */
2 + 96 + 32 + 32 + /* AMPE (96 + max GTKlen + max IGTKlen) */
2 + 16; /* MIC */
-#ifdef CONFIG_IEEE80211N
if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
buf_len += 2 + 26 + /* HT capabilities */
2 + 22; /* HT operation */
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
buf_len += 2 + 12 + /* VHT Capabilities */
@@ -354,7 +352,6 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
wpabuf_put(buf, PMKID_LEN));
}
-#ifdef CONFIG_IEEE80211N
if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
u8 ht_capa_oper[2 + 26 + 2 + 22];
@@ -362,7 +359,6 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
pos = hostapd_eid_ht_operation(bss, pos);
wpabuf_put_data(buf, ht_capa_oper, pos - ht_capa_oper);
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
u8 vht_capa_oper[2 + 12 + 2 + 5];
@@ -696,9 +692,7 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
struct hostapd_data *data = wpa_s->ifmsh->bss[0];
struct sta_info *sta;
-#ifdef CONFIG_IEEE80211N
struct ieee80211_ht_operation *oper;
-#endif /* CONFIG_IEEE80211N */
int ret;
if (elems->mesh_config_len >= 7 &&
@@ -710,11 +704,12 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
}
sta = ap_get_sta(data, addr);
- if (!sta) {
- sta = ap_sta_add(data, addr);
- if (!sta)
- return NULL;
- }
+ if (sta)
+ return NULL;
+
+ sta = ap_sta_add(data, addr);
+ if (!sta)
+ return NULL;
/* Set WMM by default since Mesh STAs are QoS STAs */
sta->flags |= WLAN_STA_WMM;
@@ -728,7 +723,6 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
if (!sta->my_lid)
mesh_mpm_init_link(wpa_s, sta);
-#ifdef CONFIG_IEEE80211N
copy_sta_ht_capab(data, sta, elems->ht_capabilities);
oper = (struct ieee80211_ht_operation *) elems->ht_operation;
@@ -742,7 +736,6 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
}
update_ht_state(data, sta);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
copy_sta_vht_capab(data, sta, elems->vht_capabilities);
@@ -876,7 +869,8 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len);
wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->pairwise_cipher),
sta->addr, 0, 0, seq, sizeof(seq),
- sta->mtk, sta->mtk_len);
+ sta->mtk, sta->mtk_len,
+ KEY_FLAG_PAIRWISE_RX_TX);
wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK Key RSC",
sta->mgtk_rsc, sizeof(sta->mgtk_rsc));
@@ -885,7 +879,8 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->group_cipher),
sta->addr, sta->mgtk_key_id, 0,
sta->mgtk_rsc, sizeof(sta->mgtk_rsc),
- sta->mgtk, sta->mgtk_len);
+ sta->mgtk, sta->mgtk_len,
+ KEY_FLAG_GROUP_RX);
if (sta->igtk_len) {
wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK Key RSC",
@@ -897,7 +892,8 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
wpa_cipher_to_alg(conf->mgmt_group_cipher),
sta->addr, sta->igtk_key_id, 0,
sta->igtk_rsc, sizeof(sta->igtk_rsc),
- sta->igtk, sta->igtk_len);
+ sta->igtk, sta->igtk_len,
+ KEY_FLAG_GROUP_RX);
}
}
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index e730b633..f19bfbfc 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -100,7 +100,8 @@ static const u8 *auth_get_psk(void *ctx, const u8 *addr,
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)
+ const u8 *addr, int idx, u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
struct mesh_rsn *mesh_rsn = ctx;
u8 seq[6];
@@ -118,7 +119,7 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
return wpa_drv_set_key(mesh_rsn->wpa_s, alg, addr, idx,
- 1, seq, 6, key, key_len);
+ 1, seq, 6, key, key_len, key_flag);
}
@@ -196,7 +197,8 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
wpa_drv_set_key(rsn->wpa_s,
wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL,
rsn->igtk_key_id, 1,
- seq, sizeof(seq), rsn->igtk, rsn->igtk_len);
+ seq, sizeof(seq), rsn->igtk, rsn->igtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT);
}
/* group privacy / data frames */
@@ -204,7 +206,7 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
rsn->mgtk, rsn->mgtk_len);
wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL,
rsn->mgtk_key_id, 1, seq, sizeof(seq),
- rsn->mgtk, rsn->mgtk_len);
+ rsn->mgtk, rsn->mgtk_len, KEY_FLAG_GROUP_TX_DEFAULT);
return 0;
}
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
index b74be7da..e40cf5bb 100644
--- a/wpa_supplicant/offchannel.c
+++ b/wpa_supplicant/offchannel.c
@@ -226,10 +226,10 @@ void offchannel_send_action_tx_status(
}
#ifdef CONFIG_P2P
- if (wpa_s->p2p_long_listen > 0) {
+ if (wpa_s->global->p2p_long_listen > 0) {
/* Continue the listen */
wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
- wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+ wpas_p2p_listen_start(wpa_s, wpa_s->global->p2p_long_listen);
}
#endif /* CONFIG_P2P */
}
@@ -246,7 +246,7 @@ void offchannel_send_action_tx_status(
* @buf: Frame to transmit starting from the Category field
* @len: Length of @buf in bytes
* @wait_time: Wait time for response in milliseconds
- * @tx_cb: Callback function for indicating TX status or %NULL for now callback
+ * @tx_cb: Callback function for indicating TX status or %NULL for no callback
* @no_cck: Whether CCK rates are to be disallowed for TX rate selection
* Returns: 0 on success or -1 on failure
*
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index b15ac9e3..983801fa 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -14,6 +14,7 @@
#include "utils/common.h"
#include "common/ieee802_11_common.h"
#include "wpa_supplicant_i.h"
+#include "bss.h"
static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode,
@@ -228,7 +229,8 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
int freq2 = 0;
int freq5 = 0;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode,
+ is_6ghz_op_class(op_class->op_class));
if (!mode)
return 0;
@@ -355,9 +357,25 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
}
+static int wpas_sta_secondary_channel_offset(struct wpa_bss *bss, u8 *current,
+ u8 *channel)
+{
+
+ u8 *ies, phy_type;
+ size_t ies_len;
+
+ if (!bss)
+ return -1;
+ ies = (u8 *) (bss + 1);
+ ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+ return wpas_get_op_chan_phy(bss->freq, ies, ies_len, current,
+ channel, &phy_type);
+}
+
+
size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- int freq, u8 *pos, size_t len)
+ struct wpa_bss *bss, u8 *pos, size_t len)
{
struct wpabuf *buf;
u8 op, current, chan;
@@ -365,11 +383,13 @@ size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
size_t res;
/*
- * Assume 20 MHz channel for now.
- * TODO: Use the secondary channel and VHT channel width that will be
- * used after association.
+ * Determine the current operating class correct mode based on
+ * advertised BSS capabilities, if available. Fall back to a less
+ * accurate guess based on frequency if the needed IEs are not available
+ * or used.
*/
- if (ieee80211_freq_to_channel_ext(freq, 0, CHANWIDTH_USE_HT,
+ if (wpas_sta_secondary_channel_offset(bss, &current, &chan) < 0 &&
+ ieee80211_freq_to_channel_ext(bss->freq, 0, CHANWIDTH_USE_HT,
&current, &chan) == NUM_HOSTAPD_MODES)
return 0;
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index a3c4574e..2c8754bd 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1912,7 +1912,7 @@ static int wpas_p2p_freq_to_edmg_channel(struct wpa_supplicant *wpa_s,
return -1;
hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
- HOSTAPD_MODE_IEEE80211AD);
+ HOSTAPD_MODE_IEEE80211AD, 0);
if (!hwmode) {
wpa_printf(MSG_ERROR,
"Unsupported AP mode: HOSTAPD_MODE_IEEE80211AD");
@@ -2422,7 +2422,7 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
wpas_start_wps_enrollee(group_wpa_s, res);
}
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
@@ -2701,7 +2701,7 @@ static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf,
{
struct wpa_supplicant *wpa_s = ctx;
return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
- freq);
+ freq, 0);
}
@@ -3735,7 +3735,8 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
if (o->p2p == NO_P2P_SUPP)
continue;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode,
+ is_6ghz_op_class(o->op_class));
if (mode == NULL)
continue;
if (mode->mode == HOSTAPD_MODE_IEEE80211G)
@@ -3745,23 +3746,32 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
if (res == ALLOWED) {
if (reg == NULL) {
+ if (cla == P2P_MAX_REG_CLASSES)
+ continue;
wpa_printf(MSG_DEBUG, "P2P: Add operating class %u",
o->op_class);
reg = &chan->reg_class[cla];
cla++;
reg->reg_class = o->op_class;
}
+ if (reg->channels == P2P_MAX_REG_CLASS_CHANNELS)
+ continue;
reg->channel[reg->channels] = ch;
reg->channels++;
} else if (res == NO_IR &&
wpa_s->conf->p2p_add_cli_chan) {
if (cli_reg == NULL) {
+ if (cli_cla == P2P_MAX_REG_CLASSES)
+ continue;
wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)",
o->op_class);
cli_reg = &cli_chan->reg_class[cli_cla];
cli_cla++;
cli_reg->reg_class = o->op_class;
}
+ if (cli_reg->channels ==
+ P2P_MAX_REG_CLASS_CHANNELS)
+ continue;
cli_reg->channel[cli_reg->channels] = ch;
cli_reg->channels++;
}
@@ -4758,7 +4768,7 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_p2p_psk_failure_removal, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
wpas_p2p_remove_pending_group_interface(wpa_s);
@@ -5643,7 +5653,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
go_intent = wpa_s->conf->p2p_go_intent;
if (!auth)
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
wpa_s->p2p_wps_method = wps_method;
wpa_s->p2p_persistent_group = !!persistent_group;
@@ -5813,19 +5823,20 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
{
wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
"(p2p_long_listen=%d ms pending_action_tx=%p)",
- wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
+ wpa_s->global->p2p_long_listen,
+ offchannel_pending_action_tx(wpa_s));
wpas_p2p_listen_work_done(wpa_s);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
- if (wpa_s->p2p_long_listen > 0)
- wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
+ if (wpa_s->global->p2p_long_listen > 0)
+ wpa_s->global->p2p_long_listen -= wpa_s->max_remain_on_chan;
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
return; /* P2P module started a new operation */
if (offchannel_pending_action_tx(wpa_s))
return;
- if (wpa_s->p2p_long_listen > 0) {
+ if (wpa_s->global->p2p_long_listen > 0) {
wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
- wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+ wpas_p2p_listen_start(wpa_s, wpa_s->global->p2p_long_listen);
} else {
/*
* When listen duration is over, stop listen & update p2p_state
@@ -6298,7 +6309,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
cand = wpa_s->p2p_group_common_freqs[i];
mode = ieee80211_freq_to_chan(cand, &chan);
hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
- mode);
+ mode, is_6ghz_freq(cand));
if (!hwmode ||
wpas_p2p_verify_channel(wpa_s, hwmode, chan,
BW80) != ALLOWED)
@@ -6325,7 +6336,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
cand = wpa_s->p2p_group_common_freqs[i];
mode = ieee80211_freq_to_chan(cand, &chan);
hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
- mode);
+ mode, is_6ghz_freq(cand));
if (!wpas_same_band(wpa_s->current_ssid->frequency,
cand) ||
!hwmode ||
@@ -6960,7 +6971,7 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
u8 seek_cnt, const char **seek_string, int freq)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
wpa_s->p2p_in_provisioning) {
@@ -7005,7 +7016,7 @@ static void wpas_p2p_scan_res_ignore_search(struct wpa_supplicant *wpa_s,
static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
@@ -7031,7 +7042,7 @@ void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
}
@@ -7060,7 +7071,7 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
timeout = 3600;
}
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
/*
* Stop previous find/listen operation to avoid trying to request a new
@@ -7072,7 +7083,7 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
res = wpas_p2p_listen_start(wpa_s, timeout * 1000);
if (res == 0 && timeout * 1000 > wpa_s->max_remain_on_chan) {
- wpa_s->p2p_long_listen = timeout * 1000;
+ wpa_s->global->p2p_long_listen = timeout * 1000;
eloop_register_timeout(timeout, 0,
wpas_p2p_long_listen_timeout,
wpa_s, NULL);
@@ -7179,7 +7190,7 @@ static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s)
int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
{
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index 3f2da34e..4a8f4ff8 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -41,6 +41,12 @@ static void _wpa_supplicant_deauthenticate(void *wpa_s, u16 reason_code)
}
+static void _wpa_supplicant_reconnect(void *wpa_s)
+{
+ wpa_supplicant_reconnect(wpa_s);
+}
+
+
static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
const void *data, u16 data_len,
size_t *msg_len, void **data_pos)
@@ -127,7 +133,8 @@ static int wpa_supplicant_get_bssid(void *wpa_s, u8 *bssid)
static int wpa_supplicant_set_key(void *wpa_s, 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)
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
printf("%s - not implemented\n", __func__);
return -1;
@@ -146,7 +153,8 @@ static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr,
static int wpa_supplicant_add_pmkid(void *wpa_s, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *fils_cache_id,
- const u8 *pmk, size_t pmk_len)
+ const u8 *pmk, size_t pmk_len,
+ u32 pmk_lifetime, u8 pmk_reauth_threshold)
{
printf("%s - not implemented\n", __func__);
return -1;
@@ -244,6 +252,7 @@ static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname)
ctx->set_config_blob = wpa_supplicant_set_config_blob;
ctx->get_config_blob = wpa_supplicant_get_config_blob;
ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection;
+ ctx->reconnect = _wpa_supplicant_reconnect;
wpa_s->wpa = wpa_sm_init(ctx);
assert(wpa_s->wpa != NULL);
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index 7930e012..afc11727 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -609,7 +609,8 @@ static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, int active,
pos++;
left--;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode,
+ is_6ghz_op_class(op->op_class));
if (!mode)
continue;
@@ -661,7 +662,8 @@ static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s,
return NULL;
}
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode,
+ is_6ghz_op_class(op->op_class));
if (!mode)
return NULL;
@@ -693,8 +695,8 @@ static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s,
}
-static int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
- u8 *op_class, u8 *chan, u8 *phy_type)
+int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
+ u8 *op_class, u8 *chan, u8 *phy_type)
{
const u8 *ie;
int sec_chan = 0, vht = 0;
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 4d158a9c..b4757309 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -668,13 +668,14 @@ static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
enum hostapd_hw_mode band,
- struct wpa_driver_scan_params *params)
+ struct wpa_driver_scan_params *params,
+ int is_6ghz)
{
/* Include only supported channels for the specified band */
struct hostapd_hw_modes *mode;
int count, i;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, is_6ghz);
if (mode == NULL) {
/* No channels supported in this band - use empty list */
params->freqs = os_zalloc(sizeof(int));
@@ -701,10 +702,10 @@ static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s,
return; /* already using a limited channel set */
if (wpa_s->setband == WPA_SETBAND_5G)
wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
- params);
+ params, 0);
else if (wpa_s->setband == WPA_SETBAND_2G)
wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
- params);
+ params, 0);
}
@@ -1108,7 +1109,9 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
tssid = tssid->next) {
if (wpas_network_disabled(wpa_s, tssid))
continue;
- if ((params.freqs || !freqs_set) && tssid->scan_freq) {
+ if (((params.freqs || !freqs_set) &&
+ tssid->scan_freq) &&
+ int_array_len(params.freqs) < 100) {
int_array_concat(&params.freqs,
tssid->scan_freq);
} else {
@@ -1250,7 +1253,8 @@ ssid_list_set:
params.bssid = wpa_s->next_scan_bssid;
bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid);
- if (bss && bss->ssid_len && params.num_ssids == 1 &&
+ if (!wpa_s->next_scan_bssid_wildcard_ssid &&
+ bss && bss->ssid_len && params.num_ssids == 1 &&
params.ssids[0].ssid_len == 0) {
params.ssids[0].ssid = bss->ssid;
params.ssids[0].ssid_len = bss->ssid_len;
@@ -1327,6 +1331,7 @@ scan:
#ifdef CONFIG_INTERWORKING
wpa_s->interworking_fast_assoc_tried = 0;
#endif /* CONFIG_INTERWORKING */
+ wpa_s->next_scan_bssid_wildcard_ssid = 0;
if (params.bssid)
os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN);
}
@@ -1956,20 +1961,6 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
}
-/*
- * Channels with a great SNR can operate at full rate. What is a great SNR?
- * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general
- * rule of thumb is that any SNR above 20 is good." This one
- * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23
- * recommends 25 as a minimum SNR for 54 Mbps data rate. The estimates used in
- * scan_est_throughput() allow even smaller SNR values for the maximum rates
- * (21 for 54 Mbps, 22 for VHT80 MCS9, 24 for HT40 and HT20 MCS7). Use 25 as a
- * somewhat conservative value here.
- */
-#define GREAT_SNR 25
-
-#define IS_5GHZ(n) (n > 4000)
-
/* Compare function for sorting scan results. Return >0 if @b is considered
* better. */
static int wpa_scan_result_compar(const void *a, const void *b)
@@ -2178,14 +2169,6 @@ void filter_scan_res(struct wpa_supplicant *wpa_s,
}
-/*
- * Noise floor values to use when we have signal strength
- * measurements, but no noise floor measurements. These values were
- * measured in an office environment with many APs.
- */
-#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
-#define DEFAULT_NOISE_FLOOR_5GHZ (-92)
-
void scan_snr(struct wpa_scan_res *res)
{
if (res->flags & WPA_SCAN_NOISE_INVALID) {
@@ -2204,86 +2187,83 @@ void scan_snr(struct wpa_scan_res *res)
}
-static unsigned int max_ht20_rate(int snr)
+static unsigned int interpolate_rate(int snr, int snr0, int snr1,
+ int rate0, int rate1)
+{
+ return rate0 + (snr - snr0) * (rate1 - rate0) / (snr1 - snr0);
+}
+
+
+#define INTERPOLATE_RATE(snr0, snr1, rate0, rate1) \
+ if (snr < (snr1)) \
+ return interpolate_rate(snr, (snr0), (snr1), (rate0), (rate1))
+
+static unsigned int max_ht20_rate(int snr, int vht)
{
- if (snr < 6)
- return 6500; /* HT20 MCS0 */
- if (snr < 8)
- return 13000; /* HT20 MCS1 */
- if (snr < 13)
- return 19500; /* HT20 MCS2 */
- if (snr < 17)
- return 26000; /* HT20 MCS3 */
- if (snr < 20)
- return 39000; /* HT20 MCS4 */
- if (snr < 23)
- return 52000; /* HT20 MCS5 */
- if (snr < 24)
- return 58500; /* HT20 MCS6 */
- return 65000; /* HT20 MCS7 */
+ if (snr < 0)
+ return 0;
+ INTERPOLATE_RATE(0, 2, 0, 6500); /* HT20 MCS0 */
+ INTERPOLATE_RATE(2, 5, 6500, 13000); /* HT20 MCS1 */
+ INTERPOLATE_RATE(5, 9, 13000, 19500); /* HT20 MCS2 */
+ INTERPOLATE_RATE(9, 11, 19500, 26000); /* HT20 MCS3 */
+ INTERPOLATE_RATE(11, 15, 26000, 39000); /* HT20 MCS4 */
+ INTERPOLATE_RATE(15, 18, 39000, 52000); /* HT20 MCS5 */
+ INTERPOLATE_RATE(18, 20, 52000, 58500); /* HT20 MCS6 */
+ INTERPOLATE_RATE(20, 25, 58500, 65000); /* HT20 MCS7 */
+ if (!vht)
+ return 65000;
+ INTERPOLATE_RATE(25, 29, 65000, 78000); /* VHT20 MCS8 */
+ return 78000;
}
-static unsigned int max_ht40_rate(int snr)
+static unsigned int max_ht40_rate(int snr, int vht)
{
- if (snr < 3)
- return 13500; /* HT40 MCS0 */
- if (snr < 6)
- return 27000; /* HT40 MCS1 */
- if (snr < 10)
- return 40500; /* HT40 MCS2 */
- if (snr < 15)
- return 54000; /* HT40 MCS3 */
- if (snr < 17)
- return 81000; /* HT40 MCS4 */
- if (snr < 22)
- return 108000; /* HT40 MCS5 */
- if (snr < 24)
- return 121500; /* HT40 MCS6 */
- return 135000; /* HT40 MCS7 */
+ if (snr < 0)
+ return 0;
+ INTERPOLATE_RATE(0, 5, 0, 13500); /* HT40 MCS0 */
+ INTERPOLATE_RATE(5, 8, 13500, 27000); /* HT40 MCS1 */
+ INTERPOLATE_RATE(8, 12, 27000, 40500); /* HT40 MCS2 */
+ INTERPOLATE_RATE(12, 14, 40500, 54000); /* HT40 MCS3 */
+ INTERPOLATE_RATE(14, 18, 54000, 81000); /* HT40 MCS4 */
+ INTERPOLATE_RATE(18, 21, 81000, 108000); /* HT40 MCS5 */
+ INTERPOLATE_RATE(21, 23, 108000, 121500); /* HT40 MCS6 */
+ INTERPOLATE_RATE(23, 28, 121500, 135000); /* HT40 MCS7 */
+ if (!vht)
+ return 135000;
+ INTERPOLATE_RATE(28, 32, 135000, 162000); /* VHT40 MCS8 */
+ INTERPOLATE_RATE(32, 34, 162000, 180000); /* VHT40 MCS9 */
+ return 180000;
}
static unsigned int max_vht80_rate(int snr)
{
- if (snr < 1)
+ if (snr < 0)
return 0;
- if (snr < 2)
- return 29300; /* VHT80 MCS0 */
- if (snr < 5)
- return 58500; /* VHT80 MCS1 */
- if (snr < 9)
- return 87800; /* VHT80 MCS2 */
- if (snr < 11)
- return 117000; /* VHT80 MCS3 */
- if (snr < 15)
- return 175500; /* VHT80 MCS4 */
- if (snr < 16)
- return 234000; /* VHT80 MCS5 */
- if (snr < 18)
- return 263300; /* VHT80 MCS6 */
- if (snr < 20)
- return 292500; /* VHT80 MCS7 */
- if (snr < 22)
- return 351000; /* VHT80 MCS8 */
- return 390000; /* VHT80 MCS9 */
+ INTERPOLATE_RATE(0, 8, 0, 29300); /* VHT80 MCS0 */
+ INTERPOLATE_RATE(8, 11, 29300, 58500); /* VHT80 MCS1 */
+ INTERPOLATE_RATE(11, 15, 58500, 87800); /* VHT80 MCS2 */
+ INTERPOLATE_RATE(15, 17, 87800, 117000); /* VHT80 MCS3 */
+ INTERPOLATE_RATE(17, 21, 117000, 175500); /* VHT80 MCS4 */
+ INTERPOLATE_RATE(21, 24, 175500, 234000); /* VHT80 MCS5 */
+ INTERPOLATE_RATE(24, 26, 234000, 263300); /* VHT80 MCS6 */
+ INTERPOLATE_RATE(26, 31, 263300, 292500); /* VHT80 MCS7 */
+ INTERPOLATE_RATE(31, 35, 292500, 351000); /* VHT80 MCS8 */
+ INTERPOLATE_RATE(35, 37, 351000, 390000); /* VHT80 MCS9 */
+ return 390000;
}
+#undef INTERPOLATE_RATE
-void scan_est_throughput(struct wpa_supplicant *wpa_s,
- struct wpa_scan_res *res)
+
+unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len, int rate,
+ int snr)
{
enum local_hw_capab capab = wpa_s->hw_capab;
- int rate; /* max legacy rate in 500 kb/s units */
- const u8 *ie;
unsigned int est, tmp;
- int snr = res->snr;
-
- if (res->est_throughput)
- return;
-
- /* Get maximum legacy rate */
- rate = wpa_scan_get_max_rate(res);
+ const u8 *ie;
/* Limit based on estimated SNR */
if (rate > 1 * 2 && snr < 1)
@@ -2296,32 +2276,50 @@ void scan_est_throughput(struct wpa_supplicant *wpa_s,
rate = 9 * 2;
else if (rate > 12 * 2 && snr < 7)
rate = 12 * 2;
+ else if (rate > 12 * 2 && snr < 8)
+ rate = 14 * 2;
+ else if (rate > 12 * 2 && snr < 9)
+ rate = 16 * 2;
else if (rate > 18 * 2 && snr < 10)
rate = 18 * 2;
else if (rate > 24 * 2 && snr < 11)
rate = 24 * 2;
+ else if (rate > 24 * 2 && snr < 12)
+ rate = 27 * 2;
+ else if (rate > 24 * 2 && snr < 13)
+ rate = 30 * 2;
+ else if (rate > 24 * 2 && snr < 14)
+ rate = 33 * 2;
else if (rate > 36 * 2 && snr < 15)
rate = 36 * 2;
+ else if (rate > 36 * 2 && snr < 16)
+ rate = 39 * 2;
+ else if (rate > 36 * 2 && snr < 17)
+ rate = 42 * 2;
+ else if (rate > 36 * 2 && snr < 18)
+ rate = 45 * 2;
else if (rate > 48 * 2 && snr < 19)
rate = 48 * 2;
+ else if (rate > 48 * 2 && snr < 20)
+ rate = 51 * 2;
else if (rate > 54 * 2 && snr < 21)
rate = 54 * 2;
est = rate * 500;
if (capab == CAPAB_HT || capab == CAPAB_HT40 || capab == CAPAB_VHT) {
- ie = wpa_scan_get_ie(res, WLAN_EID_HT_CAP);
+ ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP);
if (ie) {
- tmp = max_ht20_rate(snr);
+ tmp = max_ht20_rate(snr, 0);
if (tmp > est)
est = tmp;
}
}
if (capab == CAPAB_HT40 || capab == CAPAB_VHT) {
- ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION);
+ ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
if (ie && ie[1] >= 2 &&
(ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
- tmp = max_ht40_rate(snr);
+ tmp = max_ht40_rate(snr, 0);
if (tmp > est)
est = tmp;
}
@@ -2329,22 +2327,22 @@ void scan_est_throughput(struct wpa_supplicant *wpa_s,
if (capab == CAPAB_VHT) {
/* Use +1 to assume VHT is always faster than HT */
- ie = wpa_scan_get_ie(res, WLAN_EID_VHT_CAP);
+ ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP);
if (ie) {
- tmp = max_ht20_rate(snr) + 1;
+ tmp = max_ht20_rate(snr, 1) + 1;
if (tmp > est)
est = tmp;
- ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION);
+ ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
if (ie && ie[1] >= 2 &&
(ie[3] &
HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
- tmp = max_ht40_rate(snr) + 1;
+ tmp = max_ht40_rate(snr, 1) + 1;
if (tmp > est)
est = tmp;
}
- ie = wpa_scan_get_ie(res, WLAN_EID_VHT_OPERATION);
+ ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION);
if (ie && ie[1] >= 1 &&
(ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK)) {
tmp = max_vht80_rate(snr) + 1;
@@ -2354,9 +2352,30 @@ void scan_est_throughput(struct wpa_supplicant *wpa_s,
}
}
- /* TODO: channel utilization and AP load (e.g., from AP Beacon) */
+ return est;
+}
+
+
+void scan_est_throughput(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *res)
+{
+ int rate; /* max legacy rate in 500 kb/s units */
+ int snr = res->snr;
+ const u8 *ies = (const void *) (res + 1);
+ size_t ie_len = res->ie_len;
+
+ if (res->est_throughput)
+ return;
+
+ /* Get maximum legacy rate */
+ rate = wpa_scan_get_max_rate(res);
+
+ if (!ie_len)
+ ie_len = res->beacon_ie_len;
+ res->est_throughput =
+ wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr);
- res->est_throughput = est;
+ /* TODO: channel utilization and AP load (e.g., from AP Beacon) */
}
@@ -2611,8 +2630,8 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params)
int wpas_start_pno(struct wpa_supplicant *wpa_s)
{
- int ret, prio;
- size_t i, num_ssid, num_match_ssid;
+ int ret;
+ size_t prio, i, num_ssid, num_match_ssid;
struct wpa_ssid *ssid;
struct wpa_driver_scan_params params;
struct sched_scan_plan scan_plan;
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 58caa781..c9ce2cec 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -9,6 +9,28 @@
#ifndef SCAN_H
#define SCAN_H
+/*
+ * Noise floor values to use when we have signal strength
+ * measurements, but no noise floor measurements. These values were
+ * measured in an office environment with many APs.
+ */
+#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
+#define DEFAULT_NOISE_FLOOR_5GHZ (-92)
+
+/*
+ * Channels with a great SNR can operate at full rate. What is a great SNR?
+ * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general
+ * rule of thumb is that any SNR above 20 is good." This one
+ * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23
+ * recommends 25 as a minimum SNR for 54 Mbps data rate. The estimates used in
+ * scan_est_throughput() allow even smaller SNR values for the maximum rates
+ * (21 for 54 Mbps, 22 for VHT80 MCS9, 24 for HT40 and HT20 MCS7). Use 25 as a
+ * somewhat conservative value here.
+ */
+#define GREAT_SNR 25
+
+#define IS_5GHZ(n) (n > 4000)
+
int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s);
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
@@ -60,6 +82,9 @@ void filter_scan_res(struct wpa_supplicant *wpa_s,
void scan_snr(struct wpa_scan_res *res);
void scan_est_throughput(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res);
+unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len, int rate,
+ int snr);
void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s);
#endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 08d7e3ec..0cc81bf0 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -131,7 +131,10 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
return NULL;
}
- if (wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) {
+ if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3)
+ use_pt = 1;
+
+ if (use_pt || 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;
@@ -142,7 +145,9 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
BIT(WLAN_RSNX_CAPAB_SAE_H2E));
}
- if (wpa_s->conf->sae_pwe == 1 && !use_pt) {
+ if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
+ wpa_s->conf->sae_pwe != 3 &&
+ !use_pt) {
wpa_printf(MSG_DEBUG,
"SAE: Cannot use H2E with the selected AP");
return NULL;
@@ -166,7 +171,7 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN);
reuse_data:
- len = wpa_s->sme.sae_token ? wpabuf_len(wpa_s->sme.sae_token) : 0;
+ len = wpa_s->sme.sae_token ? 3 + wpabuf_len(wpa_s->sme.sae_token) : 0;
if (ssid->sae_password_id)
len += 4 + os_strlen(ssid->sae_password_id);
buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
@@ -177,8 +182,11 @@ reuse_data:
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 (sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
+ ssid->sae_password_id) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
if (ret_use_pt)
*ret_use_pt = use_pt;
@@ -281,7 +289,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
const u8 *md = NULL;
#endif /* CONFIG_IEEE80211R || CONFIG_FILS */
- int i, bssid_changed;
+ int bssid_changed;
struct wpabuf *resp = NULL;
u8 ext_capab[18];
int ext_capab_len;
@@ -291,6 +299,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_MBO
const u8 *mbo_ie;
#endif /* CONFIG_MBO */
+ int omit_rsnxe = 0;
if (bss == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -365,18 +374,18 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_SAE */
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (ssid->wep_key_len[i])
- params.wep_key[i] = ssid->wep_key[i];
- params.wep_key_len[i] = ssid->wep_key_len[i];
- }
- params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+#ifdef CONFIG_WEP
+ {
+ int i;
- bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
- os_memset(wpa_s->bssid, 0, ETH_ALEN);
- os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
- if (bssid_changed)
- wpas_notify_bssid_changed(wpa_s);
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i])
+ params.wep_key[i] = ssid->wep_key[i];
+ params.wep_key_len[i] = ssid->wep_key_len[i];
+ }
+ params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+ }
+#endif /* CONFIG_WEP */
if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
@@ -498,6 +507,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "SME: FT mobility domain %02x%02x",
md[0], md[1]);
+ omit_rsnxe = !wpa_bss_get_ie(bss, WLAN_EID_RSNX);
if (wpa_s->sme.assoc_req_ie_len + 5 <
sizeof(wpa_s->sme.assoc_req_ie)) {
struct rsn_mdie *mdie;
@@ -570,7 +580,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
sme_auth_handle_rrm(wpa_s, bss);
wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie(
- wpa_s, ssid, bss->freq,
+ wpa_s, ssid, bss,
wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len);
@@ -606,7 +616,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->rsnxe_len > 0 &&
wpa_s->rsnxe_len <=
- sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) {
+ sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len &&
+ !omit_rsnxe) {
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;
@@ -718,6 +729,12 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_SAE */
+ bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
+ os_memset(wpa_s->bssid, 0, ETH_ALEN);
+ os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+ if (bssid_changed)
+ wpas_notify_bssid_changed(wpa_s);
+
old_ssid = wpa_s->current_ssid;
wpa_s->current_ssid = ssid;
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
@@ -1010,7 +1027,7 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
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);
+ wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
wpabuf_free(resp);
wpabuf_free(buf);
@@ -1080,7 +1097,7 @@ static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s,
sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
da, 2, wpa_s->sme.seq_num,
WLAN_STATUS_SUCCESS);
- wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
+ wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
wpabuf_free(resp);
wpabuf_free(buf);
}
@@ -1177,11 +1194,16 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
(external || wpa_s->current_bss) && wpa_s->current_ssid) {
int default_groups[] = { 19, 20, 21, 0 };
u16 group;
+ const u8 *token_pos;
+ size_t token_len;
+ int h2e = 0;
groups = wpa_s->conf->sae_groups;
if (!groups || groups[0] <= 0)
groups = default_groups;
+ wpa_hexdump(MSG_DEBUG, "SME: SAE anti-clogging token request",
+ data, len);
if (len < sizeof(le16)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SME: Too short SAE anti-clogging token request");
@@ -1199,8 +1221,30 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
return -1;
}
wpabuf_free(wpa_s->sme.sae_token);
- wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16),
- len - sizeof(le16));
+ token_pos = data + sizeof(le16);
+ token_len = len - sizeof(le16);
+ if (wpa_s->sme.sae.tmp)
+ h2e = wpa_s->sme.sae.tmp->h2e;
+ if (h2e) {
+ if (token_len < 3) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Too short SAE anti-clogging token container");
+ return -1;
+ }
+ if (token_pos[0] != WLAN_EID_EXTENSION ||
+ token_pos[1] == 0 ||
+ token_pos[1] > token_len - 2 ||
+ token_pos[2] != WLAN_EID_EXT_ANTI_CLOGGING_TOKEN) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Invalid SAE anti-clogging token container header");
+ return -1;
+ }
+ token_len = token_pos[1] - 1;
+ token_pos += 3;
+ }
+ wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len);
+ wpa_hexdump_buf(MSG_DEBUG, "SME: Requested anti-clogging token",
+ wpa_s->sme.sae_token);
if (!external)
sme_send_authentication(wpa_s, wpa_s->current_bss,
wpa_s->current_ssid, 2);
@@ -1260,6 +1304,19 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
"SAE: Ignore commit message while waiting for confirm");
return 0;
}
+ if (wpa_s->sme.sae.tmp && wpa_s->sme.sae.tmp->h2e &&
+ status_code == WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Unexpected use of status code 0 in SAE commit when H2E was expected");
+ return -1;
+ }
+ if (wpa_s->sme.sae.tmp && !wpa_s->sme.sae.tmp->h2e &&
+ status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Unexpected use of status code for H2E in SAE commit when H2E was not expected");
+ return -1;
+ }
+
if (groups && groups[0] <= 0)
groups = NULL;
res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
@@ -1736,7 +1793,9 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
#ifdef CONFIG_DPP2
if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->current_ssid &&
- wpa_s->current_ssid->dpp_netaccesskey) {
+ wpa_s->current_ssid->dpp_netaccesskey &&
+ wpa_s->current_ssid->dpp_pfs != 2 &&
+ !wpa_s->current_ssid->dpp_pfs_fallback) {
struct wpa_ssid *ssid = wpa_s->current_ssid;
dpp_pfs_free(wpa_s->dpp_pfs);
@@ -1810,6 +1869,9 @@ pfs_fail:
params.vhtcaps_mask = &vhtcaps_mask;
wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, &params);
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ wpa_supplicant_apply_he_overrides(wpa_s, wpa_s->current_ssid, &params);
+#endif /* CONFIG_HE_OVERRIDES */
#ifdef CONFIG_IEEE80211R
if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies &&
get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len,
@@ -2308,7 +2370,7 @@ static void wpa_obss_scan_freqs_list(struct wpa_supplicant *wpa_s,
int start, end;
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
- HOSTAPD_MODE_IEEE80211G);
+ HOSTAPD_MODE_IEEE80211G, 0);
if (mode == NULL) {
/* No channels supported in this band - use empty list */
params->freqs = os_zalloc(sizeof(int));
@@ -2601,6 +2663,10 @@ void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
return;
if (wpa_s->sme.sa_query_count > 0)
return;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->disable_sa_query)
+ return;
+#endif /* CONFIG_TESTING_OPTIONS */
os_get_reltime(&now);
if (wpa_s->sme.last_unprot_disconnect.sec &&
diff --git a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
index 03ac5070..da69a870 100644
--- a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
+++ b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
@@ -12,4 +12,4 @@ Type=simple
ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-%I.conf -Dnl80211 -i%I
[Install]
-Alias=multi-user.target.wants/wpa_supplicant-nl80211@%i.service
+WantedBy=multi-user.target
diff --git a/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
index c8a744d6..ca3054bc 100644
--- a/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
+++ b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
@@ -12,4 +12,4 @@ Type=simple
ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-wired-%I.conf -Dwired -i%I
[Install]
-Alias=multi-user.target.wants/wpa_supplicant-wired@%i.service
+WantedBy=multi-user.target
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
index 7788b380..55d2b9c8 100644
--- a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
+++ b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
@@ -12,4 +12,4 @@ Type=simple
ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I
[Install]
-Alias=multi-user.target.wants/wpa_supplicant@%i.service
+WantedBy=multi-user.target
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 1c0399f4..2e09102d 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -280,6 +280,15 @@ static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
wpa_wnmsleep_install_key(wpa_s->wpa,
WNM_SLEEP_SUBELEM_IGTK, ptr);
ptr += 10 + WPA_IGTK_LEN;
+ } else if (*ptr == WNM_SLEEP_SUBELEM_BIGTK) {
+ if (ptr[1] < 2 + 6 + WPA_BIGTK_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Too short BIGTK subelem");
+ break;
+ }
+ wpa_wnmsleep_install_key(wpa_s->wpa,
+ WNM_SLEEP_SUBELEM_BIGTK, ptr);
+ ptr += 10 + WPA_BIGTK_LEN;
} else
break; /* skip the loop */
}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index a1b06151..07d5f315 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -502,6 +502,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
"ignore_auth_resp",
#endif /* CONFIG_TESTING_OPTIONS */
"relative_rssi", "relative_band_adjust",
+ "extended_key_id",
};
int i, num_fields = ARRAY_SIZE(fields);
@@ -593,7 +594,7 @@ static char ** wpa_cli_complete_get(const char *str, int pos)
"tdls_external_control", "osu_dir", "wowlan_triggers",
"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
- "reassoc_same_bss_optim"
+ "reassoc_same_bss_optim", "extended_key_id"
};
int i, num_fields = ARRAY_SIZE(fields);
@@ -1302,7 +1303,7 @@ static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
+ return wpa_cli_cmd(ctrl, "LIST_NETWORKS", 0, argc, argv);
}
@@ -1441,6 +1442,7 @@ static const char *network_fields[] = {
"dot11MeshHoldingTimeout",
#endif /* CONFIG_MESH */
"wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid",
+ "wpa_deny_ptk0_rekey",
"enable_edmg", "edmg_channel",
#ifdef CONFIG_P2P
"go_p2p_dev_addr", "p2p_client_list", "psk_list",
@@ -1458,6 +1460,9 @@ static const char *network_fields[] = {
"vht_tx_mcs_nss_3", "vht_tx_mcs_nss_4", "vht_tx_mcs_nss_5",
"vht_tx_mcs_nss_6", "vht_tx_mcs_nss_7", "vht_tx_mcs_nss_8",
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ "disable_he",
+#endif /* CONFIG_HE_OVERRIDES */
"ap_max_inactivity", "dtim_period", "beacon_int",
#ifdef CONFIG_MACSEC
"macsec_policy",
@@ -1782,7 +1787,7 @@ static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
- printf("Connected to interface '%s.\n", ctrl_ifname);
+ printf("Connected to interface '%s'.\n", ctrl_ifname);
} else {
printf("Could not connect to interface '%s' - re-trying\n",
ctrl_ifname);
@@ -4004,6 +4009,10 @@ static void wpa_cli_action_process(const char *msg)
wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, WPS_EVENT_ACTIVE)) {
wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, WPS_EVENT_PIN_ACTIVE)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, WPS_EVENT_CANCEL)) {
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, WPS_EVENT_TIMEOUT)) {
wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, WPS_EVENT_FAIL)) {
diff --git a/wpa_supplicant/wpa_gui-qt4/peers.cpp b/wpa_supplicant/wpa_gui-qt4/peers.cpp
index 3bcf2f51..0a0b3ffc 100644
--- a/wpa_supplicant/wpa_gui-qt4/peers.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/peers.cpp
@@ -476,7 +476,9 @@ void Peers::add_stations()
add_station(info);
reply_len = sizeof(reply) - 1;
- snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply);
+ res = snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply);
+ if (res < 0 || (size_t) res >= sizeof(cmd))
+ break;
res = wpagui->ctrlRequest(cmd, reply, &reply_len);
} while (res >= 0);
}
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
index a0aa05ed..9404ab42 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
@@ -12,6 +12,8 @@
#include <cstdio>
#include <unistd.h>
+#include <chrono>
+#include <thread>
#include <QMessageBox>
#include <QCloseEvent>
#include <QImageReader>
@@ -713,9 +715,22 @@ void WpaGui::updateNetworks()
strstr(flags, "[DISABLED]") == NULL)
first_active = networkSelect->count() - 1;
- if (last)
- break;
start = end + 1;
+ if (*start && strchr(start, '\n'))
+ continue;
+
+ /* avoid race conditions */
+ std::this_thread::sleep_for(std::chrono::milliseconds(200));
+ QString cmd("LIST_NETWORKS LAST_ID=");
+ cmd.append(id);
+ if (ctrlRequest(cmd.toLocal8Bit().constData(), buf, &len) < 0)
+ break;
+
+ buf[len] = '\0';
+ start = strchr(buf, '\n');
+ if (!start)
+ break;
+ start++;
}
if (networkSelect->count() > 1)
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index f1973527..c5d71686 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -391,6 +391,7 @@ static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface,
{
struct privsep_cmd_set_key *params;
int res;
+ struct wpa_driver_set_key_params p;
if (iface->drv_priv == NULL || iface->driver->set_key == NULL)
return;
@@ -402,14 +403,19 @@ static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface,
params = buf;
- res = iface->driver->set_key(iface->ifname, iface->drv_priv,
- params->alg,
- params->addr, params->key_idx,
- params->set_tx,
- params->seq_len ? params->seq : NULL,
- params->seq_len,
- params->key_len ? params->key : NULL,
- params->key_len);
+ os_memset(&p, 0, sizeof(p));
+ p.ifname = iface->ifname;
+ p.alg = params->alg;
+ p.addr = params->addr;
+ p.key_idx = params->key_idx;
+ p.set_tx = params->set_tx;
+ p.seq = params->seq_len ? params->seq : NULL;
+ p.seq_len = params->seq_len;
+ p.key = params->key_len ? params->key : NULL;
+ p.key_len = params->key_len;
+ p.key_flag = params->key_flag;
+
+ res = iface->driver->set_key(iface->drv_priv, &p);
wpa_printf(MSG_DEBUG, "drv->set_key: res=%d", res);
}
@@ -1184,14 +1190,15 @@ static void wpa_priv_fd_workaround(void)
static void usage(void)
{
- printf("wpa_priv v" VERSION_STR "\n"
+ printf("wpa_priv v%s\n"
"Copyright (c) 2007-2017, Jouni Malinen <j@w1.fi> and "
"contributors\n"
"\n"
"usage:\n"
" wpa_priv [-Bdd] [-c<ctrl dir>] [-P<pid file>] "
"<driver:ifname> \\\n"
- " [driver:ifname ...]\n");
+ " [driver:ifname ...]\n",
+ VERSION_STR);
}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 73e63ab5..d4294966 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -130,6 +130,7 @@ static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s);
#endif /* CONFIG_OWE */
+#ifdef CONFIG_WEP
/* Configure default/group WEP keys for static WEP */
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
@@ -142,11 +143,15 @@ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
set = 1;
wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
i, i == ssid->wep_tx_keyidx, NULL, 0,
- ssid->wep_key[i], ssid->wep_key_len[i]);
+ ssid->wep_key[i], ssid->wep_key_len[i],
+ i == ssid->wep_tx_keyidx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX);
}
return set;
}
+#endif /* CONFIG_WEP */
int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
@@ -200,7 +205,8 @@ int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
/* TODO: should actually remember the previously used seq#, both for TX
* and RX from each STA.. */
- ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+ ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT);
os_memset(key, 0, sizeof(key));
return ret;
}
@@ -393,7 +399,9 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
+#ifdef CONFIG_WEP
int i;
+#endif /* CONFIG_WEP */
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
@@ -411,6 +419,7 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
wpa_s->group_cipher = WPA_CIPHER_NONE;
wpa_s->mgmt_group_cipher = 0;
+#ifdef CONFIG_WEP
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (ssid->wep_key_len[i] > 5) {
wpa_s->pairwise_cipher = WPA_CIPHER_WEP104;
@@ -422,6 +431,7 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
break;
}
}
+#endif /* CONFIG_WEP */
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
@@ -477,6 +487,31 @@ void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s)
}
+void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
+ return;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Clear cached state on disabled interface");
+ wpa_bss_flush(wpa_s);
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s)
+{
+ struct driver_signal_override *dso;
+
+ while ((dso = dl_list_first(&wpa_s->drv_signal_override,
+ struct driver_signal_override, list))) {
+ dl_list_del(&dso->list);
+ os_free(dso);
+ }
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
int i;
@@ -502,10 +537,13 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_s->last_assoc_req_wpa_ie = NULL;
os_free(wpa_s->extra_sae_rejected_groups);
wpa_s->extra_sae_rejected_groups = NULL;
+ wpabuf_free(wpa_s->rsne_override_eapol);
+ wpa_s->rsne_override_eapol = NULL;
wpabuf_free(wpa_s->rsnxe_override_assoc);
wpa_s->rsnxe_override_assoc = NULL;
wpabuf_free(wpa_s->rsnxe_override_eapol);
wpa_s->rsnxe_override_eapol = NULL;
+ wpas_clear_driver_signal_override(wpa_s);
#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->conf != NULL) {
@@ -552,6 +590,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_clear_disabled_interface, wpa_s, NULL);
wpas_wps_deinit(wpa_s);
@@ -708,12 +747,17 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
if (wpa_s->keys_cleared & BIT(i))
continue;
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
- NULL, 0);
+ NULL, 0, KEY_FLAG_GROUP);
}
- if (!(wpa_s->keys_cleared & BIT(0)) && addr &&
+ /* Pairwise Key ID 1 for Extended Key ID is tracked in bit 15 */
+ if (~wpa_s->keys_cleared & (BIT(0) | BIT(15)) && addr &&
!is_zero_ether_addr(addr)) {
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
- 0);
+ if (!(wpa_s->keys_cleared & BIT(0)))
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
+ if (!(wpa_s->keys_cleared & BIT(15)))
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 1, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
/* MLME-SETPROTECTION.request(None) */
wpa_drv_mlme_setprotection(
wpa_s, addr,
@@ -1242,7 +1286,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
u8 *wpa_ie, size_t *wpa_ie_len)
{
struct wpa_ie_data ie;
- int sel, proto;
+ int sel, proto, sae_pwe;
const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
if (bss) {
@@ -1421,13 +1465,18 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_NO_WPA */
sel = ie.key_mgmt & ssid->key_mgmt;
- wpa_dbg(wpa_s, MSG_DEBUG,
- "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
- ie.key_mgmt, ssid->key_mgmt, sel);
#ifdef CONFIG_SAE
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
#endif /* CONFIG_SAE */
+#ifdef CONFIG_IEEE80211R
+ if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME |
+ WPA_DRIVER_FLAGS_UPDATE_FT_IES)))
+ sel &= ~WPA_KEY_MGMT_FT;
+#endif /* CONFIG_IEEE80211R */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
+ ie.key_mgmt, ssid->key_mgmt, sel);
if (0) {
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SHA384
@@ -1587,7 +1636,34 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
#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);
+ sae_pwe = wpa_s->conf->sae_pwe;
+ if (ssid->sae_password_id && sae_pwe != 3)
+ sae_pwe = 1;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, sae_pwe);
+
+ /* Extended Key ID is only supported in infrastructure BSS so far */
+ if (ssid->mode == WPAS_MODE_INFRA && wpa_s->conf->extended_key_id &&
+ (ssid->proto & WPA_PROTO_RSN) &&
+ ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 |
+ WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)) {
+ int use_ext_key_id = 0;
+
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "WPA: Enable Extended Key ID support");
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID,
+ wpa_s->conf->extended_key_id);
+ if (bss_rsn &&
+ wpa_s->conf->extended_key_id &&
+ wpa_s->pairwise_cipher != WPA_CIPHER_TKIP &&
+ (ie.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST))
+ use_ext_key_id = 1;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID,
+ use_ext_key_id);
+ } else {
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID, 0);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, 0);
+ }
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");
@@ -1722,6 +1798,20 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
} else
wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
+ if (ssid->mode != WPAS_MODE_IBSS &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED) &&
+ (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER ||
+ (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Disable PTK0 rekey support - replaced with reconnect");
+ wpa_s->deny_ptk0_rekey = 1;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 1);
+ } else {
+ wpa_s->deny_ptk0_rekey = 0;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 0);
+ }
+
return 0;
}
@@ -1963,7 +2053,8 @@ static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid)
if (!password)
password = ssid->passphrase;
- if (conf->sae_pwe == 0 || !password) {
+ if ((conf->sae_pwe == 0 && !ssid->sae_password_id) || !password ||
+ conf->sae_pwe == 3) {
/* PT derivation not needed */
sae_deinit_pt(ssid->pt);
ssid->pt = NULL;
@@ -2018,6 +2109,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
int rand_style;
wpa_s->own_disconnect_req = 0;
+ wpa_s->own_reconnect_req = 0;
/*
* If we are starting a new connection, any previously pending EAPOL
@@ -2031,6 +2123,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
else
rand_style = ssid->mac_addr;
+ wpa_s->multi_ap_ie = 0;
wmm_ac_clear_saved_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 0;
wpa_s->reassoc_same_ess = 0;
@@ -2314,6 +2407,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
/* 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;
+#ifdef CONFIG_HE_OVERRIDES
+ if (is_24ghz && ssid->disable_he)
+ freq->he_enabled = 0;
+#endif /* CONFIG_HE_OVERRIDES */
/* Setup higher BW only for 5 GHz */
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
@@ -2336,8 +2433,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_ht40) {
+#ifdef CONFIG_VHT_OVERRIDES
if (ssid->disable_vht)
return;
+#endif /* CONFIG_VHT_OVERRIDES */
goto skip_ht40;
}
#endif /* CONFIG_HT_OVERRIDES */
@@ -2434,8 +2533,8 @@ skip_ht40:
if (!vht_freq.vht_enabled)
return;
- /* Enable HE for VHT */
- vht_freq.he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+ /* Enable HE with VHT for 5 GHz */
+ freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
/* setup center_freq1, bandwidth */
for (j = 0; j < ARRAY_SIZE(vht80); j++) {
@@ -2510,6 +2609,12 @@ skip_ht40:
#endif /* CONFIG_HT_OVERRIDES */
}
+#ifdef CONFIG_HE_OVERRIDES
+ if (ssid->disable_he) {
+ vht_freq.he_enabled = 0;
+ freq->he_enabled = 0;
+ }
+#endif /* CONFIG_HE_OVERRIDES */
if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
freq->channel, ssid->enable_edmg,
ssid->edmg_channel, freq->ht_enabled,
@@ -2828,7 +2933,7 @@ static u8 * wpas_populate_assoc_ies(
#endif /* CONFIG_P2P */
if (bss) {
- wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss->freq,
+ wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss,
wpa_ie + wpa_ie_len,
max_wpa_ie_len -
wpa_ie_len);
@@ -2977,7 +3082,8 @@ static u8 * wpas_populate_assoc_ies(
#ifdef CONFIG_DPP2
if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
- ssid->dpp_netaccesskey) {
+ ssid->dpp_netaccesskey &&
+ ssid->dpp_pfs != 2 && !ssid->dpp_pfs_fallback) {
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
ssid->dpp_netaccesskey_len);
@@ -3216,7 +3322,7 @@ get_supported_edmg(struct wpa_supplicant *wpa_s,
if (hw_mode == NUM_HOSTAPD_MODES)
goto fail;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode, 0);
if (!mode)
goto fail;
@@ -3265,10 +3371,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
struct wpa_supplicant *wpa_s = work->wpa_s;
u8 *wpa_ie;
const u8 *edmg_ie_oper;
- int use_crypt, ret, i, bssid_changed;
+ int use_crypt, ret, bssid_changed;
unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
struct wpa_driver_associate_params params;
+#if defined(CONFIG_WEP) || defined(IEEE8021X_EAPOL)
int wep_keys_set = 0;
+#endif /* CONFIG_WEP || IEEE8021X_EAPOL */
int assoc_failed = 0;
struct wpa_ssid *old_ssid;
u8 prev_bssid[ETH_ALEN];
@@ -3375,10 +3483,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
use_crypt = 0;
+#ifdef CONFIG_WEP
if (wpa_set_wep_keys(wpa_s, ssid)) {
use_crypt = 1;
wep_keys_set = 1;
}
+#endif /* CONFIG_WEP */
}
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
use_crypt = 0;
@@ -3523,12 +3633,18 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_s->auth_alg = params.auth_alg;
params.mode = ssid->mode;
params.bg_scan_period = ssid->bg_scan_period;
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (ssid->wep_key_len[i])
- params.wep_key[i] = ssid->wep_key[i];
- params.wep_key_len[i] = ssid->wep_key_len[i];
+#ifdef CONFIG_WEP
+ {
+ int i;
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i])
+ params.wep_key[i] = ssid->wep_key[i];
+ params.wep_key_len[i] = ssid->wep_key_len[i];
+ }
+ params.wep_tx_keyidx = ssid->wep_tx_keyidx;
}
- params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+#endif /* CONFIG_WEP */
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
(params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
@@ -3605,6 +3721,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.vhtcaps_mask = &vhtcaps_mask;
wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ wpa_supplicant_apply_he_overrides(wpa_s, ssid, &params);
+#endif /* CONFIG_HE_OVERRIDES */
#ifdef CONFIG_P2P
/*
@@ -3686,11 +3805,13 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
}
+#ifdef CONFIG_WEP
if (wep_keys_set &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) {
/* Set static WEP keys again */
wpa_set_wep_keys(wpa_s, ssid);
}
+#endif /* CONFIG_WEP */
if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
/*
@@ -3804,6 +3925,15 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
wpa_supplicant_clear_connection(wpa_s, addr);
}
+
+void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->own_reconnect_req = 1;
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
+
+}
+
+
static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
@@ -4791,6 +4921,9 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
dl_list_init(&wpa_s->bss_tmp_disallowed);
dl_list_init(&wpa_s->fils_hlp_req);
+#ifdef CONFIG_TESTING_OPTIONS
+ dl_list_init(&wpa_s->drv_signal_override);
+#endif /* CONFIG_TESTING_OPTIONS */
return wpa_s;
}
@@ -5153,6 +5286,19 @@ void wpa_supplicant_apply_vht_overrides(
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+void wpa_supplicant_apply_he_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params)
+{
+ if (!ssid)
+ return;
+
+ params->disable_he = ssid->disable_he;
+}
+#endif /* CONFIG_HE_OVERRIDES */
+
+
static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
{
#ifdef PCSC_FUNCS
@@ -6095,7 +6241,6 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
wpa_s->drv_capa_known = 1;
wpa_s->drv_flags = capa.flags;
wpa_s->drv_enc = capa.enc;
- wpa_s->drv_smps_modes = capa.smps_modes;
wpa_s->drv_rrm_flags = capa.rrm_flags;
wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
wpa_s->max_scan_ssids = capa.max_scan_ssids;
@@ -6319,11 +6464,17 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
wpa_s->disconnected = 1;
if (wpa_s->drv_priv) {
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
+ /* Don't deauthenticate if WoWLAN is enabled */
+ if (!wpa_drv_get_wowlan(wpa_s)) {
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
- wpa_drv_set_countermeasures(wpa_s, 0);
- wpa_clear_keys(wpa_s, NULL);
+ wpa_drv_set_countermeasures(wpa_s, 0);
+ wpa_clear_keys(wpa_s, NULL);
+ } else {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Do not deauthenticate as part of interface deinit since WoWLAN is enabled");
+ }
}
wpa_supplicant_cleanup(wpa_s);
@@ -6704,7 +6855,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
if (params->wpa_debug_file_path)
wpa_debug_open_file(params->wpa_debug_file_path);
- else
+ if (!params->wpa_debug_file_path && !params->wpa_debug_syslog)
wpa_debug_setup_stdout();
if (params->wpa_debug_syslog)
wpa_debug_open_syslog();
@@ -6772,7 +6923,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
wpa_debug_timestamp = global->params.wpa_debug_timestamp =
params->wpa_debug_timestamp;
- wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);
+ wpa_printf(MSG_DEBUG, "wpa_supplicant v%s", VERSION_STR);
if (eloop_init()) {
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
@@ -7036,7 +7187,7 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
* There is no point in blacklisting the AP if this event is
* generated based on local request to disconnect.
*/
- if (wpa_s->own_disconnect_req) {
+ if (wpa_s->own_disconnect_req || wpa_s->own_reconnect_req) {
wpa_s->own_disconnect_req = 0;
wpa_dbg(wpa_s, MSG_DEBUG,
"Ignore connection failure due to local request to disconnect");
@@ -7301,8 +7452,10 @@ int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
+#ifdef CONFIG_WEP
int i;
unsigned int drv_enc;
+#endif /* CONFIG_WEP */
if (wpa_s->p2p_mgmt)
return 1; /* no normal network profiles on p2p_mgmt interface */
@@ -7313,6 +7466,7 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
if (ssid->disabled)
return 1;
+#ifdef CONFIG_WEP
if (wpa_s->drv_capa_known)
drv_enc = wpa_s->drv_enc;
else
@@ -7330,6 +7484,7 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
continue;
return 1; /* invalid WEP key */
}
+#endif /* CONFIG_WEP */
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
(!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
@@ -7727,12 +7882,17 @@ int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
- u16 num_modes, enum hostapd_hw_mode mode)
+ u16 num_modes, enum hostapd_hw_mode mode,
+ int is_6ghz)
{
u16 i;
for (i = 0; i < num_modes; i++) {
- if (modes[i].mode == mode)
+ if (modes[i].mode != mode ||
+ !modes[i].num_channels || !modes[i].channels)
+ continue;
+ if ((!is_6ghz && !is_6ghz_freq(modes[i].channels[0].freq)) ||
+ (is_6ghz && is_6ghz_freq(modes[i].channels[0].freq)))
return &modes[i];
}
@@ -7909,3 +8069,87 @@ int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
return 0;
}
+
+
+int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
+ struct wpa_signal_info *si)
+{
+ int res;
+
+ if (!wpa_s->driver->signal_poll)
+ return -1;
+
+ res = wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (res == 0) {
+ struct driver_signal_override *dso;
+
+ dl_list_for_each(dso, &wpa_s->drv_signal_override,
+ struct driver_signal_override, list) {
+ if (os_memcmp(wpa_s->bssid, dso->bssid,
+ ETH_ALEN) != 0)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "Override driver signal_poll information: current_signal: %d->%d avg_signal: %d->%d avg_beacon_signal: %d->%d current_noise: %d->%d",
+ si->current_signal,
+ dso->si_current_signal,
+ si->avg_signal,
+ dso->si_avg_signal,
+ si->avg_beacon_signal,
+ dso->si_avg_beacon_signal,
+ si->current_noise,
+ dso->si_current_noise);
+ si->current_signal = dso->si_current_signal;
+ si->avg_signal = dso->si_avg_signal;
+ si->avg_beacon_signal = dso->si_avg_beacon_signal;
+ si->current_noise = dso->si_current_noise;
+ break;
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return res;
+}
+
+
+struct wpa_scan_results *
+wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_scan_results *scan_res;
+#ifdef CONFIG_TESTING_OPTIONS
+ size_t idx;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!wpa_s->driver->get_scan_results2)
+ return NULL;
+
+ scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ for (idx = 0; scan_res && idx < scan_res->num; idx++) {
+ struct driver_signal_override *dso;
+ struct wpa_scan_res *res = scan_res->res[idx];
+
+ dl_list_for_each(dso, &wpa_s->drv_signal_override,
+ struct driver_signal_override, list) {
+ if (os_memcmp(res->bssid, dso->bssid, ETH_ALEN) != 0)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "Override driver scan signal level %d->%d for "
+ MACSTR,
+ res->level, dso->scan_level,
+ MAC2STR(res->bssid));
+ res->flags |= WPA_SCAN_QUAL_INVALID;
+ if (dso->scan_level < 0)
+ res->flags |= WPA_SCAN_LEVEL_DBM;
+ else
+ res->flags &= ~WPA_SCAN_LEVEL_DBM;
+ res->level = dso->scan_level;
+ break;
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return scan_res;
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 328f91a9..f242c3a9 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -94,11 +94,8 @@ eapol_version=1
# 1: wpa_supplicant initiates scanning and AP selection; if no APs matching to
# the currently enabled networks are found, a new network (IBSS or AP mode
# operation) may be initialized (if configured) (default)
-# 0: driver takes care of scanning, AP selection, and IEEE 802.11 association
-# parameters (e.g., WPA IE generation); this mode can also be used with
-# non-WPA drivers when using IEEE 802.1X mode; do not try to associate with
-# APs (i.e., external program needs to control association). This mode must
-# also be used when using wired Ethernet drivers (including MACsec).
+# 0: This mode must only be used when using wired Ethernet drivers
+# (including MACsec).
# 2: like 0, but associate with APs using security policy and SSID (but not
# BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to
# enable operation with hidden SSIDs and optimized roaming; in this mode,
@@ -106,8 +103,8 @@ eapol_version=1
# the driver reports successful association; each network block should have
# explicit security policy (i.e., only one option in the lists) for
# key_mgmt, pairwise, group, proto variables
-# Note: ap_scan=2 should not be used with the nl80211 driver interface (the
-# current Linux interface). ap_scan=1 is optimized work working with nl80211.
+# Note: ap_scan=0/2 should not be used with the nl80211 driver interface (the
+# current Linux interface). ap_scan=1 is the only option working with nl80211.
# For finding networks using hidden SSID, scan_ssid=1 in the network block can
# be used with nl80211.
# When using IBSS or AP mode, ap_scan=2 mode can force the new network to be
@@ -426,11 +423,13 @@ fast_reauth=1
#sae_groups=19 20 21
# SAE mechanism for PWE derivation
-# 0 = hunting-and-pecking loop only (default)
-# 1 = hash-to-element only
+# 0 = hunting-and-pecking loop only (default without password identifier)
+# 1 = hash-to-element only (default with password identifier)
# 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.
+# When using SAE password identifier, the hash-to-element mechanism is used
+# regardless of the sae_pwe parameter value.
#sae_pwe=0
# Default value for DTIM period (if not overridden in network block)
@@ -803,6 +802,11 @@ fast_reauth=1
# Set BIT(1) to Enable OCE in STA-CFON mode
#oce=1
+# Extended Key ID support for Individually Addressed frames
+# 0 = force off: Do not use Extended Key ID (default)
+# 1 = auto: Activate Extended Key ID support if the driver supports it
+#extended_key_id=0
+
# network block
#
# Each network (usually AP's sharing the same SSID) is configured as a separate
@@ -1102,6 +1106,18 @@ fast_reauth=1
# wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
# enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
#
+# wpa_deny_ptk0_rekey: Workaround for PTK rekey issues
+# PTK0 rekeys (using only one Key ID value for pairwise keys) can degrade the
+# security and stability with some cards.
+# To avoid the issues wpa_supplicant can replace those PTK rekeys (including
+# EAP reauthentications) with fast reconnects.
+#
+# Available options:
+# 0 = always rekey when configured/instructed (default)
+# 1 = only rekey when the local driver is explicitly indicating it can perform
+# this operation without issues
+# 2 = never allow problematic PTK0 rekeys
+#
# group_rekey: Group rekeying time in seconds. This value, if non-zero, is used
# as the dot11RSNAConfigGroupRekeyTime parameter when operating in
# Authenticator role in IBSS, or in AP and mesh modes.
@@ -1445,6 +1461,12 @@ fast_reauth=1
# 1-65535 = DH Group to use for FILS PFS
#fils_dh_group=0
+# DPP PFS
+# 0: allow PFS to be used or not used (default)
+# 1: require PFS to be used (note: not compatible with DPP R1)
+# 2: do not allow PFS to be used
+#dpp_pfs=0
+
# MAC address policy
# 0 = use permanent MAC address
# 1 = use random MAC address for each ESS connection
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 967298bf..8b1d0d04 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -47,6 +47,9 @@ struct ctrl_iface_global_priv;
struct wpas_dbus_priv;
struct wpas_hidl_priv;
+/* How many seconds to consider old scan results valid for association. */
+#define SCAN_RES_VALID_FOR_CONNECT 5
+
/**
* struct wpa_interface - Parameters for wpa_supplicant_add_iface()
*/
@@ -280,6 +283,7 @@ struct wpa_global {
struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
int p2p_disabled;
int cross_connection;
+ int p2p_long_listen; /* remaining time in long Listen state in ms */
struct wpa_freq_range_list p2p_disallow_freq;
struct wpa_freq_range_list p2p_go_avoid_freq;
enum wpa_conc_pref {
@@ -477,6 +481,16 @@ struct fils_hlp_req {
struct wpabuf *pkt;
};
+struct driver_signal_override {
+ struct dl_list list;
+ u8 bssid[ETH_ALEN];
+ int si_current_signal;
+ int si_avg_signal;
+ int si_avg_beacon_signal;
+ int si_current_noise;
+ int scan_level;
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -540,6 +554,7 @@ struct wpa_supplicant {
/* Selected configuration (based on Beacon/ProbeResp WPA IE) */
int pairwise_cipher;
+ int deny_ptk0_rekey;
int group_cipher;
int key_mgmt;
int wpa_proto;
@@ -592,8 +607,8 @@ struct wpa_supplicant {
* results.
*/
struct wpa_bss **last_scan_res;
- unsigned int last_scan_res_used;
- unsigned int last_scan_res_size;
+ size_t last_scan_res_used;
+ size_t last_scan_res_size;
struct os_reltime last_scan;
const struct wpa_driver_ops *driver;
@@ -700,6 +715,7 @@ struct wpa_supplicant {
int scan_id[MAX_SCAN_ID];
unsigned int scan_id_count;
u8 next_scan_bssid[ETH_ALEN];
+ unsigned int next_scan_bssid_wildcard_ssid:1;
struct wpa_ssid_value *ssids_from_scan_req;
unsigned int num_ssids_from_scan_req;
@@ -710,7 +726,6 @@ struct wpa_supplicant {
u64 drv_flags;
unsigned int drv_enc;
- unsigned int drv_smps_modes;
unsigned int drv_rrm_flags;
/*
@@ -880,7 +895,6 @@ struct wpa_supplicant {
P2P_GROUP_INTERFACE_CLIENT
} p2p_group_interface;
struct p2p_group *p2p_group;
- int p2p_long_listen; /* remaining time in long Listen state in ms */
char p2p_pin[10];
int p2p_wps_method;
u8 p2p_auth_invite[ETH_ALEN];
@@ -1064,6 +1078,7 @@ struct wpa_supplicant {
unsigned int wmm_ac_supported:1;
unsigned int ext_work_in_progress:1;
unsigned int own_disconnect_req:1;
+ unsigned int own_reconnect_req:1;
unsigned int ignore_post_flush_scan_res:1;
#define MAC_ADDR_RAND_SCAN BIT(0)
@@ -1126,6 +1141,7 @@ struct wpa_supplicant {
unsigned int p2p_go_csa_on_inv:1;
unsigned int ignore_auth_resp:1;
unsigned int ignore_assoc_disallow:1;
+ unsigned int disable_sa_query:1;
unsigned int testing_resend_assoc:1;
unsigned int ignore_sae_h2e_only:1;
struct wpabuf *sae_commit_override;
@@ -1136,8 +1152,10 @@ struct wpa_supplicant {
size_t last_tk_len;
struct wpabuf *last_assoc_req_wpa_ie;
int *extra_sae_rejected_groups;
+ struct wpabuf *rsne_override_eapol;
struct wpabuf *rsnxe_override_assoc;
struct wpabuf *rsnxe_override_eapol;
+ struct dl_list drv_signal_override;
#endif /* CONFIG_TESTING_OPTIONS */
struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -1264,6 +1282,15 @@ struct wpa_supplicant {
size_t dpp_last_ssid_len;
#ifdef CONFIG_DPP2
struct dpp_pfs *dpp_pfs;
+ int dpp_pfs_fallback;
+ struct wpabuf *dpp_presence_announcement;
+ struct dpp_bootstrap_info *dpp_chirp_bi;
+ int dpp_chirp_freq;
+ int *dpp_chirp_freqs;
+ int dpp_chirp_iter;
+ int dpp_chirp_round;
+ int dpp_chirp_scan_done;
+ int dpp_chirp_listen;
#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override;
@@ -1280,6 +1307,9 @@ struct wpa_supplicant {
unsigned int enabled_4addr_mode:1;
unsigned int multi_bss_support:1;
unsigned int drv_authorized_port:1;
+ unsigned int multi_ap_ie:1;
+ unsigned int multi_ap_backhaul:1;
+ unsigned int multi_ap_fronthaul:1;
};
@@ -1290,6 +1320,9 @@ void wpa_supplicant_apply_ht_overrides(
void wpa_supplicant_apply_vht_overrides(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_driver_associate_params *params);
+void wpa_supplicant_apply_he_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params);
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
@@ -1321,6 +1354,7 @@ const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s);
void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
u16 reason_code);
+void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s);
struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s);
int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id);
@@ -1386,6 +1420,8 @@ int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style);
int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
void add_freq(int *freqs, int *num_freqs, int freq);
+int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
+ u8 *op_class, u8 *chan, u8 *phy_type);
void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
const u8 *report, size_t report_len);
@@ -1408,6 +1444,7 @@ int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s,
struct scan_info *info);
void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s);
void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s);
+void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx);
/* MBO functions */
@@ -1444,7 +1481,7 @@ 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);
+ struct wpa_bss *bss, 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,
@@ -1567,7 +1604,8 @@ void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s,
int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd);
struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
- u16 num_modes, enum hostapd_hw_mode mode);
+ u16 num_modes, enum hostapd_hw_mode mode,
+ int is_6ghz);
void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
unsigned int sec, int rssi_threshold);
@@ -1588,4 +1626,6 @@ int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
int wpa_is_fils_supported(struct wpa_supplicant *wpa_s);
int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s);
+void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s);
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index d80b8f28..6bd271e1 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -112,6 +112,14 @@ static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
}
#endif /* CONFIG_TESTING_OPTIONS */
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) {
+ int encrypt = wpa_s->wpa &&
+ wpa_sm_has_ptk_installed(wpa_s->wpa);
+
+ return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len,
+ !encrypt);
+ }
+
if (wpa_s->l2) {
return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
}
@@ -219,6 +227,7 @@ static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
}
+#ifdef CONFIG_WEP
/**
* wpa_eapol_set_wep_key - set WEP key for the driver
* @ctx: Pointer to wpa_supplicant data (wpa_s)
@@ -242,8 +251,11 @@ static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx,
}
return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
unicast ? wpa_s->bssid : NULL,
- keyidx, unicast, NULL, 0, key, keylen);
+ keyidx, unicast, NULL, 0, key, keylen,
+ unicast ? KEY_FLAG_PAIRWISE_RX_TX :
+ KEY_FLAG_GROUP_RX_TX_DEFAULT);
}
+#endif /* CONFIG_WEP */
static void wpa_supplicant_aborted_cached(void *ctx)
@@ -340,8 +352,8 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol,
wpa_hexdump_key(MSG_DEBUG, "RSN: Configure PMK for driver-based 4-way "
"handshake", pmk, pmk_len);
- if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk,
- pmk_len)) {
+ if (wpa_drv_set_key(wpa_s, 0, NULL, 0, 0, NULL, 0, pmk,
+ pmk_len, KEY_FLAG_PMK)) {
wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
}
@@ -386,6 +398,13 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
curr = bss;
break;
}
+#ifdef CONFIG_OWE
+ if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ (bss->flags & WPA_BSS_OWE_TRANSITION)) {
+ curr = bss;
+ break;
+ }
+#endif /* CONFIG_OWE */
}
if (curr) {
@@ -476,6 +495,12 @@ static void _wpa_supplicant_deauthenticate(void *wpa_s, u16 reason_code)
}
+static void _wpa_supplicant_reconnect(void *wpa_s)
+{
+ wpa_supplicant_reconnect(wpa_s);
+}
+
+
static void * wpa_supplicant_get_network_ctx(void *wpa_s)
{
return wpa_supplicant_get_ssid(wpa_s);
@@ -492,7 +517,8 @@ static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid)
static int wpa_supplicant_set_key(void *_wpa_s, 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)
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
struct wpa_supplicant *wpa_s = _wpa_s;
if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) {
@@ -507,7 +533,8 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
}
#endif /* CONFIG_TESTING_GET_GTK */
#ifdef CONFIG_TESTING_OPTIONS
- if (addr && !is_broadcast_ether_addr(addr)) {
+ if (addr && !is_broadcast_ether_addr(addr) &&
+ !(key_flag & KEY_FLAG_MODIFY)) {
wpa_s->last_tk_alg = alg;
os_memcpy(wpa_s->last_tk_addr, addr, ETH_ALEN);
wpa_s->last_tk_key_idx = key_idx;
@@ -517,7 +544,7 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
}
#endif /* CONFIG_TESTING_OPTIONS */
return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
- key, key_len);
+ key, key_len, key_flag);
}
@@ -547,7 +574,8 @@ static struct wpa_ssid * wpas_get_network_ctx(struct wpa_supplicant *wpa_s,
static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *fils_cache_id,
- const u8 *pmk, size_t pmk_len)
+ const u8 *pmk, size_t pmk_len,
+ u32 pmk_lifetime, u8 pmk_reauth_threshold)
{
struct wpa_supplicant *wpa_s = _wpa_s;
struct wpa_ssid *ssid;
@@ -569,6 +597,8 @@ static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
params.pmkid = pmkid;
params.pmk = pmk;
params.pmk_len = pmk_len;
+ params.pmk_lifetime = pmk_lifetime;
+ params.pmk_reauth_threshold = pmk_reauth_threshold;
return wpa_drv_add_pmkid(wpa_s, &params);
}
@@ -1047,6 +1077,21 @@ static void wpa_supplicant_eap_error_cb(void *ctx, int error_code)
}
+static int wpa_supplicant_eap_auth_start_cb(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (!wpa_s->new_connection && wpa_s->deny_ptk0_rekey &&
+ !wpa_sm_ext_key_id_active(wpa_s->wpa)) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "WPA: PTK0 rekey not allowed, reconnecting");
+ wpa_supplicant_reconnect(wpa_s);
+ return -1;
+ }
+ return 0;
+}
+
+
static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -1102,7 +1147,9 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
ctx->preauth = 0;
ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
ctx->eapol_send = wpa_supplicant_eapol_send;
+#ifdef CONFIG_WEP
ctx->set_wep_key = wpa_eapol_set_wep_key;
+#endif /* CONFIG_WEP */
#ifndef CONFIG_NO_CONFIG_BLOBS
ctx->set_config_blob = wpa_supplicant_set_config_blob;
ctx->get_config_blob = wpa_supplicant_get_config_blob;
@@ -1125,6 +1172,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
ctx->cert_in_cb = wpa_s->conf->cert_in_cb;
ctx->status_cb = wpa_supplicant_status_cb;
ctx->eap_error_cb = wpa_supplicant_eap_error_cb;
+ ctx->confirm_auth_cb = wpa_supplicant_eap_auth_start_cb;
ctx->set_anon_id = wpa_supplicant_set_anon_id;
ctx->cb_ctx = wpa_s;
wpa_s->eapol = eapol_sm_init(ctx);
@@ -1160,8 +1208,8 @@ static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk,
if (wpa_s->conf->key_mgmt_offload &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
- return wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0,
- NULL, 0, pmk, pmk_len);
+ return wpa_drv_set_key(wpa_s, 0, NULL, 0, 0,
+ NULL, 0, pmk, pmk_len, KEY_FLAG_PMK);
else
return 0;
}
@@ -1193,6 +1241,73 @@ static int wpa_supplicant_channel_info(void *_wpa_s,
return wpa_drv_channel_info(wpa_s, ci);
}
+
+static void disable_wpa_wpa2(struct wpa_ssid *ssid)
+{
+ ssid->proto &= ~WPA_PROTO_WPA;
+ ssid->proto |= WPA_PROTO_RSN;
+ ssid->key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256);
+ ssid->group_cipher &= ~WPA_CIPHER_TKIP;
+ if (!(ssid->group_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+ WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)))
+ ssid->group_cipher |= WPA_CIPHER_CCMP;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+}
+
+
+static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap)
+{
+ struct wpa_supplicant *wpa_s = _wpa_s;
+ struct wpa_ssid *ssid;
+ int changed = 0;
+
+ wpa_msg(wpa_s, MSG_INFO, TRANSITION_DISABLE "%02x", bitmap);
+
+ ssid = wpa_s->current_ssid;
+ if (!ssid)
+ return;
+
+ if ((bitmap & TRANSITION_DISABLE_WPA3_PERSONAL) &&
+ wpa_key_mgmt_sae(wpa_s->key_mgmt) &&
+ (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) &&
+ (ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
+ (ssid->group_cipher & WPA_CIPHER_TKIP))) {
+ wpa_printf(MSG_DEBUG,
+ "WPA3-Personal transition mode disabled based on AP notification");
+ disable_wpa_wpa2(ssid);
+ changed = 1;
+ }
+
+ if ((bitmap & TRANSITION_DISABLE_WPA3_ENTERPRISE) &&
+ wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
+ (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X |
+ WPA_KEY_MGMT_FT_IEEE8021X |
+ WPA_KEY_MGMT_IEEE8021X_SHA256)) &&
+ (ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
+ (ssid->group_cipher & WPA_CIPHER_TKIP))) {
+ disable_wpa_wpa2(ssid);
+ changed = 1;
+ }
+
+ if ((bitmap & TRANSITION_DISABLE_ENHANCED_OPEN) &&
+ wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
+ (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ !ssid->owe_only) {
+ ssid->owe_only = 1;
+ changed = 1;
+ }
+
+ if (!changed)
+ return;
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->conf->update_config &&
+ wpa_config_write(wpa_s->confname, wpa_s->conf))
+ wpa_printf(MSG_DEBUG, "Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+}
+
#endif /* CONFIG_NO_WPA */
@@ -1211,6 +1326,7 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
ctx->set_state = _wpa_supplicant_set_state;
ctx->get_state = _wpa_supplicant_get_state;
ctx->deauthenticate = _wpa_supplicant_deauthenticate;
+ ctx->reconnect = _wpa_supplicant_reconnect;
ctx->set_key = wpa_supplicant_set_key;
ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
ctx->get_bssid = wpa_supplicant_get_bssid;
@@ -1244,6 +1360,7 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk;
ctx->fils_hlp_rx = wpa_supplicant_fils_hlp_rx;
ctx->channel_info = wpa_supplicant_channel_info;
+ ctx->transition_disable = wpa_supplicant_transition_disable;
wpa_s->wpa = wpa_sm_init(ctx);
if (wpa_s->wpa == NULL) {
@@ -1275,6 +1392,8 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
conf.ssid = ssid->ssid;
conf.ssid_len = ssid->ssid_len;
conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
+ conf.wpa_deny_ptk0_rekey = ssid->wpa_deny_ptk0_rekey;
+ conf.owe_ptk_workaround = ssid->owe_ptk_workaround;
#ifdef CONFIG_P2P
if (ssid->p2p_group && wpa_s->current_bss &&
!wpa_s->p2p_disable_ip_addr_req) {
@@ -1297,6 +1416,7 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
conf.fils_cache_id =
wpa_bss_get_fils_cache_id(wpa_s->current_bss);
#endif /* CONFIG_FILS */
+ conf.beacon_prot = ssid->beacon_prot;
}
wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
}
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 8387fc3a..e6171585 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -532,6 +532,7 @@ static int wpa_supplicant_wps_cred(void *ctx,
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
if (wpa_s->conf->wps_cred_add_sae &&
cred->key_len != 2 * PMK_LEN) {
+ ssid->auth_alg = 0;
ssid->key_mgmt |= WPA_KEY_MGMT_SAE;
ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
}
@@ -1829,6 +1830,10 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "WPS: Check whether PBC session overlap is "
"present in scan results; selected BSSID " MACSTR,
MAC2STR(selected->bssid));
+ if (!is_zero_ether_addr(ssid->bssid))
+ wpa_printf(MSG_DEBUG,
+ "WPS: Network profile limited to accept only a single BSSID " MACSTR,
+ MAC2STR(ssid->bssid));
/* Make sure that only one AP is in active PBC mode */
wps_ie = wpa_bss_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE);
@@ -1849,6 +1854,14 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0)
continue;
+ if (!is_zero_ether_addr(ssid->bssid) &&
+ os_memcmp(ap->bssid, ssid->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Ignore another BSS " MACSTR
+ " in active PBC mode due to local BSSID limitation",
+ MAC2STR(ap->bssid));
+ continue;
+ }
+
wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: "
MACSTR, MAC2STR(ap->bssid));
wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",