aboutsummaryrefslogtreecommitdiffstats
path: root/wpa_supplicant
diff options
context:
space:
mode:
Diffstat (limited to 'wpa_supplicant')
-rw-r--r--wpa_supplicant/Android.mk40
-rw-r--r--wpa_supplicant/Makefile44
-rw-r--r--wpa_supplicant/README-DPP69
-rw-r--r--wpa_supplicant/android.config12
-rw-r--r--wpa_supplicant/ap.c41
-rw-r--r--wpa_supplicant/bss.c2
-rw-r--r--wpa_supplicant/bss.h1
-rw-r--r--wpa_supplicant/config.c78
-rw-r--r--wpa_supplicant/config.h35
-rw-r--r--wpa_supplicant/config_file.c73
-rw-r--r--wpa_supplicant/config_ssid.h122
-rw-r--r--wpa_supplicant/config_winreg.c25
-rw-r--r--wpa_supplicant/ctrl_iface.c723
-rw-r--r--wpa_supplicant/ctrl_iface.h6
-rw-r--r--wpa_supplicant/ctrl_iface_named_pipe.c2
-rw-r--r--wpa_supplicant/ctrl_iface_udp.c57
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c30
-rw-r--r--wpa_supplicant/dbus/dbus_new.c62
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c243
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.h2
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.c77
-rw-r--r--wpa_supplicant/dbus/dbus_new_introspect.c2
-rw-r--r--wpa_supplicant/defconfig31
-rw-r--r--wpa_supplicant/dpp_supplicant.c1410
-rw-r--r--wpa_supplicant/dpp_supplicant.h11
-rw-r--r--wpa_supplicant/driver_i.h99
-rw-r--r--wpa_supplicant/eapol_test.c8
-rw-r--r--wpa_supplicant/events.c1347
-rwxr-xr-xwpa_supplicant/examples/dpp-nfc.py1186
-rw-r--r--wpa_supplicant/examples/p2p/p2p_connect.py2
-rw-r--r--wpa_supplicant/gas_query.c62
-rw-r--r--wpa_supplicant/gas_query.h2
-rw-r--r--wpa_supplicant/hs20_supplicant.c5
-rw-r--r--wpa_supplicant/ibss_rsn.c45
-rw-r--r--wpa_supplicant/interworking.c40
-rw-r--r--wpa_supplicant/interworking.h2
-rw-r--r--wpa_supplicant/mesh.c11
-rw-r--r--wpa_supplicant/mesh_mpm.c48
-rw-r--r--wpa_supplicant/mesh_rsn.c10
-rw-r--r--wpa_supplicant/offchannel.c6
-rw-r--r--wpa_supplicant/op_classes.c105
-rw-r--r--wpa_supplicant/p2p_supplicant.c220
-rw-r--r--wpa_supplicant/p2p_supplicant.h16
-rw-r--r--wpa_supplicant/preauth_test.c14
-rw-r--r--wpa_supplicant/robust_av.c157
-rw-r--r--wpa_supplicant/rrm.c46
-rw-r--r--wpa_supplicant/scan.c366
-rw-r--r--wpa_supplicant/scan.h27
-rw-r--r--wpa_supplicant/sme.c449
-rw-r--r--wpa_supplicant/sme.h6
-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.c23
-rw-r--r--wpa_supplicant/wpa_cli.c178
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons/Makefile18
-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_passphrase.c8
-rw-r--r--wpa_supplicant/wpa_priv.c32
-rw-r--r--wpa_supplicant/wpa_supplicant.c747
-rw-r--r--wpa_supplicant/wpa_supplicant.conf114
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h106
-rw-r--r--wpa_supplicant/wpas_glue.c177
-rw-r--r--wpa_supplicant/wpas_kay.c12
-rw-r--r--wpa_supplicant/wps_supplicant.c43
66 files changed, 7651 insertions, 1313 deletions
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index ce8a352..ed7e358 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -94,9 +94,11 @@ 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
+OBJS += robust_av.c
OBJS_p = wpa_passphrase.c
OBJS_p += src/utils/common.c
OBJS_p += src/utils/wpa_debug.c
@@ -165,6 +167,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
@@ -230,14 +236,28 @@ endif
ifdef CONFIG_SAE
L_CFLAGS += -DCONFIG_SAE
OBJS += src/common/sae.c
+ifdef CONFIG_SAE_PK
+L_CFLAGS += -DCONFIG_SAE_PK
+OBJS += src/common/sae_pk.c
+endif
NEED_ECC=y
NEED_DH_GROUPS=y
+NEED_HMAC_SHA256_KDF=y
NEED_DRAGONFLY=y
+ifdef CONFIG_TESTING_OPTIONS
+NEED_DH_GROUPS_ALL=y
+endif
endif
ifdef CONFIG_DPP
L_CFLAGS += -DCONFIG_DPP
OBJS += src/common/dpp.c
+OBJS += src/common/dpp_auth.c
+OBJS += src/common/dpp_backup.c
+OBJS += src/common/dpp_crypto.c
+OBJS += src/common/dpp_pkex.c
+OBJS += src/common/dpp_reconfig.c
+OBJS += src/common/dpp_tcp.c
OBJS += dpp_supplicant.c
NEED_AES_SIV=y
NEED_HMAC_SHA256_KDF=y
@@ -249,6 +269,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
@@ -373,6 +394,14 @@ OBJS += src/fst/fst_ctrl_iface.c
endif
endif
+ifdef CONFIG_WEP
+L_CFLAGS += -DCONFIG_WEP
+endif
+
+ifdef CONFIG_NO_TKIP
+L_CFLAGS += -DCONFIG_NO_TKIP
+endif
+
include $(LOCAL_PATH)/src/drivers/drivers.mk
@@ -853,7 +882,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
@@ -861,7 +889,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
@@ -881,15 +908,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
@@ -1085,7 +1109,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
@@ -1375,6 +1399,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 a6329c0..a01a329 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -104,8 +104,10 @@ 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 += robust_av.o
OBJS_p = wpa_passphrase.o
OBJS_p += ../src/utils/common.o
OBJS_p += ../src/utils/wpa_debug.o
@@ -197,6 +199,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
@@ -262,14 +268,28 @@ endif
ifdef CONFIG_SAE
CFLAGS += -DCONFIG_SAE
OBJS += ../src/common/sae.o
+ifdef CONFIG_SAE_PK
+CFLAGS += -DCONFIG_SAE_PK
+OBJS += ../src/common/sae_pk.o
+endif
NEED_ECC=y
NEED_DH_GROUPS=y
+NEED_HMAC_SHA256_KDF=y
NEED_DRAGONFLY=y
+ifdef CONFIG_TESTING_OPTIONS
+NEED_DH_GROUPS_ALL=y
+endif
endif
ifdef CONFIG_DPP
CFLAGS += -DCONFIG_DPP
OBJS += ../src/common/dpp.o
+OBJS += ../src/common/dpp_auth.o
+OBJS += ../src/common/dpp_backup.o
+OBJS += ../src/common/dpp_crypto.o
+OBJS += ../src/common/dpp_pkex.o
+OBJS += ../src/common/dpp_reconfig.o
+OBJS += ../src/common/dpp_tcp.o
OBJS += dpp_supplicant.o
NEED_AES_SIV=y
NEED_HMAC_SHA256_KDF=y
@@ -281,6 +301,7 @@ NEED_ECC=y
NEED_JSON=y
NEED_GAS_SERVER=y
NEED_BASE64=y
+NEED_ASN1=y
ifdef CONFIG_DPP2
CFLAGS += -DCONFIG_DPP2
endif
@@ -899,7 +920,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
@@ -907,7 +927,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
@@ -927,15 +946,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
@@ -1066,7 +1082,7 @@ endif
ifeq ($(CONFIG_TLS), wolfssl)
ifdef TLS_FUNCS
-CFLAGS += -DWOLFSSL_DER_LOAD -I/usr/local/include/wolfssl
+CFLAGS += -DWOLFSSL_DER_LOAD
OBJS += ../src/crypto/tls_wolfssl.o
endif
OBJS += ../src/crypto/crypto_wolfssl.o
@@ -1149,12 +1165,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
@@ -1228,12 +1244,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
@@ -1516,6 +1532,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
@@ -1839,6 +1859,14 @@ OBJS_t2 += $(FST_OBJS)
OBJS_nfc += $(FST_OBJS)
endif
+ifdef CONFIG_WEP
+CFLAGS += -DCONFIG_WEP
+endif
+
+ifdef CONFIG_NO_TKIP
+CFLAGS += -DCONFIG_NO_TKIP
+endif
+
ifndef LDO
LDO=$(CC)
endif
diff --git a/wpa_supplicant/README-DPP b/wpa_supplicant/README-DPP
index 96b1735..d378245 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,39 +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)
-> dpp_auth_init peer=<qr-code-id> conf=<ap-dpp|sta-dpp> configurator=<configurator-id>
+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.
@@ -154,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 f9d3712..283f8eb 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -438,11 +438,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)
@@ -538,4 +534,12 @@ CONFIG_WIFI_DISPLAY=y
# Experimental implementation of draft-harkins-owe-07.txt
#CONFIG_OWE=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 725e096..2accf92 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) {
@@ -434,6 +434,8 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
pw->next = bss->sae_passwords;
bss->sae_passwords = pw;
}
+
+ bss->sae_pwe = wpa_s->conf->sae_pwe;
#endif /* CONFIG_SAE */
if (wpa_s->conf->go_interworking) {
@@ -487,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;
@@ -509,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;
@@ -603,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;
}
@@ -773,6 +779,21 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
ssid->frequency = 2462; /* default channel 11 */
params.freq.freq = ssid->frequency;
+ if ((ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO) &&
+ ssid->enable_edmg) {
+ u8 primary_channel;
+
+ if (ieee80211_freq_to_chan(ssid->frequency, &primary_channel) ==
+ NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_WARNING,
+ "EDMG: Failed to get the primary channel");
+ return -1;
+ }
+
+ hostapd_encode_edmg_chan(ssid->enable_edmg, ssid->edmg_channel,
+ primary_channel, &params.freq.edmg);
+ }
+
params.wpa_proto = ssid->proto;
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
@@ -822,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;
@@ -838,6 +858,9 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
wpa_s->conf->wmm_ac_params,
sizeof(wpa_s->conf->wmm_ac_params));
+ os_memcpy(wpa_s->ap_iface->conf->tx_queue, wpa_s->conf->tx_queue,
+ sizeof(wpa_s->conf->tx_queue));
+
if (params.uapsd > 0) {
conf->bss[0]->wmm_enabled = 1;
conf->bss[0]->wmm_uapsd = 1;
@@ -911,6 +934,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
wpa_s->assoc_freq = ssid->frequency;
+ wpa_s->ap_iface->conf->enable_edmg = ssid->enable_edmg;
+ wpa_s->ap_iface->conf->edmg_channel = ssid->edmg_channel;
#if defined(CONFIG_P2P) && defined(CONFIG_ACS)
if (wpa_s->p2p_go_do_acs) {
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 943a340..127f43e 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 3ce8cd3..0716761 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 5ad6fc7..0b4a66a 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -12,6 +12,7 @@
#include "utils/uuid.h"
#include "utils/ip_addr.h"
#include "common/ieee802_1x_defs.h"
+#include "common/sae.h"
#include "crypto/sha1.h"
#include "rsn_supp/wpa.h"
#include "eap_peer/eap.h"
@@ -1855,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)
{
@@ -1965,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
@@ -2450,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) },
@@ -2481,6 +2488,8 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(mixed_cell, 0, 1) },
{ INT_RANGE(frequency, 0, 70200) },
{ INT_RANGE(fixed_freq, 0, 1) },
+ { INT_RANGE(enable_edmg, 0, 1) },
+ { INT_RANGE(edmg_channel, 9, 13) },
#ifdef CONFIG_ACS
{ INT_RANGE(acs, 0, 1) },
#endif /* CONFIG_ACS */
@@ -2492,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) },
@@ -2534,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) },
@@ -2560,11 +2573,16 @@ 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) },
+ { INT_RANGE(sae_pk, 0, 2) },
};
#undef OFFSET
@@ -2600,7 +2618,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;
/*
@@ -2763,6 +2781,9 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
dl_list_del(&psk->list);
bin_clear_free(psk, sizeof(*psk));
}
+#ifdef CONFIG_SAE
+ sae_deinit_pt(ssid->pt);
+#endif /* CONFIG_SAE */
bin_clear_free(ssid, sizeof(*ssid));
}
@@ -3012,6 +3033,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
@@ -3102,6 +3124,15 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
}
ret = -1;
}
+#ifdef CONFIG_SAE
+ if (os_strcmp(var, "ssid") == 0 ||
+ os_strcmp(var, "psk") == 0 ||
+ os_strcmp(var, "sae_password") == 0 ||
+ os_strcmp(var, "sae_password_id") == 0) {
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ }
+#endif /* CONFIG_SAE */
break;
}
if (i == NUM_SSID_FIELDS) {
@@ -4224,6 +4255,8 @@ int wpa_config_remove_blob(struct wpa_config *config, const char *name)
struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const char *driver_param)
{
+#define ecw2cw(ecw) ((1 << (ecw)) - 1)
+
struct wpa_config *config;
const int aCWmin = 4, aCWmax = 10;
const struct hostapd_wmm_ac_params ac_bk =
@@ -4234,6 +4267,17 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
{ aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
+ const struct hostapd_tx_queue_params txq_bk =
+ { 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
+ const struct hostapd_tx_queue_params txq_be =
+ { 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0 };
+ const struct hostapd_tx_queue_params txq_vi =
+ { 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30 };
+ const struct hostapd_tx_queue_params txq_vo =
+ { 1, (ecw2cw(aCWmin) + 1) / 4 - 1,
+ (ecw2cw(aCWmin) + 1) / 2 - 1, 15 };
+
+#undef ecw2cw
config = os_zalloc(sizeof(*config));
if (config == NULL)
@@ -4263,11 +4307,16 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->wmm_ac_params[1] = ac_bk;
config->wmm_ac_params[2] = ac_vi;
config->wmm_ac_params[3] = ac_vo;
+ config->tx_queue[0] = txq_vo;
+ config->tx_queue[1] = txq_vi;
+ config->tx_queue[2] = txq_be;
+ config->tx_queue[3] = txq_bk;
config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
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;
@@ -4293,7 +4342,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++) {
@@ -4624,7 +4673,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;
@@ -4936,6 +4985,7 @@ static const struct global_parse_data global_fields[] = {
{ INT(p2p_go_ht40), 0 },
{ INT(p2p_go_vht), 0 },
{ INT(p2p_go_he), 0 },
+ { INT(p2p_go_edmg), 0 },
{ INT(p2p_disabled), 0 },
{ INT_RANGE(p2p_go_ctwindow, 0, 127), 0 },
{ INT(p2p_no_group_iface), 0 },
@@ -4982,6 +5032,7 @@ static const struct global_parse_data global_fields[] = {
{ INT(okc), 0 },
{ INT(pmf), 0 },
{ FUNC(sae_groups), 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 },
@@ -5030,6 +5081,7 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(coloc_intf_reporting, 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 */
};
@@ -5130,6 +5182,26 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
}
if (i == NUM_GLOBAL_FIELDS) {
#ifdef CONFIG_AP
+ if (os_strncmp(pos, "tx_queue_", 9) == 0) {
+ char *tmp = os_strchr(pos, '=');
+
+ if (!tmp) {
+ if (line < 0)
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid line %s",
+ line, pos);
+ return -1;
+ }
+ *tmp++ = '\0';
+ if (hostapd_config_tx_queue(config->tx_queue, pos,
+ tmp)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid TX queue item",
+ line);
+ return -1;
+ }
+ }
+
if (os_strncmp(pos, "wmm_ac_", 7) == 0) {
char *tmp = os_strchr(pos, '=');
if (tmp == NULL) {
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 1734e00..a385da5 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
@@ -1057,6 +1058,7 @@ struct wpa_config {
int p2p_go_max_inactivity;
struct hostapd_wmm_ac_params wmm_ac_params[4];
+ struct hostapd_tx_queue_params tx_queue[4];
/**
* auto_interworking - Whether to use network selection automatically
@@ -1090,6 +1092,16 @@ struct wpa_config {
int p2p_go_vht;
/**
+ * p2p_go_edmg - Default mode for EDMG enable when operating as GO
+ *
+ * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+ * Note that regulatory constraints and driver capabilities are
+ * consulted anyway, so setting it to 1 can't do real harm.
+ * By default: 0 (disabled)
+ */
+ int p2p_go_edmg;
+
+ /**
* p2p_go_he - Default mode for 11ax HE enable when operating as GO
*
* This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
@@ -1165,6 +1177,14 @@ struct wpa_config {
int *sae_groups;
/**
+ * sae_pwe - SAE mechanism for PWE derivation
+ * 0 = hunting-and-pecking loop only
+ * 1 = hash-to-element only
+ * 2 = both hunting-and-pecking loop and hash-to-element enabled
+ */
+ int sae_pwe;
+
+ /**
* sae_pmkid_in_assoc - Whether to include PMKID in SAE Assoc Req
*/
int sae_pmkid_in_assoc;
@@ -1552,6 +1572,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 5005aa9..1ca2548 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) {
@@ -296,7 +310,7 @@ static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line,
{
struct wpa_config_blob *blob;
char buf[256], *pos;
- unsigned char *encoded = NULL, *nencoded;
+ char *encoded = NULL, *nencoded;
int end = 0;
size_t encoded_len = 0, len;
@@ -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);
@@ -847,6 +867,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT(mode);
INT(no_auto_peer);
INT(frequency);
+ INT(enable_edmg);
+ INT(edmg_channel);
INT(fixed_freq);
#ifdef CONFIG_ACS
INT(acs);
@@ -898,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
@@ -905,11 +928,16 @@ 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);
+ INT(sae_pk);
#ifdef CONFIG_HT_OVERRIDES
INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40);
@@ -944,6 +972,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
@@ -1096,7 +1127,7 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
#ifndef CONFIG_NO_CONFIG_BLOBS
static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
{
- unsigned char *encoded;
+ char *encoded;
encoded = base64_encode(blob->data, blob->len, NULL);
if (encoded == NULL)
@@ -1285,6 +1316,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
fprintf(f, "p2p_go_vht=%d\n", config->p2p_go_vht);
if (config->p2p_go_he)
fprintf(f, "p2p_go_he=%d\n", config->p2p_go_he);
+ if (config->p2p_go_edmg)
+ fprintf(f, "p2p_go_edmg=%d\n", config->p2p_go_edmg);
if (config->p2p_go_ctwindow != DEFAULT_P2P_GO_CTWINDOW)
fprintf(f, "p2p_go_ctwindow=%d\n", config->p2p_go_ctwindow);
if (config->p2p_disabled)
@@ -1405,6 +1438,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
fprintf(f, "\n");
}
+ if (config->sae_pwe)
+ fprintf(f, "sae_pwe=%d\n", config->sae_pwe);
+
if (config->sae_pmkid_in_assoc)
fprintf(f, "sae_pmkid_in_assoc=%d\n",
config->sae_pmkid_in_assoc);
@@ -1566,6 +1602,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
config->p2p_interface_random_mac_addr);
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 */
@@ -1582,9 +1621,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;
@@ -1612,8 +1658,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 649f8c8..2c08c02 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -19,8 +19,13 @@
EAPOL_FLAG_REQUIRE_KEY_BROADCAST)
#define DEFAULT_PROTO (WPA_PROTO_WPA | WPA_PROTO_RSN)
#define DEFAULT_KEY_MGMT (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X)
+#ifdef CONFIG_NO_TKIP
+#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP)
+#define DEFAULT_GROUP (WPA_CIPHER_CCMP)
+#else /* CONFIG_NO_TKIP */
#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
#define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
+#endif /* CONFIG_NO_TKIP */
#define DEFAULT_FRAGMENT_SIZE 1398
#define DEFAULT_BG_SCAN_PERIOD -1
@@ -57,6 +62,12 @@ enum wpas_mode {
WPAS_MODE_MESH = 5,
};
+enum sae_pk_mode {
+ SAE_PK_MODE_AUTOMATIC = 0,
+ SAE_PK_MODE_ONLY = 1,
+ SAE_PK_MODE_DISABLED = 2,
+};
+
/**
* struct wpa_ssid - Network configuration data
*
@@ -213,6 +224,8 @@ struct wpa_ssid {
*/
char *sae_password_id;
+ struct sae_pt *pt;
+
/**
* ext_psk - PSK/passphrase name in external storage
*
@@ -298,6 +311,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
/**
@@ -314,6 +328,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
@@ -484,6 +499,23 @@ struct wpa_ssid {
int frequency;
/**
+ * enable_edmg - Enable EDMG feature in STA/AP mode
+ *
+ * This flag is used for enabling the EDMG capability in STA/AP mode.
+ */
+ int enable_edmg;
+
+ /**
+ * edmg_channel - EDMG channel number
+ *
+ * This value is used to configure the EDMG channel bonding feature.
+ * In AP mode it defines the EDMG channel to start the AP on.
+ * in STA mode it defines the EDMG channel to use for connection
+ * (if supported by AP).
+ */
+ u8 edmg_channel;
+
+ /**
* fixed_freq - Use fixed frequency for IBSS
*/
int fixed_freq;
@@ -534,6 +566,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
*
@@ -745,6 +790,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
*
@@ -969,6 +1024,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
@@ -990,6 +1061,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
@@ -1015,6 +1099,44 @@ 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;
+
+ /**
+ * sae_pk - SAE-PK mode
+ * 0 = automatic SAE/SAE-PK selection based on password; enable
+ * transition mode (allow SAE authentication without SAE-PK)
+ * 1 = SAE-PK only (disable transition mode; allow SAE authentication
+ * only with SAE-PK)
+ * 2 = disable SAE-PK (allow SAE authentication only without SAE-PK)
+ */
+ enum sae_pk_mode sae_pk;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 0f2a30a..1b7f96e 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 65d0271..5048ee8 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -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)
{
@@ -638,6 +696,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
ret = -1;
else
dpp_nonce_override_len = hex_len / 2;
+ } else if (os_strcasecmp(cmd, "dpp_version_override") == 0) {
+ dpp_version_override = atoi(value);
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_DPP */
#ifdef CONFIG_TESTING_OPTIONS
@@ -663,6 +723,72 @@ 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) {
+ char *pos;
+
+ os_free(wpa_s->extra_sae_rejected_groups);
+ wpa_s->extra_sae_rejected_groups = NULL;
+ pos = value;
+ while (pos && pos[0]) {
+ int group;
+
+ group = atoi(pos);
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Extra rejection of SAE group %d",
+ group);
+ if (group)
+ int_array_add_unique(
+ &wpa_s->extra_sae_rejected_groups,
+ group);
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ break;
+ pos++;
+ }
+ } else if (os_strcasecmp(cmd, "ft_rsnxe_used") == 0) {
+ wpa_s->ft_rsnxe_used = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_eapol") == 0) {
+ wpa_s->oci_freq_override_eapol = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_saquery_req") == 0) {
+ wpa_s->oci_freq_override_saquery_req = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_saquery_resp") == 0) {
+ wpa_s->oci_freq_override_saquery_resp = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_eapol_g2") == 0) {
+ wpa_s->oci_freq_override_eapol_g2 = atoi(value);
+ /* Populate value to wpa_sm if already associated. */
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL_G2,
+ wpa_s->oci_freq_override_eapol_g2);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_ft_assoc") == 0) {
+ wpa_s->oci_freq_override_ft_assoc = atoi(value);
+ /* Populate value to wpa_sm if already associated. */
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FT_ASSOC,
+ wpa_s->oci_freq_override_ft_assoc);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_fils_assoc") == 0) {
+ wpa_s->oci_freq_override_fils_assoc = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_wnm_sleep") == 0) {
+ wpa_s->oci_freq_override_wnm_sleep = atoi(value);
+ } 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)
+ wpa_s->rsnxe_override_assoc = NULL;
+ else
+ wpa_s->rsnxe_override_assoc = wpabuf_parse_bin(value);
+ } else if (os_strcasecmp(cmd, "rsnxe_override_eapol") == 0) {
+ wpabuf_free(wpa_s->rsnxe_override_eapol);
+ if (os_strcmp(value, "NULL") == 0)
+ wpa_s->rsnxe_override_eapol = NULL;
+ else
+ wpa_s->rsnxe_override_eapol = wpabuf_parse_bin(value);
} else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) {
wpa_s->reject_btm_req_reason = atoi(value);
} else if (os_strcasecmp(cmd, "get_pref_freq_list_override") == 0) {
@@ -677,6 +803,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);
@@ -785,6 +913,8 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
if (os_strcmp(cmd, "version") == 0) {
res = os_snprintf(buf, buflen, "%s", VERSION_STR);
+ } else if (os_strcasecmp(cmd, "max_command_len") == 0) {
+ res = os_snprintf(buf, buflen, "%u", CTRL_IFACE_MAX_LEN);
} else if (os_strcasecmp(cmd, "country") == 0) {
if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
res = os_snprintf(buf, buflen, "%c%c",
@@ -815,6 +945,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);
@@ -2165,8 +2297,12 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
!wpa_s->ap_iface &&
#endif /* CONFIG_AP */
wpa_s->sme.sae.state == SAE_ACCEPTED) {
- ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
- wpa_s->sme.sae.group);
+ ret = os_snprintf(pos, end - pos, "sae_group=%d\n"
+ "sae_h2e=%d\n"
+ "sae_pk=%d\n",
+ wpa_s->sme.sae.group,
+ wpa_s->sme.sae.h2e,
+ wpa_s->sme.sae.pk);
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -2822,7 +2958,7 @@ static int wpa_supplicant_ctrl_iface_scan_result(
{
char *pos, *end;
int ret;
- const u8 *ie, *ie2, *osen_ie, *p2p, *mesh, *owe;
+ const u8 *ie, *ie2, *osen_ie, *p2p, *mesh, *owe, *rsnxe;
mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
@@ -2849,6 +2985,21 @@ static int wpa_supplicant_ctrl_iface_scan_result(
pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
ie2, 2 + ie2[1]);
}
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (rsnxe && rsnxe[1] >= 1) {
+ if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)) {
+ ret = os_snprintf(pos, end - pos, "[SAE-H2E]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_PK)) {
+ ret = os_snprintf(pos, end - pos, "[SAE-PK]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
if (osen_ie)
pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
@@ -2876,6 +3027,15 @@ static int wpa_supplicant_ctrl_iface_scan_result(
}
if (bss_is_dmg(bss)) {
const char *s;
+
+ if (get_ie_ext((const u8 *) (bss + 1), bss->ie_len,
+ WLAN_EID_EXT_EDMG_OPERATION)) {
+ ret = os_snprintf(pos, end - pos, "[EDMG]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
ret = os_snprintf(pos, end - pos, "[DMG]");
if (os_snprintf_error(end - pos, ret))
return -1;
@@ -3842,10 +4002,14 @@ static const struct cipher_info ciphers[] = {
{ WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 },
{ WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 },
{ WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
+#ifndef CONFIG_NO_TKIP
{ WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
+#endif /* CONFIG_NO_TKIP */
{ 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[] = {
@@ -3856,7 +4020,7 @@ static const struct cipher_info ciphers_group_mgmt[] = {
};
-static int ctrl_iface_get_capability_pairwise(int res, char *strict,
+static int ctrl_iface_get_capability_pairwise(int res, bool strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
@@ -3871,7 +4035,11 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict,
if (res < 0) {
if (strict)
return 0;
+#ifdef CONFIG_NO_TKIP
+ len = os_strlcpy(buf, "CCMP NONE", buflen);
+#else /* CONFIG_NO_TKIP */
len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
+#endif /* CONFIG_NO_TKIP */
if (len >= buflen)
return -1;
return len;
@@ -3892,7 +4060,7 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict,
}
-static int ctrl_iface_get_capability_group(int res, char *strict,
+static int ctrl_iface_get_capability_group(int res, bool strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
@@ -3907,7 +4075,19 @@ static int ctrl_iface_get_capability_group(int res, char *strict,
if (res < 0) {
if (strict)
return 0;
+#ifdef CONFIG_WEP
+#ifdef CONFIG_NO_TKIP
+ len = os_strlcpy(buf, "CCMP WEP104 WEP40", buflen);
+#else /* CONFIG_NO_TKIP */
len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
+#endif /* CONFIG_NO_TKIP */
+#else /* CONFIG_WEP */
+#ifdef CONFIG_NO_TKIP
+ len = os_strlcpy(buf, "CCMP", buflen);
+#else /* CONFIG_NO_TKIP */
+ len = os_strlcpy(buf, "CCMP TKIP", buflen);
+#endif /* CONFIG_NO_TKIP */
+#endif /* CONFIG_WEP */
if (len >= buflen)
return -1;
return len;
@@ -3928,7 +4108,7 @@ static int ctrl_iface_get_capability_group(int res, char *strict,
}
-static int ctrl_iface_get_capability_group_mgmt(int res, char *strict,
+static int ctrl_iface_get_capability_group_mgmt(int res, bool strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
@@ -3957,11 +4137,49 @@ static int ctrl_iface_get_capability_group_mgmt(int res, char *strict,
}
-static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
+static int iftype_str_to_index(const char *iftype_str)
+{
+ if (!iftype_str)
+ return WPA_IF_MAX;
+
+ if (os_strcmp(iftype_str, "STATION") == 0)
+ return WPA_IF_STATION;
+
+ if (os_strcmp(iftype_str, "AP_VLAN") == 0)
+ return WPA_IF_AP_VLAN;
+
+ if (os_strcmp(iftype_str, "AP") == 0)
+ return WPA_IF_AP_BSS;
+
+ if (os_strcmp(iftype_str, "P2P_GO") == 0)
+ return WPA_IF_P2P_GO;
+
+ if (os_strcmp(iftype_str, "P2P_CLIENT") == 0)
+ return WPA_IF_P2P_CLIENT;
+
+ if (os_strcmp(iftype_str, "P2P_DEVICE") == 0)
+ return WPA_IF_P2P_DEVICE;
+
+ if (os_strcmp(iftype_str, "MESH") == 0)
+ return WPA_IF_MESH;
+
+ if (os_strcmp(iftype_str, "IBSS") == 0)
+ return WPA_IF_IBSS;
+
+ if (os_strcmp(iftype_str, "NAN") == 0)
+ return WPA_IF_NAN;
+
+ return WPA_IF_MAX;
+}
+
+
+static int ctrl_iface_get_capability_key_mgmt(int res, bool strict,
struct wpa_driver_capa *capa,
+ const char *iftype_str,
char *buf, size_t buflen)
{
int ret;
+ unsigned int key_mgmt;
char *pos, *end;
size_t len;
@@ -3978,36 +4196,68 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
return len;
}
+ if (iftype_str) {
+ enum wpa_driver_if_type iftype;
+
+ iftype = iftype_str_to_index(iftype_str);
+ if (iftype == WPA_IF_MAX)
+ return -1;
+ key_mgmt = capa->key_mgmt_iftype[iftype];
+ } else {
+ key_mgmt = capa->key_mgmt;
+ }
+
ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
- if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
+ if (key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
ret = os_snprintf(pos, end - pos, " WPA-EAP");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
- if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+ if (key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
ret = os_snprintf(pos, end - pos, " WPA-PSK");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
ret = os_snprintf(pos, end - pos, " WPA-NONE");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK) {
+ ret = os_snprintf(pos, end - pos, " WAPI-PSK");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_TPK_HANDSHAKE) {
+ ret = os_snprintf(pos, end - pos, " TPK-HANDSHAKE");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_CCKM) {
+ ret = os_snprintf(pos, end - pos, " CCKM");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
#ifdef CONFIG_SUITEB
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
@@ -4015,7 +4265,7 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
}
#endif /* CONFIG_SUITEB */
#ifdef CONFIG_SUITEB192
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
@@ -4023,7 +4273,7 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
}
#endif /* CONFIG_SUITEB192 */
#ifdef CONFIG_OWE
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) {
ret = os_snprintf(pos, end - pos, " OWE");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
@@ -4031,7 +4281,7 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
}
#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) {
ret = os_snprintf(pos, end - pos, " DPP");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
@@ -4039,26 +4289,26 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
}
#endif /* CONFIG_DPP */
#ifdef CONFIG_FILS
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256) {
ret = os_snprintf(pos, end - pos, " FILS-SHA256");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384) {
ret = os_snprintf(pos, end - pos, " FILS-SHA384");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
#ifdef CONFIG_IEEE80211R
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256) {
ret = os_snprintf(pos, end - pos, " FT-FILS-SHA256");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384) {
ret = os_snprintf(pos, end - pos, " FT-FILS-SHA384");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
@@ -4067,27 +4317,72 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
#endif /* CONFIG_IEEE80211R */
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) {
ret = os_snprintf(pos, end - pos, " FT-PSK");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) {
+ ret = os_snprintf(pos, end - pos, " FT-EAP");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#ifdef CONFIG_SAE
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE) {
+ ret = os_snprintf(pos, end - pos, " FT-SAE");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_SHA384
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384) {
+ ret = os_snprintf(pos, end - pos, " FT-EAP-SHA384");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_SAE
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) {
ret = os_snprintf(pos, end - pos, " SAE");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
#endif /* CONFIG_SAE */
+#ifdef CONFIG_SHA256
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_802_1X_SHA256) {
+ ret = os_snprintf(pos, end - pos, " WPA-EAP-SHA256");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_PSK_SHA256) {
+ ret = os_snprintf(pos, end - pos, " WPA-PSK-SHA256");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_HS20
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OSEN) {
+ ret = os_snprintf(pos, end - pos, " OSEN");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_HS20 */
return pos - buf;
}
-static int ctrl_iface_get_capability_proto(int res, char *strict,
+static int ctrl_iface_get_capability_proto(int res, bool strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
@@ -4130,7 +4425,7 @@ static int ctrl_iface_get_capability_proto(int res, char *strict,
static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
- int res, char *strict,
+ int res, bool strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
@@ -4208,7 +4503,7 @@ static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
}
-static int ctrl_iface_get_capability_modes(int res, char *strict,
+static int ctrl_iface_get_capability_modes(int res, bool strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
@@ -4371,23 +4666,36 @@ static int wpa_supplicant_ctrl_iface_get_capability(
{
struct wpa_driver_capa capa;
int res;
- char *strict;
- char field[30];
+ char *next_param, *curr_param, *iftype = NULL;
+ bool strict = false;
+ char field[50];
size_t len;
/* Determine whether or not strict checking was requested */
len = os_strlcpy(field, _field, sizeof(field));
if (len >= sizeof(field))
return -1;
- strict = os_strchr(field, ' ');
- if (strict != NULL) {
- *strict++ = '\0';
- if (os_strcmp(strict, "strict") != 0)
+
+ next_param = os_strchr(field, ' ');
+ while (next_param) {
+ *next_param++ = '\0';
+ curr_param = next_param;
+ next_param = os_strchr(next_param, ' ');
+
+ if (next_param)
+ *next_param = '\0';
+
+ if (os_strcmp(curr_param, "strict") == 0)
+ strict = true;
+ else if (os_strncmp(curr_param, "iftype=", 7) == 0)
+ iftype = curr_param + 7;
+ else
return -1;
}
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
- field, strict ? strict : "");
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s'%s%s%s",
+ field, iftype ? " iftype=" : "", iftype ? iftype : "",
+ strict ? " strict" : "");
if (os_strcmp(field, "eap") == 0) {
return eap_get_names(buf, buflen);
@@ -4409,7 +4717,7 @@ static int wpa_supplicant_ctrl_iface_get_capability(
if (os_strcmp(field, "key_mgmt") == 0)
return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
- buf, buflen);
+ iftype, buf, buflen);
if (os_strcmp(field, "proto") == 0)
return ctrl_iface_get_capability_proto(res, strict, &capa,
@@ -4502,6 +4810,20 @@ static int wpa_supplicant_ctrl_iface_get_capability(
}
#endif /* CONFIG_DPP */
+#ifdef CONFIG_SAE
+ if (os_strcmp(field, "sae") == 0 &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
+#ifdef CONFIG_SAE_PK
+ res = os_snprintf(buf, buflen, "H2E PK");
+#else /* CONFIG_SAE_PK */
+ res = os_snprintf(buf, buflen, "H2E");
+#endif /* CONFIG_SAE_PK */
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_SAE */
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -4622,7 +4944,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
size_t i;
int ret;
char *pos, *end;
- const u8 *ie, *ie2, *osen_ie, *mesh, *owe;
+ const u8 *ie, *ie2, *osen_ie, *mesh, *owe, *rsnxe;
pos = buf;
end = buf + buflen;
@@ -4742,6 +5064,21 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
pos = wpa_supplicant_ie_txt(pos, end,
mesh ? "RSN" : "WPA2", ie2,
2 + ie2[1]);
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (rsnxe && rsnxe[1] >= 1) {
+ if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)) {
+ ret = os_snprintf(pos, end - pos, "[SAE-H2E]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_PK)) {
+ ret = os_snprintf(pos, end - pos, "[SAE-PK]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
if (osen_ie)
pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
@@ -5240,15 +5577,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,
@@ -5628,6 +5974,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
int freq = 0;
int pd;
int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
+ int edmg;
u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL;
size_t group_ssid_len = 0;
int he;
@@ -5643,7 +5990,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
* [persistent|persistent=<network id>]
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
- * [ht40] [vht] [he] [auto] [ssid=<hexdump>] */
+ * [ht40] [vht] [he] [edmg] [auto] [ssid=<hexdump>] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -5675,6 +6022,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
vht;
he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
+ edmg = (os_strstr(cmd, " edmg") != NULL) || wpa_s->conf->p2p_go_edmg;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -5745,7 +6093,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, automatic, join,
auth, go_intent, freq, freq2, persistent_id,
- pd, ht40, vht, max_oper_chwidth, he,
+ pd, ht40, vht, max_oper_chwidth, he, edmg,
group_ssid, group_ssid_len);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
@@ -6302,6 +6650,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
u8 *_peer = NULL, peer[ETH_ALEN];
int freq = 0, pref_freq = 0;
int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0;
+ int edmg;
id = atoi(cmd);
pos = os_strstr(cmd, " peer=");
@@ -6339,6 +6688,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
vht;
he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
+ edmg = (os_strstr(cmd, " edmg") != NULL) || wpa_s->conf->p2p_go_edmg;
pos = os_strstr(cmd, "freq2=");
if (pos)
@@ -6353,7 +6703,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
return -1;
return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
- max_oper_chwidth, pref_freq, he);
+ max_oper_chwidth, pref_freq, he, edmg);
}
@@ -6402,7 +6752,7 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
int id, int freq, int vht_center_freq2,
int ht40, int vht, int vht_chwidth,
- int he)
+ int he, int edmg)
{
struct wpa_ssid *ssid;
@@ -6416,7 +6766,8 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
vht_center_freq2, 0, ht40, vht,
- vht_chwidth, he, NULL, 0, 0);
+ vht_chwidth, he, edmg,
+ NULL, 0, 0);
}
@@ -6426,6 +6777,7 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
int he = wpa_s->conf->p2p_go_he;
+ int edmg = wpa_s->conf->p2p_go_edmg;
int max_oper_chwidth, chwidth = 0, freq2 = 0;
char *token, *context = NULL;
#ifdef CONFIG_ACS
@@ -6450,6 +6802,8 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
ht40 = 1;
} else if (os_strcmp(token, "he") == 0) {
he = 1;
+ } else if (os_strcmp(token, "edmg") == 0) {
+ edmg = 1;
} else if (os_strcmp(token, "persistent") == 0) {
persistent = 1;
} else {
@@ -6487,10 +6841,11 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
if (group_id >= 0)
return p2p_ctrl_group_add_persistent(wpa_s, group_id,
freq, freq2, ht40, vht,
- max_oper_chwidth, he);
+ max_oper_chwidth, he,
+ edmg);
return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
- max_oper_chwidth, he);
+ max_oper_chwidth, he, edmg);
}
@@ -7076,7 +7431,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));
@@ -7111,7 +7466,7 @@ static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst,
static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
{
u8 dst_addr[ETH_ALEN];
- int used;
+ int used, freq = 0;
char *pos;
#define MAX_ANQP_INFO_ID 100
u16 id[MAX_ANQP_INFO_ID];
@@ -7125,6 +7480,15 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
pos = dst + used;
if (*pos == ' ')
pos++;
+
+ if (os_strncmp(pos, "freq=", 5) == 0) {
+ freq = atoi(pos + 5);
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+ }
+
while (num_id < MAX_ANQP_INFO_ID) {
if (os_strncmp(pos, "hs20:", 5) == 0) {
#ifdef CONFIG_HS20
@@ -7159,7 +7523,7 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
if (num_id == 0 && !subtypes && !mbo_subtypes)
return -1;
- return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
+ return anqp_send_req(wpa_s, dst_addr, freq, id, num_id, subtypes,
mbo_subtypes);
}
@@ -7805,6 +8169,34 @@ static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s,
}
+static int wpas_ctrl_iface_driver_flags2(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ ret = os_snprintf(buf, buflen, "%016llX:\n",
+ (long long unsigned) wpa_s->drv_flags2);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+
+ pos = buf + ret;
+ end = buf + buflen;
+
+ for (i = 0; i < 64; i++) {
+ if (wpa_s->drv_flags2 & (1LLU << i)) {
+ ret = os_snprintf(pos, end - pos, "%s\n",
+ driver_flag2_to_string(1LLU << i));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen)
{
@@ -7965,12 +8357,21 @@ 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);
dpp_pkex_ephemeral_key_override_len = 0;
dpp_protocol_key_override_len = 0;
dpp_nonce_override_len = 0;
+#ifdef CONFIG_DPP2
+ dpp_version_override = 2;
+#else /* CONFIG_DPP2 */
+ dpp_version_override = 1;
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_DPP */
@@ -7984,9 +8385,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;
@@ -8013,7 +8417,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
- eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+ eapol_sm_notify_logoff(wpa_s->eapol, false);
radio_remove_works(wpa_s, NULL, 1);
wpa_s->ext_work_in_progress = 0;
@@ -8035,13 +8439,32 @@ 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->ft_rsnxe_used = 0;
wpa_s->reject_btm_req_reason = 0;
wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
os_free(wpa_s->get_pref_freq_list_override);
wpa_s->get_pref_freq_list_override = NULL;
wpabuf_free(wpa_s->sae_commit_override);
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);
+ wpa_s->oci_freq_override_eapol = 0;
+ wpa_s->oci_freq_override_saquery_req = 0;
+ wpa_s->oci_freq_override_saquery_resp = 0;
+ wpa_s->oci_freq_override_eapol_g2 = 0;
+ wpa_s->oci_freq_override_ft_assoc = 0;
+ wpa_s->oci_freq_override_fils_assoc = 0;
+ wpa_s->oci_freq_override_wnm_sleep = 0;
#ifdef CONFIG_DPP
os_free(wpa_s->dpp_config_obj_override);
wpa_s->dpp_config_obj_override = NULL;
@@ -8056,8 +8479,11 @@ 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;
+ os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data));
wpa_bss_flush(wpa_s);
if (!dl_list_empty(&wpa_s->bss)) {
@@ -8074,6 +8500,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);
@@ -8082,6 +8509,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_supplicant_update_channel_list(wpa_s, NULL);
free_bss_tmp_disallowed(wpa_s);
+
+ os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data));
}
@@ -8390,6 +8819,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;
@@ -8901,7 +9333,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];
@@ -8917,14 +9349,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");
@@ -8933,8 +9364,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);
}
@@ -8986,7 +9417,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;
@@ -9025,17 +9456,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;
@@ -9228,13 +9659,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);
}
@@ -9456,16 +9889,16 @@ static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
if (pos[0] != WLAN_EID_NEIGHBOR_REPORT ||
nr_len < NR_IE_MIN_LEN) {
- wpa_printf(MSG_DEBUG,
- "CTRL: Invalid Neighbor Report element: id=%u len=%u",
- data[0], nr_len);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "CTRL: Invalid Neighbor Report element: id=%u len=%u",
+ data[0], nr_len);
goto out;
}
if (2U + nr_len > len) {
- wpa_printf(MSG_DEBUG,
- "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
- data[0], len, nr_len);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
+ data[0], len, nr_len);
goto out;
}
pos += 2;
@@ -9535,8 +9968,8 @@ static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s,
ssid_s = os_strstr(cmd, "ssid=");
if (ssid_s) {
if (ssid_parse(ssid_s + 5, &ssid)) {
- wpa_printf(MSG_ERROR,
- "CTRL: Send Neighbor Report: bad SSID");
+ wpa_msg(wpa_s, MSG_INFO,
+ "CTRL: Send Neighbor Report: bad SSID");
return -1;
}
@@ -9912,6 +10345,76 @@ static int wpas_ctrl_cmd_debug_level(const char *cmd)
}
+static int wpas_ctrl_iface_configure_mscs(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ size_t frame_classifier_len;
+ const char *pos, *end;
+ struct robust_av_data *robust_av = &wpa_s->robust_av;
+ int val;
+
+ /*
+ * format:
+ * <add|remove|change> [up_bitmap=<hex byte>] [up_limit=<integer>]
+ * [stream_timeout=<in TUs>] [frame_classifier=<hex bytes>]
+ */
+ os_memset(robust_av, 0, sizeof(struct robust_av_data));
+ if (os_strncmp(cmd, "add ", 4) == 0) {
+ robust_av->request_type = SCS_REQ_ADD;
+ } else if (os_strcmp(cmd, "remove") == 0) {
+ robust_av->request_type = SCS_REQ_REMOVE;
+ robust_av->valid_config = false;
+ return wpas_send_mscs_req(wpa_s);
+ } else if (os_strncmp(cmd, "change ", 7) == 0) {
+ robust_av->request_type = SCS_REQ_CHANGE;
+ } else {
+ return -1;
+ }
+
+ pos = os_strstr(cmd, "up_bitmap=");
+ if (!pos)
+ return -1;
+
+ val = hex2byte(pos + 10);
+ if (val < 0)
+ return -1;
+ robust_av->up_bitmap = val;
+
+ pos = os_strstr(cmd, "up_limit=");
+ if (!pos)
+ return -1;
+
+ robust_av->up_limit = atoi(pos + 9);
+
+ pos = os_strstr(cmd, "stream_timeout=");
+ if (!pos)
+ return -1;
+
+ robust_av->stream_timeout = atoi(pos + 15);
+ if (robust_av->stream_timeout == 0)
+ return -1;
+
+ pos = os_strstr(cmd, "frame_classifier=");
+ if (!pos)
+ return -1;
+
+ pos += 17;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ end = pos + os_strlen(pos);
+
+ frame_classifier_len = (end - pos) / 2;
+ if (frame_classifier_len > sizeof(robust_av->frame_classifier) ||
+ hexstr2bin(pos, robust_av->frame_classifier, frame_classifier_len))
+ return -1;
+
+ robust_av->frame_classifier_len = frame_classifier_len;
+ robust_av->valid_config = true;
+
+ return wpas_send_mscs_req(wpa_s);
+}
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
@@ -10008,9 +10511,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
reply, reply_size);
} else if (os_strcmp(buf, "LOGON") == 0) {
- eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+ eapol_sm_notify_logoff(wpa_s->eapol, false);
} else if (os_strcmp(buf, "LOGOFF") == 0) {
- eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
+ eapol_sm_notify_logoff(wpa_s->eapol, true);
} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
reply_len = -1;
@@ -10549,6 +11052,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply,
reply_size);
+ } else if (os_strcmp(buf, "DRIVER_FLAGS2") == 0) {
+ reply_len = wpas_ctrl_iface_driver_flags2(wpa_s, reply,
+ reply_size);
#ifdef ANDROID
} else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
@@ -10669,6 +11175,39 @@ 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_URI ", 12) == 0) {
+ int res;
+
+ res = wpas_dpp_nfc_uri(wpa_s, buf + 12);
+ 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_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;
@@ -10697,6 +11236,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;
@@ -10750,8 +11293,22 @@ 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);
+ } else if (os_strncmp(buf, "DPP_RECONFIG ", 13) == 0) {
+ if (wpas_dpp_reconfig(wpa_s, buf + 13) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_CA_SET ", 11) == 0) {
+ if (wpas_dpp_ca_set(wpa_s, buf + 10) < 0)
+ reply_len = -1;
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
+ } else if (os_strncmp(buf, "MSCS ", 5) == 0) {
+ if (wpas_ctrl_iface_configure_mscs(wpa_s, buf + 5))
+ reply_len = -1;
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h
index d54cc07..510668d 100644
--- a/wpa_supplicant/ctrl_iface.h
+++ b/wpa_supplicant/ctrl_iface.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,10 @@
#ifdef CONFIG_CTRL_IFACE
+#ifndef CTRL_IFACE_MAX_LEN
+#define CTRL_IFACE_MAX_LEN 8192
+#endif /* CTRL_IFACE_MAX_LEN */
+
/* Shared functions from ctrl_iface.c; to be called by ctrl_iface backends */
/**
diff --git a/wpa_supplicant/ctrl_iface_named_pipe.c b/wpa_supplicant/ctrl_iface_named_pipe.c
index 9c0a47e..79ff787 100644
--- a/wpa_supplicant/ctrl_iface_named_pipe.c
+++ b/wpa_supplicant/ctrl_iface_named_pipe.c
@@ -45,7 +45,7 @@ ConvertStringSecurityDescriptorToSecurityDescriptorA
/* Per-interface ctrl_iface */
-#define REQUEST_BUFSIZE 256
+#define REQUEST_BUFSIZE CTRL_IFACE_MAX_LEN
#define REPLY_BUFSIZE 4096
struct ctrl_iface_priv;
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 8a6057a..1512080 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / UDP socket -based control interface
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -219,7 +219,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct ctrl_iface_priv *priv = sock_ctx;
- char buf[4096], *pos;
+ char *buf, *pos;
int res;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
struct sockaddr_in6 from;
@@ -235,11 +235,15 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
int new_attached = 0;
u8 cookie[COOKIE_LEN];
- res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
+ if (!buf)
+ return;
+ res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
strerror(errno));
+ os_free(buf);
return;
}
@@ -249,6 +253,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
if (os_strcmp(addr, "::1")) {
wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected source %s",
addr);
+ os_free(buf);
+ return;
}
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
@@ -260,11 +266,17 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
*/
wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
"source %s", inet_ntoa(from.sin_addr));
+ os_free(buf);
return;
}
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+ if ((size_t) res > CTRL_IFACE_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
+ os_free(buf);
+ return;
+ }
buf[res] = '\0';
if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -282,18 +294,21 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
if (os_strncmp(buf, "COOKIE=", 7) != 0) {
wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
"drop request");
+ os_free(buf);
return;
}
if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
"request - drop request");
+ os_free(buf);
return;
}
if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
"drop request");
+ os_free(buf);
return;
}
@@ -339,6 +354,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
fromlen);
}
+ os_free(buf);
+
if (new_attached)
eapol_sm_notify_ctrl_attached(wpa_s->eapol);
}
@@ -516,7 +533,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);
@@ -600,10 +617,13 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
{
struct wpa_global *global = eloop_ctx;
struct ctrl_iface_global_priv *priv = sock_ctx;
- char buf[4096], *pos;
+ char *buf, *pos;
int res;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
struct sockaddr_in6 from;
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
+ char addr[INET6_ADDRSTRLEN];
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
struct sockaddr_in from;
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
@@ -612,16 +632,28 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
size_t reply_len;
u8 cookie[COOKIE_LEN];
- res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
+ if (!buf)
+ return;
+ res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
strerror(errno));
+ os_free(buf);
return;
}
#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
-#ifndef CONFIG_CTRL_IFACE_UDP_IPV6
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ inet_ntop(AF_INET6, &from.sin6_addr, addr, sizeof(from));
+ if (os_strcmp(addr, "::1")) {
+ wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected source %s",
+ addr);
+ os_free(buf);
+ return;
+ }
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
/*
* The OS networking stack is expected to drop this kind of
@@ -631,11 +663,17 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
*/
wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
"source %s", inet_ntoa(from.sin_addr));
+ os_free(buf);
return;
}
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+ if ((size_t) res > CTRL_IFACE_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
+ os_free(buf);
+ return;
+ }
buf[res] = '\0';
if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -646,18 +684,21 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
if (os_strncmp(buf, "COOKIE=", 7) != 0) {
wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
"drop request");
+ os_free(buf);
return;
}
if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
"request - drop request");
+ os_free(buf);
return;
}
if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
"drop request");
+ os_free(buf);
return;
}
@@ -694,6 +735,8 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
fromlen);
}
+
+ os_free(buf);
}
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 71fe7ed..953fd2c 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -131,7 +131,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct ctrl_iface_priv *priv = sock_ctx;
- char buf[4096];
+ char *buf;
int res;
struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
@@ -139,11 +139,20 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
size_t reply_len = 0;
int new_attached = 0;
- res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
+ if (!buf)
+ return;
+ res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN + 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
strerror(errno));
+ os_free(buf);
+ return;
+ }
+ if ((size_t) res > CTRL_IFACE_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
+ os_free(buf);
return;
}
buf[res] = '\0';
@@ -221,6 +230,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
}
}
os_free(reply_buf);
+ os_free(buf);
if (new_attached)
eapol_sm_notify_ctrl_attached(wpa_s->eapol);
@@ -1046,18 +1056,27 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
{
struct wpa_global *global = eloop_ctx;
struct ctrl_iface_global_priv *priv = sock_ctx;
- char buf[4096];
+ char *buf;
int res;
struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
char *reply = NULL, *reply_buf = NULL;
size_t reply_len;
- res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
+ if (!buf)
+ return;
+ res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN + 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
strerror(errno));
+ os_free(buf);
+ return;
+ }
+ if ((size_t) res > CTRL_IFACE_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
+ os_free(buf);
return;
}
buf[res] = '\0';
@@ -1105,6 +1124,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
}
}
os_free(reply_buf);
+ os_free(buf);
}
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index fc2fc2e..793a881 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -750,10 +750,12 @@ void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
if (cred->auth_type & WPS_AUTH_OPEN)
auth_type[at_num++] = "open";
+#ifndef CONFIG_NO_TKIP
if (cred->auth_type & WPS_AUTH_WPAPSK)
auth_type[at_num++] = "wpa-psk";
if (cred->auth_type & WPS_AUTH_WPA)
auth_type[at_num++] = "wpa-eap";
+#endif /* CONFIG_NO_TKIP */
if (cred->auth_type & WPS_AUTH_WPA2)
auth_type[at_num++] = "wpa2-eap";
if (cred->auth_type & WPS_AUTH_WPA2PSK)
@@ -761,8 +763,10 @@ void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
if (cred->encr_type & WPS_ENCR_NONE)
encr_type[et_num++] = "none";
+#ifndef CONFIG_NO_TKIP
if (cred->encr_type & WPS_ENCR_TKIP)
encr_type[et_num++] = "tkip";
+#endif /* CONFIG_NO_TKIP */
if (cred->encr_type & WPS_ENCR_AES)
encr_type[et_num++] = "aes";
@@ -2855,30 +2859,6 @@ static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
NULL,
NULL
},
- {
- "RoamTime", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
- wpas_dbus_getter_roam_time,
- NULL,
- NULL
- },
- {
- "RoamComplete", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
- wpas_dbus_getter_roam_complete,
- NULL,
- NULL
- },
- {
- "SessionLength", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
- wpas_dbus_getter_session_length,
- NULL,
- NULL
- },
- {
- "BSSTMStatus", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
- wpas_dbus_getter_bss_tm_status,
- NULL,
- NULL
- },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -3786,6 +3766,30 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
NULL,
NULL
},
+ {
+ "RoamTime", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_roam_time,
+ NULL,
+ NULL
+ },
+ {
+ "RoamComplete", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
+ wpas_dbus_getter_roam_complete,
+ NULL,
+ NULL
+ },
+ {
+ "SessionLength", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_session_length,
+ NULL,
+ NULL
+ },
+ {
+ "BSSTMStatus", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_bss_tm_status,
+ NULL,
+ NULL
+ },
#ifdef CONFIG_MESH
{ "MeshPeers", WPAS_DBUS_NEW_IFACE_MESH, "aay",
wpas_dbus_getter_mesh_peers,
@@ -3803,6 +3807,12 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
NULL,
NULL
},
+ { "MACAddressRandomizationMask", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "a{say}",
+ wpas_dbus_getter_mac_address_randomization_mask,
+ wpas_dbus_setter_mac_address_randomization_mask,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -4791,8 +4801,8 @@ void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
if (!wpa_s->dbus_groupobj_path) {
wpa_printf(MSG_DEBUG,
- "%s: Group object '%s' already unregistered",
- __func__, wpa_s->dbus_groupobj_path);
+ "%s: Group object has already unregistered",
+ __func__);
return;
}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index d2c84e5..d1f9607 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -137,8 +137,15 @@ DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message)
static const char * const dont_quote[] = {
"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
- "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
- "bssid", "scan_freq", "freq_list", NULL
+ "bssid", "scan_freq", "freq_list", "scan_ssid", "bssid_hint",
+ "bssid_blacklist", "bssid_whitelist", "group_mgmt",
+#ifdef CONFIG_MESH
+ "mesh_basic_rates",
+#endif /* CONFIG_MESH */
+#ifdef CONFIG_P2P
+ "go_p2p_dev_addr", "p2p_client_list", "psk_list",
+#endif /* CONFIG_P2P */
+ NULL
};
static dbus_bool_t should_quote_opt(const char *key)
@@ -984,21 +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[10] = { NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL };
+ 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";
@@ -1028,6 +1039,11 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(
#ifdef CONFIG_SHA384
capabilities[num_items++] = "sha384";
#endif /* CONFIG_SHA384 */
+#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,
@@ -1137,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;
@@ -1168,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;
}
@@ -1199,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,
@@ -2616,7 +2632,11 @@ dbus_bool_t wpas_dbus_getter_capabilities(
/***** pairwise cipher */
if (res < 0) {
+#ifdef CONFIG_NO_TKIP
+ const char *args[] = {"ccmp", "none"};
+#else /* CONFIG_NO_TKIP */
const char *args[] = {"ccmp", "tkip", "none"};
+#endif /* CONFIG_NO_TKIP */
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Pairwise", args,
@@ -2639,9 +2659,11 @@ dbus_bool_t wpas_dbus_getter_capabilities(
((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "gcmp")) ||
+#ifndef CONFIG_NO_TKIP
((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "tkip")) ||
+#endif /* CONFIG_NO_TKIP */
((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "none")) ||
@@ -2655,7 +2677,13 @@ dbus_bool_t wpas_dbus_getter_capabilities(
/***** group cipher */
if (res < 0) {
const char *args[] = {
- "ccmp", "tkip", "wep104", "wep40"
+ "ccmp",
+#ifndef CONFIG_NO_TKIP
+ "tkip",
+#endif /* CONFIG_NO_TKIP */
+#ifdef CONFIG_WEP
+ "wep104", "wep40"
+#endif /* CONFIG_WEP */
};
if (!wpa_dbus_dict_append_string_array(
@@ -2679,15 +2707,19 @@ dbus_bool_t wpas_dbus_getter_capabilities(
((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "gcmp")) ||
+#ifndef CONFIG_NO_TKIP
((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "tkip")) ||
+#endif /* CONFIG_NO_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,
@@ -2784,6 +2816,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,
@@ -3984,6 +4022,173 @@ out:
/**
+ * wpas_dbus_setter_mac_address_randomization_mask - Set masks used for
+ * MAC address randomization
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "MACAddressRandomizationMask" property.
+ */
+dbus_bool_t wpas_dbus_setter_mac_address_randomization_mask(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
+ const char *key;
+ unsigned int rand_type = 0;
+ const u8 *mask;
+ int mask_len;
+ unsigned int rand_types_to_disable = MAC_ADDR_RAND_ALL;
+
+ dbus_message_iter_recurse(iter, &variant_iter);
+ if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY) {
+ dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+ "invalid message format");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(&variant_iter, &dict_iter);
+ while (dbus_message_iter_get_arg_type(&dict_iter) ==
+ DBUS_TYPE_DICT_ENTRY) {
+ dbus_message_iter_recurse(&dict_iter, &entry_iter);
+ if (dbus_message_iter_get_arg_type(&entry_iter) !=
+ DBUS_TYPE_STRING) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: key not a string", __func__);
+ return FALSE;
+ }
+ dbus_message_iter_get_basic(&entry_iter, &key);
+ dbus_message_iter_next(&entry_iter);
+ if (dbus_message_iter_get_arg_type(&entry_iter) !=
+ DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&entry_iter) !=
+ DBUS_TYPE_BYTE) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: mask was not a byte array",
+ __func__);
+ return FALSE;
+ }
+ dbus_message_iter_recurse(&entry_iter, &array_iter);
+ dbus_message_iter_get_fixed_array(&array_iter, &mask,
+ &mask_len);
+
+ if (os_strcmp(key, "scan") == 0) {
+ rand_type = MAC_ADDR_RAND_SCAN;
+ } else if (os_strcmp(key, "sched_scan") == 0) {
+ rand_type = MAC_ADDR_RAND_SCHED_SCAN;
+ } else if (os_strcmp(key, "pno") == 0) {
+ rand_type = MAC_ADDR_RAND_PNO;
+ } else {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: bad scan type \"%s\"",
+ __func__, key);
+ return FALSE;
+ }
+
+ if (mask_len != ETH_ALEN) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: malformed MAC mask given",
+ __func__);
+ return FALSE;
+ }
+
+ if (wpas_enable_mac_addr_randomization(
+ wpa_s, rand_type, wpa_s->perm_addr, mask)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to set up MAC address randomization for %s",
+ __func__, key);
+ return FALSE;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "%s: Enabled MAC address randomization for %s with mask: "
+ MACSTR, wpa_s->ifname, key, MAC2STR(mask));
+ rand_types_to_disable &= ~rand_type;
+ dbus_message_iter_next(&dict_iter);
+ }
+
+ if (rand_types_to_disable &&
+ wpas_disable_mac_addr_randomization(wpa_s, rand_types_to_disable)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to disable MAC address randomization",
+ __func__);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_mac_address_randomization_mask(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
+ unsigned int i;
+ u8 mask_buf[ETH_ALEN];
+ /* Read docs on dbus_message_iter_append_fixed_array() for why this
+ * is necessary... */
+ u8 *mask = mask_buf;
+ static const struct {
+ const char *key;
+ unsigned int type;
+ } types[] = {
+ { "scan", MAC_ADDR_RAND_SCAN },
+ { "sched_scan", MAC_ADDR_RAND_SCHED_SCAN },
+ { "pno", MAC_ADDR_RAND_PNO }
+ };
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ "a{say}", &variant_iter) ||
+ !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ "{say}", &dict_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(types); i++) {
+ if (wpas_mac_addr_rand_scan_get_mask(wpa_s, types[i].type,
+ mask))
+ continue;
+
+ if (!dbus_message_iter_open_container(&dict_iter,
+ DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry_iter) ||
+ !dbus_message_iter_append_basic(&entry_iter,
+ DBUS_TYPE_STRING,
+ &types[i].key) ||
+ !dbus_message_iter_open_container(&entry_iter,
+ DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &array_iter) ||
+ !dbus_message_iter_append_fixed_array(&array_iter,
+ DBUS_TYPE_BYTE,
+ &mask,
+ ETH_ALEN) ||
+ !dbus_message_iter_close_container(&entry_iter,
+ &array_iter) ||
+ !dbus_message_iter_close_container(&dict_iter,
+ &entry_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+ "no memory");
+ return FALSE;
+ }
+ }
+
+ if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
* wpas_dbus_getter_sta_address - Return the address of a connected station
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -4491,7 +4696,7 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(
DBusMessageIter iter_dict, variant_iter;
const char *group;
const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
- const char *key_mgmt[15]; /* max 15 key managements may be supported */
+ const char *key_mgmt[16]; /* max 16 key managements may be supported */
int n;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -4544,6 +4749,10 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(
if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE)
key_mgmt[n++] = "ft-sae";
#endif /* CONFIG_SAE */
+#ifdef CONFIG_OWE
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_OWE)
+ key_mgmt[n++] = "owe";
+#endif /* CONFIG_OWE */
if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
key_mgmt[n++] = "wpa-none";
@@ -4553,21 +4762,25 @@ 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 */
+#ifndef CONFIG_NO_TKIP
case WPA_CIPHER_TKIP:
group = "tkip";
break;
+#endif /* CONFIG_NO_TKIP */
case WPA_CIPHER_CCMP:
group = "ccmp";
break;
case WPA_CIPHER_GCMP:
group = "gcmp";
break;
- case WPA_CIPHER_WEP104:
- group = "wep104";
- break;
case WPA_CIPHER_CCMP_256:
group = "ccmp-256";
break;
@@ -4584,8 +4797,10 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(
/* Pairwise */
n = 0;
+#ifndef CONFIG_NO_TKIP
if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
pairwise[n++] = "tkip";
+#endif /* CONFIG_NO_TKIP */
if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
pairwise[n++] = "ccmp";
if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index d922ce1..afa26ef 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -177,6 +177,8 @@ DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_engine_path);
DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_module_path);
DECLARE_ACCESSOR(wpas_dbus_getter_blobs);
DECLARE_ACCESSOR(wpas_dbus_getter_stas);
+DECLARE_ACCESSOR(wpas_dbus_getter_mac_address_randomization_mask);
+DECLARE_ACCESSOR(wpas_dbus_setter_mac_address_randomization_mask);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_address);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 8cdd885..7a65673 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -40,6 +40,14 @@ static int wpas_dbus_validate_dbus_ipaddr(struct wpa_dbus_dict_entry entry)
}
+static dbus_bool_t no_p2p_mgmt_interface(DBusError *error)
+{
+ dbus_set_error_const(error, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+ "Could not find P2P mgmt interface");
+ return FALSE;
+}
+
+
/**
* Parses out the mac address from the peer object path.
* @peer_path - object path of the form
@@ -78,6 +86,22 @@ wpas_dbus_error_persistent_group_unknown(DBusMessage *message)
}
+/**
+ * wpas_dbus_error_no_p2p_mgmt_iface - Return a new InterfaceUnknown error
+ * message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an unknown interface error.
+ */
+static DBusMessage * wpas_dbus_error_no_p2p_mgmt_iface(DBusMessage *message)
+{
+ wpa_printf(MSG_DEBUG, "dbus: Could not find P2P mgmt interface");
+ return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+ "Could not find P2P mgmt interface");
+}
+
+
DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
@@ -145,6 +169,10 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto error_nop2p;
+ }
if (wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types,
req_dev_types, NULL, 0, 0, NULL, freq))
@@ -157,8 +185,9 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
error_clear:
wpa_dbus_dict_entry_clear(&entry);
error:
- os_free(req_dev_types);
reply = wpas_dbus_error_invalid_args(message, entry.key);
+error_nop2p:
+ os_free(req_dev_types);
return reply;
}
@@ -166,7 +195,9 @@ error:
DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
- wpas_p2p_stop_find(wpa_s->global->p2p_init_wpa_s);
+ wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (wpa_s)
+ wpas_p2p_stop_find(wpa_s);
return NULL;
}
@@ -185,6 +216,8 @@ DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message,
return wpas_dbus_error_invalid_args(message, NULL);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
return wpas_dbus_error_unknown_error(message,
@@ -204,6 +237,8 @@ DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message,
return wpas_dbus_error_no_memory(message);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_listen(wpa_s, (unsigned int) timeout)) {
return dbus_message_new_error(message,
@@ -245,6 +280,8 @@ DBusMessage * wpas_dbus_handler_p2p_extendedlisten(
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_ext_listen(wpa_s, period, interval))
return wpas_dbus_error_unknown_error(
@@ -350,6 +387,10 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto out;
+ }
if (pg_object_path != NULL) {
char *net_id_str;
@@ -384,14 +425,14 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
goto inv_args;
if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0,
- 0, 0, 0, NULL, 0, 0)) {
+ 0, 0, 0, 0, NULL, 0, 0)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
goto out;
}
} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0, 0,
- 0, 0))
+ 0, 0, 0))
goto inv_args;
out:
@@ -433,6 +474,12 @@ static dbus_bool_t wpa_dbus_p2p_check_enabled(struct wpa_supplicant *wpa_s,
"P2P is not available for this interface");
return FALSE;
}
+ if (!wpa_s->global->p2p_init_wpa_s) {
+ if (out_reply)
+ *out_reply = wpas_dbus_error_no_p2p_mgmt_iface(
+ message);
+ return no_p2p_mgmt_interface(error);
+ }
return TRUE;
}
@@ -605,7 +652,7 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, 0, join, authorize_only,
- go_intent, freq, 0, -1, 0, 0, 0, 0, 0,
+ go_intent, freq, 0, -1, 0, 0, 0, 0, 0, 0,
NULL, 0);
if (new_pin >= 0) {
@@ -763,7 +810,7 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
goto err;
if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0,
- 0, 0) < 0) {
+ 0, 0, 0) < 0) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
@@ -822,6 +869,8 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
return wpas_dbus_error_invalid_args(message, NULL);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
WPAS_P2P_PD_FOR_GO_NEG, NULL) < 0)
@@ -1882,6 +1931,8 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_groups(
wpa_s = peer_args->wpa_s;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return no_p2p_mgmt_interface(error);
wpa_s_go = wpas_get_p2p_client_iface(wpa_s, info->p2p_device_addr);
if (wpa_s_go) {
@@ -1963,6 +2014,9 @@ dbus_bool_t wpas_dbus_getter_persistent_groups(
dbus_bool_t success = FALSE;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return no_p2p_mgmt_interface(error);
+
if (!wpa_s->parent->dbus_new_path)
return FALSE;
@@ -2077,6 +2131,11 @@ DBusMessage * wpas_dbus_handler_add_persistent_group(
dbus_message_iter_init(message, &iter);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto err;
+ }
+
if (wpa_s->parent->dbus_new_path)
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL) {
@@ -2159,6 +2218,10 @@ DBusMessage * wpas_dbus_handler_remove_persistent_group(
DBUS_TYPE_INVALID);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto out;
+ }
/*
* Extract the network ID and ensure the network is actually a child of
@@ -2235,6 +2298,8 @@ DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
struct wpa_config *config;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
config = wpa_s->conf;
ssid = config->ssid;
diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/wpa_supplicant/dbus/dbus_new_introspect.c
index aee105b..6c721bf 100644
--- a/wpa_supplicant/dbus/dbus_new_introspect.c
+++ b/wpa_supplicant/dbus/dbus_new_introspect.c
@@ -257,7 +257,7 @@ DBusMessage * wpa_dbus_introspect(DBusMessage *message,
DBusMessage *reply;
struct wpabuf *xml;
- xml = wpabuf_alloc(20000);
+ xml = wpabuf_alloc(30000);
if (xml == NULL)
return NULL;
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 6ae07a4..a0fe94e 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
@@ -362,7 +362,7 @@ CONFIG_BACKEND=file
#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
# Add support for new DBus control interface
-# (fi.w1.hostap.wpa_supplicant1)
+# (fi.w1.wpa_supplicant1)
CONFIG_CTRL_IFACE_DBUS_NEW=y
# Add introspection support for new DBus control interface
@@ -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)
@@ -510,7 +506,7 @@ CONFIG_AP=y
CONFIG_P2P=y
# Enable TDLS support
-#CONFIG_TDLS=y
+CONFIG_TDLS=y
# Wi-Fi Display
# This can be used to enable Wi-Fi Display extensions for P2P using an external
@@ -607,3 +603,20 @@ CONFIG_BGSCAN_SIMPLE=y
# Device Provisioning Protocol (DPP)
CONFIG_DPP=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
+
+# Remove all TKIP functionality
+# TKIP is an old cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used anymore for anything else than a
+# backwards compatibility option as a group cipher when connecting to APs that
+# use WPA+WPA2 mixed mode. For now, the default wpa_supplicant build includes
+# support for this by default, but that functionality is subject to be removed
+# in the future.
+#CONFIG_NO_TKIP=y
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index b4341f1..28404b8 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.
@@ -12,6 +12,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/ip_addr.h"
+#include "utils/base64.h"
#include "common/dpp.h"
#include "common/gas.h"
#include "common/gas_server.h"
@@ -45,6 +46,13 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
const u8 *src, const u8 *bssid,
const u8 *data, size_t data_len,
enum offchannel_send_action_result result);
+#ifdef CONFIG_DPP2
+static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s);
+static int wpas_dpp_process_conf_obj(void *ctx,
+ struct dpp_authentication *auth);
+#endif /* CONFIG_DPP2 */
static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -84,10 +92,99 @@ int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd)
500, wpas_dpp_tx_status, 0);
}
+#ifdef CONFIG_DPP2
+ dpp_controller_new_qr_code(wpa_s->dpp, bi);
+#endif /* CONFIG_DPP2 */
+
return bi->id;
}
+/**
+ * wpas_dpp_nfc_uri - Parse and add DPP bootstrapping info from NFC Tag (URI)
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @cmd: DPP URI read from a NFC Tag (URI NDEF message)
+ * Returns: Identifier of the stored info or -1 on failure
+ */
+int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_add_nfc_uri(wpa_s->dpp, cmd);
+ if (!bi)
+ return -1;
+
+ return bi->id;
+}
+
+
+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;
+ own_bi->nfc_negotiated = 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;
+ own_bi->nfc_negotiated = 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;
@@ -161,6 +258,35 @@ static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_DPP2
+static void wpas_dpp_stop_listen_for_tx(struct wpa_supplicant *wpa_s,
+ unsigned int freq,
+ unsigned int wait_time)
+{
+ struct os_reltime now, res;
+ unsigned int remaining;
+
+ if (!wpa_s->dpp_listen_freq)
+ return;
+
+ os_get_reltime(&now);
+ if (os_reltime_before(&now, &wpa_s->dpp_listen_end)) {
+ os_reltime_sub(&wpa_s->dpp_listen_end, &now, &res);
+ remaining = res.sec * 1000 + res.usec / 1000;
+ } else {
+ remaining = 0;
+ }
+ if (wpa_s->dpp_listen_freq == freq && remaining > wait_time)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Stop listen on %u MHz ending in %u ms to allow immediate TX on %u MHz for %u ms",
+ wpa_s->dpp_listen_freq, remaining, freq, wait_time);
+ wpas_dpp_listen_stop(wpa_s);
+
+ /* TODO: Restart listen in some cases after TX? */
+}
+
+
static void wpas_dpp_conn_status_result_timeout(void *eloop_ctx,
void *timeout_ctx)
{
@@ -179,6 +305,8 @@ static void wpas_dpp_conn_status_result_timeout(void *eloop_ctx,
result = DPP_STATUS_NO_AP;
else
result = 255; /* What to report here for unexpected state? */
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpas_abort_ongoing_scan(wpa_s);
wpas_dpp_send_conn_status_result(wpa_s, result);
}
@@ -347,6 +475,10 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
NULL);
+#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
+ wpa_s, NULL);
+#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
@@ -660,7 +792,14 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
pos = os_strstr(cmd, " netrole=");
if (pos) {
pos += 9;
- wpa_s->dpp_netrole_ap = os_strncmp(pos, "ap", 2) == 0;
+ if (os_strncmp(pos, "ap", 2) == 0)
+ wpa_s->dpp_netrole = DPP_NETROLE_AP;
+ else if (os_strncmp(pos, "configurator", 12) == 0)
+ 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=");
@@ -672,17 +811,21 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
NULL);
+#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
+ wpa_s, NULL);
+#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
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;
}
@@ -694,7 +837,9 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
#ifdef CONFIG_DPP2
if (tcp)
- return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port);
+ return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port,
+ wpa_s->conf->dpp_name, DPP_NETROLE_STA,
+ wpa_s, wpa_s, wpas_dpp_process_conf_obj);
#endif /* CONFIG_DPP2 */
wpa_s->dpp_auth = auth;
@@ -763,6 +908,7 @@ static void dpp_start_listen_cb(struct wpa_radio_work *work, int deinit)
}
wpa_s->off_channel_freq = 0;
wpa_s->roc_waiting_drv_freq = lwork->freq;
+ wpa_drv_dpp_listen(wpa_s, true);
}
@@ -812,7 +958,12 @@ int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd)
wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
DPP_CAPAB_ENROLLEE;
wpa_s->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
- wpa_s->dpp_netrole_ap = os_strstr(cmd, " netrole=ap") != NULL;
+ if (os_strstr(cmd, " netrole=ap"))
+ wpa_s->dpp_netrole = DPP_NETROLE_AP;
+ else if (os_strstr(cmd, " netrole=configurator"))
+ wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
+ else
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
if (wpa_s->dpp_listen_freq == (unsigned int) freq) {
wpa_printf(MSG_DEBUG, "DPP: Already listening on %u MHz",
freq);
@@ -832,11 +983,30 @@ void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "DPP: Stop listen on %u MHz",
wpa_s->dpp_listen_freq);
wpa_drv_cancel_remain_on_channel(wpa_s);
+ wpa_drv_dpp_listen(wpa_s, false);
wpa_s->dpp_listen_freq = 0;
wpas_dpp_listen_work_done(wpa_s);
}
+void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+ unsigned int freq, unsigned int duration)
+{
+ if (wpa_s->dpp_listen_freq != freq)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Remain-on-channel started for listen on %u MHz for %u ms",
+ freq, duration);
+ os_get_reltime(&wpa_s->dpp_listen_end);
+ wpa_s->dpp_listen_end.usec += duration * 1000;
+ while (wpa_s->dpp_listen_end.usec >= 1000000) {
+ wpa_s->dpp_listen_end.sec++;
+ wpa_s->dpp_listen_end.usec -= 1000000;
+ }
+}
+
+
void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq)
{
@@ -878,6 +1048,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) {
@@ -916,7 +1090,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) {
@@ -924,7 +1099,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;
@@ -958,19 +1133,21 @@ static void wpas_dpp_start_gas_server(struct wpa_supplicant *wpa_s)
static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
struct wpa_ssid *ssid;
#ifdef CONFIG_DPP2
- if (auth->akm == DPP_AKM_SAE) {
+ if (conf->akm == DPP_AKM_SAE) {
#ifdef CONFIG_SAE
struct wpa_driver_capa capa;
int res;
res = wpa_drv_get_capa(wpa_s, &capa);
if (res == 0 &&
- !(capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
+ !(capa.key_mgmt_iftype[WPA_IF_STATION] &
+ WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
wpa_printf(MSG_DEBUG,
"DPP: SAE not supported by the driver");
@@ -990,27 +1167,29 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
wpa_config_set_network_defaults(ssid);
ssid->disabled = 1;
- ssid->ssid = os_malloc(auth->ssid_len);
+ ssid->ssid = os_malloc(conf->ssid_len);
if (!ssid->ssid)
goto fail;
- os_memcpy(ssid->ssid, auth->ssid, auth->ssid_len);
- ssid->ssid_len = auth->ssid_len;
+ os_memcpy(ssid->ssid, conf->ssid, conf->ssid_len);
+ ssid->ssid_len = conf->ssid_len;
- if (auth->connector) {
- ssid->key_mgmt = WPA_KEY_MGMT_DPP;
- ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
- ssid->dpp_connector = os_strdup(auth->connector);
+ if (conf->connector) {
+ 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;
}
- if (auth->c_sign_key) {
- ssid->dpp_csign = os_malloc(wpabuf_len(auth->c_sign_key));
+ if (conf->c_sign_key) {
+ ssid->dpp_csign = os_malloc(wpabuf_len(conf->c_sign_key));
if (!ssid->dpp_csign)
goto fail;
- os_memcpy(ssid->dpp_csign, wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
- ssid->dpp_csign_len = wpabuf_len(auth->c_sign_key);
+ os_memcpy(ssid->dpp_csign, wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
+ ssid->dpp_csign_len = wpabuf_len(conf->c_sign_key);
}
if (auth->net_access_key) {
@@ -1025,31 +1204,127 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry;
}
- if (!auth->connector || dpp_akm_psk(auth->akm) ||
- dpp_akm_sae(auth->akm)) {
- if (!auth->connector)
+ if (!conf->connector || dpp_akm_psk(conf->akm) ||
+ dpp_akm_sae(conf->akm)) {
+ if (!conf->connector || !dpp_akm_dpp(conf->akm))
ssid->key_mgmt = 0;
- if (dpp_akm_psk(auth->akm))
+ if (dpp_akm_psk(conf->akm))
ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
- if (dpp_akm_sae(auth->akm))
+ if (dpp_akm_sae(conf->akm))
ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
WPA_KEY_MGMT_FT_SAE;
ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
- if (auth->passphrase[0]) {
+ if (conf->passphrase[0]) {
if (wpa_config_set_quoted(ssid, "psk",
- auth->passphrase) < 0)
+ conf->passphrase) < 0)
goto fail;
wpa_config_update_psk(ssid);
ssid->export_keys = 1;
} else {
- ssid->psk_set = auth->psk_set;
- os_memcpy(ssid->psk, auth->psk, PMK_LEN);
+ ssid->psk_set = conf->psk_set;
+ os_memcpy(ssid->psk, conf->psk, PMK_LEN);
}
}
- os_memcpy(wpa_s->dpp_last_ssid, auth->ssid, auth->ssid_len);
- wpa_s->dpp_last_ssid_len = auth->ssid_len;
+#if defined(CONFIG_DPP2) && defined(IEEE8021X_EAPOL)
+ if (conf->akm == DPP_AKM_DOT1X) {
+ int i;
+ char name[100], blobname[128];
+ struct wpa_config_blob *blob;
+
+ ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X |
+ WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_IEEE8021X_SHA256;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
+
+ if (conf->cacert) {
+ /* caCert is DER-encoded X.509v3 certificate for the
+ * server certificate if that is different from the
+ * trust root included in certBag. */
+ /* TODO: ssid->eap.cert.ca_cert */
+ }
+
+ if (conf->certs) {
+ for (i = 0; ; i++) {
+ os_snprintf(name, sizeof(name), "dpp-certs-%d",
+ i);
+ if (!wpa_config_get_blob(wpa_s->conf, name))
+ break;
+ }
+
+ blob = os_zalloc(sizeof(*blob));
+ if (!blob)
+ goto fail;
+ blob->len = wpabuf_len(conf->certs);
+ blob->name = os_strdup(name);
+ blob->data = os_malloc(blob->len);
+ if (!blob->name || !blob->data) {
+ wpa_config_free_blob(blob);
+ goto fail;
+ }
+ os_memcpy(blob->data, wpabuf_head(conf->certs),
+ blob->len);
+ os_snprintf(blobname, sizeof(blobname), "blob://%s",
+ name);
+ wpa_config_set_blob(wpa_s->conf, blob);
+ wpa_printf(MSG_DEBUG, "DPP: Added certificate blob %s",
+ name);
+ ssid->eap.cert.client_cert = os_strdup(blobname);
+ if (!ssid->eap.cert.client_cert)
+ goto fail;
+
+ /* TODO: ssid->eap.identity from own certificate */
+ if (wpa_config_set(ssid, "identity", "\"dpp-ent\"",
+ 0) < 0)
+ goto fail;
+ }
+
+ if (auth->priv_key) {
+ for (i = 0; ; i++) {
+ os_snprintf(name, sizeof(name), "dpp-key-%d",
+ i);
+ if (!wpa_config_get_blob(wpa_s->conf, name))
+ break;
+ }
+
+ blob = os_zalloc(sizeof(*blob));
+ if (!blob)
+ goto fail;
+ blob->len = wpabuf_len(auth->priv_key);
+ blob->name = os_strdup(name);
+ blob->data = os_malloc(blob->len);
+ if (!blob->name || !blob->data) {
+ wpa_config_free_blob(blob);
+ goto fail;
+ }
+ os_memcpy(blob->data, wpabuf_head(auth->priv_key),
+ blob->len);
+ os_snprintf(blobname, sizeof(blobname), "blob://%s",
+ name);
+ wpa_config_set_blob(wpa_s->conf, blob);
+ wpa_printf(MSG_DEBUG, "DPP: Added private key blob %s",
+ name);
+ ssid->eap.cert.private_key = os_strdup(blobname);
+ if (!ssid->eap.cert.private_key)
+ goto fail;
+ }
+
+ if (conf->server_name) {
+ ssid->eap.cert.domain_suffix_match =
+ os_strdup(conf->server_name);
+ if (!ssid->eap.cert.domain_suffix_match)
+ goto fail;
+ }
+
+ /* TODO: Use entCreds::eapMethods */
+ if (wpa_config_set(ssid, "eap", "TLS", 0) < 0)
+ goto fail;
+ }
+#endif /* CONFIG_DPP2 && IEEE8021X_EAPOL */
+
+ os_memcpy(wpa_s->dpp_last_ssid, conf->ssid, conf->ssid_len);
+ wpa_s->dpp_last_ssid_len = conf->ssid_len;
return ssid;
fail:
@@ -1060,14 +1335,15 @@ fail:
static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
struct wpa_ssid *ssid;
if (wpa_s->conf->dpp_config_processing < 1)
return 0;
- ssid = wpas_dpp_add_network(wpa_s, auth);
+ ssid = wpas_dpp_add_network(wpa_s, auth, conf);
if (!ssid)
return -1;
@@ -1081,49 +1357,73 @@ static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "DPP: Failed to update configuration");
#endif /* CONFIG_NO_CONFIG_WRITE */
+ return 0;
+}
+
+
+static void wpas_dpp_post_process_config(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth)
+{
+#ifdef CONFIG_DPP2
+ if (auth->reconfig && wpa_s->dpp_reconfig_ssid &&
+ wpa_config_get_network(wpa_s->conf, wpa_s->dpp_reconfig_ssid_id) ==
+ wpa_s->dpp_reconfig_ssid) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Remove reconfigured network profile");
+ wpas_notify_network_removed(wpa_s, wpa_s->dpp_reconfig_ssid);
+ wpa_config_remove_network(wpa_s->conf,
+ wpa_s->dpp_reconfig_ssid_id);
+ wpa_s->dpp_reconfig_ssid = NULL;
+ wpa_s->dpp_reconfig_ssid_id = -1;
+ }
+#endif /* CONFIG_DPP2 */
+
if (wpa_s->conf->dpp_config_processing < 2)
- return 0;
+ return;
#ifdef CONFIG_DPP2
if (auth->peer_version >= 2) {
wpa_printf(MSG_DEBUG,
"DPP: Postpone connection attempt to wait for completion of DPP Configuration Result");
auth->connect_on_tx_status = 1;
- return 0;
+ return;
}
#endif /* CONFIG_DPP2 */
wpas_dpp_try_to_connect(wpa_s);
- return 0;
}
static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
- if (auth->ssid_len)
+ if (conf->ssid_len)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
- wpa_ssid_txt(auth->ssid, auth->ssid_len));
- if (auth->connector) {
+ wpa_ssid_txt(conf->ssid, conf->ssid_len));
+ if (conf->ssid_charset)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID_CHARSET "%d",
+ conf->ssid_charset);
+ if (conf->connector) {
/* TODO: Save the Connector and consider using a command
* to fetch the value instead of sending an event with
* it. The Connector could end up being larger than what
* most clients are ready to receive as an event
* message. */
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
- auth->connector);
+ conf->connector);
}
- if (auth->c_sign_key) {
+ if (conf->c_sign_key) {
char *hex;
size_t hexlen;
- hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
+ hexlen = 2 * wpabuf_len(conf->c_sign_key) + 1;
hex = os_malloc(hexlen);
if (hex) {
wpa_snprintf_hex(hex, hexlen,
- wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
+ wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY "%s",
hex);
os_free(hex);
@@ -1151,10 +1451,88 @@ static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
}
}
- return wpas_dpp_process_config(wpa_s, auth);
+#ifdef CONFIG_DPP2
+ if (conf->certbag) {
+ char *b64;
+
+ b64 = base64_encode_no_lf(wpabuf_head(conf->certbag),
+ wpabuf_len(conf->certbag), NULL);
+ if (b64)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CERTBAG "%s", b64);
+ os_free(b64);
+ }
+
+ if (conf->cacert) {
+ char *b64;
+
+ b64 = base64_encode_no_lf(wpabuf_head(conf->cacert),
+ wpabuf_len(conf->cacert), NULL);
+ if (b64)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CACERT "%s", b64);
+ os_free(b64);
+ }
+
+ if (conf->server_name)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_SERVER_NAME "%s",
+ conf->server_name);
+#endif /* CONFIG_DPP2 */
+
+ return wpas_dpp_process_config(wpa_s, auth, conf);
+}
+
+
+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);
+ wpa_s->dpp_conf_backup_received = true;
+
+ 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;
}
+#ifdef CONFIG_DPP2
+static void wpas_dpp_build_csr(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->csrattrs)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build CSR");
+ wpabuf_free(auth->csr);
+ /* TODO: Additional information needed for CSR based on csrAttrs */
+ auth->csr = dpp_build_csr(auth, wpa_s->conf->dpp_name ?
+ wpa_s->conf->dpp_name : "Test");
+ if (!auth->csr) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+
+ wpas_dpp_start_gas_client(wpa_s);
+}
+#endif /* CONFIG_DPP2 */
+
+
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,
@@ -1165,10 +1543,12 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
struct dpp_authentication *auth = wpa_s->dpp_auth;
int res;
enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
+ unsigned int i;
wpa_s->dpp_gas_dialog_token = -1;
- if (!auth || !auth->auth_success) {
+ if (!auth || (!auth->auth_success && !auth->reconfig_success) ||
+ os_memcmp(addr, auth->peer_mac_addr, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return;
}
@@ -1197,13 +1577,29 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
goto fail;
}
- if (dpp_conf_resp_rx(auth, resp) < 0) {
+ res = dpp_conf_resp_rx(auth, resp);
+#ifdef CONFIG_DPP2
+ if (res == -2) {
+ wpa_printf(MSG_DEBUG, "DPP: CSR needed");
+ eloop_register_timeout(0, 0, wpas_dpp_build_csr, wpa_s, NULL);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+ if (res < 0) {
wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
goto fail;
}
- res = wpas_dpp_handle_config_obj(wpa_s, auth);
- if (res < 0)
+ wpa_s->dpp_conf_backup_received = false;
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ res = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[i]);
+ if (res < 0)
+ goto fail;
+ }
+ if (auth->num_conf_obj)
+ wpas_dpp_post_process_config(wpa_s, auth);
+ if (wpas_dpp_handle_key_pkg(wpa_s, auth->conf_key_pkg) < 0)
goto fail;
status = DPP_STATUS_OK;
@@ -1238,6 +1634,9 @@ fail:
wpabuf_free(msg);
/* This exchange will be terminated in the TX status handler */
+ if (wpa_s->conf->dpp_config_processing < 2 ||
+ wpa_s->dpp_conf_backup_received)
+ auth->remove_on_tx_status = 1;
return;
}
fail2:
@@ -1260,7 +1659,7 @@ static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s)
supp_op_classes = wpas_supp_op_classes(wpa_s);
buf = dpp_build_conf_req_helper(auth, wpa_s->conf->dpp_name,
- wpa_s->dpp_netrole_ap,
+ wpa_s->dpp_netrole,
wpa_s->conf->dpp_mud_url,
supp_op_classes);
os_free(supp_op_classes);
@@ -1274,7 +1673,7 @@ static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s)
MAC2STR(auth->peer_mac_addr), auth->curr_freq);
res = gas_query_req(wpa_s->gas, auth->peer_mac_addr, auth->curr_freq,
- 1, buf, wpas_dpp_gas_resp_cb, wpa_s);
+ 1, 1, buf, wpas_dpp_gas_resp_cb, wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
wpabuf_free(buf);
@@ -1522,8 +1921,332 @@ static int wpas_dpp_process_conf_obj(void *ctx,
struct dpp_authentication *auth)
{
struct wpa_supplicant *wpa_s = ctx;
+ unsigned int i;
+ int res = -1;
+
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ res = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[i]);
+ if (res)
+ break;
+ }
+ if (!res)
+ wpas_dpp_post_process_config(wpa_s, auth);
+
+ return res;
+}
+
+
+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;
+ }
+}
+
+
+static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Reply wait timeout");
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+}
+
+
+static void
+wpas_dpp_rx_reconfig_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *csign_hash, *fcgroup, *a_nonce, *e_id;
+ u16 csign_hash_len, fcgroup_len, a_nonce_len, e_id_len;
+ struct dpp_configurator *conf;
+ struct dpp_authentication *auth;
+ unsigned int wait_time, max_wait_time;
+ u16 group;
+
+ if (!wpa_s->dpp)
+ return;
+
+ if (wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Reconfig Announcement during ongoing Authentication");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Announcement from " MACSTR,
+ MAC2STR(src));
+
+ csign_hash = dpp_get_attr(buf, len, DPP_ATTR_C_SIGN_KEY_HASH,
+ &csign_hash_len);
+ if (!csign_hash || csign_hash_len != SHA256_MAC_LEN) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Configurator C-sign key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Configurator C-sign key Hash (kid)",
+ csign_hash, csign_hash_len);
+ conf = dpp_configurator_find_kid(wpa_s->dpp, csign_hash);
+ if (!conf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching Configurator information found");
+ return;
+ }
+
+ fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &fcgroup_len);
+ if (!fcgroup || fcgroup_len != 2) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Finite Cyclic Group attribute");
+ return;
+ }
+ group = WPA_GET_LE16(fcgroup);
+ wpa_printf(MSG_DEBUG, "DPP: Enrollee finite cyclic group: %u", group);
+
+ a_nonce = dpp_get_attr(buf, len, DPP_ATTR_A_NONCE, &a_nonce_len);
+ e_id = dpp_get_attr(buf, len, DPP_ATTR_E_PRIME_ID, &e_id_len);
+
+ auth = dpp_reconfig_init(wpa_s->dpp, wpa_s, conf, freq, group,
+ a_nonce, a_nonce_len, e_id, e_id_len);
+ 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;
+ }
+
+ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+ wpa_s->dpp_auth = auth;
+
+ wpa_s->dpp_in_response_listen = 0;
+ wpa_s->dpp_auth_ok_on_ack = 0;
+ wait_time = wpa_s->max_remain_on_chan;
+ max_wait_time = wpa_s->dpp_resp_wait_time ?
+ wpa_s->dpp_resp_wait_time : 2000;
+ if (wait_time > max_wait_time)
+ wait_time = max_wait_time;
+ wait_time += 10; /* give the driver some extra time to complete */
+ eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+ wpas_dpp_reconfig_reply_wait_timeout,
+ wpa_s, NULL);
+ wait_time -= 10;
+
+ wpas_dpp_stop_listen_for_tx(wpa_s, freq, wait_time);
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_REQ);
+ if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
+ wpabuf_head(auth->reconfig_req_msg),
+ wpabuf_len(auth->reconfig_req_msg),
+ wait_time, wpas_dpp_tx_status, 0) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ }
+}
+
+
+static void
+wpas_dpp_rx_reconfig_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct wpa_ssid *ssid;
+ struct dpp_authentication *auth;
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Request from "
+ MACSTR, MAC2STR(src));
+
+ if (!wpa_s->dpp)
+ return;
+ if (wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready for reconfiguration - pending authentication exchange in progress");
+ return;
+ }
+ if (!wpa_s->dpp_reconfig_ssid) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready for reconfiguration - not requested");
+ return;
+ }
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid == wpa_s->dpp_reconfig_ssid &&
+ ssid->id == wpa_s->dpp_reconfig_ssid_id)
+ break;
+ }
+ if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready for reconfiguration - no matching network profile with Connector found");
+ return;
+ }
+
+ auth = dpp_reconfig_auth_req_rx(wpa_s->dpp, wpa_s, ssid->dpp_connector,
+ ssid->dpp_netaccesskey,
+ ssid->dpp_netaccesskey_len,
+ ssid->dpp_csign, ssid->dpp_csign_len,
+ freq, hdr, buf, len);
+ if (!auth)
+ return;
+ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+ wpa_s->dpp_auth = auth;
+
+ wpas_dpp_chirp_stop(wpa_s);
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_RESP);
+ if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
+ wpabuf_head(auth->reconfig_resp_msg),
+ wpabuf_len(auth->reconfig_resp_msg),
+ 500, wpas_dpp_tx_status, 0) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ }
+}
+
+
+static void
+wpas_dpp_rx_reconfig_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ struct wpabuf *conf;
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Response from "
+ MACSTR, MAC2STR(src));
+
+ if (!auth || !auth->reconfig || !auth->configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Reconfig Authentication in progress - drop");
+ return;
+ }
+
+ if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ conf = dpp_reconfig_auth_resp_rx(auth, hdr, buf, len);
+ if (!conf)
+ return;
+
+ eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout, wpa_s, NULL);
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_CONF);
+ if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
+ wpabuf_head(conf), wpabuf_len(conf),
+ 500, wpas_dpp_tx_status, 0) < 0) {
+ wpabuf_free(conf);
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+ wpabuf_free(conf);
+
+ wpas_dpp_start_gas_server(wpa_s);
+}
+
+
+static void
+wpas_dpp_rx_reconfig_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Confirm from "
+ MACSTR, MAC2STR(src));
+
+ if (!auth || !auth->reconfig || auth->configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Reconfig Authentication in progress - drop");
+ return;
+ }
- return wpas_dpp_handle_config_obj(wpa_s, auth);
+ if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ if (dpp_reconfig_auth_conf_rx(auth, hdr, buf, len) < 0)
+ return;
+
+ wpas_dpp_start_gas_client(wpa_s);
}
#endif /* CONFIG_DPP2 */
@@ -1536,6 +2259,11 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid;
const u8 *connector, *trans_id, *status;
u16 connector_len, trans_id_len, status_len;
+#ifdef CONFIG_DPP2
+ const u8 *version;
+ u16 version_len;
+#endif /* CONFIG_DPP2 */
+ u8 peer_version = 1;
struct dpp_introduction intro;
struct rsn_pmksa_cache_entry *entry;
struct os_time now;
@@ -1636,6 +2364,13 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
os_memcpy(entry->pmk, intro.pmk, intro.pmk_len);
entry->pmk_len = intro.pmk_len;
entry->akmp = WPA_KEY_MGMT_DPP;
+#ifdef CONFIG_DPP2
+ version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
+ &version_len);
+ if (version && version_len >= 1)
+ peer_version = version[0];
+ entry->dpp_pfs = peer_version >= 2;
+#endif /* CONFIG_DPP2 */
if (expiry) {
os_get_time(&now);
seconds = expiry - now.sec;
@@ -1649,7 +2384,7 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
- " status=%u", MAC2STR(src), status[0]);
+ " status=%u version=%u", MAC2STR(src), status[0], peer_version);
wpa_printf(MSG_DEBUG,
"DPP: Try connection again after successful network introduction");
@@ -1990,6 +2725,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;
}
}
@@ -2070,6 +2806,23 @@ 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;
+ case DPP_PA_RECONFIG_ANNOUNCEMENT:
+ wpas_dpp_rx_reconfig_announcement(wpa_s, src, hdr, buf, len,
+ freq);
+ break;
+ case DPP_PA_RECONFIG_AUTH_REQ:
+ wpas_dpp_rx_reconfig_auth_req(wpa_s, src, hdr, buf, len, freq);
+ break;
+ case DPP_PA_RECONFIG_AUTH_RESP:
+ wpas_dpp_rx_reconfig_auth_resp(wpa_s, src, hdr, buf, len, freq);
+ break;
+ case DPP_PA_RECONFIG_AUTH_CONF:
+ wpas_dpp_rx_reconfig_auth_conf(wpa_s, src, hdr, buf, len, freq);
+ break;
#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
@@ -2091,8 +2844,8 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
static struct wpabuf *
-wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query,
- size_t query_len)
+wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa,
+ const u8 *query, size_t query_len, u16 *comeback_delay)
{
struct wpa_supplicant *wpa_s = ctx;
struct dpp_authentication *auth = wpa_s->dpp_auth;
@@ -2100,7 +2853,7 @@ wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query,
wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR,
MAC2STR(sa));
- if (!auth || !auth->auth_success ||
+ if (!auth || (!auth->auth_success && !auth->reconfig_success) ||
os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return NULL;
@@ -2123,6 +2876,16 @@ wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query,
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
MAC2STR(sa));
resp = dpp_conf_req_rx(auth, query, query_len);
+
+#ifdef CONFIG_DPP2
+ if (!resp && auth->waiting_cert) {
+ wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready");
+ auth->cert_resp_ctx = resp_ctx;
+ *comeback_delay = 500;
+ return NULL;
+ }
+#endif /* CONFIG_DPP2 */
+
if (!resp)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
auth->conf_resp = resp;
@@ -2148,6 +2911,14 @@ wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
return;
}
+#ifdef CONFIG_DPP2
+ if (auth->waiting_csr && ok) {
+ wpa_printf(MSG_DEBUG, "DPP: Waiting for CSR");
+ wpabuf_free(resp);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+
wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
@@ -2185,15 +2956,18 @@ 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);
+ ret = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[0]);
+ if (!ret)
+ wpas_dpp_post_process_config(wpa_s, auth);
dpp_auth_deinit(auth);
os_free(curve);
@@ -2231,6 +3005,7 @@ int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
unsigned int wait_time;
const u8 *rsn;
struct wpa_ie_data ied;
+ size_t len;
if (!(ssid->key_mgmt & WPA_KEY_MGMT_DPP) || !bss)
return 0; /* Not using DPP AKM - continue */
@@ -2264,8 +3039,11 @@ int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
"DPP: Starting network introduction protocol to derive PMKSA for "
MACSTR, MAC2STR(bss->bssid));
- msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_REQ,
- 5 + 4 + os_strlen(ssid->dpp_connector));
+ len = 5 + 4 + os_strlen(ssid->dpp_connector);
+#ifdef CONFIG_DPP2
+ len += 5;
+#endif /* CONFIG_DPP2 */
+ msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_REQ, len);
if (!msg)
return -1;
@@ -2320,6 +3098,15 @@ skip_trans_id:
skip_connector:
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_DPP2
+ if (DPP_VERSION > 1) {
+ /* Protocol Version */
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, DPP_VERSION);
+ }
+#endif /* CONFIG_DPP2 */
+
/* TODO: Timeout on AP response */
wait_time = wpa_s->max_remain_on_chan;
if (wait_time > 2000)
@@ -2460,6 +3247,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);
@@ -2486,10 +3275,9 @@ int wpas_dpp_init(struct wpa_supplicant *wpa_s)
return -1;
os_memset(&config, 0, sizeof(config));
- config.msg_ctx = 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;
@@ -2509,7 +3297,6 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_TESTING_OPTIONS */
if (!wpa_s->dpp)
return;
- dpp_global_clear(wpa_s->dpp);
eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
@@ -2519,8 +3306,14 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
+ wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_build_csr, wpa_s, NULL);
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = NULL;
+ wpas_dpp_chirp_stop(wpa_s);
+ dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
+ wpa_s->dpp_reconfig_id = NULL;
#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
@@ -2529,24 +3322,503 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
os_memset(wpa_s->dpp_intro_bssid, 0, ETH_ALEN);
os_free(wpa_s->dpp_configurator_params);
wpa_s->dpp_configurator_params = NULL;
+ dpp_global_clear(wpa_s->dpp);
}
#ifdef CONFIG_DPP2
+
int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
{
struct dpp_controller_config config;
const char *pos;
os_memset(&config, 0, sizeof(config));
+ config.allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
+ config.netrole = DPP_NETROLE_STA;
+ config.msg_ctx = wpa_s;
+ config.cb_ctx = wpa_s;
+ config.process_conf_obj = wpas_dpp_process_conf_obj;
if (cmd) {
pos = os_strstr(cmd, " tcp_port=");
if (pos) {
pos += 10;
config.tcp_port = atoi(pos);
}
+
+ pos = os_strstr(cmd, " role=");
+ if (pos) {
+ pos += 6;
+ if (os_strncmp(pos, "configurator", 12) == 0)
+ config.allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ else if (os_strncmp(pos, "enrollee", 8) == 0)
+ config.allowed_roles = DPP_CAPAB_ENROLLEE;
+ else if (os_strncmp(pos, "either", 6) == 0)
+ config.allowed_roles = DPP_CAPAB_CONFIGURATOR |
+ DPP_CAPAB_ENROLLEE;
+ else
+ return -1;
+ }
+
+ config.qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
}
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)
+{
+ struct wpabuf *msg, *announce = NULL;
+ int type;
+
+ msg = wpa_s->dpp_presence_announcement;
+ type = DPP_PA_PRESENCE_ANNOUNCEMENT;
+ if (!msg) {
+ struct wpa_ssid *ssid = wpa_s->dpp_reconfig_ssid;
+
+ if (ssid && wpa_s->dpp_reconfig_id &&
+ wpa_config_get_network(wpa_s->conf,
+ wpa_s->dpp_reconfig_ssid_id) ==
+ ssid) {
+ announce = dpp_build_reconfig_announcement(
+ ssid->dpp_csign,
+ ssid->dpp_csign_len,
+ ssid->dpp_netaccesskey,
+ ssid->dpp_netaccesskey_len,
+ wpa_s->dpp_reconfig_id);
+ msg = announce;
+ }
+ if (!msg)
+ return;
+ type = DPP_PA_RECONFIG_ANNOUNCEMENT;
+ }
+ 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, type);
+ if (offchannel_send_action(
+ wpa_s, wpa_s->dpp_chirp_freq, broadcast,
+ wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ 2000, wpas_dpp_chirp_tx_status, 0) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+
+ wpabuf_free(announce);
+}
+
+
+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 && !wpa_s->dpp_reconfig_ssid)
+ 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 */
+ if (bi) {
+ 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 (listen_freq <= 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 ||
+ wpa_s->dpp_reconfig_ssid) {
+ 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;
+ }
+}
+
+
+int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ struct wpa_ssid *ssid;
+ int iter = 1;
+ const char *pos;
+
+ ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
+ if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not a valid network profile for reconfiguration");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " iter=");
+ if (pos) {
+ iter = atoi(pos + 6);
+ if (iter <= 0)
+ return -1;
+ }
+
+ if (wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready to start reconfiguration - pending authentication exchange in progress");
+ return -1;
+ }
+
+ dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
+ wpa_s->dpp_reconfig_id = dpp_gen_reconfig_id(ssid->dpp_csign,
+ ssid->dpp_csign_len);
+ if (!wpa_s->dpp_reconfig_id) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to generate E-id for reconfiguration");
+ return -1;
+ }
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ wpa_printf(MSG_DEBUG, "DPP: Disconnect for reconfiguration");
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
+ wpas_dpp_chirp_stop(wpa_s);
+ wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ wpa_s->dpp_qr_mutual = 0;
+ wpa_s->dpp_reconfig_ssid = ssid;
+ wpa_s->dpp_reconfig_ssid_id = ssid->id;
+ wpa_s->dpp_chirp_iter = iter;
+ wpa_s->dpp_chirp_round = 0;
+ wpa_s->dpp_chirp_scan_done = 0;
+ wpa_s->dpp_chirp_listen = 0;
+
+ return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
+}
+
+
+static int wpas_dpp_build_conf_resp(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth, bool tcp)
+{
+ struct wpabuf *resp;
+
+ resp = dpp_build_conf_resp(auth, auth->e_nonce, auth->curve->nonce_len,
+ auth->e_netrole, true);
+ if (!resp)
+ return -1;
+
+ if (tcp) {
+ auth->conf_resp_tcp = resp;
+ return 0;
+ }
+
+ if (gas_server_set_resp(wpa_s->gas_server, auth->cert_resp_ctx,
+ resp) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not find pending GAS response");
+ wpabuf_free(resp);
+ return -1;
+ }
+ auth->conf_resp = resp;
+ return 0;
+}
+
+
+int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ int peer = -1;
+ const char *pos, *value;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ u8 *bin;
+ size_t bin_len;
+ struct wpabuf *buf;
+ bool tcp = false;
+
+ pos = os_strstr(cmd, " peer=");
+ if (pos) {
+ peer = atoi(pos + 6);
+ if (!auth || !auth->waiting_cert ||
+ (auth->peer_bi &&
+ (unsigned int) peer != auth->peer_bi->id)) {
+ auth = dpp_controller_get_auth(wpa_s->dpp, peer);
+ tcp = true;
+ }
+ }
+
+ if (!auth || !auth->waiting_cert) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No authentication exchange waiting for certificate information");
+ return -1;
+ }
+
+ if (peer >= 0 &&
+ (!auth->peer_bi ||
+ (unsigned int) peer != auth->peer_bi->id) &&
+ (!auth->tmp_peer_bi ||
+ (unsigned int) peer != auth->tmp_peer_bi->id)) {
+ wpa_printf(MSG_DEBUG, "DPP: Peer mismatch");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " value=");
+ if (!pos)
+ return -1;
+ value = pos + 7;
+
+ pos = os_strstr(cmd, " name=");
+ if (!pos)
+ return -1;
+ pos += 6;
+
+ if (os_strncmp(pos, "status ", 7) == 0) {
+ auth->force_conf_resp_status = atoi(value);
+ return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
+ }
+
+ if (os_strncmp(pos, "trustedEapServerName ", 21) == 0) {
+ os_free(auth->trusted_eap_server_name);
+ auth->trusted_eap_server_name = os_strdup(value);
+ return auth->trusted_eap_server_name ? 0 : -1;
+ }
+
+ bin = base64_decode(value, os_strlen(value), &bin_len);
+ if (!bin)
+ return -1;
+ buf = wpabuf_alloc_copy(bin, bin_len);
+ os_free(bin);
+
+ if (os_strncmp(pos, "caCert ", 7) == 0) {
+ wpabuf_free(auth->cacert);
+ auth->cacert = buf;
+ return 0;
+ }
+
+ if (os_strncmp(pos, "certBag ", 8) == 0) {
+ wpabuf_free(auth->certbag);
+ auth->certbag = buf;
+ return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
+ }
+
+ wpabuf_free(buf);
+ return -1;
+}
+
#endif /* CONFIG_DPP2 */
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index b337982..b0d5fcf 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.
@@ -13,9 +13,14 @@
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);
+void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+ unsigned int freq, unsigned int duration);
void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq);
void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
@@ -32,5 +37,9 @@ 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);
+int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd);
#endif /* DPP_SUPPLICANT_H */
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index cf9972a..ba8cc55 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)
{
@@ -750,7 +778,7 @@ static inline int wpa_drv_macsec_get_capability(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_enable_protect_frames(struct wpa_supplicant *wpa_s,
- Boolean enabled)
+ bool enabled)
{
if (!wpa_s->driver->enable_protect_frames)
return -1;
@@ -758,7 +786,7 @@ static inline int wpa_drv_enable_protect_frames(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_enable_encrypt(struct wpa_supplicant *wpa_s,
- Boolean enabled)
+ bool enabled)
{
if (!wpa_s->driver->enable_encrypt)
return -1;
@@ -766,7 +794,7 @@ static inline int wpa_drv_enable_encrypt(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s,
- Boolean enabled, u32 window)
+ bool enabled, u32 window)
{
if (!wpa_s->driver->set_replay_protect)
return -1;
@@ -783,7 +811,7 @@ static inline int wpa_drv_set_current_cipher_suite(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_enable_controlled_port(struct wpa_supplicant *wpa_s,
- Boolean enabled)
+ bool enabled)
{
if (!wpa_s->driver->enable_controlled_port)
return -1;
@@ -1041,14 +1069,14 @@ static inline int wpa_drv_ignore_assoc_disallow(struct wpa_supplicant *wpa_s,
return wpa_s->driver->ignore_assoc_disallow(wpa_s->drv_priv, val);
}
-static inline int wpa_drv_set_bssid_blacklist(struct wpa_supplicant *wpa_s,
- unsigned int num_bssid,
- const u8 *bssids)
+static inline int wpa_drv_set_bssid_tmp_disallow(struct wpa_supplicant *wpa_s,
+ unsigned int num_bssid,
+ const u8 *bssids)
{
- if (!wpa_s->driver->set_bssid_blacklist)
+ if (!wpa_s->driver->set_bssid_tmp_disallow)
return -1;
- return wpa_s->driver->set_bssid_blacklist(wpa_s->drv_priv, num_bssid,
- bssids);
+ return wpa_s->driver->set_bssid_tmp_disallow(wpa_s->drv_priv, num_bssid,
+ bssids);
}
static inline int wpa_drv_update_connect_params(
@@ -1080,4 +1108,11 @@ static inline int wpa_drv_set_4addr_mode(struct wpa_supplicant *wpa_s, int val)
wpa_s->bridge_ifname, val);
}
+static inline int wpa_drv_dpp_listen(struct wpa_supplicant *wpa_s, bool enable)
+{
+ if (!wpa_s->driver->dpp_listen)
+ return 0;
+ return wpa_s->driver->dpp_listen(wpa_s->drv_priv, enable);
+}
+
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 524724f..9f69736 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -439,7 +439,7 @@ static void eapol_sm_cb(struct eapol_sm *eapol, enum eapol_supp_result result,
static void eapol_test_write_cert(FILE *f, const char *subject,
const struct wpabuf *cert)
{
- unsigned char *encoded;
+ char *encoded;
encoded = base64_encode(wpabuf_head(cert), wpabuf_len(cert), NULL);
if (encoded == NULL)
@@ -644,9 +644,9 @@ static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
/* 802.1X::portControl = Auto */
- eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, true);
return 0;
}
@@ -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 ba9a5ac..15c572f 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));
@@ -312,12 +322,12 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
if (bssid_changed)
wpas_notify_bssid_changed(wpa_s);
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, false);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->key_mgmt == WPA_KEY_MGMT_OWE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_DPP || wpa_s->drv_authorized_port)
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
wpa_s->drv_authorized_port = 0;
wpa_s->ap_ies_from_associnfo = 0;
wpa_s->current_ssid = NULL;
@@ -346,6 +356,9 @@ static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
int pmksa_set = -1;
size_t i;
+ /* Start with assumption of no PMKSA cache entry match */
+ pmksa_cache_clear_current(wpa_s->wpa);
+
if (wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0 ||
ie.pmkid == NULL)
return;
@@ -479,6 +492,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 +504,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 +525,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 +557,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 +588,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 +597,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 +678,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 +687,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 +797,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 };
@@ -850,6 +875,28 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
continue;
}
+#ifdef CONFIG_SAE
+ if (flagged && ((rate_ie[j] & 0x7f) ==
+ BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY)) {
+ 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");
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_sae_h2e_only) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "TESTING: Ignore SAE H2E requirement mismatch");
+ continue;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ return 0;
+ }
+ continue;
+ }
+#endif /* CONFIG_SAE */
+
if (!flagged)
continue;
@@ -951,6 +998,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;
@@ -991,36 +1056,434 @@ 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;
+}
+
+
+static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ const u8 *match_ssid, size_t match_ssid_len,
+ struct wpa_bss *bss, struct wpa_blacklist *e,
+ bool debug_print);
+
+
+#ifdef CONFIG_SAE_PK
+static bool sae_pk_acceptable_bss_with_pk(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *orig_bss,
+ struct wpa_ssid *ssid,
+ const u8 *match_ssid,
+ size_t match_ssid_len)
+{
+ struct wpa_bss *bss;
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ struct wpa_blacklist *e;
+ const u8 *ie;
+ u8 rsnxe_capa = 0;
+
+ if (bss == orig_bss)
+ continue;
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (ie && ie[1] >= 1)
+ rsnxe_capa = ie[2];
+ if (!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)))
+ continue;
+
+ /* TODO: Could be more thorough in checking what kind of
+ * signal strength or throughput estimate would be acceptable
+ * compared to the originally selected BSS. */
+ if (bss->est_throughput < 2000)
+ return false;
+
+ e = wpa_blacklist_get(wpa_s, bss->bssid);
+ if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
+ bss, e, 0))
+ return true;
+ }
+
+ return false;
+}
+#endif /* CONFIG_SAE_PK */
+
+
+static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ const u8 *match_ssid, size_t match_ssid_len,
+ struct wpa_bss *bss, struct wpa_blacklist *e,
+ bool debug_print)
+{
+ int res;
+ bool wpa, check_ssid, osen, rsn_osen = false;
+ struct wpa_ie_data data;
+#ifdef CONFIG_MBO
+ const u8 *assoc_disallow;
+#endif /* CONFIG_MBO */
+#ifdef CONFIG_SAE
+ u8 rsnxe_capa = 0;
+#endif /* CONFIG_SAE */
+ const u8 *ie;
+
+ ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+ wpa = ie && ie[1];
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ wpa |= ie && ie[1];
+ if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
+ (data.key_mgmt & WPA_KEY_MGMT_OSEN))
+ rsn_osen = true;
+ ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
+ osen = ie != NULL;
+
+#ifdef CONFIG_SAE
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (ie && ie[1] >= 1)
+ rsnxe_capa = ie[2];
+#endif /* CONFIG_SAE */
+
+ check_ssid = wpa || ssid->ssid_len > 0;
+
+ if (wpas_network_disabled(wpa_s, ssid)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
+ return false;
+ }
+
+ res = wpas_temp_disabled(wpa_s, ssid);
+ if (res > 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - disabled temporarily for %d second(s)",
+ res);
+ return false;
+ }
+
+#ifdef CONFIG_WPS
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - blacklisted (WPS)");
+ return false;
+ }
+
+ if (wpa && ssid->ssid_len == 0 &&
+ wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
+ check_ssid = false;
+
+ if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+ /* Only allow wildcard SSID match if an AP advertises active
+ * WPS operation that matches our mode. */
+ check_ssid = ssid->ssid_len > 0 ||
+ !wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss);
+ }
+#endif /* CONFIG_WPS */
+
+ if (ssid->bssid_set && ssid->ssid_len == 0 &&
+ os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
+ check_ssid = false;
+
+ if (check_ssid &&
+ (match_ssid_len != ssid->ssid_len ||
+ os_memcmp(match_ssid, ssid->ssid, match_ssid_len) != 0)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID mismatch");
+ return false;
+ }
+
+ if (ssid->bssid_set &&
+ os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID mismatch");
+ return false;
+ }
+
+ /* check blacklist */
+ if (ssid->num_bssid_blacklist &&
+ addr_in_list(bss->bssid, ssid->bssid_blacklist,
+ ssid->num_bssid_blacklist)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID blacklisted");
+ return false;
+ }
+
+ /* if there is a whitelist, only accept those APs */
+ if (ssid->num_bssid_whitelist &&
+ !addr_in_list(bss->bssid, ssid->bssid_whitelist,
+ ssid->num_bssid_whitelist)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID not in whitelist");
+ return false;
+ }
+
+ if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss, debug_print))
+ return false;
+
+ if (!osen && !wpa &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - non-WPA network not allowed");
+ return false;
+ }
+
+#ifdef CONFIG_WEP
+ if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) && has_wep_key(ssid)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - ignore WPA/WPA2 AP for WEP network block");
+ return false;
+ }
+#endif /* CONFIG_WEP */
+
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen && !rsn_osen) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - non-OSEN network not allowed");
+ return false;
+ }
+
+ if (!wpa_supplicant_match_privacy(bss, ssid)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy mismatch");
+ return false;
+ }
+
+ if (ssid->mode != WPAS_MODE_MESH && !bss_is_ess(bss) &&
+ !bss_is_pbss(bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - not ESS, PBSS, or MBSS");
+ return false;
+ }
+
+ if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - PBSS mismatch (ssid %d bss %d)",
+ ssid->pbss, bss_is_pbss(bss));
+ return false;
+ }
+
+ if (!freq_allowed(ssid->freq_list, bss->freq)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - frequency not allowed");
+ return false;
+ }
+
+#ifdef CONFIG_MESH
+ if (ssid->mode == WPAS_MODE_MESH && ssid->frequency > 0 &&
+ ssid->frequency != bss->freq) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - frequency not allowed (mesh)");
+ return false;
+ }
+#endif /* CONFIG_MESH */
+
+ if (!rate_match(wpa_s, ssid, bss, debug_print)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - rate sets do not match");
+ return false;
+ }
+
+#ifdef CONFIG_SAE
+ if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
+ wpa_s->conf->sae_pwe != 3 && wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - SAE H2E required, but not supported by the AP");
+ return false;
+ }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_SAE_PK
+ if (ssid->sae_pk == SAE_PK_MODE_ONLY &&
+ !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - SAE-PK required, but not supported by the AP");
+ return false;
+ }
+#endif /* CONFIG_SAE_PK */
+
+#ifndef CONFIG_IBSS_RSN
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - IBSS RSN not supported in the build");
+ return false;
+ }
+#endif /* !CONFIG_IBSS_RSN */
+
+#ifdef CONFIG_P2P
+ if (ssid->p2p_group &&
+ !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+ !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P IE seen");
+ return false;
+ }
+
+ if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) {
+ struct wpabuf *p2p_ie;
+ u8 dev_addr[ETH_ALEN];
+
+ ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+ if (!ie) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no P2P element");
+ return false;
+ }
+ p2p_ie = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+ if (!p2p_ie) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - could not fetch P2P element");
+ return false;
+ }
+
+ if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0 ||
+ os_memcmp(dev_addr, ssid->go_p2p_dev_addr, ETH_ALEN) != 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no matching GO P2P Device Address in P2P element");
+ wpabuf_free(p2p_ie);
+ return false;
+ }
+ wpabuf_free(p2p_ie);
+ }
+
+ /*
+ * TODO: skip the AP if its P2P IE has Group Formation bit set in the
+ * P2P Group Capability Bitmap and we are not in Group Formation with
+ * that device.
+ */
+#endif /* CONFIG_P2P */
+
+ if (os_reltime_before(&bss->last_update, &wpa_s->scan_min_time)) {
+ struct os_reltime diff;
+
+ os_reltime_sub(&wpa_s->scan_min_time, &bss->last_update, &diff);
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - scan result not recent enough (%u.%06u seconds too old)",
+ (unsigned int) diff.sec,
+ (unsigned int) diff.usec);
+ return false;
+ }
+#ifdef CONFIG_MBO
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_assoc_disallow)
+ goto skip_assoc_disallow;
+#endif /* CONFIG_TESTING_OPTIONS */
+ assoc_disallow = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_ASSOC_DISALLOW);
+ if (assoc_disallow && assoc_disallow[1] >= 1) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MBO association disallowed (reason %u)",
+ assoc_disallow[2]);
+ return false;
+ }
+
+ if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - AP temporarily disallowed");
+ return false;
+ }
+#ifdef CONFIG_TESTING_OPTIONS
+skip_assoc_disallow:
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_MBO */
+
+#ifdef CONFIG_DPP
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
+ !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) &&
+ (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no PMKSA entry for DPP");
+ return false;
+ }
+#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_SAE_PK
+ if (ssid->sae_pk == SAE_PK_MODE_AUTOMATIC &&
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ ((ssid->sae_password &&
+ sae_pk_valid_password(ssid->sae_password)) ||
+ (!ssid->sae_password && ssid->passphrase &&
+ sae_pk_valid_password(ssid->passphrase))) &&
+ !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
+ sae_pk_acceptable_bss_with_pk(wpa_s, bss, ssid, match_ssid,
+ match_ssid_len)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - another acceptable BSS with SAE-PK in the same ESS");
+ return false;
+ }
+#endif /* CONFIG_SAE_PK */
+
+ if (bss->ssid_len == 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no SSID known for the BSS");
+ return false;
+ }
+
+ /* Matching configuration found */
+ return true;
+}
+
+
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
int only_first_ssid, int debug_print)
{
u8 wpa_ie_len, rsn_ie_len;
- int wpa;
struct wpa_blacklist *e;
const u8 *ie;
struct wpa_ssid *ssid;
- int osen, rsn_osen = 0;
-#ifdef CONFIG_MBO
- const u8 *assoc_disallow;
-#endif /* CONFIG_MBO */
+ int osen;
const u8 *match_ssid;
size_t match_ssid_len;
- struct wpa_ie_data data;
ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
wpa_ie_len = ie ? ie[1] : 0;
ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
rsn_ie_len = ie ? ie[1] : 0;
- if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
- (data.key_mgmt & WPA_KEY_MGMT_OSEN))
- rsn_osen = 1;
ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
osen = ie != NULL;
@@ -1086,283 +1549,16 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
return NULL;
}
- wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
+ if (disabled_freq(wpa_s, bss->freq)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - channel disabled");
+ return NULL;
+ }
for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) {
- int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
- int res;
-
- if (wpas_network_disabled(wpa_s, ssid)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
- continue;
- }
-
- res = wpas_temp_disabled(wpa_s, ssid);
- if (res > 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - disabled temporarily for %d second(s)",
- res);
- continue;
- }
-
-#ifdef CONFIG_WPS
- if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - blacklisted (WPS)");
- continue;
- }
-
- if (wpa && ssid->ssid_len == 0 &&
- wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
- check_ssid = 0;
-
- if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
- /* Only allow wildcard SSID match if an AP
- * advertises active WPS operation that matches
- * with our mode. */
- check_ssid = 1;
- if (ssid->ssid_len == 0 &&
- wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
- check_ssid = 0;
- }
-#endif /* CONFIG_WPS */
-
- if (ssid->bssid_set && ssid->ssid_len == 0 &&
- os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
- check_ssid = 0;
-
- if (check_ssid &&
- (match_ssid_len != ssid->ssid_len ||
- os_memcmp(match_ssid, ssid->ssid, match_ssid_len) != 0)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - SSID mismatch");
- continue;
- }
-
- if (ssid->bssid_set &&
- os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID mismatch");
- continue;
- }
-
- /* check blacklist */
- if (ssid->num_bssid_blacklist &&
- addr_in_list(bss->bssid, ssid->bssid_blacklist,
- ssid->num_bssid_blacklist)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID blacklisted");
- continue;
- }
-
- /* if there is a whitelist, only accept those APs */
- if (ssid->num_bssid_whitelist &&
- !addr_in_list(bss->bssid, ssid->bssid_whitelist,
- ssid->num_bssid_whitelist)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID not in whitelist");
- continue;
- }
-
- if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss,
- debug_print))
- continue;
-
- if (!osen && !wpa &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - non-WPA network not allowed");
- continue;
- }
-
- if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
- has_wep_key(ssid)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - ignore WPA/WPA2 AP for WEP network block");
- continue;
- }
-
- if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen &&
- !rsn_osen) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - non-OSEN network not allowed");
- continue;
- }
-
- if (!wpa_supplicant_match_privacy(bss, ssid)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - privacy mismatch");
- continue;
- }
-
- if (ssid->mode != WPAS_MODE_MESH && !bss_is_ess(bss) &&
- !bss_is_pbss(bss)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - not ESS, PBSS, or MBSS");
- continue;
- }
-
- if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - PBSS mismatch (ssid %d bss %d)",
- ssid->pbss, bss_is_pbss(bss));
- continue;
- }
-
- if (!freq_allowed(ssid->freq_list, bss->freq)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - frequency not allowed");
- continue;
- }
-
-#ifdef CONFIG_MESH
- if (ssid->mode == WPAS_MODE_MESH && ssid->frequency > 0 &&
- ssid->frequency != bss->freq) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - frequency not allowed (mesh)");
- continue;
- }
-#endif /* CONFIG_MESH */
-
- if (!rate_match(wpa_s, bss, debug_print)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - rate sets do not match");
- continue;
- }
-
-#ifndef CONFIG_IBSS_RSN
- if (ssid->mode == WPAS_MODE_IBSS &&
- !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
- WPA_KEY_MGMT_WPA_NONE))) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - IBSS RSN not supported in the build");
- continue;
- }
-#endif /* !CONFIG_IBSS_RSN */
-
-#ifdef CONFIG_P2P
- if (ssid->p2p_group &&
- !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
- !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no P2P IE seen");
- continue;
- }
-
- if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) {
- struct wpabuf *p2p_ie;
- u8 dev_addr[ETH_ALEN];
-
- ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
- if (ie == NULL) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no P2P element");
- continue;
- }
- p2p_ie = wpa_bss_get_vendor_ie_multi(
- bss, P2P_IE_VENDOR_TYPE);
- if (p2p_ie == NULL) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - could not fetch P2P element");
- continue;
- }
-
- if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0
- || os_memcmp(dev_addr, ssid->go_p2p_dev_addr,
- ETH_ALEN) != 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no matching GO P2P Device Address in P2P element");
- wpabuf_free(p2p_ie);
- continue;
- }
- wpabuf_free(p2p_ie);
- }
-
- /*
- * TODO: skip the AP if its P2P IE has Group Formation
- * bit set in the P2P Group Capability Bitmap and we
- * are not in Group Formation with that device.
- */
-#endif /* CONFIG_P2P */
-
- if (os_reltime_before(&bss->last_update, &wpa_s->scan_min_time))
- {
- struct os_reltime diff;
-
- os_reltime_sub(&wpa_s->scan_min_time,
- &bss->last_update, &diff);
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - scan result not recent enough (%u.%06u seconds too old)",
- (unsigned int) diff.sec,
- (unsigned int) diff.usec);
- continue;
- }
-#ifdef CONFIG_MBO
-#ifdef CONFIG_TESTING_OPTIONS
- if (wpa_s->ignore_assoc_disallow)
- goto skip_assoc_disallow;
-#endif /* CONFIG_TESTING_OPTIONS */
- assoc_disallow = wpas_mbo_get_bss_attr(
- bss, MBO_ATTR_ID_ASSOC_DISALLOW);
- if (assoc_disallow && assoc_disallow[1] >= 1) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - MBO association disallowed (reason %u)",
- assoc_disallow[2]);
- continue;
- }
-
- if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - AP temporarily disallowed");
- continue;
- }
-#ifdef CONFIG_TESTING_OPTIONS
- skip_assoc_disallow:
-#endif /* CONFIG_TESTING_OPTIONS */
-#endif /* CONFIG_MBO */
-
-#ifdef CONFIG_DPP
- if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
- !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) &&
- (!ssid->dpp_connector ||
- !ssid->dpp_netaccesskey ||
- !ssid->dpp_csign)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no PMKSA entry for DPP");
- continue;
- }
-#endif /* CONFIG_DPP */
-
- /* Matching configuration found */
- return ssid;
+ if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
+ bss, e, debug_print))
+ return ssid;
}
/* No matching configuration found */
@@ -1413,8 +1609,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;
@@ -1428,7 +1625,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;
@@ -1583,7 +1780,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++) {
@@ -1639,46 +1836,41 @@ static void wpa_supplicant_rsn_preauth_scan_results(
}
-static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
- struct wpa_bss *selected,
- struct wpa_ssid *ssid)
-{
- struct wpa_bss *current_bss = NULL;
#ifndef CONFIG_NO_ROAMING
- int min_diff, diff;
- int to_5ghz;
- int cur_est, sel_est;
-#endif /* CONFIG_NO_ROAMING */
- if (wpa_s->reassociate)
- return 1; /* explicit request to reassociate */
- if (wpa_s->wpa_state < WPA_ASSOCIATED)
- return 1; /* we are not associated; continue */
- if (wpa_s->current_ssid == NULL)
- return 1; /* unknown current SSID */
- if (wpa_s->current_ssid != ssid)
- return 1; /* different network block */
+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;
+}
- if (wpas_driver_bss_selection(wpa_s))
- return 0; /* Driver-based roaming */
- if (wpa_s->current_ssid->ssid)
- current_bss = wpa_bss_get(wpa_s, wpa_s->bssid,
- wpa_s->current_ssid->ssid,
- wpa_s->current_ssid->ssid_len);
- if (!current_bss)
- current_bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
+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;
- if (!current_bss)
- return 1; /* current BSS not seen in scan results */
+ return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr);
+}
- if (current_bss == selected)
- return 0;
- if (selected->last_update_idx > current_bss->last_update_idx)
- return 1; /* current BSS not seen in the last scan */
+int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *current_bss,
+ struct wpa_bss *selected)
+{
+ int min_diff, diff;
+ int to_5ghz;
+ int cur_level;
+ unsigned int cur_est, sel_est;
+ struct wpa_signal_info si;
+ int cur_snr = 0;
+ int ret = 0;
-#ifndef CONFIG_NO_ROAMING
wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR
" freq=%d level=%d snr=%d est_throughput=%u",
@@ -1698,7 +1890,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;
@@ -1706,70 +1932,121 @@ 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)",
diff, min_diff);
- return 0;
+ ret = 0;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Allow reassociation due to difference in signal level (%d >= %d)",
+ diff, min_diff);
+ ret = 1;
}
+ wpa_msg_ctrl(wpa_s, MSG_INFO, "%scur_bssid=" MACSTR
+ " cur_freq=%d cur_level=%d cur_est=%d sel_bssid=" MACSTR
+ " sel_freq=%d sel_level=%d sel_est=%d",
+ ret ? WPA_EVENT_DO_ROAM : WPA_EVENT_SKIP_ROAM,
+ MAC2STR(current_bss->bssid),
+ current_bss->freq, cur_level, cur_est,
+ MAC2STR(selected->bssid),
+ selected->freq, selected->level, sel_est);
+ return ret;
+}
- wpa_dbg(wpa_s, MSG_DEBUG,
- "Allow reassociation due to difference in signal level (%d >= %d)",
- diff, min_diff);
- return 1;
+#endif /* CONFIG_NO_ROAMING */
+
+
+static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *selected,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_bss *current_bss = NULL;
+
+ if (wpa_s->reassociate)
+ return 1; /* explicit request to reassociate */
+ if (wpa_s->wpa_state < WPA_ASSOCIATED)
+ return 1; /* we are not associated; continue */
+ if (wpa_s->current_ssid == NULL)
+ return 1; /* unknown current SSID */
+ if (wpa_s->current_ssid != ssid)
+ return 1; /* different network block */
+
+ if (wpas_driver_bss_selection(wpa_s))
+ return 0; /* Driver-based roaming */
+
+ if (wpa_s->current_ssid->ssid)
+ current_bss = wpa_bss_get(wpa_s, wpa_s->bssid,
+ wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid_len);
+ if (!current_bss)
+ current_bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
+
+ if (!current_bss)
+ return 1; /* current BSS not seen in scan results */
+
+ if (current_bss == selected)
+ return 0;
+
+ if (selected->last_update_idx > current_bss->last_update_idx)
+ return 1; /* current BSS not seen in the last scan */
+
+#ifndef CONFIG_NO_ROAMING
+ return wpa_supplicant_need_to_roam_within_ess(wpa_s, current_bss,
+ selected);
#else /* CONFIG_NO_ROAMING */
return 0;
#endif /* CONFIG_NO_ROAMING */
@@ -1854,15 +2131,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);
@@ -1879,6 +2147,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);
@@ -1888,7 +2165,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
if (wnm_scan_process(wpa_s, 1) > 0)
goto scan_work_done;
- if (sme_proc_obss_scan(wpa_s) > 0)
+ if (sme_proc_obss_scan(wpa_s, scan_res) > 0)
goto scan_work_done;
if (own_request && data &&
@@ -2161,7 +2438,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;
}
@@ -2294,28 +2572,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");
@@ -2385,13 +2676,13 @@ static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
- int l, len, found = 0, wpa_found, rsn_found;
+ int l, len, found = 0, found_x = 0, wpa_found, rsn_found;
const u8 *p;
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE)
u8 bssid[ETH_ALEN];
-#endif /* CONFIG_IEEE80211R || CONFIG_OWE */
+ bool bssid_known;
wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
+ bssid_known = wpa_drv_get_bssid(wpa_s, bssid) == 0;
if (data->assoc_info.req_ies)
wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies,
data->assoc_info.req_ies_len);
@@ -2439,8 +2730,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;
}
@@ -2457,22 +2754,29 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
p, l);
break;
}
- if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
- (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
- (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
- (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
- (p[0] == WLAN_EID_RSN && p[1] >= 2)) {
+ if (!found &&
+ ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+ (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
+ (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
+ (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
+ (p[0] == WLAN_EID_RSN && p[1] >= 2))) {
if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
break;
found = 1;
wpa_find_assoc_pmkid(wpa_s);
- break;
+ }
+ if (!found_x && p[0] == WLAN_EID_RSNX) {
+ if (wpa_sm_set_assoc_rsnxe(wpa_s->wpa, p, len))
+ break;
+ found_x = 1;
}
l -= len;
p += len;
}
if (!found && data->assoc_info.req_ies)
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ if (!found_x && data->assoc_info.req_ies)
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
#ifdef CONFIG_FILS
#ifdef CONFIG_SME
@@ -2495,7 +2799,7 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_OWE
if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
- (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ (!bssid_known ||
owe_process_assoc_resp(wpa_s->wpa, bssid,
data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len) < 0)) {
@@ -2506,7 +2810,8 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_DPP2
wpa_sm_set_dpp_z(wpa_s->wpa, NULL);
- if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->dpp_pfs) {
+ if (DPP_VERSION > 1 && wpa_s->key_mgmt == WPA_KEY_MGMT_DPP &&
+ wpa_s->dpp_pfs) {
struct ieee802_11_elems elems;
if (ieee802_11_parse_elems(data->assoc_info.resp_ies,
@@ -2529,7 +2834,7 @@ no_pfs:
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SME
if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
- if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ if (!bssid_known ||
wpa_ft_validate_reassoc_resp(wpa_s->wpa,
data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len,
@@ -2589,7 +2894,7 @@ no_pfs:
/* Process FT when SME is in the driver */
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
wpa_ft_is_completed(wpa_s->wpa)) {
- if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ if (!bssid_known ||
wpa_ft_validate_reassoc_resp(wpa_s->wpa,
data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len,
@@ -2607,6 +2912,11 @@ no_pfs:
data->assoc_info.resp_ies_len);
#endif /* CONFIG_IEEE80211R */
+ if (bssid_known)
+ wpas_handle_assoc_resp_mscs(wpa_s, bssid,
+ data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
+
/* WPA/RSN IE from Beacon/ProbeResp */
p = data->assoc_info.beacon_ies;
l = data->assoc_info.beacon_ies_len;
@@ -2634,14 +2944,19 @@ no_pfs:
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
}
+ if (p[0] == WLAN_EID_RSNX && p[1] >= 1)
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, p, len);
+
l -= len;
p += len;
}
if (!wpa_found && data->assoc_info.beacon_ies)
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
- if (!rsn_found && data->assoc_info.beacon_ies)
+ if (!rsn_found && data->assoc_info.beacon_ies) {
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
+ }
if (wpa_found || rsn_found)
wpa_s->ap_ies_from_associnfo = 1;
@@ -2661,7 +2976,7 @@ no_pfs:
static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
{
- const u8 *bss_wpa = NULL, *bss_rsn = NULL;
+ const u8 *bss_wpa = NULL, *bss_rsn = NULL, *bss_rsnx = NULL;
if (!wpa_s->current_bss || !wpa_s->current_ssid)
return -1;
@@ -2672,11 +2987,14 @@ static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
bss_wpa = wpa_bss_get_vendor_ie(wpa_s->current_bss,
WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSN);
+ bss_rsnx = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSNX);
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
- bss_rsn ? 2 + bss_rsn[1] : 0))
+ bss_rsn ? 2 + bss_rsn[1] : 0) ||
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+ bss_rsnx ? 2 + bss_rsnx[1] : 0))
return -1;
return 0;
@@ -2728,6 +3046,9 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
u8 bssid[ETH_ALEN];
int ft_completed, already_authorized;
int new_bss = 0;
+#if defined(CONFIG_FILS) || defined(CONFIG_MBO)
+ struct wpa_bss *bss;
+#endif /* CONFIG_FILS || CONFIG_MBO */
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
@@ -2743,6 +3064,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)
@@ -2792,6 +3114,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)
@@ -2822,7 +3146,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
already_authorized = data && data->assoc_info.authorized;
/*
- * Set portEnabled first to FALSE in order to get EAP state machine out
+ * Set portEnabled first to false in order to get EAP state machine out
* of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
* state machine may transit to AUTHENTICATING state based on obsolete
* eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to
@@ -2830,16 +3154,16 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
* reset the state.
*/
if (!ft_completed && !already_authorized) {
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, false);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
}
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->key_mgmt == WPA_KEY_MGMT_DPP ||
wpa_s->key_mgmt == WPA_KEY_MGMT_OWE || ft_completed ||
already_authorized || wpa_s->drv_authorized_port)
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
/* 802.1X::portControl = Auto */
- eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, true);
wpa_s->eapol_received = 0;
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE ||
@@ -2871,8 +3195,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
*/
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
- eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
+ eapol_sm_notify_eap_success(wpa_s->eapol, true);
} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
/*
@@ -2881,8 +3205,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
*/
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
- eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
+ eapol_sm_notify_eap_success(wpa_s->eapol, true);
} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
@@ -2890,11 +3214,28 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
* to allow EAPOL supplicant to complete its work without
* waiting for WPA supplicant.
*/
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
}
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");
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa,
+ wpabuf_head(wpa_s->rsnxe_override_eapol),
+ wpabuf_len(wpa_s->rsnxe_override_eapol));
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (wpa_s->pending_eapol_rx) {
struct os_reltime now, age;
os_get_reltime(&now);
@@ -2914,6 +3255,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 &&
@@ -2921,6 +3263,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 &&
@@ -2951,15 +3294,25 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wmm_ac_restore_tspecs(wpa_s);
}
+#if defined(CONFIG_FILS) || defined(CONFIG_MBO)
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+#endif /* CONFIG_FILS || CONFIG_MBO */
#ifdef CONFIG_FILS
if (wpa_key_mgmt_fils(wpa_s->key_mgmt)) {
- struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, bssid);
const u8 *fils_cache_id = wpa_bss_get_fils_cache_id(bss);
if (fils_cache_id)
wpa_sm_set_fils_cache_id(wpa_s->wpa, fils_cache_id);
}
#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_MBO
+ wpas_mbo_check_pmf(wpa_s, bss, wpa_s->current_ssid);
+#endif /* CONFIG_MBO */
+
+#ifdef CONFIG_DPP2
+ wpa_s->dpp_pfs_fallback = 0;
+#endif /* CONFIG_DPP2 */
}
@@ -3004,8 +3357,10 @@ static int could_be_psk_mismatch(struct wpa_supplicant *wpa_s, u16 reason_code,
int locally_generated)
{
if (wpa_s->wpa_state != WPA_4WAY_HANDSHAKE ||
- !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
- return 0; /* Not in 4-way handshake with PSK */
+ !wpa_s->new_connection ||
+ !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+ wpa_key_mgmt_sae(wpa_s->key_mgmt))
+ return 0; /* Not in initial 4-way handshake with PSK */
/*
* It looks like connection was lost while trying to go through PSK
@@ -3085,21 +3440,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");
@@ -3891,6 +4250,13 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_DPP */
+ if (category == WLAN_ACTION_ROBUST_AV_STREAMING &&
+ payload[0] == ROBUST_AV_MSCS_RESP) {
+ wpas_handle_robust_av_recv_action(wpa_s, mgmt->sa,
+ payload + 1, plen - 1);
+ return;
+ }
+
wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
category, payload, plen, freq);
if (wpa_s->ifmsh)
@@ -3936,8 +4302,8 @@ static void wpa_supplicant_event_port_authorized(struct wpa_supplicant *wpa_s)
if (wpa_s->wpa_state == WPA_ASSOCIATED) {
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
- eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
+ eapol_sm_notify_eap_success(wpa_s->eapol, true);
wpa_s->drv_authorized_port = 1;
}
}
@@ -4122,6 +4488,41 @@ 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 (DPP_VERSION > 1 && wpa_s->current_ssid &&
+ (wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP ||
+ ((wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
+ wpa_s->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 &&
@@ -4188,11 +4589,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 */
@@ -4495,6 +4929,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 ||
@@ -4511,7 +4959,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
#endif /* CONFIG_AP */
- sme_event_ch_switch(wpa_s);
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+ sme_event_ch_switch(wpa_s);
+
wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
wnm_clear_coloc_intf_reporting(wpa_s);
break;
@@ -4678,6 +5128,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpas_p2p_remain_on_channel_cb(
wpa_s, data->remain_on_channel.freq,
data->remain_on_channel.duration);
+#ifdef CONFIG_DPP
+ wpas_dpp_remain_on_channel_cb(
+ wpa_s, data->remain_on_channel.freq,
+ data->remain_on_channel.duration);
+#endif /* CONFIG_DPP */
break;
case EVENT_CANCEL_REMAIN_ON_CHANNEL:
#ifdef CONFIG_OFFCHANNEL
@@ -4717,6 +5172,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) {
@@ -4785,7 +5242,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);
- 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);
@@ -4962,6 +5432,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 0000000..8e865f3
--- /dev/null
+++ b/wpa_supplicant/examples/dpp-nfc.py
@@ -0,0 +1,1186 @@
+#!/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 binascii
+import errno
+import os
+import struct
+import sys
+import time
+import threading
+import argparse
+
+import nfc
+import ndef
+
+import logging
+
+scriptsdir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__))
+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
+continue_loop = True
+terminate_now = False
+summary_file = None
+success_file = None
+netrole = None
+operation_success = False
+mutex = threading.Lock()
+
+C_NORMAL = '\033[0m'
+C_RED = '\033[91m'
+C_GREEN = '\033[92m'
+C_YELLOW = '\033[93m'
+C_BLUE = '\033[94m'
+C_MAGENTA = '\033[95m'
+C_CYAN = '\033[96m'
+
+def summary(txt, color=None):
+ with mutex:
+ if color:
+ print(color + txt + C_NORMAL)
+ else:
+ 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:
+ summary("Could not find wpa_supplicant: %s", str(error))
+ return None
+
+ if len(ifaces) < 1:
+ summary("No wpa_supplicant control interface found")
+ return None
+
+ for ctrl in ifaces:
+ if ifname and ifname not in ctrl:
+ continue
+ if os.path.basename(ctrl).startswith("p2p-dev-"):
+ # skip P2P management interface
+ continue
+ try:
+ summary("Trying to use control interface " + ctrl)
+ wpas = wpaspy.Ctrl(ctrl)
+ return wpas
+ except Exception as e:
+ pass
+ summary("Could not connect to wpa_supplicant")
+ 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:
+ summary("Could not parse DPP URI from NFC URI record", color=C_RED)
+ return False
+ peer_id = int(peer_id)
+ summary("peer_id=%d for URI from NFC Tag: %s" % (peer_id, uri))
+ cmd = "DPP_AUTH_INIT peer=%d" % peer_id
+ global enrollee_only, configurator_only, config_params
+ if enrollee_only:
+ cmd += " role=enrollee"
+ elif configurator_only:
+ cmd += " role=configurator"
+ if config_params:
+ cmd += " " + config_params
+ summary("Initiate DPP authentication: " + cmd)
+ res = wpas.request(cmd)
+ if "OK" not in res:
+ summary("Failed to initiate DPP Authentication", color=C_RED)
+ return False
+ summary("DPP Authentication initiated")
+ return True
+
+def dpp_hs_tag_read(record):
+ wpas = wpas_connect()
+ if wpas is None:
+ return False
+ summary(record)
+ if len(record.data) < 5:
+ summary("Too short DPP HS", color=C_RED)
+ return False
+ if record.data[0] != 0:
+ summary("Unexpected URI Identifier Code", color=C_RED)
+ return False
+ uribuf = record.data[1:]
+ try:
+ uri = uribuf.decode()
+ except:
+ summary("Invalid URI payload", color=C_RED)
+ return False
+ summary("URI: " + uri)
+ if not uri.startswith("DPP:"):
+ summary("Not a DPP URI", color=C_RED)
+ 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:
+ summary("Ignore unexpected status line: %s" % 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):
+ addr = get_status_field(wpas, "address")
+ if addr is None:
+ addr = get_status_field(wpas, "bssid[0]")
+ return addr
+
+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)
+ if mac is None:
+ summary("Could not determine local MAC address for bootstrap info")
+ else:
+ 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 dpp_start_listen(wpas, freq):
+ if get_status_field(wpas, "bssid[0]"):
+ summary("Own AP freq: %s MHz" % str(get_status_field(wpas, "freq")))
+ if get_status_field(wpas, "beacon_set", extra="DRIVER") is None:
+ summary("Enable beaconing to have radio ready for RX")
+ wpas.request("DISABLE")
+ wpas.request("SET start_disabled 0")
+ wpas.request("ENABLE")
+ cmd = "DPP_LISTEN %d" % freq
+ global enrollee_only
+ global configurator_only
+ if enrollee_only:
+ cmd += " role=enrollee"
+ elif configurator_only:
+ cmd += " role=configurator"
+ global netrole
+ if netrole:
+ cmd += " netrole=" + netrole
+ summary(cmd)
+ res = wpas.request(cmd)
+ if "OK" not in res:
+ summary("Failed to start DPP listen", color=C_RED)
+ return False
+ return True
+
+def wpas_get_nfc_uri(start_listen=True, pick_channel=False, chan_override=None):
+ listen_freq = 2412
+ wpas = wpas_connect()
+ if wpas is None:
+ return None
+ global own_id, chanlist
+ if chan_override:
+ chan = chan_override
+ else:
+ chan = chanlist
+ if chan and chan.startswith("81/"):
+ listen_freq = int(chan[3:].split(',')[0]) * 5 + 2407
+ if chan is None and get_status_field(wpas, "bssid[0]"):
+ freq = get_status_field(wpas, "freq")
+ if freq:
+ freq = int(freq)
+ if freq >= 2412 and freq <= 2462:
+ chan = "81/%d" % ((freq - 2407) / 5)
+ summary("Use current AP operating channel (%d MHz) as the URI channel list (%s)" % (freq, chan))
+ listen_freq = freq
+ if chan is None and pick_channel:
+ chan = "81/6"
+ summary("Use channel 2437 MHz since no other preference provided")
+ listen_freq = 2437
+ own_id = dpp_bootstrap_gen(wpas, type="nfc-uri", chan=chan, mac=True)
+ res = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
+ if "FAIL" in res:
+ return None
+ if start_listen:
+ if not dpp_start_listen(wpas, listen_freq):
+ raise Exception("Failed to start listen operation on %d MHz" % listen_freq)
+ 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(handover, alt=False):
+ summary("About to start run_dpp_handover_client (alt=%s)" % str(alt))
+ if alt:
+ handover.i_m_selector = False
+ run_dpp_handover_client(handover, alt)
+ summary("Done run_dpp_handover_client (alt=%s)" % str(alt))
+
+def run_client_alt(handover, alt):
+ if handover.start_client_alt and not alt:
+ handover.start_client_alt = False
+ summary("Try to send alternative handover request")
+ dpp_handover_client(handover, alt=True)
+
+class HandoverClient(nfc.handover.HandoverClient):
+ def __init__(self, handover, llc):
+ super(HandoverClient, self).__init__(llc)
+ self.handover = handover
+
+ def recv_records(self, timeout=None):
+ msg = self.recv_octets(timeout)
+ if msg is None:
+ return None
+ records = list(ndef.message_decoder(msg, 'relax'))
+ if records and records[0].type == 'urn:nfc:wkt:Hs':
+ summary("Handover client received message '{0}'".format(records[0].type))
+ return list(ndef.message_decoder(msg, 'relax'))
+ summary("Handover client received invalid message: %s" + binascii.hexlify(msg))
+ return None
+
+ def recv_octets(self, timeout=None):
+ start = time.time()
+ msg = bytearray()
+ while True:
+ poll_timeout = 0.1 if timeout is None or timeout > 0.1 else timeout
+ if not self.socket.poll('recv', poll_timeout):
+ if timeout:
+ timeout -= time.time() - start
+ if timeout <= 0:
+ return None
+ start = time.time()
+ continue
+ try:
+ r = self.socket.recv()
+ if r is None:
+ return None
+ msg += r
+ except TypeError:
+ return b''
+ try:
+ list(ndef.message_decoder(msg, 'strict', {}))
+ return bytes(msg)
+ except ndef.DecodeError:
+ if timeout:
+ timeout -= time.time() - start
+ if timeout <= 0:
+ return None
+ start = time.time()
+ continue
+ return None
+
+def run_dpp_handover_client(handover, alt=False):
+ chan_override = None
+ if alt:
+ chan_override = handover.altchanlist
+ handover.alt_proposal_used = True
+ global test_uri, test_alt_uri
+ if test_uri:
+ summary("TEST MODE: Using specified URI (alt=%s)" % str(alt))
+ uri = test_alt_uri if alt else test_uri
+ else:
+ uri = wpas_get_nfc_uri(start_listen=False, chan_override=chan_override)
+ if uri is None:
+ summary("Cannot start handover client - no bootstrap URI available",
+ color=C_RED)
+ return
+ handover.my_uri = uri
+ uri = ndef.UriRecord(uri)
+ summary("NFC URI record for DPP: " + str(uri))
+ carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+ global test_crn
+ if test_crn:
+ prev, = struct.unpack('>H', test_crn)
+ summary("TEST MODE: Use specified crn %d" % prev)
+ crn = test_crn
+ test_crn = struct.pack('>H', prev + 0x10)
+ else:
+ crn = os.urandom(2)
+ hr = ndef.HandoverRequestRecord(version="1.4", crn=crn)
+ hr.add_alternative_carrier('active', carrier.name)
+ message = [hr, carrier]
+ summary("NFC Handover Request message for DPP: " + str(message))
+
+ if handover.peer_crn is not None and not alt:
+ summary("NFC handover request from peer was already received - do not send own")
+ return
+ if handover.client:
+ summary("Use already started handover client")
+ client = handover.client
+ else:
+ summary("Start handover client")
+ client = HandoverClient(handover, handover.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
+ handover.client = client
+
+ if handover.peer_crn is not None and not alt:
+ summary("NFC handover request from peer was already received - do not send own")
+ return
+
+ summary("Sending handover request")
+
+ handover.my_crn_ready = True
+
+ if not client.send_records(message):
+ handover.my_crn_ready = False
+ summary("Failed to send handover request", color=C_RED)
+ run_client_alt(handover, alt)
+ return
+
+ handover.my_crn, = struct.unpack('>H', crn)
+
+ summary("Receiving handover response")
+ try:
+ start = time.time()
+ message = client.recv_records(timeout=3.0)
+ end = time.time()
+ summary("Received {} record(s) in {} seconds".format(len(message) if message is not None else -1, end - start))
+ except Exception as e:
+ # This is fine if we are the handover selector
+ if handover.hs_sent:
+ summary("Client receive failed as expected since I'm the handover server: %s" % str(e))
+ elif handover.alt_proposal_used and not alt:
+ summary("Client received failed for initial proposal as expected since alternative proposal was also used: %s" % str(e))
+ else:
+ summary("Client receive failed: %s" % str(e), color=C_RED)
+ message = None
+ if message is None:
+ if handover.hs_sent:
+ summary("No response received as expected since I'm the handover server")
+ elif handover.alt_proposal_used and not alt:
+ summary("No response received for initial proposal as expected since alternative proposal was also used")
+ elif handover.try_own and not alt:
+ summary("No response received for initial proposal as expected since alternative proposal will also be sent")
+ else:
+ summary("No response received", color=C_RED)
+ run_client_alt(handover, alt)
+ return
+ summary("Received message: " + str(message))
+ if len(message) < 1 or \
+ not isinstance(message[0], ndef.HandoverSelectRecord):
+ summary("Response was not Hs - received: " + message.type)
+ return
+
+ summary("Received handover select message")
+ summary("alternative carriers: " + str(message[0].alternative_carriers))
+ if handover.i_m_selector:
+ summary("Ignore the received select since I'm the handover selector")
+ run_client_alt(handover, alt)
+ return
+
+ if handover.alt_proposal_used and not alt:
+ summary("Ignore received handover select for the initial proposal since alternative proposal was sent")
+ client.close()
+ return
+
+ dpp_found = False
+ for carrier in message:
+ if isinstance(carrier, ndef.HandoverSelectRecord):
+ continue
+ summary("Remote carrier type: " + carrier.type)
+ if carrier.type == "application/vnd.wfa.dpp":
+ if len(carrier.data) == 0 or carrier.data[0] != 0:
+ summary("URI Identifier Code 'None' not seen", color=C_RED)
+ continue
+ summary("DPP carrier type match - send to wpa_supplicant")
+ dpp_found = True
+ uri = carrier.data[1:].decode("utf-8")
+ summary("DPP URI: " + uri)
+ handover.peer_uri = uri
+ if test_uri:
+ summary("TEST MODE: Fake processing")
+ break
+ res = wpas_report_handover_sel(uri)
+ if res is None or "FAIL" in res:
+ summary("DPP handover report rejected", color=C_RED)
+ break
+
+ success_report("DPP handover reported successfully (initiator)")
+ summary("peer_id=" + res)
+ peer_id = int(res)
+ wpas = wpas_connect()
+ if wpas is None:
+ break
+
+ global enrollee_only
+ global config_params
+ if enrollee_only:
+ extra = " role=enrollee"
+ elif config_params:
+ extra = " role=configurator " + config_params
+ else:
+ # TODO: Single Configurator instance
+ res = wpas.request("DPP_CONFIGURATOR_ADD")
+ if "FAIL" in res:
+ summary("Failed to initiate Configurator", color=C_RED)
+ break
+ conf_id = int(res)
+ extra = " conf=sta-dpp configurator=%d" % conf_id
+ global own_id
+ summary("Initiate DPP authentication")
+ cmd = "DPP_AUTH_INIT peer=%d own=%d" % (peer_id, own_id)
+ cmd += extra
+ res = wpas.request(cmd)
+ if "FAIL" in res:
+ summary("Failed to initiate DPP authentication", color=C_RED)
+ break
+
+ if not dpp_found and handover.no_alt_proposal:
+ summary("DPP carrier not seen in response - do not allow alternative proposal anymore")
+ elif not dpp_found:
+ summary("DPP carrier not seen in response - allow peer to initiate a new handover with different parameters")
+ handover.alt_proposal = True
+ handover.my_crn_ready = False
+ handover.my_crn = None
+ handover.peer_crn = None
+ handover.hs_sent = False
+ summary("Returning from dpp_handover_client")
+ return
+
+ summary("Remove peer")
+ handover.close()
+ summary("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 or only_one:
+ summary("Trying to exit..")
+ global terminate_now
+ terminate_now = True
+
+ summary("Returning from dpp_handover_client")
+
+class HandoverServer(nfc.handover.HandoverServer):
+ def __init__(self, handover, llc):
+ super(HandoverServer, self).__init__(llc)
+ self.sent_carrier = None
+ self.ho_server_processing = False
+ self.success = False
+ self.llc = llc
+ self.handover = handover
+
+ def serve(self, socket):
+ peer_sap = socket.getpeername()
+ summary("Serving handover client on remote sap {0}".format(peer_sap))
+ send_miu = socket.getsockopt(nfc.llcp.SO_SNDMIU)
+ try:
+ while socket.poll("recv"):
+ req = bytearray()
+ while socket.poll("recv"):
+ r = socket.recv()
+ if r is None:
+ return None
+ summary("Received %d octets" % len(r))
+ req += r
+ if len(req) == 0:
+ continue
+ try:
+ list(ndef.message_decoder(req, 'strict', {}))
+ except ndef.DecodeError:
+ continue
+ summary("Full message received")
+ resp = self._process_request_data(req)
+ if resp is None or len(resp) == 0:
+ summary("No handover select to send out - wait for a possible alternative handover request")
+ handover.alt_proposal = True
+ req = bytearray()
+ continue
+
+ for offset in range(0, len(resp), send_miu):
+ if not socket.send(resp[offset:offset + send_miu]):
+ summary("Failed to send handover select - connection closed")
+ return
+ summary("Sent out full handover select")
+ if handover.terminate_on_hs_send_completion:
+ handover.delayed_exit()
+
+ except nfc.llcp.Error as e:
+ global terminate_now
+ summary("HandoverServer exception: %s" % e,
+ color=None if e.errno == errno.EPIPE or terminate_now else C_RED)
+ finally:
+ socket.close()
+ summary("Handover serve thread exiting")
+
+ def process_handover_request_message(self, records):
+ handover = self.handover
+ self.ho_server_processing = True
+ global in_raw_mode
+ was_in_raw_mode = in_raw_mode
+ clear_raw_mode()
+ if was_in_raw_mode:
+ print("\n")
+ summary("HandoverServer - request received: " + str(records))
+
+ for carrier in records:
+ if not isinstance(carrier, ndef.HandoverRequestRecord):
+ continue
+ if carrier.collision_resolution_number:
+ handover.peer_crn = carrier.collision_resolution_number
+ summary("peer_crn: %d" % handover.peer_crn)
+
+ if handover.my_crn is None and handover.my_crn_ready:
+ summary("Still trying to send own handover request - wait a moment to see if that succeeds before checking crn values")
+ for i in range(10):
+ if handover.my_crn is not None:
+ break
+ time.sleep(0.01)
+ if handover.my_crn is not None:
+ summary("my_crn: %d" % handover.my_crn)
+
+ if handover.my_crn is not None and handover.peer_crn is not None:
+ if handover.my_crn == handover.peer_crn:
+ summary("Same crn used - automatic collision resolution failed")
+ # TODO: Should generate a new Handover Request message
+ return ''
+ if ((handover.my_crn & 1) == (handover.peer_crn & 1) and \
+ handover.my_crn > handover.peer_crn) or \
+ ((handover.my_crn & 1) != (handover.peer_crn & 1) and \
+ handover.my_crn < handover.peer_crn):
+ summary("I'm the Handover Selector Device")
+ handover.i_m_selector = True
+ else:
+ summary("Peer is the Handover Selector device")
+ summary("Ignore the received request.")
+ return ''
+
+ hs = ndef.HandoverSelectRecord('1.4')
+ sel = [hs]
+
+ found = False
+
+ for carrier in records:
+ if isinstance(carrier, ndef.HandoverRequestRecord):
+ continue
+ summary("Remote carrier type: " + carrier.type)
+ if carrier.type == "application/vnd.wfa.dpp":
+ summary("DPP carrier type match - add DPP carrier record")
+ if len(carrier.data) == 0 or carrier.data[0] != 0:
+ summary("URI Identifier Code 'None' not seen", color=C_RED)
+ continue
+ uri = carrier.data[1:].decode("utf-8")
+ summary("Received DPP URI: " + uri)
+
+ global test_uri, test_alt_uri
+ if test_uri:
+ summary("TEST MODE: Using specified URI")
+ data = test_sel_uri if test_sel_uri else test_uri
+ elif handover.alt_proposal and handover.altchanlist:
+ summary("Use alternative channel list while processing alternative proposal from peer")
+ data = wpas_get_nfc_uri(start_listen=False,
+ chan_override=handover.altchanlist,
+ pick_channel=True)
+ else:
+ data = wpas_get_nfc_uri(start_listen=False,
+ pick_channel=True)
+ summary("Own URI (pre-processing): %s" % data)
+
+ if test_uri:
+ summary("TEST MODE: Fake processing")
+ res = "OK"
+ data += " [%s]" % uri
+ else:
+ res = wpas_report_handover_req(uri)
+ if res is None or "FAIL" in res:
+ summary("DPP handover request processing failed",
+ color=C_RED)
+ if handover.altchanlist:
+ data = wpas_get_nfc_uri(start_listen=False,
+ chan_override=handover.altchanlist)
+ summary("Own URI (try another channel list): %s" % data)
+ continue
+
+ if test_alt_uri:
+ summary("TEST MODE: Reject initial proposal")
+ continue
+
+ found = True
+
+ if not test_uri:
+ 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
+ summary("Own URI (post-processing): %s" % data)
+ handover.my_uri = data
+ handover.peer_uri = uri
+ uri = ndef.UriRecord(data)
+ summary("Own bootstrapping NFC URI record: " + str(uri))
+
+ if not test_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 or freq == 0:
+ summary("No channel negotiated over NFC - use channel 6")
+ freq = 2437
+ else:
+ summary("Negotiated channel: %d MHz" % freq)
+ if not dpp_start_listen(wpas, freq):
+ break
+
+ carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+ summary("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:
+ summary("Handover completed successfully")
+ handover.terminate_on_hs_send_completion = True
+ self.success = True
+ handover.hs_sent = True
+ handover.i_m_selector = True
+ elif handover.no_alt_proposal:
+ summary("Do not try alternative proposal anymore - handover failed",
+ color=C_RED)
+ handover.hs_sent = True
+ else:
+ summary("Try to initiate with alternative parameters")
+ handover.try_own = True
+ handover.hs_sent = False
+ handover.no_alt_proposal = True
+ if handover.client_thread:
+ handover.start_client_alt = True
+ else:
+ handover.client_thread = threading.Thread(target=llcp_worker,
+ args=(self.llc, True))
+ handover.client_thread.start()
+ 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:
+ summary(record)
+ summary("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):
+ summary("URI record: uri=" + record.uri)
+ summary("URI record: iri=" + record.iri)
+ if record.iri.startswith("DPP:"):
+ summary("DPP URI")
+ if not dpp_nfc_uri_process(record.iri):
+ break
+ success = True
+ else:
+ summary("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:
+ summary("Not a formatted NDEF tag", color=C_RED)
+ return
+ if not tag.ndef.is_writeable:
+ summary("Not a writable tag", color=C_RED)
+ return
+ global dpp_tag_data
+ if tag.ndef.capacity < len(dpp_tag_data):
+ summary("Not enough room for the message")
+ return
+ try:
+ tag.ndef.records = dpp_tag_data
+ except ValueError as e:
+ summary("Writing the tag failed: %s" % str(e), color=C_RED)
+ return
+ success_report("Tag write succeeded")
+ summary("Tag writing completed - remove tag", color=C_GREEN)
+ global only_one, operation_success
+ operation_success = True
+ 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):
+ summary("Write NFC URI record")
+ data = wpas_get_nfc_uri()
+ if data is None:
+ summary("Could not get NFC URI from wpa_supplicant", color=C_RED)
+ return
+
+ global dpp_sel_wait_remove
+ dpp_sel_wait_remove = wait_remove
+ summary("URI: %s" % data)
+ uri = ndef.UriRecord(data)
+ summary(uri)
+
+ summary("Touch an NFC tag to write URI record", color=C_CYAN)
+ 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):
+ summary("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", color=C_RED)
+ return
+
+ global dpp_sel_wait_remove
+ dpp_sel_wait_remove = wait_remove
+ summary("URI: %s" % data)
+ uri = ndef.UriRecord(data)
+ summary(uri)
+ carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+ hs = ndef.HandoverSelectRecord('1.4')
+ hs.add_alternative_carrier('active', carrier.name)
+ summary(hs)
+ summary(carrier)
+
+ summary("Touch an NFC tag to write HS record", color=C_CYAN)
+ global dpp_tag_data
+ dpp_tag_data = [hs, carrier]
+ summary(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:
+ summary("NDEF tag: " + tag.type)
+ summary(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", color=C_RED)
+ return True
+
+ return not no_wait
+
+def llcp_worker(llc, try_alt):
+ global handover
+ print("Start of llcp_worker()")
+ if try_alt:
+ summary("Starting handover client (try_alt)")
+ dpp_handover_client(handover, alt=True)
+ summary("Exiting llcp_worker thread (try_alt)")
+ return
+ global init_on_touch
+ if init_on_touch:
+ summary("Starting handover client (init_on_touch)")
+ dpp_handover_client(handover)
+ summary("Exiting llcp_worker thread (init_on_touch)")
+ return
+
+ global no_input
+ if no_input:
+ summary("Wait for handover to complete")
+ else:
+ print("Wait for handover to complete - press 'i' to initiate")
+ while not handover.wait_connection and handover.srv.sent_carrier is None:
+ if handover.try_own:
+ handover.try_own = False
+ summary("Try to initiate another handover with own parameters")
+ handover.my_crn_ready = False
+ handover.my_crn = None
+ handover.peer_crn = None
+ handover.hs_sent = False
+ dpp_handover_client(handover, alt=True)
+ summary("Exiting llcp_worker thread (retry with own parameters)")
+ return
+ if handover.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()
+ summary("Starting handover client")
+ dpp_handover_client(handover)
+ summary("Exiting llcp_worker thread (manual init)")
+ return
+
+ global in_raw_mode
+ was_in_raw_mode = in_raw_mode
+ clear_raw_mode()
+ if was_in_raw_mode:
+ print("\r")
+ summary("Exiting llcp_worker thread")
+
+class ConnectionHandover():
+ def __init__(self):
+ self.client = None
+ self.client_thread = None
+ self.reset()
+ self.exit_thread = None
+
+ def reset(self):
+ self.wait_connection = False
+ self.my_crn_ready = False
+ self.my_crn = None
+ self.peer_crn = None
+ self.hs_sent = False
+ self.no_alt_proposal = False
+ self.alt_proposal_used = False
+ self.i_m_selector = False
+ self.start_client_alt = False
+ self.terminate_on_hs_send_completion = False
+ self.try_own = False
+ self.my_uri = None
+ self.peer_uri = None
+ self.connected = False
+ self.alt_proposal = False
+
+ def start_handover_server(self, llc):
+ summary("Start handover server")
+ self.llc = llc
+ self.srv = HandoverServer(self, llc)
+
+ def close(self):
+ if self.client:
+ self.client.close()
+ self.client = None
+
+ def run_delayed_exit(self):
+ summary("Trying to exit (delayed)..")
+ time.sleep(0.25)
+ summary("Trying to exit (after wait)..")
+ global terminate_now
+ terminate_now = True
+
+ def delayed_exit(self):
+ global only_one
+ if only_one:
+ self.exit_thread = threading.Thread(target=self.run_delayed_exit)
+ self.exit_thread.start()
+
+def llcp_startup(llc):
+ global handover
+ handover.start_handover_server(llc)
+ return llc
+
+def llcp_connected(llc):
+ summary("P2P LLCP connected")
+ global handover
+ handover.connected = True
+ handover.srv.start()
+ if init_on_touch or not no_input:
+ handover.client_thread = threading.Thread(target=llcp_worker,
+ args=(llc, False))
+ handover.client_thread.start()
+ return True
+
+def llcp_release(llc):
+ summary("LLCP release")
+ global handover
+ handover.close()
+ 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('--enrollee', action='store_true',
+ help='run as Enrollee-only')
+ parser.add_argument('--configurator', action='store_true',
+ help='run as Configurator-only')
+ parser.add_argument('--config-params', default='',
+ help='configurator parameters')
+ parser.add_argument('--ctrl', default='/var/run/wpa_supplicant',
+ help='wpa_supplicant/hostapd control interface')
+ 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=None, help='channel list')
+ parser.add_argument('--altchan', default=None, help='alternative channel list')
+ parser.add_argument('--netrole', default=None, help='netrole for Enrollee')
+ parser.add_argument('--test-uri', default=None,
+ help='test mode: initial URI')
+ parser.add_argument('--test-alt-uri', default=None,
+ help='test mode: alternative URI')
+ parser.add_argument('--test-sel-uri', default=None,
+ help='test mode: handover select URI')
+ parser.add_argument('--test-crn', default=None,
+ help='test mode: hardcoded crn')
+ parser.add_argument('command', choices=['write-nfc-uri',
+ 'write-nfc-hs'],
+ nargs='?')
+ args = parser.parse_args()
+ summary(args)
+
+ global handover
+ handover = ConnectionHandover()
+
+ global only_one
+ only_one = args.only_one
+
+ global no_wait
+ no_wait = args.no_wait
+
+ global chanlist, netrole, test_uri, test_alt_uri, test_sel_uri
+ global test_crn
+ chanlist = args.chan
+ handover.altchanlist = args.altchan
+ netrole = args.netrole
+ test_uri = args.test_uri
+ test_alt_uri = args.test_alt_uri
+ test_sel_uri = args.test_sel_uri
+ if args.test_crn:
+ test_crn = struct.pack('>H', int(args.test_crn))
+ else:
+ test_crn = None
+
+ logging.basicConfig(level=args.loglevel)
+ for l in ['nfc.clf.rcs380',
+ 'nfc.clf.transport',
+ 'nfc.clf.device',
+ 'nfc.clf.__init__',
+ 'nfc.llcp',
+ 'nfc.handover']:
+ log = logging.getLogger(l)
+ log.setLevel(args.loglevel)
+
+ global init_on_touch
+ init_on_touch = args.init_on_touch
+
+ global enrollee_only
+ enrollee_only = args.enrollee
+
+ global configurator_only
+ configurator_only = args.configurator
+
+ global config_params
+ config_params = args.config_params
+
+ if args.ifname:
+ global ifname
+ ifname = args.ifname
+ summary("Selected ifname " + ifname)
+
+ if args.ctrl:
+ global wpas_ctrl
+ wpas_ctrl = args.ctrl
+
+ 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()
+
+ try:
+ if not clf.open(args.device):
+ summary("Could not open connection with an NFC device", color=C_RED)
+ raise SystemExit(1)
+
+ if args.command == "write-nfc-uri":
+ write_nfc_uri(clf, wait_remove=not args.no_wait)
+ if not operation_success:
+ raise SystemExit(1)
+ raise SystemExit
+
+ if args.command == "write-nfc-hs":
+ write_nfc_hs(clf, wait_remove=not args.no_wait)
+ if not operation_success:
+ raise SystemExit(1)
+ raise SystemExit
+
+ global continue_loop
+ while continue_loop:
+ global in_raw_mode
+ was_in_raw_mode = in_raw_mode
+ clear_raw_mode()
+ if was_in_raw_mode:
+ print("\r")
+ if args.handover_only:
+ summary("Waiting a peer to be touched", color=C_MAGENTA)
+ elif args.tag_read_only:
+ summary("Waiting for a tag to be touched", color=C_BLUE)
+ else:
+ summary("Waiting for a tag or peer to be touched",
+ color=C_GREEN)
+ handover.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:
+ summary("clf.connect failed: " + str(e))
+ break
+
+ if only_one and handover.connected:
+ role = "selector" if handover.i_m_selector else "requestor"
+ summary("Connection handover result: I'm the %s" % role,
+ color=C_YELLOW)
+ if handover.peer_uri:
+ summary("Peer URI: " + handover.peer_uri, color=C_YELLOW)
+ if handover.my_uri:
+ summary("My URI: " + handover.my_uri, color=C_YELLOW)
+ if not (handover.peer_uri and handover.my_uri):
+ summary("Negotiated connection handover failed",
+ color=C_YELLOW)
+ break
+
+ 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 6e3d94e..2f62e9c 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/gas_query.c b/wpa_supplicant/gas_query.c
index 8e977a3..e60a8c1 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -43,6 +43,7 @@ struct gas_query_pending {
unsigned int offchannel_tx_started:1;
unsigned int retry:1;
unsigned int wildcard_bssid:1;
+ unsigned int maintain_addr:1;
int freq;
u16 status_code;
struct wpabuf *req;
@@ -693,12 +694,15 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
return;
}
- if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
- wpa_msg(wpa_s, MSG_INFO,
- "Failed to assign random MAC address for GAS");
- gas_query_free(query, 1);
- radio_work_done(work);
- return;
+ if (!query->maintain_addr && !wpa_s->conf->gas_rand_mac_addr) {
+ if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to assign random MAC address for GAS");
+ gas_query_free(query, 1);
+ radio_work_done(work);
+ return;
+ }
+ os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN);
}
gas->work = work;
@@ -727,19 +731,24 @@ static void gas_query_tx_initial_req(struct gas_query *gas,
static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst)
{
- static int next_start = 0;
- int dialog_token;
-
- for (dialog_token = 0; dialog_token < 256; dialog_token++) {
- if (gas_query_dialog_token_available(
- gas, dst, (next_start + dialog_token) % 256))
+ u8 dialog_token;
+ int i;
+
+ /* There should never be more than couple active GAS queries in
+ * progress, so it should be very likely to find an available dialog
+ * token by checking random values. Use a limit on the number of
+ * iterations to handle the unexpected case of large number of pending
+ * queries cleanly. */
+ for (i = 0; i < 256; i++) {
+ /* Get a random number and check if the slot is available */
+ if (os_get_random(&dialog_token, sizeof(dialog_token)) < 0)
break;
+ if (gas_query_dialog_token_available(gas, dst, dialog_token))
+ return dialog_token;
}
- if (dialog_token == 256)
- return -1; /* Too many pending queries */
- dialog_token = (next_start + dialog_token) % 256;
- next_start = (dialog_token + 1) % 256;
- return dialog_token;
+
+ /* No dialog token value available */
+ return -1;
}
@@ -749,12 +758,23 @@ static int gas_query_set_sa(struct gas_query *gas,
struct wpa_supplicant *wpa_s = gas->wpa_s;
struct os_reltime now;
- if (!wpa_s->conf->gas_rand_mac_addr ||
+ if (query->maintain_addr ||
+ !wpa_s->conf->gas_rand_mac_addr ||
!(wpa_s->current_bss ?
(wpa_s->drv_flags &
WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED) :
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA))) {
/* Use own MAC address as the transmitter address */
+ wpa_printf(MSG_DEBUG,
+ "GAS: Use own MAC address as the transmitter address%s%s%s",
+ query->maintain_addr ? " (maintain_addr)" : "",
+ !wpa_s->conf->gas_rand_mac_addr ? " (no gas_rand_mac_adr set)" : "",
+ !(wpa_s->current_bss ?
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED) :
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA)) ?
+ " (no driver rand capa" : "");
os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN);
return 0;
}
@@ -800,6 +820,9 @@ static int gas_query_set_sa(struct gas_query *gas,
* @gas: GAS query data from gas_query_init()
* @dst: Destination MAC address for the query
* @freq: Frequency (in MHz) for the channel on which to send the query
+ * @wildcard_bssid: Force use of wildcard BSSID value
+ * @maintain_addr: Maintain own MAC address for exchange (i.e., ignore MAC
+ * address randomization rules)
* @req: GAS query payload (to be freed by gas_query module in case of success
* return)
* @cb: Callback function for reporting GAS query result and response
@@ -807,7 +830,7 @@ static int gas_query_set_sa(struct gas_query *gas,
* Returns: dialog token (>= 0) on success or -1 on failure
*/
int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
- int wildcard_bssid, struct wpabuf *req,
+ int wildcard_bssid, int maintain_addr, struct wpabuf *req,
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
@@ -829,6 +852,7 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
return -1;
query->gas = gas;
+ query->maintain_addr = !!maintain_addr;
if (gas_query_set_sa(gas, query)) {
os_free(query);
return -1;
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
index d2b4554..f9ce7b6 100644
--- a/wpa_supplicant/gas_query.h
+++ b/wpa_supplicant/gas_query.h
@@ -35,7 +35,7 @@ enum gas_query_result {
};
int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
- int wildcard_bssid, struct wpabuf *req,
+ int wildcard_bssid, int maintain_addr, struct wpabuf *req,
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index cb236df..3bf777e 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -288,7 +288,8 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, 0, buf, anqp_resp_cb,
+ wpa_s);
if (res < 0) {
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
wpabuf_free(buf);
@@ -340,7 +341,7 @@ int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
{
struct icon_entry *icon;
size_t out_size;
- unsigned char *b64;
+ char *b64;
size_t b64_size;
int reply_size;
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 6934c47..02e6390 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);
@@ -111,6 +117,7 @@ static int supp_get_beacon_ie(void *ctx)
wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
/* TODO: get correct RSN IE */
+ wpa_sm_set_ap_rsnxe(peer->supp, NULL, 0);
return wpa_sm_set_ap_rsn_ie(peer->supp,
(u8 *) "\x30\x14\x01\x00"
"\x00\x0f\xac\x04"
@@ -139,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;
@@ -166,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);
}
@@ -193,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__);
}
@@ -218,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");
@@ -286,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);
@@ -295,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];
@@ -334,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);
}
@@ -464,7 +483,7 @@ static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn,
"\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x02"
- "\x00\x00", 22, NULL, 0, NULL, 0) !=
+ "\x00\x00", 22, NULL, 0, NULL, 0, NULL, 0) !=
WPA_IE_OK) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
return -1;
@@ -486,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,
@@ -504,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);
}
@@ -851,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/interworking.c b/wpa_supplicant/interworking.c
index 0261bb7..00e1492 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -176,7 +176,7 @@ static int cred_with_nai_realm(struct wpa_supplicant *wpa_s)
continue;
if (!cred->eap_method)
return 1;
- if (cred->realm && cred->roaming_consortium_len == 0)
+ if (cred->realm)
return 1;
}
return 0;
@@ -316,7 +316,7 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, 0, buf,
+ res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, 0, 0, buf,
interworking_anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
@@ -946,7 +946,8 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
struct wpa_driver_capa capa;
res = wpa_drv_get_capa(wpa_s, &capa);
- if (res == 0 && capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) {
+ if (res == 0 && capa.key_mgmt_iftype[WPA_IF_STATION] &
+ WPA_DRIVER_CAPA_KEY_MGMT_FT) {
key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
"WPA-EAP WPA-EAP-SHA256 FT-EAP" :
"WPA-EAP FT-EAP";
@@ -958,7 +959,9 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
"WPA-EAP WPA-EAP-SHA256" : "WPA-EAP";
if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 ||
wpa_config_set(ssid, "proto", "RSN", 0) < 0 ||
- wpa_config_set(ssid, "ieee80211w", "1", 0) < 0 ||
+ wpa_config_set(ssid, "ieee80211w",
+ wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_REQUIRED ?
+ "2" : "1", 0) < 0 ||
wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
return -1;
return 0;
@@ -2262,7 +2265,7 @@ int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
realm++;
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Search for match with SIM/USIM domain %s",
- realm);
+ realm ? realm : "[NULL]");
if (realm &&
domain_name_list_contains(domain_names, realm, 1))
return 1;
@@ -2747,27 +2750,27 @@ void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
}
-int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, int freq,
u16 info_ids[], size_t num_ids, u32 subtypes,
u32 mbo_subtypes)
{
struct wpabuf *buf;
struct wpabuf *extra_buf = NULL;
int ret = 0;
- int freq;
struct wpa_bss *bss;
int res;
bss = wpa_bss_get_bssid(wpa_s, dst);
- if (!bss) {
+ if (!bss && !freq) {
wpa_printf(MSG_WARNING,
- "ANQP: Cannot send query to unknown BSS "
- MACSTR, MAC2STR(dst));
+ "ANQP: Cannot send query without BSS freq info");
return -1;
}
- wpa_bss_anqp_unshare_alloc(bss);
- freq = bss->freq;
+ if (bss)
+ wpa_bss_anqp_unshare_alloc(bss);
+ if (bss && !freq)
+ freq = bss->freq;
wpa_msg(wpa_s, MSG_DEBUG,
"ANQP: Query Request to " MACSTR " for %u id(s)",
@@ -2786,6 +2789,13 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
if (mbo_subtypes) {
struct wpabuf *mbo;
+ if (!bss) {
+ wpa_printf(MSG_WARNING,
+ "ANQP: Cannot send MBO query to unknown BSS "
+ MACSTR, MAC2STR(dst));
+ return -1;
+ }
+
mbo = mbo_build_anqp_buf(wpa_s, bss, mbo_subtypes);
if (mbo) {
if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) {
@@ -2804,7 +2814,8 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, 0, buf, anqp_resp_cb,
+ wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
wpabuf_free(buf);
@@ -3243,7 +3254,8 @@ int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
} else
wpabuf_put_le16(buf, 0);
- res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, gas_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, 0, buf, gas_resp_cb,
+ wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
wpabuf_free(buf);
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index 37ee2e9..77b2c91 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -11,7 +11,7 @@
enum gas_query_result;
-int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, int freq,
u16 info_ids[], size_t num_ids, u32 subtypes,
u32 mbo_subtypes);
void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 5c1a47d..c085466 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -114,8 +114,14 @@ static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s,
}
conf->group_cipher = cipher;
- if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
- conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ if (ssid->group_mgmt_cipher == WPA_CIPHER_BIP_GMAC_128 ||
+ ssid->group_mgmt_cipher == WPA_CIPHER_BIP_GMAC_256 ||
+ ssid->group_mgmt_cipher == WPA_CIPHER_BIP_CMAC_256)
+ conf->mgmt_group_cipher = ssid->group_mgmt_cipher;
+ else
+ conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+ }
/* defaults */
conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
@@ -262,6 +268,7 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
return -ENOMEM;
ifmsh->drv_flags = wpa_s->drv_flags;
+ ifmsh->drv_flags2 = wpa_s->drv_flags2;
ifmsh->num_bss = 1;
ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
sizeof(struct hostapd_data *));
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 4a163b6..4547eea 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -147,13 +147,13 @@ static u16 copy_supp_rates(struct wpa_supplicant *wpa_s,
/* return true if elems from a neighbor match this MBSS */
-static Boolean matches_local(struct wpa_supplicant *wpa_s,
- struct ieee802_11_elems *elems)
+static bool matches_local(struct wpa_supplicant *wpa_s,
+ struct ieee802_11_elems *elems)
{
struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
if (elems->mesh_config_len < 5)
- return FALSE;
+ return false;
return (mconf->meshid_len == elems->mesh_id_len &&
os_memcmp(mconf->meshid, elems->mesh_id,
@@ -167,17 +167,17 @@ static Boolean matches_local(struct wpa_supplicant *wpa_s,
/* check if local link id is already used with another peer */
-static Boolean llid_in_use(struct wpa_supplicant *wpa_s, u16 llid)
+static bool llid_in_use(struct wpa_supplicant *wpa_s, u16 llid)
{
struct sta_info *sta;
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (sta->my_lid == llid)
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -231,14 +231,12 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
2 + 32 + /* mesh ID */
2 + 7 + /* mesh config */
2 + 24 + /* peering management */
- 2 + 96 + /* AMPE */
+ 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];
@@ -537,6 +533,8 @@ static int mesh_mpm_plink_close(struct hostapd_data *hapd, struct sta_info *sta,
int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
if (sta) {
+ if (sta->plink_state == PLINK_ESTAB)
+ hapd->num_plinks--;
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
wpa_printf(MSG_DEBUG, "MPM closing plink sta=" MACSTR,
@@ -696,9 +694,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 +706,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 +725,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 +738,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 +871,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 +881,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 +894,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);
}
}
@@ -1294,8 +1292,8 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
tx_chanwidth, tx_seg1_idx) !=
- 0) {
- wpa_printf(MSG_WARNING, "MPM: %s",
+ OCI_SUCCESS) {
+ wpa_printf(MSG_WARNING, "MPM: OCV failed: %s",
ocv_errorstr);
return;
}
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index e730b63..f19bfbf 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 b74be7d..e40cf5b 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 5c103ec..bd97fee 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -14,15 +14,22 @@
#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, u8 chan,
+static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode,
+ u8 op_class, u8 chan,
unsigned int *flags)
{
int i;
+ int is_6ghz = op_class >= 131 && op_class <= 136;
for (i = 0; i < mode->num_channels; i++) {
- if (mode->channels[i].chan == chan)
+ int chan_is_6ghz;
+
+ chan_is_6ghz = mode->channels[i].freq >= 5935 &&
+ mode->channels[i].freq <= 7115;
+ if (is_6ghz == chan_is_6ghz && mode->channels[i].chan == chan)
break;
}
@@ -62,7 +69,8 @@ static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
}
-static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode,
+ u8 op_class, u8 channel)
{
u8 center_chan;
unsigned int i;
@@ -77,7 +85,8 @@ static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
unsigned int flags;
u8 adj_chan = center_chan - 6 + i * 4;
- if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ if (allow_channel(mode, op_class, adj_chan, &flags) ==
+ NOT_ALLOWED)
return NOT_ALLOWED;
if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
@@ -120,7 +129,7 @@ static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
- u8 channel)
+ u8 op_class, u8 channel)
{
u8 center_chan;
unsigned int i;
@@ -135,7 +144,8 @@ static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
unsigned int flags;
u8 adj_chan = center_chan - 14 + i * 4;
- if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ if (allow_channel(mode, op_class, adj_chan, &flags) ==
+ NOT_ALLOWED)
return NOT_ALLOWED;
if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
@@ -159,42 +169,42 @@ static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
}
-enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
- u8 bw)
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
+ u8 channel, u8 bw)
{
unsigned int flag = 0;
enum chan_allowed res, res2;
- res2 = res = allow_channel(mode, channel, &flag);
+ res2 = res = allow_channel(mode, op_class, channel, &flag);
if (bw == BW40MINUS) {
if (!(flag & HOSTAPD_CHAN_HT40MINUS))
return NOT_ALLOWED;
- res2 = allow_channel(mode, channel - 4, NULL);
+ res2 = allow_channel(mode, op_class, channel - 4, NULL);
} else if (bw == BW40PLUS) {
if (!(flag & HOSTAPD_CHAN_HT40PLUS))
return NOT_ALLOWED;
- res2 = allow_channel(mode, channel + 4, NULL);
+ res2 = allow_channel(mode, op_class, channel + 4, NULL);
} else if (bw == BW80) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 80 MHz specific version.
*/
- res2 = res = verify_80mhz(mode, channel);
+ res2 = res = verify_80mhz(mode, op_class, channel);
} else if (bw == BW160) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 160 MHz specific version.
*/
- res2 = res = verify_160mhz(mode, channel);
+ res2 = res = verify_160mhz(mode, op_class, channel);
} else if (bw == BW80P80) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 80 MHz specific version.
*/
- res2 = res = verify_80mhz(mode, channel);
+ res2 = res = verify_80mhz(mode, op_class, channel);
}
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -219,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;
@@ -284,7 +295,8 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
u8 channels[] = { 42, 58, 106, 122, 138, 155 };
for (i = 0; i < ARRAY_SIZE(channels); i++) {
- if (verify_channel(mode, channels[i], op_class->bw) !=
+ if (verify_channel(mode, op_class->op_class,
+ channels[i], op_class->bw) !=
NOT_ALLOWED)
return 1;
}
@@ -294,25 +306,35 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
if (op_class->op_class == 129) {
/* Check if either 160 MHz channels is allowed */
- return verify_channel(mode, 50, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 114, op_class->bw) != NOT_ALLOWED;
+ return verify_channel(mode, op_class->op_class, 50,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 114,
+ op_class->bw) != NOT_ALLOWED;
}
if (op_class->op_class == 130) {
/* Need at least two non-contiguous 80 MHz segments */
found = 0;
- if (verify_channel(mode, 42, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 58, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 42,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 58,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 122, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 106,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 122,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 138,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED &&
- verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 106,
+ op_class->bw) != NOT_ALLOWED &&
+ verify_channel(mode, op_class->op_class, 138,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 155, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 155,
+ op_class->bw) != NOT_ALLOWED)
found++;
if (found >= 2)
@@ -324,7 +346,8 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
found = 0;
for (chan = op_class->min_chan; chan <= op_class->max_chan;
chan += op_class->inc) {
- if (verify_channel(mode, chan, op_class->bw) != NOT_ALLOWED) {
+ if (verify_channel(mode, op_class->op_class, chan,
+ op_class->bw) != NOT_ALLOWED) {
found = 1;
break;
}
@@ -334,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;
@@ -344,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 55b3b08..e94bffe 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1885,6 +1885,83 @@ static void p2p_go_configured(void *ctx, void *data)
}
+/**
+ * wpas_p2p_freq_to_edmg_channel - Convert frequency into EDMG channel
+ * @freq: Frequency (MHz) to convert
+ * @op_class: Buffer for returning operating class
+ * @op_edmg_channel: Buffer for returning channel number
+ * Returns: 0 on success, -1 on failure
+ *
+ * This can be used to find the highest channel bonding which includes the
+ * specified frequency.
+ */
+static int wpas_p2p_freq_to_edmg_channel(struct wpa_supplicant *wpa_s,
+ unsigned int freq,
+ u8 *op_class, u8 *op_edmg_channel)
+{
+ struct hostapd_hw_modes *hwmode;
+ struct ieee80211_edmg_config edmg;
+ unsigned int i;
+ enum chan_width chanwidth[] = {
+ CHAN_WIDTH_8640,
+ CHAN_WIDTH_6480,
+ CHAN_WIDTH_4320,
+ };
+
+ if (!wpa_s->hw.modes)
+ return -1;
+
+ hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211AD, 0);
+ if (!hwmode) {
+ wpa_printf(MSG_ERROR,
+ "Unsupported AP mode: HOSTAPD_MODE_IEEE80211AD");
+ return -1;
+ }
+
+ /* Find the highest EDMG channel bandwidth to start the P2P GO */
+ for (i = 0; i < ARRAY_SIZE(chanwidth); i++) {
+ if (ieee80211_chaninfo_to_channel(freq, chanwidth[i], 0,
+ op_class,
+ op_edmg_channel) < 0)
+ continue;
+
+ hostapd_encode_edmg_chan(1, *op_edmg_channel, 0, &edmg);
+ if (edmg.channels &&
+ ieee802_edmg_is_allowed(hwmode->edmg, edmg)) {
+ wpa_printf(MSG_DEBUG,
+ "Freq %u to EDMG channel %u at opclass %u",
+ freq, *op_edmg_channel, *op_class);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+int wpas_p2p_try_edmg_channel(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *params)
+{
+ u8 op_channel, op_class;
+ int freq;
+
+ /* Try social channel as primary channel frequency */
+ freq = (!params->freq) ? 58320 + 1 * 2160 : params->freq;
+
+ if (wpas_p2p_freq_to_edmg_channel(wpa_s, freq, &op_class,
+ &op_channel) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "Freq %d will be used to set an EDMG connection (channel=%u opclass=%u)",
+ freq, op_channel, op_class);
+ params->freq = freq;
+ return 0;
+ }
+
+ return -1;
+}
+
+
static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
int group_formation)
@@ -1921,6 +1998,20 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
ssid->max_oper_chwidth = params->max_oper_chwidth;
ssid->vht_center_freq2 = params->vht_center_freq2;
ssid->he = params->he;
+ if (params->edmg) {
+ u8 op_channel, op_class;
+
+ if (!wpas_p2p_freq_to_edmg_channel(wpa_s, params->freq,
+ &op_class, &op_channel)) {
+ ssid->edmg_channel = op_channel;
+ ssid->enable_edmg = params->edmg;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Could not match EDMG channel, freq %d, for GO",
+ params->freq);
+ }
+ }
+
ssid->ssid = os_zalloc(params->ssid_len + 1);
if (ssid->ssid) {
os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -2270,6 +2361,8 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
res->vht = 1;
if (wpa_s->p2p_go_he)
res->he = 1;
+ if (wpa_s->p2p_go_edmg)
+ res->edmg = 1;
res->max_oper_chwidth = wpa_s->p2p_go_max_oper_chwidth;
res->vht_center_freq2 = wpa_s->p2p_go_vht_center_freq2;
@@ -2329,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);
@@ -2598,7 +2691,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);
}
@@ -3089,7 +3182,12 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
MAC2STR(sa), s->id);
}
wpas_p2p_group_add_persistent(
- wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, 0, NULL,
+ wpa_s, s, go, 0, op_freq, 0,
+ wpa_s->conf->p2p_go_ht40,
+ wpa_s->conf->p2p_go_vht,
+ 0,
+ wpa_s->conf->p2p_go_he,
+ wpa_s->conf->p2p_go_edmg, NULL,
go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0,
1);
} else if (bssid) {
@@ -3316,6 +3414,7 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
wpa_s->p2p_go_he,
+ wpa_s->p2p_go_edmg,
channels,
ssid->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
@@ -3560,6 +3659,20 @@ static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s,
}
+static enum chan_allowed wpas_p2p_verify_edmg(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel)
+{
+ struct ieee80211_edmg_config edmg;
+
+ hostapd_encode_edmg_chan(1, channel, 0, &edmg);
+ if (edmg.channels && ieee802_edmg_is_allowed(mode->edmg, edmg))
+ return ALLOWED;
+
+ return NOT_ALLOWED;
+}
+
+
static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode,
u8 channel, u8 bw)
@@ -3580,6 +3693,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
} else if (bw == BW160) {
res2 = wpas_p2p_verify_160mhz(wpa_s, mode, channel, bw);
+ } else if (bw == BW4320 || bw == BW6480 || bw == BW8640) {
+ return wpas_p2p_verify_edmg(wpa_s, mode, channel);
}
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -3614,7 +3729,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)
@@ -3624,23 +3740,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++;
}
@@ -4230,14 +4355,14 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
if (response_done && persistent_go) {
wpas_p2p_group_add_persistent(
wpa_s, persistent_go,
- 0, 0, freq, 0, 0, 0, 0, 0, NULL,
+ 0, 0, freq, 0, 0, 0, 0, 0, 0, NULL,
persistent_go->mode ==
WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
0, 0);
} else if (response_done) {
wpas_p2p_group_add(wpa_s, 1, freq,
- 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, 0, 0);
}
if (passwd_id == DEV_PW_P2PS_DEFAULT) {
@@ -4353,11 +4478,12 @@ static int wpas_prov_disc_resp_cb(void *ctx)
if (persistent_go) {
wpas_p2p_group_add_persistent(
- wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, 0, NULL,
+ wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ NULL,
persistent_go->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0);
} else {
- wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0);
+ wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0);
}
return 1;
@@ -4638,7 +4764,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);
@@ -4942,6 +5068,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
wpa_s->p2p_go_he,
+ wpa_s->p2p_go_edmg,
NULL, 0);
return;
}
@@ -5490,8 +5617,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
int persistent_group, int auto_join, int join, int auth,
int go_intent, int freq, unsigned int vht_center_freq2,
int persistent_id, int pd, int ht40, int vht,
- unsigned int vht_chwidth, int he, const u8 *group_ssid,
- size_t group_ssid_len)
+ unsigned int vht_chwidth, int he, int edmg,
+ const u8 *group_ssid, size_t group_ssid_len)
{
int force_freq = 0, pref_freq = 0;
int ret = 0, res;
@@ -5522,7 +5649,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;
@@ -5536,6 +5663,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
wpa_s->p2p_go_max_oper_chwidth = vht_chwidth;
wpa_s->p2p_go_he = !!he;
+ wpa_s->p2p_go_edmg = !!edmg;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -5691,19 +5819,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
@@ -5960,6 +6089,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
int freq, int vht_center_freq2, int ht40,
int vht, int max_oper_chwidth, int he,
+ int edmg,
const struct p2p_channels *channels)
{
struct wpa_used_freq_data *freqs;
@@ -5975,6 +6105,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
params->he = he;
params->max_oper_chwidth = max_oper_chwidth;
params->vht_center_freq2 = vht_center_freq2;
+ params->edmg = edmg;
freqs = os_calloc(wpa_s->num_multichan_concurrent,
sizeof(struct wpa_used_freq_data));
@@ -6005,6 +6136,13 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
}
}
+ /* Try to use EDMG channel */
+ if (params->edmg) {
+ if (wpas_p2p_try_edmg_channel(wpa_s, params) == 0)
+ goto success;
+ params->edmg = 0;
+ }
+
/* try using the forced freq */
if (freq) {
if (wpas_p2p_disallowed_freq(wpa_s->global, freq) ||
@@ -6167,7 +6305,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)
@@ -6194,7 +6332,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 ||
@@ -6322,6 +6460,7 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
* @ht40: Start GO with 40 MHz channel width
* @vht: Start GO with VHT support
* @vht_chwidth: channel bandwidth for GO operating with VHT support
+ * @edmg: Start GO with EDMG support
* Returns: 0 on success, -1 on failure
*
* This function creates a new P2P group with the local end as the Group Owner,
@@ -6329,7 +6468,7 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
*/
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int vht_center_freq2, int ht40, int vht,
- int max_oper_chwidth, int he)
+ int max_oper_chwidth, int he, int edmg)
{
struct p2p_go_neg_results params;
@@ -6350,7 +6489,8 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
}
if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
- ht40, vht, max_oper_chwidth, he, NULL))
+ ht40, vht, max_oper_chwidth, he, edmg,
+ NULL))
return -1;
p2p_go_params(wpa_s->global->p2p, &params);
@@ -6430,6 +6570,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
int force_freq, int neg_freq,
int vht_center_freq2, int ht40,
int vht, int max_oper_chwidth, int he,
+ int edmg,
const struct p2p_channels *channels,
int connection_timeout, int force_scan)
{
@@ -6505,7 +6646,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
}
if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
- ht40, vht, max_oper_chwidth, he, channels))
+ ht40, vht, max_oper_chwidth, he, edmg,
+ channels))
return -1;
params.role_go = 1;
@@ -6825,7 +6967,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) {
@@ -6870,7 +7012,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);
@@ -6896,7 +7038,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;
}
@@ -6925,7 +7067,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
@@ -6937,7 +7079,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);
@@ -7044,7 +7186,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;
@@ -7057,7 +7199,7 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
int vht_center_freq2, int ht40, int vht, int max_chwidth,
- int pref_freq, int he)
+ int pref_freq, int he, int edmg)
{
enum p2p_invite_role role;
u8 *bssid = NULL;
@@ -7078,6 +7220,7 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->p2p_go_he = !!he;
wpa_s->p2p_go_max_oper_chwidth = max_chwidth;
wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
+ wpa_s->p2p_go_edmg = !!edmg;
if (ssid->mode == WPAS_MODE_P2P_GO) {
role = P2P_INVITE_ROLE_GO;
if (peer_addr == NULL) {
@@ -7155,6 +7298,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
wpa_s->p2p_go_vht = 0;
wpa_s->p2p_go_vht_center_freq2 = 0;
wpa_s->p2p_go_max_oper_chwidth = 0;
+ wpa_s->p2p_go_edmg = 0;
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (os_strcmp(wpa_s->ifname, ifname) == 0)
@@ -8100,7 +8244,9 @@ static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
wpa_s->p2p_go_ht40,
wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
- wpa_s->p2p_go_he, NULL, 0);
+ wpa_s->p2p_go_he,
+ wpa_s->p2p_go_edmg,
+ NULL, 0);
return ret;
}
@@ -8636,7 +8782,7 @@ static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s,
WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent,
params->go_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
- wpa_s->p2p_go_he,
+ wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
params->go_ssid_len ? params->go_ssid : NULL,
params->go_ssid_len);
}
@@ -8716,7 +8862,8 @@ static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s,
WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent,
forced_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
- wpa_s->p2p_go_he, NULL, 0);
+ wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
+ NULL, 0);
}
@@ -8732,7 +8879,8 @@ static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s,
WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent,
forced_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
- wpa_s->p2p_go_he, NULL, 0);
+ wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
+ NULL, 0);
if (res)
return res;
@@ -9117,7 +9265,8 @@ static int wpas_p2p_move_go_csa(struct wpa_supplicant *wpa_s)
* TODO: This function may not always work correctly. For example,
* when we have a running GO and a BSS on a DFS channel.
*/
- if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, 0,
+ NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"P2P CSA: Failed to select new frequency for GO");
return -1;
@@ -9229,7 +9378,8 @@ static void wpas_p2p_move_go_no_csa(struct wpa_supplicant *wpa_s)
wpa_supplicant_ap_deinit(wpa_s);
/* Reselect the GO frequency */
- if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, 0,
+ NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Failed to reselect freq");
wpas_p2p_group_delete(wpa_s,
P2P_GROUP_REMOVAL_GO_LEAVE_CHANNEL);
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 24ec2ca..941198e 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -37,18 +37,18 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
int persistent_group, int auto_join, int join, int auth,
int go_intent, int freq, unsigned int vht_center_freq2,
int persistent_id, int pd, int ht40, int vht,
- unsigned int vht_chwidth, int he, const u8 *group_ssid,
- size_t group_ssid_len);
+ unsigned int vht_chwidth, int he, int edmg,
+ const u8 *group_ssid, size_t group_ssid_len);
int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
int freq, struct wpa_ssid *ssid);
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int vht_center_freq2, int ht40, int vht,
- int max_oper_chwidth, int he);
+ int max_oper_chwidth, int he, int edmg);
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
int force_freq, int neg_freq,
- int vht_center_freq2, int ht40,
- int vht, int max_oper_chwidth, int he,
+ int vht_center_freq2, int ht40, int vht,
+ int max_oper_chwidth, int he, int edmg,
const struct p2p_channels *channels,
int connection_timeout, int force_scan);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
@@ -116,8 +116,8 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
- int vht_center_freq2, int ht40, int vht,
- int max_oper_chwidth, int pref_freq, int he);
+ int vht_center_freq2, int ht40, int vht, int max_chwidth,
+ int pref_freq, int he, int edmg);
int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
const u8 *peer_addr, const u8 *go_dev_addr);
int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
@@ -165,6 +165,8 @@ int wpas_p2p_nfc_report_handover(struct wpa_supplicant *wpa_s, int init,
const struct wpabuf *sel, int forced_freq);
int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled);
void wpas_p2p_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx);
+int wpas_p2p_try_edmg_channel(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *params);
#ifdef CONFIG_P2P
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index 3f2da34..de49948 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,9 @@ 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,
+ int akmp)
{
printf("%s - not implemented\n", __func__);
return -1;
@@ -244,6 +253,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/robust_av.c b/wpa_supplicant/robust_av.c
new file mode 100644
index 0000000..4ac1a2b
--- /dev/null
+++ b/wpa_supplicant/robust_av.c
@@ -0,0 +1,157 @@
+/*
+ * wpa_supplicant - Robust AV procedures
+ * Copyright (c) 2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "common/wpa_ctrl.h"
+#include "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+
+
+void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
+ struct wpabuf *buf)
+{
+ u8 *len, *len1;
+
+ /* MSCS descriptor element */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ len = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_MSCS_DESCRIPTOR);
+ wpabuf_put_u8(buf, robust_av->request_type);
+ wpabuf_put_u8(buf, robust_av->up_bitmap);
+ wpabuf_put_u8(buf, robust_av->up_limit);
+ wpabuf_put_le32(buf, robust_av->stream_timeout);
+
+ if (robust_av->request_type != SCS_REQ_REMOVE) {
+ /* TCLAS mask element */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ len1 = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_TCLAS_MASK);
+
+ /* Frame classifier */
+ wpabuf_put_data(buf, robust_av->frame_classifier,
+ robust_av->frame_classifier_len);
+ *len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1;
+ }
+
+ *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
+}
+
+
+int wpas_send_mscs_req(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *buf;
+ const u8 *ext_capab = NULL;
+ size_t buf_len;
+ int ret;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
+ return 0;
+
+ if (wpa_s->current_bss)
+ ext_capab = wpa_bss_get_ie(wpa_s->current_bss,
+ WLAN_EID_EXT_CAPAB);
+
+ if (!ext_capab || ext_capab[1] < 11 || !(ext_capab[12] & 0x20)) {
+ wpa_dbg(wpa_s, MSG_INFO,
+ "AP does not support MSCS - could not send MSCS Req");
+ return -1;
+ }
+
+ if (!wpa_s->mscs_setup_done &&
+ wpa_s->robust_av.request_type != SCS_REQ_ADD) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "MSCS: Failed to send MSCS Request: request type invalid");
+ return -1;
+ }
+
+ buf_len = 3 + /* Action frame header */
+ 3 + /* MSCS descriptor IE header */
+ 1 + /* Request type */
+ 2 + /* User priority control */
+ 4 + /* Stream timeout */
+ 3 + /* TCLAS Mask IE header */
+ wpa_s->robust_av.frame_classifier_len;
+
+ buf = wpabuf_alloc(buf_len);
+ if (!buf) {
+ wpa_printf(MSG_ERROR, "Failed to allocate MSCS req");
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_ACTION_ROBUST_AV_STREAMING);
+ wpabuf_put_u8(buf, ROBUST_AV_MSCS_REQ);
+ wpa_s->robust_av.dialog_token++;
+ wpabuf_put_u8(buf, wpa_s->robust_av.dialog_token);
+
+ /* MSCS descriptor element */
+ wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, buf);
+
+ wpa_hexdump_buf(MSG_MSGDUMP, "MSCS Request", buf);
+ ret = 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 (ret < 0)
+ wpa_dbg(wpa_s, MSG_INFO, "MSCS: Failed to send MSCS Request");
+
+ wpabuf_free(buf);
+ return ret;
+}
+
+
+void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *buf, size_t len)
+{
+ u8 dialog_token;
+ u16 status_code;
+
+ if (len < 3)
+ return;
+
+ dialog_token = *buf++;
+ if (dialog_token != wpa_s->robust_av.dialog_token) {
+ wpa_printf(MSG_INFO,
+ "MSCS: Drop received frame due to dialog token mismatch: received:%u expected:%u",
+ dialog_token, wpa_s->robust_av.dialog_token);
+ return;
+ }
+
+ status_code = *buf;
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR
+ " status_code=%u", MAC2STR(src), status_code);
+ wpa_s->mscs_setup_done = status_code == WLAN_STATUS_SUCCESS;
+}
+
+
+void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const u8 *ies, size_t ies_len)
+{
+ const u8 *mscs_desc_ie, *mscs_status;
+ u16 status;
+
+ /* Process optional MSCS Status subelement when MSCS IE is in
+ * (Re)Association Response frame */
+ if (!ies || ies_len == 0 || !wpa_s->robust_av.valid_config)
+ return;
+
+ mscs_desc_ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_MSCS_DESCRIPTOR);
+ if (!mscs_desc_ie || mscs_desc_ie[1] < 1)
+ return;
+
+ mscs_status = get_ie(mscs_desc_ie, mscs_desc_ie[1],
+ MCSC_SUBELEM_STATUS);
+ if (!mscs_status || mscs_status[1] < 2)
+ return;
+
+ status = WPA_GET_LE16(mscs_status + 2);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR
+ " status_code=%u", MAC2STR(bssid), status);
+ wpa_s->mscs_setup_done = status == WLAN_STATUS_SUCCESS;
+}
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index e0723df..afc1172 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -79,7 +79,7 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
NULL);
if (!wpa_s->rrm.notify_neighbor_rep) {
- wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
+ wpa_msg(wpa_s, MSG_INFO, "RRM: Unexpected neighbor report");
return;
}
@@ -90,8 +90,8 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
return;
}
wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
- wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
- report[0]);
+ wpa_dbg(wpa_s, MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
+ report[0]);
wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
neighbor_rep);
wpa_s->rrm.notify_neighbor_rep = NULL;
@@ -148,12 +148,12 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
const u8 *rrm_ie;
if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
- wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
+ wpa_dbg(wpa_s, MSG_DEBUG, "RRM: No connection, no RRM.");
return -ENOTCONN;
}
if (!wpa_s->rrm.rrm_used) {
- wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
+ wpa_dbg(wpa_s, MSG_DEBUG, "RRM: No RRM in current connection.");
return -EOPNOTSUPP;
}
@@ -161,15 +161,15 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
WLAN_EID_RRM_ENABLED_CAPABILITIES);
if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
!(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
- wpa_printf(MSG_DEBUG,
- "RRM: No network support for Neighbor Report.");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: No network support for Neighbor Report.");
return -EOPNOTSUPP;
}
/* Refuse if there's a live request */
if (wpa_s->rrm.notify_neighbor_rep) {
- wpa_printf(MSG_DEBUG,
- "RRM: Currently handling previous Neighbor Report.");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Currently handling previous Neighbor Report.");
return -EBUSY;
}
@@ -178,14 +178,15 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
(lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) +
(civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0));
if (buf == NULL) {
- wpa_printf(MSG_DEBUG,
- "RRM: Failed to allocate Neighbor Report Request");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Failed to allocate Neighbor Report Request");
return -ENOMEM;
}
- wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
- (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
- wpa_s->rrm.next_neighbor_rep_token);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Neighbor report request (for %s), token=%d",
+ (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
+ wpa_s->rrm.next_neighbor_rep_token);
wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
@@ -267,8 +268,8 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
if (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) < 0) {
- wpa_printf(MSG_DEBUG,
- "RRM: Failed to send Neighbor Report Request");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Failed to send Neighbor Report Request");
wpabuf_free(buf);
return -ECANCELED;
}
@@ -528,7 +529,8 @@ static int * wpas_add_channels(const struct oper_class_map *op,
next_freq = freqs;
for (i = 0; i < num_chans; i++) {
u8 chan = channels ? channels[i] : op->min_chan + i * op->inc;
- enum chan_allowed res = verify_channel(mode, chan, op->bw);
+ enum chan_allowed res = verify_channel(mode, op->op_class, chan,
+ op->bw);
if (res == NOT_ALLOWED || (res == NO_IR && active))
continue;
@@ -607,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;
@@ -659,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;
@@ -691,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 7abb028..7415eae 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -79,6 +79,33 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_WPS */
+static int wpa_setup_mac_addr_rand_params(struct wpa_driver_scan_params *params,
+ const u8 *mac_addr)
+{
+ u8 *tmp;
+
+ if (params->mac_addr) {
+ params->mac_addr_mask = NULL;
+ os_free(params->mac_addr);
+ params->mac_addr = NULL;
+ }
+
+ params->mac_addr_rand = 1;
+
+ if (!mac_addr)
+ return 0;
+
+ tmp = os_malloc(2 * ETH_ALEN);
+ if (!tmp)
+ return -1;
+
+ os_memcpy(tmp, mac_addr, 2 * ETH_ALEN);
+ params->mac_addr = tmp;
+ params->mac_addr_mask = tmp + ETH_ALEN;
+ return 0;
+}
+
+
/**
* wpa_supplicant_enabled_networks - Check whether there are enabled networks
* @wpa_s: Pointer to wpa_supplicant data
@@ -169,6 +196,10 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
return;
}
+ if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(params, wpa_s->mac_addr_scan);
+
if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Failed to assign random MAC address for a scan");
@@ -637,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));
@@ -670,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);
}
@@ -1077,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 {
@@ -1211,20 +1245,16 @@ ssid_list_set:
#endif /* CONFIG_P2P */
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_scan) {
- params.mac_addr = wpa_s->mac_addr_scan;
- params.mac_addr_mask = wpa_s->mac_addr_scan + ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(&params, wpa_s->mac_addr_scan);
if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
struct wpa_bss *bss;
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;
@@ -1286,6 +1316,7 @@ scan:
wpabuf_free(extra_ie);
os_free(params.freqs);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
@@ -1300,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);
}
@@ -1664,20 +1696,16 @@ scan:
wpa_setband_scan_freqs(wpa_s, scan_params);
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_sched_scan) {
- params.mac_addr = wpa_s->mac_addr_sched_scan;
- params.mac_addr_mask = wpa_s->mac_addr_sched_scan +
- ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(&params,
+ wpa_s->mac_addr_sched_scan);
wpa_scan_set_relative_rssi_params(wpa_s, scan_params);
ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params);
wpabuf_free(extra_ie);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan");
if (prev_state != wpa_s->wpa_state)
@@ -1933,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)
@@ -2155,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) {
@@ -2181,86 +2187,111 @@ void scan_snr(struct wpa_scan_res *res)
}
-static unsigned int max_ht20_rate(int snr)
+/* Minimum SNR required to achieve a certain bitrate. */
+struct minsnr_bitrate_entry {
+ int minsnr;
+ unsigned int bitrate; /* in Mbps */
+};
+
+/* VHT needs to be enabled in order to achieve MCS8 and MCS9 rates. */
+static const int vht_mcs = 8;
+
+static const struct minsnr_bitrate_entry vht20_table[] = {
+ { 0, 0 },
+ { 2, 6500 }, /* HT20 MCS0 */
+ { 5, 13000 }, /* HT20 MCS1 */
+ { 9, 19500 }, /* HT20 MCS2 */
+ { 11, 26000 }, /* HT20 MCS3 */
+ { 15, 39000 }, /* HT20 MCS4 */
+ { 18, 52000 }, /* HT20 MCS5 */
+ { 20, 58500 }, /* HT20 MCS6 */
+ { 25, 65000 }, /* HT20 MCS7 */
+ { 29, 78000 }, /* VHT20 MCS8 */
+ { -1, 78000 } /* SNR > 29 */
+};
+
+static const struct minsnr_bitrate_entry vht40_table[] = {
+ { 0, 0 },
+ { 5, 13500 }, /* HT40 MCS0 */
+ { 8, 27000 }, /* HT40 MCS1 */
+ { 12, 40500 }, /* HT40 MCS2 */
+ { 14, 54000 }, /* HT40 MCS3 */
+ { 18, 81000 }, /* HT40 MCS4 */
+ { 21, 108000 }, /* HT40 MCS5 */
+ { 23, 121500 }, /* HT40 MCS6 */
+ { 28, 135000 }, /* HT40 MCS7 */
+ { 32, 162000 }, /* VHT40 MCS8 */
+ { 34, 180000 }, /* VHT40 MCS9 */
+ { -1, 180000 } /* SNR > 34 */
+};
+
+static const struct minsnr_bitrate_entry vht80_table[] = {
+ { 0, 0 },
+ { 8, 29300 }, /* VHT80 MCS0 */
+ { 11, 58500 }, /* VHT80 MCS1 */
+ { 15, 87800 }, /* VHT80 MCS2 */
+ { 17, 117000 }, /* VHT80 MCS3 */
+ { 21, 175500 }, /* VHT80 MCS4 */
+ { 24, 234000 }, /* VHT80 MCS5 */
+ { 26, 263300 }, /* VHT80 MCS6 */
+ { 31, 292500 }, /* VHT80 MCS7 */
+ { 35, 351000 }, /* VHT80 MCS8 */
+ { 37, 390000 }, /* VHT80 MCS9 */
+ { -1, 390000 } /* SNR > 37 */
+};
+
+
+static unsigned int interpolate_rate(int snr, int snr0, int snr1,
+ int rate0, int rate1)
+{
+ return rate0 + (snr - snr0) * (rate1 - rate0) / (snr1 - snr0);
+}
+
+
+static unsigned int max_rate(const struct minsnr_bitrate_entry table[],
+ int snr, bool 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 */
+ const struct minsnr_bitrate_entry *prev, *entry = table;
+
+ while ((entry->minsnr != -1) &&
+ (snr >= entry->minsnr) &&
+ (vht || entry - table <= vht_mcs))
+ entry++;
+ if (entry == table)
+ return entry->bitrate;
+ prev = entry - 1;
+ if (entry->minsnr == -1 || (!vht && entry - table > vht_mcs))
+ return prev->bitrate;
+ return interpolate_rate(snr, prev->minsnr, entry->minsnr, prev->bitrate,
+ entry->bitrate);
}
-static unsigned int max_ht40_rate(int snr)
+static unsigned int max_ht20_rate(int snr, bool 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 */
+ return max_rate(vht20_table, snr, vht);
+}
+
+
+static unsigned int max_ht40_rate(int snr, bool vht)
+{
+ return max_rate(vht40_table, snr, vht);
}
static unsigned int max_vht80_rate(int snr)
{
- if (snr < 1)
- 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 */
+ return max_rate(vht80_table, snr, 1);
}
-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)
@@ -2273,32 +2304,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, false);
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, false);
if (tmp > est)
est = tmp;
}
@@ -2306,22 +2355,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, true) + 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, true) + 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;
@@ -2331,9 +2380,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) */
}
@@ -2535,23 +2605,9 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
params->sched_scan_plans_num = src->sched_scan_plans_num;
}
- if (src->mac_addr_rand) {
- params->mac_addr_rand = src->mac_addr_rand;
-
- if (src->mac_addr && src->mac_addr_mask) {
- u8 *mac_addr;
-
- mac_addr = os_malloc(2 * ETH_ALEN);
- if (!mac_addr)
- goto failed;
-
- os_memcpy(mac_addr, src->mac_addr, ETH_ALEN);
- os_memcpy(mac_addr + ETH_ALEN, src->mac_addr_mask,
- ETH_ALEN);
- params->mac_addr = mac_addr;
- params->mac_addr_mask = mac_addr + ETH_ALEN;
- }
- }
+ if (src->mac_addr_rand &&
+ wpa_setup_mac_addr_rand_params(params, src->mac_addr))
+ goto failed;
if (src->bssid) {
u8 *bssid;
@@ -2602,8 +2658,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;
@@ -2738,18 +2794,14 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
}
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_pno) {
- params.mac_addr = wpa_s->mac_addr_pno;
- params.mac_addr_mask = wpa_s->mac_addr_pno + ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(&params, wpa_s->mac_addr_pno);
wpa_scan_set_relative_rssi_params(wpa_s, &params);
ret = wpa_supplicant_start_sched_scan(wpa_s, &params);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret == 0)
wpa_s->pno = 1;
else
@@ -2843,6 +2895,32 @@ int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
}
+int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
+ unsigned int type, u8 *mask)
+{
+ const u8 *to_copy;
+
+ if ((wpa_s->mac_addr_rand_enable & type) != type)
+ return -1;
+
+ if (type == MAC_ADDR_RAND_SCAN) {
+ to_copy = wpa_s->mac_addr_scan;
+ } else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
+ to_copy = wpa_s->mac_addr_sched_scan;
+ } else if (type == MAC_ADDR_RAND_PNO) {
+ to_copy = wpa_s->mac_addr_pno;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "scan: Invalid MAC randomization type=0x%x",
+ type);
+ return -1;
+ }
+
+ os_memcpy(mask, to_copy + ETH_ALEN, ETH_ALEN);
+ return 0;
+}
+
+
int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
{
struct wpa_radio_work *work;
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 2aa0a8b..c9ce2ce 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,
@@ -52,12 +74,17 @@ void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
unsigned int type, const u8 *addr,
const u8 *mask);
+int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
+ unsigned int type, u8 *mask);
int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s);
void filter_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *res);
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 ad533a1..7fec1cd 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -13,6 +13,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
+#include "common/hw_features_common.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "common/wpa_common.h"
#include "common/sae.h"
@@ -84,11 +85,21 @@ static int sme_set_sae_group(struct wpa_supplicant *wpa_s)
static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
const u8 *bssid, int external,
- int reuse)
+ int reuse, int *ret_use_pt,
+ bool *ret_use_pk)
{
struct wpabuf *buf;
size_t len;
const char *password;
+ struct wpa_bss *bss;
+ int use_pt = 0;
+ bool use_pk = false;
+ u8 rsnxe_capa = 0;
+
+ if (ret_use_pt)
+ *ret_use_pt = 0;
+ if (ret_use_pk)
+ *ret_use_pk = false;
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_s->sae_commit_override) {
@@ -117,6 +128,8 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
os_memcmp(bssid, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) {
wpa_printf(MSG_DEBUG,
"SAE: Reuse previously generated PWE on a retry with the same AP");
+ use_pt = wpa_s->sme.sae.h2e;
+ use_pk = wpa_s->sme.sae.pk;
goto reuse_data;
}
if (sme_set_sae_group(wpa_s) < 0) {
@@ -124,18 +137,74 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
return NULL;
}
- if (sae_prepare_commit(wpa_s->own_addr, bssid,
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+ if (bss) {
+ const u8 *rsnxe;
+
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (rsnxe && rsnxe[1] >= 1)
+ rsnxe_capa = rsnxe[2];
+ }
+
+ if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3)
+ use_pt = 1;
+#ifdef CONFIG_SAE_PK
+ if ((rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
+ ssid->sae_pk != SAE_PK_MODE_DISABLED &&
+ ((ssid->sae_password &&
+ sae_pk_valid_password(ssid->sae_password)) ||
+ (!ssid->sae_password && ssid->passphrase &&
+ sae_pk_valid_password(ssid->passphrase)))) {
+ use_pt = 1;
+ use_pk = true;
+ }
+
+ if (ssid->sae_pk == SAE_PK_MODE_ONLY && !use_pk) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Cannot use PK with the selected AP");
+ return NULL;
+ }
+#endif /* CONFIG_SAE_PK */
+
+ if (use_pt || wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) {
+ use_pt = !!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E));
+
+ 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;
+ }
+ }
+
+ if (use_pt &&
+ sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt,
+ wpa_s->own_addr, bssid,
+ wpa_s->sme.sae_rejected_groups, NULL) < 0)
+ return NULL;
+ if (!use_pt &&
+ sae_prepare_commit(wpa_s->own_addr, bssid,
(u8 *) password, os_strlen(password),
ssid->sae_password_id,
&wpa_s->sme.sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
return NULL;
}
- if (wpa_s->sme.sae.tmp)
+ if (wpa_s->sme.sae.tmp) {
os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN);
+ if (use_pt && use_pk)
+ wpa_s->sme.sae.pk = 1;
+#ifdef CONFIG_SAE_PK
+ os_memcpy(wpa_s->sme.sae.tmp->own_addr, wpa_s->own_addr,
+ ETH_ALEN);
+ os_memcpy(wpa_s->sme.sae.tmp->peer_addr, bssid, ETH_ALEN);
+ sae_pk_set_password(&wpa_s->sme.sae, password);
+#endif /* CONFIG_SAE_PK */
+ }
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);
@@ -143,10 +212,22 @@ reuse_data:
return NULL;
if (!external) {
wpabuf_put_le16(buf, 1); /* Transaction seq# */
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ if (use_pk)
+ wpabuf_put_le16(buf, WLAN_STATUS_SAE_PK);
+ else if (use_pt)
+ wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
+ else
+ wpabuf_put_le16(buf,WLAN_STATUS_SUCCESS);
+ }
+ if (sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
+ ssid->sae_password_id) < 0) {
+ wpabuf_free(buf);
+ return NULL;
}
- sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
- ssid->sae_password_id);
+ if (ret_use_pt)
+ *ret_use_pt = use_pt;
+ if (ret_use_pk)
+ *ret_use_pk = use_pk;
return buf;
}
@@ -247,7 +328,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;
@@ -257,6 +338,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 "
@@ -331,18 +413,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)) &&
@@ -464,6 +546,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;
@@ -536,7 +619,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);
@@ -558,6 +641,27 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
os_memcpy(pos, ext_capab, ext_capab_len);
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->rsnxe_override_assoc &&
+ wpabuf_len(wpa_s->rsnxe_override_assoc) <=
+ sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) {
+ wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
+ os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ wpabuf_head(wpa_s->rsnxe_override_assoc),
+ wpabuf_len(wpa_s->rsnxe_override_assoc));
+ wpa_s->sme.assoc_req_ie_len +=
+ wpabuf_len(wpa_s->rsnxe_override_assoc);
+ } else
+#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 &&
+ !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;
+ }
+
#ifdef CONFIG_HS20
if (is_hs20_network(wpa_s, ssid, bss)) {
struct wpabuf *hs20;
@@ -651,7 +755,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
if (start)
resp = sme_auth_build_sae_commit(wpa_s, ssid,
bss->bssid, 0,
- start == 2);
+ start == 2, NULL,
+ NULL);
else
resp = sme_auth_build_sae_confirm(wpa_s, 0);
if (resp == NULL) {
@@ -664,6 +769,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);
@@ -757,7 +868,7 @@ no_fils:
" (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
wpa_clear_keys(wpa_s, bss->bssid);
wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
if (old_ssid != wpa_s->current_ssid)
@@ -851,6 +962,8 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
/* Starting new connection, so clear the possibly used WPA IE from the
* previous association. */
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
}
@@ -905,7 +1018,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
static int sme_external_auth_build_buf(struct wpabuf *buf,
struct wpabuf *params,
const u8 *sa, const u8 *da,
- u16 auth_transaction, u16 seq_num)
+ u16 auth_transaction, u16 seq_num,
+ u16 status_code)
{
struct ieee80211_mgmt *resp;
@@ -920,7 +1034,7 @@ static int sme_external_auth_build_buf(struct wpabuf *buf,
resp->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE);
resp->seq_ctrl = host_to_le16(seq_num << 4);
resp->u.auth.auth_transaction = host_to_le16(auth_transaction);
- resp->u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS);
+ resp->u.auth.status_code = host_to_le16(status_code);
if (params)
wpabuf_put_buf(buf, params);
@@ -933,8 +1047,12 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
struct wpabuf *resp, *buf;
+ int use_pt;
+ bool use_pk;
+ u16 status;
- resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0);
+ resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0, &use_pt,
+ &use_pk);
if (!resp) {
wpa_printf(MSG_DEBUG, "SAE: Failed to build SAE commit");
return -1;
@@ -948,9 +1066,15 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
}
wpa_s->sme.seq_num++;
+ if (use_pk)
+ status = WLAN_STATUS_SAE_PK;
+ else if (use_pt)
+ status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
+ else
+ status = WLAN_STATUS_SUCCESS;
sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
- bssid, 1, wpa_s->sme.seq_num);
- wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
+ bssid, 1, wpa_s->sme.seq_num, status);
+ wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
wpabuf_free(resp);
wpabuf_free(buf);
@@ -1018,8 +1142,9 @@ static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s,
}
wpa_s->sme.seq_num++;
sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
- da, 2, wpa_s->sme.seq_num);
- wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
+ da, 2, wpa_s->sme.seq_num,
+ WLAN_STATUS_SUCCESS);
+ wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
wpabuf_free(resp);
wpabuf_free(buf);
}
@@ -1055,6 +1180,52 @@ void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
}
+static int sme_sae_is_group_enabled(struct wpa_supplicant *wpa_s, int group)
+{
+ int *groups = wpa_s->conf->sae_groups;
+ int default_groups[] = { 19, 20, 21, 0 };
+ int i;
+
+ if (!groups)
+ groups = default_groups;
+
+ for (i = 0; groups[i] > 0; i++) {
+ if (groups[i] == group)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int sme_check_sae_rejected_groups(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *groups)
+{
+ size_t i, count;
+ const u8 *pos;
+
+ if (!groups)
+ return 0;
+
+ pos = wpabuf_head(groups);
+ count = wpabuf_len(groups) / 2;
+ for (i = 0; i < count; i++) {
+ int enabled;
+ u16 group;
+
+ group = WPA_GET_LE16(pos);
+ pos += 2;
+ enabled = sme_sae_is_group_enabled(wpa_s, group);
+ wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
+ group, enabled ? "enabled" : "disabled");
+ if (enabled)
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
u16 status_code, const u8 *data, size_t len,
int external, const u8 *sa)
@@ -1070,11 +1241,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");
@@ -1092,8 +1268,29 @@ 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);
+ h2e = wpa_s->sme.sae.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);
@@ -1109,6 +1306,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
wpa_s->sme.sae.state == SAE_COMMITTED &&
(external || wpa_s->current_bss) && wpa_s->current_ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
+ int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
+ wpa_s->sme.sae.group);
wpa_s->sme.sae_group_index++;
if (sme_set_sae_group(wpa_s) < 0)
return -1; /* no other groups enabled */
@@ -1133,7 +1332,9 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
return -1;
}
- if (status_code != WLAN_STATUS_SUCCESS)
+ if (status_code != WLAN_STATUS_SUCCESS &&
+ status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT &&
+ status_code != WLAN_STATUS_SAE_PK)
return -1;
if (auth_transaction == 1) {
@@ -1145,12 +1346,35 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
if ((!external && wpa_s->current_bss == NULL) ||
wpa_s->current_ssid == NULL)
return -1;
- if (wpa_s->sme.sae.state != SAE_COMMITTED)
+ if (wpa_s->sme.sae.state != SAE_COMMITTED) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Ignore commit message while waiting for confirm");
+ return 0;
+ }
+ if (wpa_s->sme.sae.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.h2e || wpa_s->sme.sae.pk) &&
+ 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 (!wpa_s->sme.sae.pk &&
+ status_code == WLAN_STATUS_SAE_PK) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Unexpected use of status code for PK in SAE commit when PK was not expected");
+ return -1;
+ }
+
if (groups && groups[0] <= 0)
groups = NULL;
res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
- groups);
+ groups, status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK);
if (res == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message due to reflection attack");
@@ -1159,6 +1383,12 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
if (res != WLAN_STATUS_SUCCESS)
return -1;
+ if (wpa_s->sme.sae.tmp &&
+ sme_check_sae_rejected_groups(
+ wpa_s,
+ wpa_s->sme.sae.tmp->peer_rejected_groups))
+ return -1;
+
if (sae_process_commit(&wpa_s->sme.sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Failed to process peer "
"commit");
@@ -1174,6 +1404,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
sme_external_auth_send_sae_confirm(wpa_s, sa);
return 0;
} else if (auth_transaction == 2) {
+ if (status_code != WLAN_STATUS_SUCCESS)
+ return -1;
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
if (wpa_s->sme.sae.state != SAE_CONFIRMED)
return -1;
@@ -1467,6 +1699,7 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
{
struct wpa_driver_associate_params params;
struct ieee802_11_elems elems;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
#ifdef CONFIG_FILS
u8 nonces[2 * FILS_NONCE_LEN];
#endif /* CONFIG_FILS */
@@ -1576,8 +1809,8 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
struct wpabuf *owe_ie;
u16 group;
- if (wpa_s->current_ssid && wpa_s->current_ssid->owe_group) {
- group = wpa_s->current_ssid->owe_group;
+ if (ssid && ssid->owe_group) {
+ group = ssid->owe_group;
} else if (wpa_s->assoc_status_code ==
WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
if (wpa_s->last_owe_group == 19)
@@ -1613,9 +1846,14 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP2
- if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->current_ssid &&
- wpa_s->current_ssid->dpp_netaccesskey) {
- struct wpa_ssid *ssid = wpa_s->current_ssid;
+ if (DPP_VERSION > 1 && wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && ssid &&
+ ssid->dpp_netaccesskey && ssid->dpp_pfs != 2 &&
+ !ssid->dpp_pfs_fallback) {
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = pmksa_cache_get_current(wpa_s->wpa);
+ if (!pmksa || !pmksa->dpp_pfs)
+ goto pfs_fail;
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
@@ -1642,7 +1880,43 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
pfs_fail:
#endif /* CONFIG_DPP2 */
- if (wpa_s->current_ssid && wpa_s->current_ssid->multi_ap_backhaul_sta) {
+ wpa_s->mscs_setup_done = false;
+ if (wpa_s->current_bss && wpa_s->robust_av.valid_config) {
+ struct wpabuf *mscs_ie;
+ size_t mscs_ie_len, buf_len, *wpa_ie_len, max_ie_len;
+
+ if (!wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_MSCS))
+ goto mscs_fail;
+
+ buf_len = 3 + /* MSCS descriptor IE header */
+ 1 + /* Request type */
+ 2 + /* User priority control */
+ 4 + /* Stream timeout */
+ 3 + /* TCLAS Mask IE header */
+ wpa_s->robust_av.frame_classifier_len;
+ mscs_ie = wpabuf_alloc(buf_len);
+ if (!mscs_ie) {
+ wpa_printf(MSG_INFO,
+ "MSCS: Failed to allocate MSCS IE");
+ goto mscs_fail;
+ }
+
+ wpa_ie_len = &wpa_s->sme.assoc_req_ie_len;
+ max_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
+ wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
+ if ((*wpa_ie_len + wpabuf_len(mscs_ie)) <= max_ie_len) {
+ wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE", mscs_ie);
+ mscs_ie_len = wpabuf_len(mscs_ie);
+ os_memcpy(wpa_s->sme.assoc_req_ie + *wpa_ie_len,
+ wpabuf_head(mscs_ie), mscs_ie_len);
+ *wpa_ie_len += mscs_ie_len;
+ }
+
+ wpabuf_free(mscs_ie);
+ }
+mscs_fail:
+
+ if (ssid && ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
multi_ap_ie_len = add_multi_ap_ie(
@@ -1662,8 +1936,7 @@ pfs_fail:
params.ssid = wpa_s->sme.ssid;
params.ssid_len = wpa_s->sme.ssid_len;
params.freq.freq = wpa_s->sme.freq;
- params.bg_scan_period = wpa_s->current_ssid ?
- wpa_s->current_ssid->bg_scan_period : -1;
+ params.bg_scan_period = ssid ? ssid->bg_scan_period : -1;
params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
wpa_s->sme.assoc_req_ie : NULL;
params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
@@ -1679,15 +1952,18 @@ pfs_fail:
os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
params.htcaps = (u8 *) &htcaps;
params.htcaps_mask = (u8 *) &htcaps_mask;
- wpa_supplicant_apply_ht_overrides(wpa_s, wpa_s->current_ssid, &params);
+ wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
#endif /* CONFIG_HT_OVERRIDES */
#ifdef CONFIG_VHT_OVERRIDES
os_memset(&vhtcaps, 0, sizeof(vhtcaps));
os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
params.vhtcaps = &vhtcaps;
params.vhtcaps_mask = &vhtcaps_mask;
- wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, &params);
+ 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_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,
@@ -1803,7 +2079,12 @@ pfs_fail:
elems.osen_len + 2);
} else
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
- if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
+ if (elems.rsnxe)
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, elems.rsnxe - 2,
+ elems.rsnxe_len + 2);
+ else
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ if (ssid && ssid->p2p_group)
params.p2p = 1;
if (wpa_s->p2pdev->set_sta_uapsd)
@@ -2027,6 +2308,10 @@ void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s)
void sme_deinit(struct wpa_supplicant *wpa_s)
{
sme_clear_on_disassoc(wpa_s);
+#ifdef CONFIG_SAE
+ os_free(wpa_s->sme.sae_rejected_groups);
+ wpa_s->sme.sae_rejected_groups = NULL;
+#endif /* CONFIG_SAE */
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
@@ -2084,13 +2369,14 @@ static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
}
-int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
{
- struct wpa_bss *bss;
const u8 *ie;
- u16 ht_cap;
u8 chan_list[P2P_MAX_CHANNELS], channel;
u8 num_channels = 0, num_intol = 0, i;
+ size_t j;
+ int pri_freq, sec_freq;
if (!wpa_s->sme.sched_obss_scan)
return 0;
@@ -2118,22 +2404,36 @@ int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
os_memset(chan_list, 0, sizeof(chan_list));
- dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
- /* Skip other band bss */
+ pri_freq = wpa_s->assoc_freq;
+
+ switch (wpa_s->sme.ht_sec_chan) {
+ case HT_SEC_CHAN_ABOVE:
+ sec_freq = pri_freq + 20;
+ break;
+ case HT_SEC_CHAN_BELOW:
+ sec_freq = pri_freq - 20;
+ break;
+ case HT_SEC_CHAN_UNKNOWN:
+ default:
+ wpa_msg(wpa_s, MSG_WARNING,
+ "Undefined secondary channel: drop OBSS scan results");
+ return 1;
+ }
+
+ for (j = 0; j < scan_res->num; j++) {
+ struct wpa_scan_res *bss = scan_res->res[j];
enum hostapd_hw_mode mode;
+ int res;
+
+ /* Skip other band bss */
mode = ieee80211_freq_to_chan(bss->freq, &channel);
if (mode != HOSTAPD_MODE_IEEE80211G &&
mode != HOSTAPD_MODE_IEEE80211B)
continue;
- ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
- ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0;
- wpa_printf(MSG_DEBUG, "SME OBSS scan BSS " MACSTR
- " freq=%u chan=%u ht_cap=0x%x",
- MAC2STR(bss->bssid), bss->freq, channel, ht_cap);
-
- if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) {
- if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)
+ res = check_bss_coex_40mhz(bss, pri_freq, sec_freq);
+ if (res) {
+ if (res == 2)
num_intol++;
/* Check whether the channel is already considered */
@@ -2162,7 +2462,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));
@@ -2362,6 +2662,16 @@ static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s,
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->oci_freq_override_saquery_req) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override SA Query Request OCI frequency %d -> %d MHz",
+ ci.frequency,
+ wpa_s->oci_freq_override_saquery_req);
+ ci.frequency = wpa_s->oci_freq_override_saquery_req;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (ocv_insert_extended_oci(&ci, req + req_len) < 0)
return;
@@ -2455,6 +2765,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 &&
@@ -2512,6 +2826,16 @@ static void sme_process_sa_query_request(struct wpa_supplicant *wpa_s,
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->oci_freq_override_saquery_resp) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override SA Query Response OCI frequency %d -> %d MHz",
+ ci.frequency,
+ wpa_s->oci_freq_override_saquery_resp);
+ ci.frequency = wpa_s->oci_freq_override_saquery_resp;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (ocv_insert_extended_oci(&ci, resp + resp_len) < 0)
return;
@@ -2591,8 +2915,11 @@ void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(wpa_s, MSG_INFO, OCV_FAILURE "addr=" MACSTR
+ " frame=saquery%s error=%s",
+ MAC2STR(sa), data[0] == WLAN_SA_QUERY_REQUEST ?
+ "req" : "resp", ocv_errorstr);
return;
}
}
diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index 1a7f9e8..42d5a83 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -37,7 +37,8 @@ void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s);
void sme_deinit(struct wpa_supplicant *wpa_s);
-int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable);
void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
union wpa_event_data *data);
@@ -112,7 +113,8 @@ static inline void sme_deinit(struct wpa_supplicant *wpa_s)
{
}
-static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
{
return 0;
}
diff --git a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
index 03ac507..da69a87 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 c8a744d..ca3054b 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 7788b38..55d2b9c 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 270be9e..19f1eca 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -121,6 +121,15 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
os_free(wnmtfs_ie);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->oci_freq_override_wnm_sleep) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency,
+ wpa_s->oci_freq_override_wnm_sleep);
+ ci.frequency = wpa_s->oci_freq_override_wnm_sleep;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@@ -280,6 +289,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 */
}
@@ -365,8 +383,9 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(wpa_s, MSG_WARNING, "WNM: %s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(wpa_s, MSG_WARNING, "WNM: OCV failed: %s",
+ ocv_errorstr);
return;
}
}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index fa24121..f5b02f6 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -52,6 +52,7 @@ static char *ctrl_ifname = NULL;
static const char *global = NULL;
static const char *pid_file = NULL;
static const char *action_file = NULL;
+static int reconnect = 0;
static int ping_interval = 5;
static int interactive = 0;
static char *ifname_prefix = NULL;
@@ -80,7 +81,7 @@ static void update_ifnames(struct wpa_ctrl *ctrl);
static void usage(void)
{
- printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
+ printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvBr] "
"[-a<action file>] \\\n"
" [-P<pid file>] [-g<global ctrl>] [-G<ping interval>] "
"\\\n"
@@ -91,6 +92,8 @@ static void usage(void)
" -a = run in daemon mode executing the action file based on "
"events from\n"
" wpa_supplicant\n"
+ " -r = try to reconnect when client socket is disconnected.\n"
+ " This is useful only when used with -a.\n"
" -B = run a daemon in the background\n"
" default path: " CONFIG_CTRL_IFACE_DIR "\n"
" default interface: first interface found in socket path\n");
@@ -474,7 +477,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
"p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht",
"p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface",
"p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask",
- "ip_addr_start", "ip_addr_end",
+ "ip_addr_start", "ip_addr_end", "p2p_go_edmg",
#endif /* CONFIG_P2P */
"country", "bss_max_count", "bss_expiration_age",
"bss_expiration_scan_count", "filter_ssids", "filter_rssi",
@@ -499,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);
@@ -590,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);
@@ -1299,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);
}
@@ -1406,7 +1410,7 @@ static const char *network_fields[] = {
"bssid_whitelist", "psk", "proto", "key_mgmt",
"bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq",
"freq_list", "max_oper_chwidth", "ht40", "vht", "vht_center_freq1",
- "vht_center_freq2", "ht",
+ "vht_center_freq2", "ht", "edmg",
#ifdef IEEE8021X_EAPOL
"eap", "identity", "anonymous_identity", "password", "ca_cert",
"ca_path", "client_cert", "private_key", "private_key_passwd",
@@ -1427,20 +1431,19 @@ static const char *network_fields[] = {
#ifdef IEEE8021X_EAPOL
"eap_workaround", "pac_file", "fragment_size", "ocsp",
#endif /* IEEE8021X_EAPOL */
-#ifdef CONFIG_MESH
- "mode", "no_auto_peer", "mesh_rssi_threshold",
-#else /* CONFIG_MESH */
"mode",
-#endif /* CONFIG_MESH */
"proactive_key_caching", "disabled", "id_str",
"ieee80211w",
"mixed_cell", "frequency", "fixed_freq",
#ifdef CONFIG_MESH
+ "no_auto_peer", "mesh_rssi_threshold",
"mesh_basic_rates", "dot11MeshMaxRetries",
"dot11MeshRetryTimeout", "dot11MeshConfirmTimeout",
"dot11MeshHoldingTimeout",
#endif /* CONFIG_MESH */
"wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid",
+ "wpa_deny_ptk0_rekey",
+ "enable_edmg", "edmg_channel",
#ifdef CONFIG_P2P
"go_p2p_dev_addr", "p2p_client_list", "psk_list",
#endif /* CONFIG_P2P */
@@ -1457,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",
@@ -1700,15 +1706,25 @@ static char ** wpa_cli_complete_bss(const char *str, int pos)
static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- if (argc < 1 || argc > 2) {
- printf("Invalid GET_CAPABILITY command: need either one or "
- "two arguments\n");
+ if (argc < 1 || argc > 3) {
+ printf("Invalid GET_CAPABILITY command: need at least one argument and max three arguments\n");
+ return -1;
+ }
+
+ if (argc > 1 && os_strcmp(argv[0], "key_mgmt") != 0 &&
+ os_strncmp(argv[1], "iftype=", 7) == 0) {
+ printf("Invalid GET_CAPABILITY command: 'iftype=' param is allowed only for 'key_mgmt'\n");
+ return -1;
+ }
+
+ if (argc == 2 && os_strcmp(argv[1], "strict") != 0 &&
+ os_strncmp(argv[1], "iftype=", 7) != 0) {
+ printf("Invalid GET_CAPABILITY command: the second argument, if any, must be 'strict' OR 'iftype=<iftype_name>'\n");
return -1;
}
- if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
- printf("Invalid GET_CAPABILITY command: second argument, "
- "if any, must be 'strict'\n");
+ if (argc == 3 && os_strcmp(argv[2], "strict") != 0) {
+ printf("Invalid GET_CAPABILITY command: the third argument, if any, must be 'strict'\n");
return -1;
}
@@ -1735,7 +1751,13 @@ static char ** wpa_cli_complete_get_capability(const char *str, int pos)
"acs",
#endif /* CONFIG_ACS */
};
+ const char *iftypes[] = {
+ "iftype=STATION", "iftype=AP", "iftype=P2P_CLIENT",
+ "iftype=P2P_GO", "iftype=AP_VLAN", "iftype=IBSS", "iftype=NAN",
+ "iftype=P2P_DEVICE", "iftype=MESH",
+ };
int i, num_fields = ARRAY_SIZE(fields);
+ int num_iftypes = ARRAY_SIZE(iftypes);
char **res = NULL;
if (arg == 1) {
@@ -1749,6 +1771,21 @@ static char ** wpa_cli_complete_get_capability(const char *str, int pos)
}
}
if (arg == 2) {
+ /* the second argument can be "iftype=<iftype_name>" OR
+ * "strict" */
+ res = os_calloc(num_iftypes + 2, sizeof(char *));
+ if (!res)
+ return NULL;
+ res[0] = os_strdup("strict");
+ if (!res[0])
+ return res;
+ for (i = 0; i < num_iftypes; i++) {
+ res[i + 1] = os_strdup(iftypes[i]);
+ if (!res[i + 1])
+ return res;
+ }
+ }
+ if (arg == 3) {
res = os_calloc(1 + 1, sizeof(char *));
if (res == NULL)
return NULL;
@@ -1781,7 +1818,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);
@@ -3022,6 +3059,78 @@ static int wpa_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
#endif /* CONFIG_DPP */
+static int wpa_ctrl_command_bss(struct wpa_ctrl *ctrl, const char *cmd)
+{
+ char buf[512], *pos, *bssid, *freq, *level, *flags, *ssid;
+ size_t len;
+ int ret, id = -1;
+
+ if (!ctrl_conn)
+ return -1;
+ len = sizeof(buf) - 1;
+ ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
+ wpa_cli_msg_cb);
+ if (ret == -2) {
+ printf("'%s' command timed out.\n", cmd);
+ return -2;
+ } else if (ret < 0) {
+ printf("'%s' command failed.\n", cmd);
+ return -1;
+ }
+
+ buf[len] = '\0';
+ if (os_memcmp(buf, "FAIL", 4) == 0)
+ return -1;
+
+ pos = buf;
+ while (*pos != '\0') {
+ if (str_starts(pos, "id="))
+ id = atoi(pos + 3);
+ if (str_starts(pos, "bssid="))
+ bssid = pos + 6;
+ if (str_starts(pos, "freq="))
+ freq = pos + 5;
+ if (str_starts(pos, "level="))
+ level = pos + 6;
+ if (str_starts(pos, "flags="))
+ flags = pos + 6;
+ if (str_starts(pos, "ssid="))
+ ssid = pos + 5;
+
+ while (*pos != '\0' && *pos != '\n')
+ pos++;
+ *pos++ = '\0';
+ }
+ if (id != -1)
+ printf("%s\t%s\t%s\t%s\t%s\n", bssid, freq, level, flags, ssid);
+ return id;
+}
+
+
+static int wpa_cli_cmd_all_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[64];
+ int id = -1;
+ unsigned int mask;
+
+ printf("bssid / frequency / signal level / flags / ssid\n");
+
+ mask = WPA_BSS_MASK_ID | WPA_BSS_MASK_BSSID | WPA_BSS_MASK_FREQ |
+ WPA_BSS_MASK_LEVEL | WPA_BSS_MASK_FLAGS | WPA_BSS_MASK_SSID;
+ do {
+ if (id < 0)
+ os_snprintf(cmd, sizeof(cmd), "BSS FIRST MASK=0x%x",
+ mask);
+ else
+ os_snprintf(cmd, sizeof(cmd), "BSS NEXT-%d MASK=0x%x",
+ id, mask);
+ id = wpa_ctrl_command_bss(ctrl, cmd);
+ } while (id >= 0);
+
+ return 0;
+}
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -3681,6 +3790,8 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
cli_cmd_flag_none,
"*|<id> = remove DPP pkex information" },
#endif /* CONFIG_DPP */
+ { "all_bss", wpa_cli_cmd_all_bss, NULL, cli_cmd_flag_none,
+ "= list all BSS entries (scan results)" },
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
@@ -4003,6 +4114,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)) {
@@ -4037,7 +4152,8 @@ static void wpa_cli_action_process(const char *msg)
wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, WPA_EVENT_TERMINATING)) {
printf("wpa_supplicant is terminating - stop monitoring\n");
- wpa_cli_quit = 1;
+ if (!reconnect)
+ wpa_cli_quit = 1;
}
}
@@ -4229,6 +4345,10 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
if (wpa_ctrl_pending(ctrl) < 0) {
printf("Connection to wpa_supplicant lost - trying to "
"reconnect\n");
+ if (reconnect) {
+ eloop_terminate();
+ return;
+ }
wpa_cli_reconnect();
}
}
@@ -4576,6 +4696,8 @@ static void wpa_cli_cleanup(void)
static void wpa_cli_terminate(int sig, void *ctx)
{
eloop_terminate();
+ if (reconnect)
+ wpa_cli_quit = 1;
}
@@ -4656,7 +4778,7 @@ int main(int argc, char *argv[])
return -1;
for (;;) {
- c = getopt(argc, argv, "a:Bg:G:hi:p:P:s:v");
+ c = getopt(argc, argv, "a:Bg:G:hi:p:P:rs:v");
if (c < 0)
break;
switch (c) {
@@ -4688,6 +4810,9 @@ int main(int argc, char *argv[])
case 'P':
pid_file = optarg;
break;
+ case 'r':
+ reconnect = 1;
+ break;
case 's':
client_socket_dir = optarg;
break;
@@ -4713,7 +4838,22 @@ int main(int argc, char *argv[])
if (ctrl_ifname == NULL)
ctrl_ifname = wpa_cli_get_default_ifname();
- if (interactive) {
+ if (reconnect && action_file && ctrl_ifname) {
+ while (!wpa_cli_quit) {
+ if (ctrl_conn)
+ wpa_cli_action(ctrl_conn);
+ else
+ os_sleep(1, 0);
+ wpa_cli_close_connection();
+ wpa_cli_open_connection(ctrl_ifname, 0);
+ if (ctrl_conn) {
+ if (wpa_ctrl_attach(ctrl_conn) != 0)
+ wpa_cli_close_connection();
+ else
+ wpa_cli_attached = 1;
+ }
+ }
+ } else if (interactive) {
wpa_cli_interactive();
} else {
if (!global &&
diff --git a/wpa_supplicant/wpa_gui-qt4/icons/Makefile b/wpa_supplicant/wpa_gui-qt4/icons/Makefile
index 709514c..88efc3c 100644
--- a/wpa_supplicant/wpa_gui-qt4/icons/Makefile
+++ b/wpa_supplicant/wpa_gui-qt4/icons/Makefile
@@ -5,14 +5,28 @@ SIZES := 16x16 22x22 32x32 48x48 64x64 128x128
ICONS := $(addsuffix .png, $(foreach name, $(NAMES), $(foreach size, $(SIZES), $(size)/$(name))))
ICONS += $(addsuffix .xpm, $(NAMES))
+ifeq (1, $(shell which inkscape; echo $$?))
+$(error "No inkscape in PATH, it is required for exporting icons.")
+else
+ifeq (0, $(shell inkscape --without-gui 2>&1 > /dev/null; echo $$?))
+# Inkscape < 1.0
+INKSCAPE_GUI_FLAG := --without-gui
+INKSCAPE_OUTPUT_FLAG := --export-png
+else
+# Inkscape >= 1.0
+INKSCAPE_GUI_FLAG :=
+INKSCAPE_OUTPUT_FLAG := --export-filename
+endif
+endif
+
all: $(ICONS)
%.png:
mkdir -p hicolor/$(word 1, $(subst /, ,$(@)))/apps/
- inkscape $(subst .png,.svg, $(word 2, $(subst /, , $(@)))) --without-gui \
+ inkscape $(subst .png,.svg, $(word 2, $(subst /, , $(@)))) $(INKSCAPE_GUI_FLAG) \
--export-width=$(word 1, $(subst x, , $(@))) \
--export-height=$(word 2, $(subst x, , $(subst /, , $(@)))) \
- --export-png=hicolor/$(word 1, $(subst /, ,$(@)))/apps/$(word 2, $(subst /, , $@))
+ $(INKSCAPE_OUTPUT_FLAG)=hicolor/$(word 1, $(subst /, ,$(@)))/apps/$(word 2, $(subst /, , $@))
%.xpm:
mkdir -p pixmaps/
diff --git a/wpa_supplicant/wpa_gui-qt4/peers.cpp b/wpa_supplicant/wpa_gui-qt4/peers.cpp
index 3bcf2f5..0a0b3ff 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 a0aa05e..9404ab4 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_passphrase.c b/wpa_supplicant/wpa_passphrase.c
index adca1cc..538997e 100644
--- a/wpa_supplicant/wpa_passphrase.c
+++ b/wpa_supplicant/wpa_passphrase.c
@@ -31,9 +31,9 @@ int main(int argc, char *argv[])
if (argc > 2) {
passphrase = argv[2];
} else {
- printf("# reading passphrase from stdin\n");
+ fprintf(stderr, "# reading passphrase from stdin\n");
if (fgets(buf, sizeof(buf), stdin) == NULL) {
- printf("Failed to read passphrase\n");
+ fprintf(stderr, "Failed to read passphrase\n");
return 1;
}
buf[sizeof(buf) - 1] = '\0';
@@ -50,11 +50,11 @@ int main(int argc, char *argv[])
len = os_strlen(passphrase);
if (len < 8 || len > 63) {
- printf("Passphrase must be 8..63 characters\n");
+ fprintf(stderr, "Passphrase must be 8..63 characters\n");
return 1;
}
if (has_ctrl_char((u8 *) passphrase, len)) {
- printf("Invalid passphrase character\n");
+ fprintf(stderr, "Invalid passphrase character\n");
return 1;
}
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index b3ad45e..c5d7168 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);
}
@@ -598,7 +604,7 @@ static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
}
dst_addr = buf;
- os_memcpy(&proto, buf + ETH_ALEN, 2);
+ os_memcpy(&proto, (char *) buf + ETH_ALEN, 2);
if (!wpa_priv_allowed_l2_proto(proto)) {
wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype "
@@ -607,7 +613,8 @@ static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
}
res = l2_packet_send(iface->l2[idx], dst_addr, proto,
- buf + ETH_ALEN + 2, len - ETH_ALEN - 2);
+ (unsigned char *) buf + ETH_ALEN + 2,
+ len - ETH_ALEN - 2);
wpa_printf(MSG_DEBUG, "L2 send[idx=%d]: res=%d", idx, res);
}
@@ -1183,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 e7ddaa1..39e92fb 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;
}
@@ -313,14 +319,14 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
* per-BSSID EAPOL authentication.
*/
eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
- eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
- eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, true);
+ eapol_sm_notify_eap_fail(wpa_s->eapol, false);
return;
}
#endif /* CONFIG_IBSS_RSN */
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
- eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
+ eapol_sm_notify_eap_fail(wpa_s->eapol, false);
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
@@ -392,7 +398,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;
@@ -402,11 +410,15 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
wpa_s->group_cipher = WPA_CIPHER_NONE;
wpa_s->mgmt_group_cipher = 0;
+#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;
@@ -418,6 +430,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);
@@ -473,6 +486,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;
@@ -496,6 +534,15 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_s->get_pref_freq_list_override = NULL;
wpabuf_free(wpa_s->last_assoc_req_wpa_ie);
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) {
@@ -542,6 +589,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);
@@ -698,12 +746,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,
@@ -841,7 +894,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
{
enum wpa_states old_state = wpa_s->wpa_state;
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
- Boolean update_fils_connect_params = FALSE;
+ bool update_fils_connect_params = false;
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
@@ -940,7 +993,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
if (!fils_hlp_sent && ssid && ssid->eap.erp)
- update_fils_connect_params = TRUE;
+ update_fils_connect_params = true;
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
#ifdef CONFIG_OWE
if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE))
@@ -1107,7 +1160,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
* Clear forced success to clear EAP state for next
* authentication.
*/
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
}
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_sm_set_config(wpa_s->wpa, NULL);
@@ -1232,15 +1285,17 @@ 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;
- const u8 *bss_wpa, *bss_rsn, *bss_osen;
+ int sel, proto, sae_pwe;
+ const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
if (bss) {
bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ bss_rsnx = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
- } else
- bss_wpa = bss_rsn = bss_osen = NULL;
+ } else {
+ bss_wpa = bss_rsn = bss_rsnx = bss_osen = NULL;
+ }
if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
@@ -1371,7 +1426,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
- bss_rsn ? 2 + bss_rsn[1] : 0))
+ bss_rsn ? 2 + bss_rsn[1] : 0) ||
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+ bss_rsnx ? 2 + bss_rsnx[1] : 0))
return -1;
}
@@ -1407,13 +1464,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
@@ -1573,17 +1635,76 @@ 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 */
+ 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);
+#ifdef CONFIG_SAE_PK
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PK,
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ ssid->sae_pk != SAE_PK_MODE_DISABLED &&
+ ((ssid->sae_password &&
+ sae_pk_valid_password(ssid->sae_password)) ||
+ (!ssid->sae_password && ssid->passphrase &&
+ sae_pk_valid_password(ssid->passphrase))));
+#endif /* CONFIG_SAE_PK */
+#ifdef CONFIG_TESTING_OPTIONS
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_RSNXE_USED,
+ wpa_s->ft_rsnxe_used);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL,
+ wpa_s->oci_freq_override_eapol);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL_G2,
+ wpa_s->oci_freq_override_eapol_g2);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FT_ASSOC,
+ wpa_s->oci_freq_override_ft_assoc);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FILS_ASSOC,
+ wpa_s->oci_freq_override_fils_assoc);
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* 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");
return -1;
}
+ wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe);
+ if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe,
+ &wpa_s->rsnxe_len)) {
+ wpa_msg(wpa_s, MSG_WARNING, "RSN: Failed to generate RSNXE");
+ return -1;
+ }
+
if (0) {
#ifdef CONFIG_DPP
} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
/* Use PMK from DPP network introduction (PMKSA entry) */
wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
+#ifdef CONFIG_DPP2
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DPP_PFS, ssid->dpp_pfs);
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
} else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
int psk_set = 0;
@@ -1700,6 +1821,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;
}
@@ -1764,6 +1899,9 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
*pos |= 0x01;
#endif /* CONFIG_FILS */
break;
+ case 10: /* Bits 80-87 */
+ *pos |= 0x20; /* Bit 85 - Mirrored SCS */
+ break;
}
}
@@ -1771,7 +1909,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
{
u8 *pos = buf;
- u8 len = 10, i;
+ u8 len = 11, i;
if (len < wpa_s->extended_capa_len)
len = wpa_s->extended_capa_len;
@@ -1927,6 +2065,61 @@ int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
}
+static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_SAE
+ int *groups = conf->sae_groups;
+ int default_groups[] = { 19, 20, 21, 0 };
+ const char *password;
+
+ if (!groups || groups[0] <= 0)
+ groups = default_groups;
+
+ password = ssid->sae_password;
+ if (!password)
+ password = ssid->passphrase;
+
+ if (!password ||
+ (conf->sae_pwe == 0 && !ssid->sae_password_id &&
+ !sae_pk_valid_password(password)) ||
+ conf->sae_pwe == 3) {
+ /* PT derivation not needed */
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ return;
+ }
+
+ if (ssid->pt)
+ return; /* PT already derived */
+ ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
+ (const u8 *) password, os_strlen(password),
+ ssid->sae_password_id);
+#endif /* CONFIG_SAE */
+}
+
+
+static void wpa_s_clear_sae_rejected(struct wpa_supplicant *wpa_s)
+{
+#if defined(CONFIG_SAE) && defined(CONFIG_SME)
+ os_free(wpa_s->sme.sae_rejected_groups);
+ wpa_s->sme.sae_rejected_groups = NULL;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->extra_sae_rejected_groups) {
+ int i, *groups = wpa_s->extra_sae_rejected_groups;
+
+ for (i = 0; groups[i]; i++) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Indicate rejection of an extra SAE group %d",
+ groups[i]);
+ int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
+ groups[i]);
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_SAE && CONFIG_SME */
+}
+
+
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
/**
@@ -1944,6 +2137,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
@@ -1957,6 +2151,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;
@@ -1973,6 +2168,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
} else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
os_get_reltime(&wpa_s->roam_start);
}
+ } else {
+#ifdef CONFIG_SAE
+ wpa_s_clear_sae_rejected(wpa_s);
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+#endif /* CONFIG_SAE */
}
if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
@@ -2235,6 +2435,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)
@@ -2257,8 +2461,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 */
@@ -2304,8 +2510,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
return;
}
- res = check_40mhz_5g(mode, scan_res, pri_chan->chan,
- sec_chan->chan);
+ res = check_40mhz_5g(scan_res, pri_chan, sec_chan);
switch (res) {
case 0:
/* Back to HT20 */
@@ -2356,8 +2561,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++) {
@@ -2432,8 +2637,15 @@ 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, freq->ht_enabled,
+ freq->channel, ssid->enable_edmg,
+ ssid->edmg_channel, freq->ht_enabled,
vht_freq.vht_enabled, freq->he_enabled,
freq->sec_channel_offset,
chwidth, seg0, seg1, vht_caps,
@@ -2551,9 +2763,9 @@ static u8 * wpas_populate_assoc_ies(
#ifdef CONFIG_MBO
const u8 *mbo_ie;
#endif
-#ifdef CONFIG_SAE
- int sae_pmksa_cached = 0;
-#endif /* CONFIG_SAE */
+#if defined(CONFIG_SAE) || defined(CONFIG_FILS)
+ int pmksa_cached = 0;
+#endif /* CONFIG_SAE || CONFIG_FILS */
#ifdef CONFIG_FILS
const u8 *realm, *username, *rrk;
size_t realm_len, username_len, rrk_len;
@@ -2593,9 +2805,9 @@ static u8 * wpas_populate_assoc_ies(
ssid, try_opportunistic,
cache_id, 0) == 0) {
eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
-#ifdef CONFIG_SAE
- sae_pmksa_cached = 1;
-#endif /* CONFIG_SAE */
+#if defined(CONFIG_SAE) || defined(CONFIG_FILS)
+ pmksa_cached = 1;
+#endif /* CONFIG_SAE || CONFIG_FILS */
}
wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
@@ -2694,6 +2906,10 @@ static u8 * wpas_populate_assoc_ies(
if (mask)
*mask |= WPA_DRV_UPDATE_FILS_ERP_INFO;
+ } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) &&
+ ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
+ pmksa_cached) {
+ algs = WPA_AUTH_ALG_FILS;
}
#endif /* CONFIG_FILS */
#endif /* IEEE8021X_EAPOL */
@@ -2710,7 +2926,7 @@ static u8 * wpas_populate_assoc_ies(
}
#ifdef CONFIG_SAE
- if (sae_pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
+ if (pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SAE: Use WPA_AUTH_ALG_OPEN for PMKSA caching attempt");
algs = WPA_AUTH_ALG_OPEN;
@@ -2749,7 +2965,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);
@@ -2897,8 +3113,16 @@ static u8 * wpas_populate_assoc_ies(
#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP2
- if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
- ssid->dpp_netaccesskey) {
+ if (DPP_VERSION > 1 &&
+ wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
+ ssid->dpp_netaccesskey &&
+ ssid->dpp_pfs != 2 && !ssid->dpp_pfs_fallback) {
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = pmksa_cache_get_current(wpa_s->wpa);
+ if (!pmksa || !pmksa->dpp_pfs)
+ goto pfs_fail;
+
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
ssid->dpp_netaccesskey_len);
@@ -2951,6 +3175,56 @@ pfs_fail:
}
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->rsnxe_override_assoc &&
+ wpabuf_len(wpa_s->rsnxe_override_assoc) <=
+ max_wpa_ie_len - wpa_ie_len) {
+ wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
+ os_memcpy(wpa_ie + wpa_ie_len,
+ wpabuf_head(wpa_s->rsnxe_override_assoc),
+ wpabuf_len(wpa_s->rsnxe_override_assoc));
+ wpa_ie_len += wpabuf_len(wpa_s->rsnxe_override_assoc);
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (wpa_s->rsnxe_len > 0 &&
+ wpa_s->rsnxe_len <= max_wpa_ie_len - wpa_ie_len) {
+ os_memcpy(wpa_ie + wpa_ie_len, wpa_s->rsnxe, wpa_s->rsnxe_len);
+ wpa_ie_len += wpa_s->rsnxe_len;
+ }
+
+ if (bss && wpa_s->robust_av.valid_config) {
+ struct wpabuf *mscs_ie;
+ size_t mscs_ie_len, buf_len;
+
+ if (!wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_MSCS))
+ goto mscs_fail;
+
+ buf_len = 3 + /* MSCS descriptor IE header */
+ 1 + /* Request type */
+ 2 + /* User priority control */
+ 4 + /* Stream timeout */
+ 3 + /* TCLAS Mask IE header */
+ wpa_s->robust_av.frame_classifier_len;
+ mscs_ie = wpabuf_alloc(buf_len);
+ if (!mscs_ie) {
+ wpa_printf(MSG_INFO,
+ "MSCS: Failed to allocate MSCS IE");
+ goto mscs_fail;
+ }
+
+ wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
+ if ((wpa_ie_len + wpabuf_len(mscs_ie)) <= max_wpa_ie_len) {
+ wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE", mscs_ie);
+ mscs_ie_len = wpabuf_len(mscs_ie);
+ os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(mscs_ie),
+ mscs_ie_len);
+ wpa_ie_len += mscs_ie_len;
+ }
+
+ wpabuf_free(mscs_ie);
+ }
+mscs_fail:
+
if (ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
@@ -3022,6 +3296,117 @@ static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+static u8 wpa_ie_get_edmg_oper_chans(const u8 *edmg_ie)
+{
+ if (!edmg_ie || edmg_ie[1] < 6)
+ return 0;
+ return edmg_ie[EDMG_BSS_OPERATING_CHANNELS_OFFSET];
+}
+
+
+static u8 wpa_ie_get_edmg_oper_chan_width(const u8 *edmg_ie)
+{
+ if (!edmg_ie || edmg_ie[1] < 6)
+ return 0;
+ return edmg_ie[EDMG_OPERATING_CHANNEL_WIDTH_OFFSET];
+}
+
+
+/* Returns the intersection of two EDMG configurations.
+ * Note: The current implementation is limited to CB2 only (CB1 included),
+ * i.e., the implementation supports up to 2 contiguous channels.
+ * For supporting non-contiguous (aggregated) channels and for supporting
+ * CB3 and above, this function will need to be extended.
+ */
+static struct ieee80211_edmg_config
+get_edmg_intersection(struct ieee80211_edmg_config a,
+ struct ieee80211_edmg_config b,
+ u8 primary_channel)
+{
+ struct ieee80211_edmg_config result;
+ int i, contiguous = 0;
+ int max_contiguous = 0;
+
+ result.channels = b.channels & a.channels;
+ if (!result.channels) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: cannot intersect channels 0x%x and 0x%x",
+ a.channels, b.channels);
+ goto fail;
+ }
+
+ if (!(result.channels & BIT(primary_channel - 1))) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: the primary channel %d is not one of the intersected channels 0x%x",
+ primary_channel, result.channels);
+ goto fail;
+ }
+
+ /* Find max contiguous channels */
+ for (i = 0; i < 6; i++) {
+ if (result.channels & BIT(i))
+ contiguous++;
+ else
+ contiguous = 0;
+
+ if (contiguous > max_contiguous)
+ max_contiguous = contiguous;
+ }
+
+ /* Assuming AP and STA supports ONLY contiguous channels,
+ * bw configuration can have value between 4-7.
+ */
+ if ((b.bw_config < a.bw_config))
+ result.bw_config = b.bw_config;
+ else
+ result.bw_config = a.bw_config;
+
+ if ((max_contiguous >= 2 && result.bw_config < EDMG_BW_CONFIG_5) ||
+ (max_contiguous >= 1 && result.bw_config < EDMG_BW_CONFIG_4)) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: not enough contiguous channels %d for supporting CB1 or CB2",
+ max_contiguous);
+ goto fail;
+ }
+
+ return result;
+
+fail:
+ result.channels = 0;
+ result.bw_config = 0;
+ return result;
+}
+
+
+static struct ieee80211_edmg_config
+get_supported_edmg(struct wpa_supplicant *wpa_s,
+ struct hostapd_freq_params *freq,
+ struct ieee80211_edmg_config request_edmg)
+{
+ enum hostapd_hw_mode hw_mode;
+ struct hostapd_hw_modes *mode = NULL;
+ u8 primary_channel;
+
+ if (!wpa_s->hw.modes)
+ goto fail;
+
+ hw_mode = ieee80211_freq_to_chan(freq->freq, &primary_channel);
+ if (hw_mode == NUM_HOSTAPD_MODES)
+ goto fail;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode, 0);
+ if (!mode)
+ goto fail;
+
+ return get_edmg_intersection(mode->edmg, request_edmg, primary_channel);
+
+fail:
+ request_edmg.channels = 0;
+ request_edmg.bw_config = 0;
+ return request_edmg;
+}
+
+
#ifdef CONFIG_MBO
void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s)
{
@@ -3057,10 +3442,13 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
struct wpa_ssid *ssid = cwork->ssid;
struct wpa_supplicant *wpa_s = work->wpa_s;
u8 *wpa_ie;
- int use_crypt, ret, i, bssid_changed;
+ const u8 *edmg_ie_oper;
+ 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];
@@ -3149,6 +3537,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
/* Starting new association, so clear the possibly used WPA IE from the
* previous association. */
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
+ wpa_s->mscs_setup_done = false;
wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
if (!wpa_ie) {
@@ -3165,10 +3556,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;
@@ -3240,6 +3633,71 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.beacon_int = wpa_s->conf->beacon_int;
}
+ if (bss && ssid->enable_edmg)
+ edmg_ie_oper = get_ie_ext((const u8 *) (bss + 1), bss->ie_len,
+ WLAN_EID_EXT_EDMG_OPERATION);
+ else
+ edmg_ie_oper = NULL;
+
+ if (edmg_ie_oper) {
+ params.freq.edmg.channels =
+ wpa_ie_get_edmg_oper_chans(edmg_ie_oper);
+ params.freq.edmg.bw_config =
+ wpa_ie_get_edmg_oper_chan_width(edmg_ie_oper);
+ wpa_printf(MSG_DEBUG,
+ "AP supports EDMG channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+
+ /* User may ask for specific EDMG channel for EDMG connection
+ * (must be supported by AP)
+ */
+ if (ssid->edmg_channel) {
+ struct ieee80211_edmg_config configured_edmg;
+ enum hostapd_hw_mode hw_mode;
+ u8 primary_channel;
+
+ hw_mode = ieee80211_freq_to_chan(bss->freq,
+ &primary_channel);
+ if (hw_mode == NUM_HOSTAPD_MODES)
+ goto edmg_fail;
+
+ hostapd_encode_edmg_chan(ssid->enable_edmg,
+ ssid->edmg_channel,
+ primary_channel,
+ &configured_edmg);
+
+ if (ieee802_edmg_is_allowed(params.freq.edmg,
+ configured_edmg)) {
+ params.freq.edmg = configured_edmg;
+ wpa_printf(MSG_DEBUG,
+ "Use EDMG channel %d for connection",
+ ssid->edmg_channel);
+ } else {
+ edmg_fail:
+ params.freq.edmg.channels = 0;
+ params.freq.edmg.bw_config = 0;
+ wpa_printf(MSG_WARNING,
+ "EDMG channel %d not supported by AP, fallback to DMG",
+ ssid->edmg_channel);
+ }
+ }
+
+ if (params.freq.edmg.channels) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG before: channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+ params.freq.edmg = get_supported_edmg(wpa_s,
+ &params.freq,
+ params.freq.edmg);
+ wpa_printf(MSG_DEBUG,
+ "EDMG after: channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+ }
+ }
+
params.pairwise_suite = cipher_pairwise;
params.group_suite = cipher_group;
params.mgmt_group_suite = cipher_group_mgmt;
@@ -3248,12 +3706,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 ||
@@ -3330,6 +3794,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
/*
@@ -3411,11 +3878,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) {
/*
@@ -3529,6 +3998,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)
{
@@ -3800,9 +4278,12 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+ wpa_s_clear_sae_rejected(wpa_s);
wpa_s->last_owe_group = 0;
- if (ssid)
+ if (ssid) {
ssid->owe_transition_bss_select_count = 0;
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+ }
if (wpa_s->connect_without_scan ||
wpa_supplicant_fast_associate(wpa_s) != 1) {
@@ -4340,16 +4821,23 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
- * Set portValid = TRUE here since we are going to skip 4-way
+ * Set portValid = true here since we are going to skip 4-way
* handshake processing which would normally set portValid. We
* need this to allow the EAPOL state machines to be completed
* without going through EAPOL-Key handshake.
*/
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
}
}
+static int wpas_eapol_needs_l2_packet(struct wpa_supplicant *wpa_s)
+{
+ return !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) ||
+ !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX);
+}
+
+
int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
{
if ((!wpa_s->p2p_mgmt ||
@@ -4359,7 +4847,9 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
wpa_s->l2 = l2_packet_init(wpa_s->ifname,
wpa_drv_get_mac_addr(wpa_s),
ETH_P_EAPOL,
- wpa_supplicant_rx_eapol, wpa_s, 0);
+ wpas_eapol_needs_l2_packet(wpa_s) ?
+ wpa_supplicant_rx_eapol : NULL,
+ wpa_s, 0);
if (wpa_s->l2 == NULL)
return -1;
@@ -4367,20 +4857,26 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
L2_PACKET_FILTER_PKTTYPE))
wpa_dbg(wpa_s, MSG_DEBUG,
"Failed to attach pkt_type filter");
+
+ if (l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to get own L2 address");
+ return -1;
+ }
} else {
const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
if (addr)
os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
}
- if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
- wpa_msg(wpa_s, MSG_ERROR, "Failed to get own L2 address");
- return -1;
- }
-
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
wpas_wps_update_mac_addr(wpa_s);
+#ifdef CONFIG_FST
+ if (wpa_s->fst)
+ fst_update_mac_addr(wpa_s->fst, wpa_s->own_addr);
+#endif /* CONFIG_FST */
+
return 0;
}
@@ -4431,7 +4927,7 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
os_memcpy(wpa_s->perm_addr, wpa_s->own_addr, ETH_ALEN);
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
- if (wpa_s->bridge_ifname[0]) {
+ if (wpa_s->bridge_ifname[0] && wpas_eapol_needs_l2_packet(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
"interface '%s'", wpa_s->bridge_ifname);
wpa_s->l2_br = l2_packet_init_bridge(
@@ -4508,6 +5004,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;
}
@@ -4870,6 +5369,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
@@ -5033,7 +5545,7 @@ static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr,
static const u8 * wpas_fst_get_peer_first(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -5047,7 +5559,7 @@ static const u8 * wpas_fst_get_peer_first(void *ctx,
static const u8 * wpas_fst_get_peer_next(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
return NULL;
}
@@ -5743,8 +6255,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
}
/* RSNA Supplicant Key Management - INITIALIZE */
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, false);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
/* Initialize driver interface and register driver event handler before
* L2 receive handler so that association events are processed before
@@ -5811,8 +6323,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
if (capa_res == 0) {
wpa_s->drv_capa_known = 1;
wpa_s->drv_flags = capa.flags;
+ wpa_s->drv_flags2 = capa.flags2;
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;
@@ -6036,11 +6548,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);
@@ -6419,7 +6937,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();
@@ -6487,7 +7005,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");
@@ -6751,7 +7269,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");
@@ -6976,8 +7494,10 @@ int wpa_supplicant_ctrl_iface_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 */
@@ -6988,6 +7508,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
@@ -7005,6 +7526,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 &&
@@ -7402,12 +7924,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];
}
@@ -7447,7 +7974,7 @@ static int wpa_set_driver_tmp_disallow_list(struct wpa_supplicant *wpa_s)
ETH_ALEN);
num_bssid++;
}
- ret = wpa_drv_set_bssid_blacklist(wpa_s, num_bssid, bssids);
+ ret = wpa_drv_set_bssid_tmp_disallow(wpa_s, num_bssid, bssids);
os_free(bssids);
return ret;
}
@@ -7584,3 +8111,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 0babadc..1250834 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
@@ -425,6 +422,16 @@ fast_reauth=1
# since all implementations are required to support group 19.
#sae_groups=19 20 21
+# SAE mechanism for PWE derivation
+# 0 = hunting-and-pecking loop only (default 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)
#dtim_period=2
@@ -474,6 +481,11 @@ fast_reauth=1
# 0 = use permanent MAC address
# 1 = use random MAC address
# 2 = like 1, but maintain OUI (with local admin bit set)
+# Note that this setting is ignored when a specific MAC address is needed for
+# a full protocol exchange that includes GAS, e.g., when going through a DPP
+# exchange that exposes the configured interface address as part of the DP
+# Public Action frame exchanges before using GAS. That same address is then used
+# during the GAS exchange as well to avoid breaking the protocol expectations.
#gas_rand_mac_addr=0
# Lifetime of GAS random MAC address in seconds (default: 60)
@@ -795,6 +807,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
@@ -947,7 +964,8 @@ fast_reauth=1
# management frames) certification program are:
# PMF enabled: ieee80211w=1 and key_mgmt=WPA-EAP WPA-EAP-SHA256
# PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256
-# (and similarly for WPA-PSK and WPA-WPSK-SHA256 if WPA2-Personal is used)
+# (and similarly for WPA-PSK and WPA-PSK-SHA256 if WPA2-Personal is used)
+# WPA3-Personal-only mode: ieee80211w=2 and key_mgmt=SAE
#
# ocv: whether operating channel validation is enabled
# This is a countermeasure against multi-channel man-in-the-middle attacks.
@@ -1093,6 +1111,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.
@@ -1436,6 +1466,64 @@ 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
+
+# Whether Beacon protection is enabled
+# This depends on management frame protection (ieee80211w) being enabled.
+#beacon_prot=0
+
+# OWE DH Group
+# 0: use default (19) first and then try all supported groups one by one if AP
+# rejects the selected group
+# 1-65535: DH Group to use for OWE
+# Groups 19 (NIST P-256), 20 (NIST P-384), and 21 (NIST P-521) are
+# currently supported.
+#owe_group=0
+
+# OWE-only mode (disable transition mode)
+# 0: enable transition mode (allow connection to either OWE or open BSS)
+# 1 = disable transition mode (allow connection only with OWE)
+#owe_only=0
+
+# 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.
+#owe_ptk_workaround=0
+
+# 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)
+
+# SAE-PK mode
+# 0: automatic SAE/SAE-PK selection based on password; enable
+# transition mode (allow SAE authentication without SAE-PK)
+# 1: SAE-PK only (disable transition mode; allow SAE authentication
+# only with SAE-PK)
+# 2: disable SAE-PK (allow SAE authentication only without SAE-PK)
+#sae_pk=0
+
# MAC address policy
# 0 = use permanent MAC address
# 1 = use random MAC address for each ESS connection
@@ -1548,6 +1636,16 @@ fast_reauth=1
# Set to 1 to disable BSS transition management
#disable_btm=0
+# Enable EDMG capability in STA/AP mode, default value is false
+#enable_edmg=1
+
+# This value is used to configure the channel bonding feature.
+# Default value is 0.
+# Relevant only if enable_edmg is true
+# In AP mode it defines the EDMG channel to use for AP operation.
+# In STA mode it defines the EDMG channel for connection (if supported by AP).
+#edmg_channel=9
+
# Example blocks:
# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index af93806..31a9b74 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_binder_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,27 @@ 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 robust_av_data {
+ u8 dialog_token;
+ enum scs_request_type request_type;
+ u8 up_bitmap;
+ u8 up_limit;
+ u32 stream_timeout;
+ u8 frame_classifier[48];
+ size_t frame_classifier_len;
+ bool valid_config;
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -540,6 +565,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 +618,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;
@@ -614,6 +640,9 @@ struct wpa_supplicant {
int eapol_received; /* number of EAPOL packets received after the
* previous association event */
+ u8 rsnxe[20];
+ size_t rsnxe_len;
+
struct scard_data *scard;
char imsi[20];
int mnc_len;
@@ -697,6 +726,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;
@@ -706,8 +736,8 @@ struct wpa_supplicant {
unsigned int no_suitable_network;
u64 drv_flags;
+ u64 drv_flags2;
unsigned int drv_enc;
- unsigned int drv_smps_modes;
unsigned int drv_rrm_flags;
/*
@@ -810,6 +840,7 @@ struct wpa_supplicant {
u8 ext_auth_bssid[ETH_ALEN];
u8 ext_auth_ssid[SSID_MAX_LEN];
size_t ext_auth_ssid_len;
+ int *sae_rejected_groups;
#endif /* CONFIG_SAE */
} sme;
#endif /* CONFIG_SME */
@@ -873,7 +904,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];
@@ -927,6 +957,7 @@ struct wpa_supplicant {
unsigned int p2p_pd_before_go_neg:1;
unsigned int p2p_go_ht40:1;
unsigned int p2p_go_vht:1;
+ unsigned int p2p_go_edmg:1;
unsigned int p2p_go_he:1;
unsigned int user_initiated_pd:1;
unsigned int p2p_go_group_formation_completed:1;
@@ -1054,6 +1085,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)
@@ -1112,7 +1144,10 @@ 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;
+ int ft_rsnxe_used;
struct wpabuf *sae_commit_override;
enum wpa_alg last_tk_alg;
u8 last_tk_addr[ETH_ALEN];
@@ -1120,6 +1155,18 @@ struct wpa_supplicant {
u8 last_tk[WPA_TK_MAX_LEN];
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;
+ unsigned int oci_freq_override_eapol;
+ unsigned int oci_freq_override_saquery_req;
+ unsigned int oci_freq_override_saquery_resp;
+ unsigned int oci_freq_override_eapol_g2;
+ unsigned int oci_freq_override_ft_assoc;
+ unsigned int oci_freq_override_fils_assoc;
+ unsigned int oci_freq_override_wnm_sleep;
#endif /* CONFIG_TESTING_OPTIONS */
struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -1220,9 +1267,10 @@ struct wpa_supplicant {
struct wpa_radio_work *dpp_listen_work;
unsigned int dpp_pending_listen_freq;
unsigned int dpp_listen_freq;
+ struct os_reltime dpp_listen_end;
u8 dpp_allowed_roles;
int dpp_qr_mutual;
- int dpp_netrole_ap;
+ int dpp_netrole;
int dpp_auth_ok_on_ack;
int dpp_in_response_listen;
int dpp_gas_client;
@@ -1244,8 +1292,21 @@ struct wpa_supplicant {
unsigned int dpp_resp_retry_time;
u8 dpp_last_ssid[SSID_MAX_LEN];
size_t dpp_last_ssid_len;
+ bool dpp_conf_backup_received;
#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;
+ struct wpa_ssid *dpp_reconfig_ssid;
+ int dpp_reconfig_ssid_id;
+ struct dpp_reconfig_id *dpp_reconfig_id;
#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override;
@@ -1262,6 +1323,11 @@ 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;
+ struct robust_av_data robust_av;
+ bool mscs_setup_done;
};
@@ -1272,6 +1338,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,
@@ -1303,6 +1372,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);
@@ -1368,6 +1438,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);
@@ -1390,6 +1462,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 */
@@ -1422,11 +1495,11 @@ enum chan_allowed {
NOT_ALLOWED, NO_IR, ALLOWED
};
-enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
- u8 bw);
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
+ u8 channel, u8 bw);
size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- int freq, u8 *pos, size_t len);
+ 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,
@@ -1468,6 +1541,9 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
struct channel_list_changed *info);
+int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *current_bss,
+ struct wpa_bss *seleceted);
/* eap_register.c */
int eap_register_methods(void);
@@ -1536,7 +1612,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);
@@ -1557,4 +1634,15 @@ 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);
+
+int wpas_send_mscs_req(struct wpa_supplicant *wpa_s);
+void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
+ struct wpabuf *buf);
+void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *buf,
+ size_t len);
+void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const u8 *ies, size_t ies_len);
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 62af7f6..a9a66ba 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) {
@@ -396,6 +415,10 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
ie = wpa_bss_get_ie(curr, WLAN_EID_RSN);
if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
ret = -1;
+
+ ie = wpa_bss_get_ie(curr, WLAN_EID_RSNX);
+ if (wpa_sm_set_ap_rsnxe(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
+ ret = -1;
} else {
ret = -1;
}
@@ -472,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);
@@ -488,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) {
@@ -503,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;
@@ -513,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);
}
@@ -543,7 +574,9 @@ 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,
+ int akmp)
{
struct wpa_supplicant *wpa_s = _wpa_s;
struct wpa_ssid *ssid;
@@ -551,9 +584,22 @@ static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
os_memset(&params, 0, sizeof(params));
ssid = wpas_get_network_ctx(wpa_s, network_ctx);
- if (ssid)
+ if (ssid) {
wpa_msg(wpa_s, MSG_INFO, PMKSA_CACHE_ADDED MACSTR " %d",
MAC2STR(bssid), ssid->id);
+ if ((akmp == WPA_KEY_MGMT_FT_IEEE8021X ||
+ akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
+ !ssid->ft_eap_pmksa_caching) {
+ /* Since we will not be using PMKSA caching for FT-EAP
+ * within wpa_supplicant to avoid known interop issues
+ * with APs, do not add this PMKID to the driver either
+ * so that we won't be hitting those interop issues
+ * with driver-based RSNE generation. */
+ wpa_printf(MSG_DEBUG,
+ "FT: Do not add PMKID entry to the driver since FT-EAP PMKSA caching is not enabled in configuration");
+ return 0;
+ }
+ }
if (ssid && fils_cache_id) {
params.ssid = ssid->ssid;
params.ssid_len = ssid->ssid_len;
@@ -565,6 +611,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);
}
@@ -1043,6 +1091,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;
@@ -1098,7 +1161,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;
@@ -1121,6 +1186,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);
@@ -1156,8 +1222,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;
}
@@ -1189,6 +1255,92 @@ 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;
+
+#ifdef CONFIG_SAE
+ 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_SAE_PK) &&
+ wpa_key_mgmt_sae(wpa_s->key_mgmt) &&
+#ifdef CONFIG_SME
+ wpa_s->sme.sae.state == SAE_ACCEPTED &&
+ wpa_s->sme.sae.pk &&
+#endif /* CONFIG_SME */
+ (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) &&
+ (ssid->sae_pk != SAE_PK_MODE_ONLY ||
+ ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
+ (ssid->group_cipher & WPA_CIPHER_TKIP))) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: SAE authentication without PK disabled based on AP notification");
+ disable_wpa_wpa2(ssid);
+ ssid->sae_pk = SAE_PK_MODE_ONLY;
+ changed = 1;
+ }
+#endif /* CONFIG_SAE */
+
+ 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 */
@@ -1207,6 +1359,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;
@@ -1240,6 +1393,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) {
@@ -1271,6 +1425,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) {
@@ -1293,6 +1449,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/wpas_kay.c b/wpa_supplicant/wpas_kay.c
index 41477d5..defd0f2 100644
--- a/wpa_supplicant/wpas_kay.c
+++ b/wpa_supplicant/wpas_kay.c
@@ -44,19 +44,19 @@ static int wpas_macsec_get_capability(void *priv, enum macsec_cap *cap)
}
-static int wpas_enable_protect_frames(void *wpa_s, Boolean enabled)
+static int wpas_enable_protect_frames(void *wpa_s, bool enabled)
{
return wpa_drv_enable_protect_frames(wpa_s, enabled);
}
-static int wpas_enable_encrypt(void *wpa_s, Boolean enabled)
+static int wpas_enable_encrypt(void *wpa_s, bool enabled)
{
return wpa_drv_enable_encrypt(wpa_s, enabled);
}
-static int wpas_set_replay_protect(void *wpa_s, Boolean enabled, u32 window)
+static int wpas_set_replay_protect(void *wpa_s, bool enabled, u32 window)
{
return wpa_drv_set_replay_protect(wpa_s, enabled, window);
}
@@ -68,7 +68,7 @@ static int wpas_set_current_cipher_suite(void *wpa_s, u64 cs)
}
-static int wpas_enable_controlled_port(void *wpa_s, Boolean enabled)
+static int wpas_enable_controlled_port(void *wpa_s, bool enabled)
{
return wpa_drv_enable_controlled_port(wpa_s, enabled);
}
@@ -376,7 +376,7 @@ void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s,
wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0,
- EAP_EXCHANGE, FALSE);
+ EAP_EXCHANGE, false);
fail:
if (msk) {
@@ -424,7 +424,7 @@ void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
ckn->len = ssid->mka_ckn_len;
os_memcpy(ckn->name, ssid->mka_ckn, ckn->len);
- res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, FALSE);
+ res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, false);
if (res)
goto free_cak;
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 6b03634..b7680f0 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -188,6 +188,7 @@ static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
const u8 *ie;
struct wpa_ie_data adv;
int wpa2 = 0, ccmp = 0;
+ enum wpa_driver_if_type iftype;
/*
* Many existing WPS APs do not know how to negotiate WPA2 or CCMP in
@@ -239,9 +240,12 @@ static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
return;
}
+ iftype = ssid->p2p_group ? WPA_IF_P2P_CLIENT : WPA_IF_STATION;
+
if (ccmp && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
(ssid->pairwise_cipher & WPA_CIPHER_TKIP) &&
- (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+ (capa.key_mgmt_iftype[iftype] &
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
wpa_printf(MSG_DEBUG, "WPS: Add CCMP into the credential "
"based on scan results");
if (wpa_s->conf->ap_scan == 1)
@@ -484,7 +488,7 @@ static int wpa_supplicant_wps_cred(void *ctx,
case WPS_ENCR_NONE:
break;
case WPS_ENCR_TKIP:
- ssid->pairwise_cipher = WPA_CIPHER_TKIP;
+ ssid->pairwise_cipher = WPA_CIPHER_TKIP | WPA_CIPHER_CCMP;
break;
case WPS_ENCR_AES:
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
@@ -525,13 +529,14 @@ static int wpa_supplicant_wps_cred(void *ctx,
case WPS_AUTH_WPAPSK:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
- ssid->proto = WPA_PROTO_WPA;
+ ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
break;
case WPS_AUTH_WPA2PSK:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
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;
}
@@ -1178,6 +1183,11 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
/* P2P in 60 GHz uses PBSS */
ssid->pbss = 1;
}
+ if (wpa_s->go_params->edmg &&
+ wpas_p2p_try_edmg_channel(wpa_s,
+ wpa_s->go_params) == 0)
+ ssid->enable_edmg = 1;
+
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
"SSID", ssid->ssid, ssid->ssid_len);
}
@@ -1261,6 +1271,11 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
/* P2P in 60 GHz uses PBSS */
ssid->pbss = 1;
}
+ if (wpa_s->go_params->edmg &&
+ wpas_p2p_try_edmg_channel(wpa_s,
+ wpa_s->go_params) == 0)
+ ssid->enable_edmg = 1;
+
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
"SSID", ssid->ssid, ssid->ssid_len);
}
@@ -1284,6 +1299,10 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "WPS: Failed to set phase1 '%s'", val);
return -1;
}
+
+ if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER)
+ wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_PIN_ACTIVE);
+
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
@@ -1349,6 +1368,7 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
wpas_clear_wps(wpa_s);
}
+ wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CANCEL);
wpa_s->after_wps = 0;
return 0;
@@ -1602,8 +1622,13 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
wpas_wps_set_uuid(wpa_s, wps);
+#ifdef CONFIG_NO_TKIP
+ wps->auth_types = WPS_AUTH_WPA2PSK;
+ wps->encr_types = WPS_ENCR_AES;
+#else /* CONFIG_NO_TKIP */
wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
os_memset(&rcfg, 0, sizeof(rcfg));
rcfg.new_psk_cb = wpas_wps_new_psk_cb;
@@ -1814,6 +1839,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);
@@ -1834,6 +1863,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",