aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2021-10-06 22:53:23 +0000
committerXin Li <delphij@google.com>2021-10-06 22:53:23 +0000
commitd4fa44373b060703c7857cc76a4d8480e53f346c (patch)
treed968edbb057d20e475067e8eb01fa61a11ed5f55
parent96e84352e6145bf0ccfca761a4ef61826328a122 (diff)
parent12405a05cf6e16c11db301d4a7a71131737d3643 (diff)
downloadwpa_supplicant_8-d4fa44373b060703c7857cc76a4d8480e53f346c.tar.gz
Merge Android 12
Bug: 202323961 Merged-In: I264384190bf2ef047afc6503538fd4496597ba33 Change-Id: Iafe413e785b4d380bf3129442d4358530832032f
-rw-r--r--OWNERS4
-rw-r--r--hostapd/Android.mk24
-rw-r--r--hostapd/ChangeLog4
-rw-r--r--hostapd/Makefile128
-rw-r--r--hostapd/android.config25
-rw-r--r--hostapd/android.hardware.wifi.hostapd.xml2
-rw-r--r--hostapd/config_file.c276
-rw-r--r--hostapd/ctrl_iface.c182
-rw-r--r--hostapd/defconfig9
-rw-r--r--hostapd/hidl/1.2/hostapd.cpp649
-rw-r--r--hostapd/hidl/1.3/hidl.cpp (renamed from hostapd/hidl/1.2/hidl.cpp)8
-rw-r--r--hostapd/hidl/1.3/hidl.h (renamed from hostapd/hidl/1.2/hidl.h)0
-rw-r--r--hostapd/hidl/1.3/hidl_return_util.h (renamed from hostapd/hidl/1.2/hidl_return_util.h)4
-rw-r--r--hostapd/hidl/1.3/hostapd.cpp1034
-rw-r--r--hostapd/hidl/1.3/hostapd.h (renamed from hostapd/hidl/1.2/hostapd.h)57
-rw-r--r--hostapd/hostapd.android.rc1
-rw-r--r--hostapd/hostapd.conf125
-rw-r--r--hostapd/hostapd_cli.c61
-rw-r--r--hostapd/main.c1
-rw-r--r--hostapd/sae_pk_gen.c196
-rw-r--r--hs20/client/Makefile46
-rw-r--r--hs20/server/.gitignore1
-rw-r--r--hs20/server/Makefile26
-rw-r--r--src/Makefile4
-rw-r--r--src/ap/Makefile15
-rw-r--r--src/ap/ap_config.c171
-rw-r--r--src/ap/ap_config.h61
-rw-r--r--src/ap/ap_drv_ops.c8
-rw-r--r--src/ap/ap_drv_ops.h8
-rw-r--r--src/ap/beacon.c318
-rw-r--r--src/ap/beacon.h2
-rw-r--r--src/ap/ctrl_iface_ap.c6
-rw-r--r--src/ap/dfs.c50
-rw-r--r--src/ap/dpp_hostapd.c199
-rw-r--r--src/ap/dpp_hostapd.h1
-rw-r--r--src/ap/drv_callbacks.c111
-rw-r--r--src/ap/gas_serv.c10
-rw-r--r--src/ap/hostapd.c77
-rw-r--r--src/ap/hostapd.h12
-rw-r--r--src/ap/hs20.c4
-rw-r--r--src/ap/hw_features.c77
-rw-r--r--src/ap/hw_features.h6
-rw-r--r--src/ap/ieee802_11.c1605
-rw-r--r--src/ap/ieee802_11_he.c53
-rw-r--r--src/ap/ieee802_11_shared.c101
-rw-r--r--src/ap/ieee802_11_vht.c169
-rw-r--r--src/ap/ieee802_1x.c3
-rw-r--r--src/ap/neighbor_db.c2
-rw-r--r--src/ap/sta_info.c35
-rw-r--r--src/ap/sta_info.h46
-rw-r--r--src/ap/wnm_ap.c21
-rw-r--r--src/ap/wpa_auth.c224
-rw-r--r--src/ap/wpa_auth.h48
-rw-r--r--src/ap/wpa_auth_ft.c137
-rw-r--r--src/ap/wpa_auth_glue.c68
-rw-r--r--src/ap/wpa_auth_i.h3
-rw-r--r--src/ap/wpa_auth_ie.c210
-rw-r--r--src/ap/wps_hostapd.c105
-rw-r--r--src/build.rules109
-rw-r--r--src/common/Makefile17
-rw-r--r--src/common/brcm_vendor.h75
-rw-r--r--src/common/common_module_tests.c263
-rw-r--r--src/common/defs.h12
-rw-r--r--src/common/dpp.c417
-rw-r--r--src/common/dpp.h83
-rw-r--r--src/common/dpp_auth.c1
-rw-r--r--src/common/dpp_backup.c97
-rw-r--r--src/common/dpp_crypto.c568
-rw-r--r--src/common/dpp_i.h12
-rw-r--r--src/common/dpp_reconfig.c349
-rw-r--r--src/common/dpp_tcp.c402
-rw-r--r--src/common/gas_server.c140
-rw-r--r--src/common/gas_server.h9
-rw-r--r--src/common/hw_features_common.c80
-rw-r--r--src/common/hw_features_common.h3
-rw-r--r--src/common/ieee802_11_common.c240
-rw-r--r--src/common/ieee802_11_common.h27
-rw-r--r--src/common/ieee802_11_defs.h134
-rw-r--r--src/common/ocv.c39
-rw-r--r--src/common/ocv.h13
-rw-r--r--src/common/ptksa_cache.c321
-rw-r--r--src/common/ptksa_cache.h79
-rw-r--r--src/common/qca-vendor.h1912
-rw-r--r--src/common/sae.c105
-rw-r--r--src/common/sae.h67
-rw-r--r--src/common/sae_pk.c884
-rw-r--r--src/common/wpa_common.c803
-rw-r--r--src/common/wpa_common.h82
-rw-r--r--src/common/wpa_ctrl.h24
-rw-r--r--src/crypto/Makefile17
-rw-r--r--src/crypto/crypto.h12
-rw-r--r--src/crypto/crypto_module_tests.c150
-rw-r--r--src/crypto/crypto_openssl.c169
-rw-r--r--src/crypto/tls.h14
-rw-r--r--src/crypto/tls_openssl.c239
-rw-r--r--src/crypto/tls_wolfssl.c61
-rw-r--r--src/drivers/driver.h171
-rw-r--r--src/drivers/driver_bsd.c123
-rw-r--r--src/drivers/driver_common.c1
-rw-r--r--src/drivers/driver_macsec_linux.c3
-rw-r--r--src/drivers/driver_nl80211.c914
-rw-r--r--src/drivers/driver_nl80211.h26
-rw-r--r--src/drivers/driver_nl80211_capa.c98
-rw-r--r--src/drivers/driver_nl80211_event.c318
-rw-r--r--src/drivers/driver_nl80211_scan.c23
-rw-r--r--src/drivers/drivers.mak4
-rw-r--r--src/drivers/drivers.mk3
-rw-r--r--src/drivers/nl80211_copy.h583
-rw-r--r--src/eap_common/Makefile15
-rw-r--r--src/eap_common/eap_sim_common.c22
-rw-r--r--src/eap_peer/.gitignore1
-rw-r--r--src/eap_peer/Makefile22
-rw-r--r--src/eap_peer/eap_aka.c34
-rw-r--r--src/eap_peer/eap_peap.c27
-rw-r--r--src/eap_peer/eap_teap.c9
-rw-r--r--src/eap_peer/eap_tls.c12
-rw-r--r--src/eap_peer/eap_tls_common.c6
-rw-r--r--src/eap_peer/eap_ttls.c33
-rw-r--r--src/eap_peer/ikev2.c10
-rw-r--r--src/eap_server/Makefile15
-rw-r--r--src/eap_server/eap_server_peap.c72
-rw-r--r--src/eap_server/eap_server_teap.c24
-rw-r--r--src/eap_server/eap_server_tls.c33
-rw-r--r--src/eap_server/eap_server_tls_common.c54
-rw-r--r--src/eap_server/eap_server_ttls.c30
-rw-r--r--src/eapol_auth/Makefile16
-rw-r--r--src/eapol_supp/Makefile15
-rw-r--r--src/l2_packet/Makefile15
-rw-r--r--src/lib.rules38
-rw-r--r--src/objs.mk3
-rw-r--r--src/p2p/Makefile15
-rw-r--r--src/p2p/p2p.c18
-rw-r--r--src/p2p/p2p.h10
-rw-r--r--src/radius/Makefile16
-rw-r--r--src/radius/radius.h3
-rw-r--r--src/radius/radius_client.c17
-rw-r--r--src/radius/radius_server.c5
-rw-r--r--src/rsn_supp/Makefile15
-rw-r--r--src/rsn_supp/pmksa_cache.c6
-rw-r--r--src/rsn_supp/preauth.c3
-rw-r--r--src/rsn_supp/tdls.c21
-rw-r--r--src/rsn_supp/wpa.c220
-rw-r--r--src/rsn_supp/wpa.h60
-rw-r--r--src/rsn_supp/wpa_ft.c167
-rw-r--r--src/rsn_supp/wpa_i.h43
-rw-r--r--src/rsn_supp/wpa_ie.c36
-rw-r--r--src/tls/Makefile17
-rw-r--r--src/tls/rsa.c2
-rw-r--r--src/utils/Makefile17
-rw-r--r--src/utils/base64.c24
-rw-r--r--src/utils/base64.h1
-rw-r--r--src/utils/config.c97
-rw-r--r--src/utils/config.h29
-rw-r--r--src/utils/ext_password.c3
-rw-r--r--src/utils/ext_password_file.c136
-rw-r--r--src/utils/ext_password_i.h4
-rw-r--r--src/utils/json.c36
-rw-r--r--src/utils/json.h4
-rw-r--r--src/utils/list.h8
-rw-r--r--src/utils/os_unix.c2
-rw-r--r--src/utils/platform.h23
-rw-r--r--src/utils/radiotap.c12
-rw-r--r--src/utils/radiotap.h407
-rw-r--r--src/utils/wpabuf.h15
-rw-r--r--src/wps/Makefile15
-rw-r--r--src/wps/wps.h5
-rw-r--r--src/wps/wps_er.c2
-rw-r--r--src/wps/wps_registrar.c29
-rw-r--r--src/wps/wps_upnp.c53
-rw-r--r--src/wps/wps_upnp_ap.c4
-rw-r--r--src/wps/wps_upnp_event.c7
-rw-r--r--src/wps/wps_upnp_i.h3
-rw-r--r--wpa_supplicant/Android.mk39
-rw-r--r--wpa_supplicant/ChangeLog10
-rw-r--r--wpa_supplicant/Makefile149
-rw-r--r--wpa_supplicant/README4
-rw-r--r--wpa_supplicant/README-HS202
-rw-r--r--wpa_supplicant/android.config6
-rw-r--r--wpa_supplicant/ap.c143
-rw-r--r--wpa_supplicant/blacklist.c141
-rw-r--r--wpa_supplicant/blacklist.h24
-rw-r--r--wpa_supplicant/bss.c124
-rw-r--r--wpa_supplicant/bss.h24
-rw-r--r--wpa_supplicant/bssid_ignore.c221
-rw-r--r--wpa_supplicant/bssid_ignore.h33
-rw-r--r--wpa_supplicant/config.c230
-rw-r--r--wpa_supplicant/config.h74
-rw-r--r--wpa_supplicant/config_file.c127
-rw-r--r--wpa_supplicant/config_ssid.h47
-rw-r--r--wpa_supplicant/ctrl_iface.c465
-rw-r--r--wpa_supplicant/dbus/dbus_common.c23
-rw-r--r--wpa_supplicant/dbus/dbus_new.c14
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c167
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.h4
-rw-r--r--wpa_supplicant/defconfig8
-rw-r--r--wpa_supplicant/doc/docbook/.gitignore1
-rw-r--r--wpa_supplicant/doc/docbook/eapol_test.sgml4
-rw-r--r--wpa_supplicant/doc/docbook/wpa_background.sgml4
-rw-r--r--wpa_supplicant/doc/docbook/wpa_cli.sgml4
-rw-r--r--wpa_supplicant/doc/docbook/wpa_gui.sgml4
-rw-r--r--wpa_supplicant/doc/docbook/wpa_passphrase.sgml4
-rw-r--r--wpa_supplicant/doc/docbook/wpa_priv.sgml4
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml4
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.sgml4
-rw-r--r--wpa_supplicant/dpp_supplicant.c574
-rw-r--r--wpa_supplicant/dpp_supplicant.h3
-rw-r--r--wpa_supplicant/driver_i.h22
-rw-r--r--wpa_supplicant/events.c1017
-rwxr-xr-xwpa_supplicant/examples/dpp-nfc.py660
-rwxr-xr-xwpa_supplicant/examples/p2p-action-udhcp.sh4
-rwxr-xr-xwpa_supplicant/examples/p2p-action.sh4
-rw-r--r--wpa_supplicant/examples/p2p/p2p_connect.py16
-rw-r--r--wpa_supplicant/examples/p2p/p2p_disconnect.py2
-rw-r--r--wpa_supplicant/examples/p2p/p2p_find.py2
-rw-r--r--wpa_supplicant/examples/p2p/p2p_flush.py2
-rw-r--r--wpa_supplicant/examples/p2p/p2p_group_add.py14
-rw-r--r--wpa_supplicant/examples/p2p/p2p_invite.py10
-rw-r--r--wpa_supplicant/examples/p2p/p2p_listen.py2
-rw-r--r--wpa_supplicant/examples/p2p/p2p_stop_find.py2
-rw-r--r--wpa_supplicant/examples/udhcpd-p2p.conf12
-rw-r--r--wpa_supplicant/gas_query.c16
-rw-r--r--wpa_supplicant/hidl/1.4/android.hardware.wifi.supplicant-service.rc (renamed from wpa_supplicant/hidl/1.3/android.hardware.wifi.supplicant-service.rc)1
-rw-r--r--wpa_supplicant/hidl/1.4/android.hardware.wifi.supplicant.xml (renamed from wpa_supplicant/hidl/1.3/manifest.xml)2
-rw-r--r--wpa_supplicant/hidl/1.4/hidl.cpp (renamed from wpa_supplicant/hidl/1.3/hidl.cpp)66
-rw-r--r--wpa_supplicant/hidl/1.4/hidl.h (renamed from wpa_supplicant/hidl/1.3/hidl.h)26
-rw-r--r--wpa_supplicant/hidl/1.4/hidl_constants.h (renamed from wpa_supplicant/hidl/1.3/hidl_constants.h)0
-rw-r--r--wpa_supplicant/hidl/1.4/hidl_i.h (renamed from wpa_supplicant/hidl/1.3/hidl_i.h)0
-rw-r--r--wpa_supplicant/hidl/1.4/hidl_manager.cpp (renamed from wpa_supplicant/hidl/1.3/hidl_manager.cpp)508
-rw-r--r--wpa_supplicant/hidl/1.4/hidl_manager.h (renamed from wpa_supplicant/hidl/1.3/hidl_manager.h)156
-rw-r--r--wpa_supplicant/hidl/1.4/hidl_return_util.h (renamed from wpa_supplicant/hidl/1.3/hidl_return_util.h)31
-rw-r--r--wpa_supplicant/hidl/1.4/iface_config_utils.cpp (renamed from wpa_supplicant/hidl/1.3/iface_config_utils.cpp)6
-rw-r--r--wpa_supplicant/hidl/1.4/iface_config_utils.h (renamed from wpa_supplicant/hidl/1.3/iface_config_utils.h)4
-rw-r--r--wpa_supplicant/hidl/1.4/misc_utils.h (renamed from wpa_supplicant/hidl/1.3/misc_utils.h)4
-rw-r--r--wpa_supplicant/hidl/1.4/p2p_iface.cpp (renamed from wpa_supplicant/hidl/1.3/p2p_iface.cpp)263
-rw-r--r--wpa_supplicant/hidl/1.4/p2p_iface.h (renamed from wpa_supplicant/hidl/1.3/p2p_iface.h)24
-rw-r--r--wpa_supplicant/hidl/1.4/p2p_network.cpp (renamed from wpa_supplicant/hidl/1.3/p2p_network.cpp)4
-rw-r--r--wpa_supplicant/hidl/1.4/p2p_network.h (renamed from wpa_supplicant/hidl/1.3/p2p_network.h)4
-rw-r--r--wpa_supplicant/hidl/1.4/sta_iface.cpp (renamed from wpa_supplicant/hidl/1.3/sta_iface.cpp)351
-rw-r--r--wpa_supplicant/hidl/1.4/sta_iface.h (renamed from wpa_supplicant/hidl/1.3/sta_iface.h)44
-rw-r--r--wpa_supplicant/hidl/1.4/sta_network.cpp (renamed from wpa_supplicant/hidl/1.3/sta_network.cpp)187
-rw-r--r--wpa_supplicant/hidl/1.4/sta_network.h (renamed from wpa_supplicant/hidl/1.3/sta_network.h)43
-rw-r--r--wpa_supplicant/hidl/1.4/supplicant.cpp (renamed from wpa_supplicant/hidl/1.3/supplicant.cpp)55
-rw-r--r--wpa_supplicant/hidl/1.4/supplicant.h (renamed from wpa_supplicant/hidl/1.3/supplicant.h)10
-rw-r--r--wpa_supplicant/hs20_supplicant.c39
-rw-r--r--wpa_supplicant/hs20_supplicant.h1
-rw-r--r--wpa_supplicant/interworking.c43
-rw-r--r--wpa_supplicant/interworking.h2
-rw-r--r--wpa_supplicant/mesh.c230
-rw-r--r--wpa_supplicant/mesh.h6
-rw-r--r--wpa_supplicant/mesh_mpm.c7
-rw-r--r--wpa_supplicant/mesh_rsn.c6
-rw-r--r--wpa_supplicant/nmake.mak2
-rw-r--r--wpa_supplicant/notify.c49
-rw-r--r--wpa_supplicant/notify.h11
-rw-r--r--wpa_supplicant/op_classes.c117
-rw-r--r--wpa_supplicant/p2p_supplicant.c185
-rw-r--r--wpa_supplicant/pasn_supplicant.c1509
-rw-r--r--wpa_supplicant/preauth_test.c3
-rw-r--r--wpa_supplicant/robust_av.c155
-rw-r--r--wpa_supplicant/rrm.c39
-rw-r--r--wpa_supplicant/scan.c278
-rw-r--r--wpa_supplicant/scan.h4
-rw-r--r--wpa_supplicant/sme.c174
-rw-r--r--wpa_supplicant/wmm_ac.c2
-rw-r--r--wpa_supplicant/wnm_sta.c32
-rw-r--r--wpa_supplicant/wpa_cli.c196
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons/.gitignore2
-rw-r--r--wpa_supplicant/wpa_supplicant.c420
-rw-r--r--wpa_supplicant/wpa_supplicant.conf86
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h160
-rw-r--r--wpa_supplicant/wpa_supplicant_template.conf2
-rw-r--r--wpa_supplicant/wpas_glue.c92
-rw-r--r--wpa_supplicant/wpas_module_tests.c85
-rw-r--r--wpa_supplicant/wps_supplicant.c19
274 files changed, 24329 insertions, 5135 deletions
diff --git a/OWNERS b/OWNERS
index 6542bef8..cd9dfa9a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,3 @@
-dimitrysh@google.com
etancohen@google.com
-rpius@google.com
+haishalom@google.com
+arabawy@google.com
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 83a779e1..df0dc95c 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -66,6 +66,10 @@ INCLUDES += external/libnl-headers
endif
endif
+ifdef CONFIG_TESTING_OPTIONS
+L_CFLAGS += -DCONFIG_TESTING_OPTIONS
+CONFIG_WPS_TESTING=y
+endif
ifndef CONFIG_OS
ifdef CONFIG_NATIVE_WINDOWS
@@ -258,6 +262,10 @@ 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
@@ -422,7 +430,7 @@ endif
ifdef CONFIG_EAP_SIM_COMMON
OBJS += src/eap_common/eap_sim_common.c
# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
-# replaced with another file implementating the interface specified in
+# replaced with another file implementing the interface specified in
# eap_sim_db.h.
OBJS += src/eap_server/eap_sim_db.c
NEED_FIPS186_2_PRF=y
@@ -573,6 +581,16 @@ L_CFLAGS += -DCONFIG_DPP2
endif
endif
+ifdef CONFIG_PASN
+L_CFLAGS += -DCONFIG_PASN
+L_CFLAGS += -DCONFIG_PTKSA_CACHE
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+OBJS += src/common/ptksa_cache.c
+endif
+
ifdef CONFIG_EAP_IKEV2
L_CFLAGS += -DEAP_SERVER_IKEV2
OBJS += src/eap_server/eap_server_ikev2.c src/eap_server/ikev2.c
@@ -1156,6 +1174,7 @@ ifeq ($(HOSTAPD_USE_HIDL), y)
LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.0
LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.1
LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.2
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.3
LOCAL_SHARED_LIBRARIES += libbase libhidlbase libutils
LOCAL_STATIC_LIBRARIES += libhostapd_hidl
endif
@@ -1204,7 +1223,7 @@ LOCAL_VENDOR_MODULE := true
LOCAL_CPPFLAGS := $(L_CPPFLAGS)
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_C_INCLUDES := $(INCLUDES)
-HIDL_INTERFACE_VERSION = 1.2
+HIDL_INTERFACE_VERSION = 1.3
LOCAL_SRC_FILES := \
hidl/$(HIDL_INTERFACE_VERSION)/hidl.cpp \
hidl/$(HIDL_INTERFACE_VERSION)/hostapd.cpp
@@ -1212,6 +1231,7 @@ LOCAL_SHARED_LIBRARIES := \
android.hardware.wifi.hostapd@1.0 \
android.hardware.wifi.hostapd@1.1 \
android.hardware.wifi.hostapd@1.2 \
+ android.hardware.wifi.hostapd@1.3 \
libbase \
libhidlbase \
libutils \
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index 6c4410e8..34a8a081 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -362,7 +362,7 @@ ChangeLog for hostapd
* RADIUS server functionality
- add minimal RADIUS accounting server support (hostapd-as-server);
this is mainly to enable testing coverage with hwsim scripts
- - allow authentication log to be written into SQLite databse
+ - allow authentication log to be written into SQLite database
- added option for TLS protocol testing of an EAP peer by simulating
various misbehaviors/known attacks
- MAC ACL support for testing purposes
@@ -668,7 +668,7 @@ ChangeLog for hostapd
* fixed HT Capabilities IE with nl80211 drivers
* moved generic AP functionality code into src/ap
* WPS: handle Selected Registrar as union of info from all Registrars
- * remove obsolte Prism54.org driver wrapper
+ * remove obsolete Prism54.org driver wrapper
* added internal debugging mechanism with backtrace support and memory
allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y)
* EAP-FAST server: piggyback Phase 2 start with the end of Phase 1
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 95ef0859..ce7d2153 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -1,10 +1,7 @@
-ifndef CC
-CC=gcc
-endif
+ALL=hostapd hostapd_cli
+CONFIG_FILE = .config
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
-endif
+include ../src/build.rules
ifdef LIBS
# If LIBS is set with some global build system defaults, clone those for
@@ -19,6 +16,9 @@ endif
ifndef LIBS_n
LIBS_n := $(LIBS)
endif
+ifndef LIBS_s
+LIBS_s := $(LIBS)
+endif
endif
CFLAGS += $(EXTRA_CFLAGS)
@@ -27,8 +27,6 @@ CFLAGS += -I$(abspath ../src/utils)
export BINDIR ?= /usr/local/bin/
--include .config
-
ifndef CONFIG_NO_GITVER
# Add VERSION_STR postfix for builds from a git repository
ifeq ($(wildcard ../.git),../.git)
@@ -122,6 +120,7 @@ LIBS += -lbfd -ldl -liberty -lz
LIBS_c += -lbfd -ldl -liberty -lz
LIBS_h += -lbfd -ldl -liberty -lz
LIBS_n += -lbfd -ldl -liberty -lz
+LIBS_s += -lbfd -ldl -liberty -lz
endif
endif
@@ -294,6 +293,10 @@ 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
@@ -445,7 +448,7 @@ endif
ifdef CONFIG_EAP_SIM_COMMON
OBJS += ../src/eap_common/eap_sim_common.o
# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
-# replaced with another file implementating the interface specified in
+# replaced with another file implementing the interface specified in
# eap_sim_db.h.
OBJS += ../src/eap_server/eap_sim_db.o
NEED_FIPS186_2_PRF=y
@@ -596,6 +599,16 @@ CFLAGS += -DCONFIG_DPP2
endif
endif
+ifdef CONFIG_PASN
+CFLAGS += -DCONFIG_PASN
+CFLAGS += -DCONFIG_PTKSA_CACHE
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+OBJS += ../src/common/ptksa_cache.o
+endif
+
ifdef CONFIG_EAP_IKEV2
CFLAGS += -DEAP_SERVER_IKEV2
OBJS += ../src/eap_server/eap_server_ikev2.o ../src/eap_server/ikev2.o
@@ -704,6 +717,7 @@ LIBS += -lssl
endif
OBJS += ../src/crypto/crypto_openssl.o
HOBJS += ../src/crypto/crypto_openssl.o
+SOBJS += ../src/crypto/crypto_openssl.o
ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_openssl.o
endif
@@ -711,9 +725,11 @@ NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_h += -lcrypto
LIBS_n += -lcrypto
+LIBS_s += -lcrypto
ifdef CONFIG_TLS_ADD_DL
LIBS += -ldl
LIBS_h += -ldl
+LIBS_s += -ldl
endif
ifndef CONFIG_TLS_DEFAULT_CIPHERS
CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW"
@@ -1257,60 +1273,25 @@ ifdef CONFIG_NO_TKIP
CFLAGS += -DCONFIG_NO_TKIP
endif
-ALL=hostapd hostapd_cli
-
-all: verify_config $(ALL)
-
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-ifeq ($(QUIET), 1)
-Q=@
-E=true
-endif
-
-ifdef CONFIG_CODE_COVERAGE
-%.o: %.c
- @$(E) " CC " $<
- $(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<)
-else
-%.o: %.c
- $(Q)$(CC) -c -o $@ $(CFLAGS) $<
- @$(E) " CC " $<
-endif
-
-verify_config:
- @if [ ! -r .config ]; then \
- echo 'Building hostapd requires a configuration file'; \
- echo '(.config). See README for more instructions. You can'; \
- echo 'run "cp defconfig .config" to create an example'; \
- echo 'configuration.'; \
- exit 1; \
- fi
-
$(DESTDIR)$(BINDIR)/%: %
install -D $(<) $(@)
install: $(addprefix $(DESTDIR)$(BINDIR)/,$(ALL))
-../src/drivers/build.hostapd:
- @if [ -f ../src/drivers/build.wpa_supplicant ]; then \
- $(MAKE) -C ../src/drivers clean; \
- fi
- @touch ../src/drivers/build.hostapd
-
-BCHECK=../src/drivers/build.hostapd
+_OBJS_VAR := OBJS
+include ../src/objs.mk
-hostapd: $(BCHECK) $(OBJS)
+hostapd: $(OBJS)
$(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
@$(E) " LD " $@
ifdef CONFIG_WPA_TRACE
OBJS_c += ../src/utils/trace.o
endif
+
+_OBJS_VAR := OBJS_c
+include ../src/objs.mk
+
hostapd_cli: $(OBJS_c)
$(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c)
@$(E) " LD " $@
@@ -1345,6 +1326,35 @@ ifeq ($(CONFIG_TLS), linux)
HOBJS += ../src/crypto/crypto_linux.o
endif
+SOBJS += sae_pk_gen.o
+SOBJS += ../src/utils/common.o
+SOBJS += ../src/utils/os_$(CONFIG_OS).o
+SOBJS += ../src/utils/base64.o
+SOBJS += ../src/utils/wpa_debug.o
+SOBJS += ../src/utils/wpabuf.o
+ifdef CONFIG_WPA_TRACE
+SOBJS += ../src/utils/trace.o
+endif
+SOBJS += ../src/common/ieee802_11_common.o
+SOBJS += ../src/common/sae.o
+SOBJS += ../src/common/sae_pk.o
+SOBJS += ../src/common/dragonfly.o
+SOBJS += $(AESOBJS)
+SOBJS += ../src/crypto/sha256-prf.o
+SOBJS += ../src/crypto/sha384-prf.o
+SOBJS += ../src/crypto/sha512-prf.o
+SOBJS += ../src/crypto/dh_groups.o
+SOBJS += ../src/crypto/sha256-kdf.o
+SOBJS += ../src/crypto/sha384-kdf.o
+SOBJS += ../src/crypto/sha512-kdf.o
+
+_OBJS_VAR := NOBJS
+include ../src/objs.mk
+_OBJS_VAR := HOBJS
+include ../src/objs.mk
+_OBJS_VAR := SOBJS
+include ../src/objs.mk
+
nt_password_hash: $(NOBJS)
$(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n)
@$(E) " LD " $@
@@ -1353,15 +1363,17 @@ hlr_auc_gw: $(HOBJS)
$(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
@$(E) " LD " $@
+sae_pk_gen: $(SOBJS)
+ $(Q)$(CC) $(LDFLAGS) -o sae_pk_gen $(SOBJS) $(LIBS_s)
+ @$(E) " LD " $@
+
+.PHONY: lcov-html
lcov-html:
- lcov -c -d .. > lcov.info
+ lcov -c -d $(BUILDDIR) > lcov.info
genhtml lcov.info --output-directory lcov-html
-clean:
- $(MAKE) -C ../src clean
- rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
- rm -f *.d *.gcno *.gcda *.gcov
+clean: common-clean
+ rm -f core *~ nt_password_hash hlr_auc_gw
+ rm -f sae_pk_gen
rm -f lcov.info
rm -rf lcov-html
-
--include $(OBJS:%.o=%.d)
diff --git a/hostapd/android.config b/hostapd/android.config
index cd54efc2..fd3c1a1d 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -25,9 +25,13 @@
#LIBS += -L$(LIBNL)/lib
CONFIG_LIBNL20=y
+# BCM vendor extensions to nl80211
+ifeq ($(BOARD_WLAN_DEVICE),bcmdhd)
+CONFIG_DRIVER_NL80211_BRCM=y
+else
# QCA vendor extensions to nl80211
CONFIG_DRIVER_NL80211_QCA=y
-
+endif
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
@@ -128,6 +132,11 @@ CONFIG_IPV6=y
# IEEE 802.11ac (Very High Throughput) support
CONFIG_IEEE80211AC=y
+# IEEE 802.11ax (High Efficiency) support
+ifeq ($(WIFI_FEATURE_HOSTAPD_11AX), true)
+CONFIG_IEEE80211AX=y
+endif
+
# Remove debugging code that is printing out debug messages to stdout.
# This can be used to reduce the size of the hostapd considerably if debugging
# code is not needed.
@@ -187,7 +196,7 @@ CONFIG_AP=y
#CONFIG_FST=y
# Multiband Operation support
-# These extentions facilitate efficient use of multiple frequency bands
+# These extensions facilitate efficient use of multiple frequency bands
# available to the AP and the devices that may associate with it.
#CONFIG_MBO=y
@@ -231,3 +240,15 @@ CONFIG_SAE=y
# be completely removed in a future release.
CONFIG_WEP=y
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks.
+CONFIG_INTERWORKING=y
+
+# Testing options
+# This can be used to enable some testing options (see also the example
+# configuration file) that are useful for testing clients that
+# connect to this hostapd. These options allow, for example, to drop a
+# certain percentage of probe requests or auth/(re)assoc frames.
+# Each test case requires a flag set in hostapd.conf or through hostapd_cli
+#CONFIG_TESTING_OPTIONS=y
diff --git a/hostapd/android.hardware.wifi.hostapd.xml b/hostapd/android.hardware.wifi.hostapd.xml
index 4dc1701c..c688d3e0 100644
--- a/hostapd/android.hardware.wifi.hostapd.xml
+++ b/hostapd/android.hardware.wifi.hostapd.xml
@@ -2,7 +2,7 @@
<hal format="hidl">
<name>android.hardware.wifi.hostapd</name>
<transport>hwbinder</transport>
- <version>1.2</version>
+ <version>1.3</version>
<interface>
<name>IHostapd</name>
<instance>default</instance>
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index cc1855dc..03371e1d 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -14,6 +14,7 @@
#include "utils/common.h"
#include "utils/uuid.h"
#include "common/ieee802_11_defs.h"
+#include "common/sae.h"
#include "crypto/sha256.h"
#include "crypto/tls.h"
#include "drivers/driver.h"
@@ -340,7 +341,7 @@ static int hostapd_config_read_eap_user(const char *fname,
struct hostapd_radius_attr *attr, *a;
attr = hostapd_parse_radius_attr(buf + 19);
if (attr == NULL) {
- wpa_printf(MSG_ERROR, "Invalid radius_auth_req_attr: %s",
+ wpa_printf(MSG_ERROR, "Invalid radius_accept_attr: %s",
buf + 19);
user = NULL; /* already in the BSS list */
goto failed;
@@ -753,6 +754,10 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
else if (os_strcmp(start, "OSEN") == 0)
val |= WPA_KEY_MGMT_OSEN;
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_PASN
+ else if (os_strcmp(start, "PASN") == 0)
+ val |= WPA_KEY_MGMT_PASN;
+#endif /* CONFIG_PASN */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -942,104 +947,6 @@ static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
}
-/* convert floats with one decimal place to value*10 int, i.e.,
- * "1.5" will return 15 */
-static int hostapd_config_read_int10(const char *value)
-{
- int i, d;
- char *pos;
-
- i = atoi(value);
- pos = os_strchr(value, '.');
- d = 0;
- if (pos) {
- pos++;
- if (*pos >= '0' && *pos <= '9')
- d = *pos - '0';
- }
-
- return i * 10 + d;
-}
-
-
-static int valid_cw(int cw)
-{
- return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
- cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
- cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
- cw == 32767);
-}
-
-
-enum {
- IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
- IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
- IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
- IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
-};
-
-static int hostapd_config_tx_queue(struct hostapd_config *conf,
- const char *name, const char *val)
-{
- int num;
- const char *pos;
- struct hostapd_tx_queue_params *queue;
-
- /* skip 'tx_queue_' prefix */
- pos = name + 9;
- if (os_strncmp(pos, "data", 4) == 0 &&
- pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
- num = pos[4] - '0';
- pos += 6;
- } else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
- os_strncmp(pos, "beacon_", 7) == 0) {
- wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
- return 0;
- } else {
- wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
- return -1;
- }
-
- if (num >= NUM_TX_QUEUES) {
- /* for backwards compatibility, do not trigger failure */
- wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
- return 0;
- }
-
- queue = &conf->tx_queue[num];
-
- if (os_strcmp(pos, "aifs") == 0) {
- queue->aifs = atoi(val);
- if (queue->aifs < 0 || queue->aifs > 255) {
- wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
- queue->aifs);
- return -1;
- }
- } else if (os_strcmp(pos, "cwmin") == 0) {
- queue->cwmin = atoi(val);
- if (!valid_cw(queue->cwmin)) {
- wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
- queue->cwmin);
- return -1;
- }
- } else if (os_strcmp(pos, "cwmax") == 0) {
- queue->cwmax = atoi(val);
- if (!valid_cw(queue->cwmax)) {
- wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
- queue->cwmax);
- return -1;
- }
- } else if (os_strcmp(pos, "burst") == 0) {
- queue->burst = hostapd_config_read_int10(val);
- } else {
- wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos);
- return -1;
- }
-
- return 0;
-}
-
-
#ifdef CONFIG_IEEE80211R_AP
static int rkh_derive_key(const char *pos, u8 *key, size_t key_len)
@@ -1313,6 +1220,32 @@ static u8 set_he_cap(int val, u8 mask)
return (u8) (mask & (val << find_bit_offset(mask)));
}
+
+static int hostapd_parse_he_srg_bitmap(u8 *bitmap, char *val)
+{
+ int bitpos;
+ char *pos, *end;
+
+ os_memset(bitmap, 0, 8);
+ pos = val;
+ while (*pos != '\0') {
+ end = os_strchr(pos, ' ');
+ if (end)
+ *end = '\0';
+
+ bitpos = atoi(pos);
+ if (bitpos < 0 || bitpos > 64)
+ return -1;
+
+ bitmap[bitpos / 8] |= BIT(bitpos % 8);
+ if (!end)
+ break;
+ pos = end + 1;
+ }
+
+ return 0;
+}
+
#endif /* CONFIG_IEEE80211AX */
@@ -2290,6 +2223,35 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
pw->vlan_id = atoi(pos2);
}
+#ifdef CONFIG_SAE_PK
+ pos2 = os_strstr(pos, "|pk=");
+ if (pos2) {
+ const char *epos;
+ char *tmp;
+
+ if (!end)
+ end = pos2;
+ pos2 += 4;
+ epos = os_strchr(pos2, '|');
+ if (epos) {
+ tmp = os_malloc(epos - pos2 + 1);
+ if (!tmp)
+ goto fail;
+ os_memcpy(tmp, pos2, epos - pos2);
+ tmp[epos - pos2] = '\0';
+ } else {
+ tmp = os_strdup(pos2);
+ if (!tmp)
+ goto fail;
+ }
+
+ pw->pk = sae_parse_pk(tmp);
+ str_clear_free(tmp);
+ if (!pw->pk)
+ goto fail;
+ }
+#endif /* CONFIG_SAE_PK */
+
pos2 = os_strstr(pos, "|id=");
if (pos2) {
if (!end)
@@ -2312,6 +2274,18 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
pw->password[end - val] = '\0';
}
+#ifdef CONFIG_SAE_PK
+ if (pw->pk &&
+#ifdef CONFIG_TESTING_OPTIONS
+ !bss->sae_pk_password_check_skip &&
+#endif /* CONFIG_TESTING_OPTIONS */
+ !sae_pk_valid_password(pw->password)) {
+ wpa_printf(MSG_INFO,
+ "Invalid SAE password for a SAE-PK sae_password entry");
+ goto fail;
+ }
+#endif /* CONFIG_SAE_PK */
+
pw->next = bss->sae_passwords;
bss->sae_passwords = pw;
@@ -2319,6 +2293,9 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
fail:
str_clear_free(pw->password);
os_free(pw->identifier);
+#ifdef CONFIG_SAE_PK
+ sae_deinit_pk(pw->pk);
+#endif /* CONFIG_SAE_PK */
os_free(pw);
return -1;
}
@@ -2612,7 +2589,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "eap_teap_auth") == 0) {
int val = atoi(pos);
- if (val < 0 || val > 1) {
+ if (val < 0 || val > 2) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid eap_teap_auth value",
line);
@@ -3312,6 +3289,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
conf->rate_type = BEACON_RATE_VHT;
conf->beacon_rate = val;
+ } else if (os_strncmp(pos, "he:", 3) == 0) {
+ val = atoi(pos + 3);
+ if (val < 0 || val > 11) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid beacon_rate HE-MCS %d",
+ line, val);
+ return 1;
+ }
+ conf->rate_type = BEACON_RATE_HE;
+ conf->beacon_rate = val;
} else {
val = atoi(pos);
if (val < 10 || val > 10000) {
@@ -3383,7 +3370,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
conf->ap_table_expiration_time = atoi(pos);
} else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
- if (hostapd_config_tx_queue(conf, buf, pos)) {
+ if (hostapd_config_tx_queue(conf->tx_queue, buf, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid TX queue item",
line);
return 1;
@@ -3593,19 +3580,53 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_TIMER_IDX] =
atoi(pos) & 0xff;
} else if (os_strcmp(buf, "he_spr_sr_control") == 0) {
- conf->spr.sr_control = atoi(pos) & 0xff;
+ conf->spr.sr_control = atoi(pos) & 0x1f;
} else if (os_strcmp(buf, "he_spr_non_srg_obss_pd_max_offset") == 0) {
conf->spr.non_srg_obss_pd_max_offset = atoi(pos);
} else if (os_strcmp(buf, "he_spr_srg_obss_pd_min_offset") == 0) {
conf->spr.srg_obss_pd_min_offset = atoi(pos);
} else if (os_strcmp(buf, "he_spr_srg_obss_pd_max_offset") == 0) {
conf->spr.srg_obss_pd_max_offset = atoi(pos);
+ } else if (os_strcmp(buf, "he_spr_srg_bss_colors") == 0) {
+ if (hostapd_parse_he_srg_bitmap(
+ conf->spr.srg_bss_color_bitmap, pos)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid srg bss colors list '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "he_spr_srg_partial_bssid") == 0) {
+ if (hostapd_parse_he_srg_bitmap(
+ conf->spr.srg_partial_bssid_bitmap, pos)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid srg partial bssid list '%s'",
+ line, pos);
+ return 1;
+ }
} else if (os_strcmp(buf, "he_oper_chwidth") == 0) {
conf->he_oper_chwidth = atoi(pos);
} else if (os_strcmp(buf, "he_oper_centr_freq_seg0_idx") == 0) {
conf->he_oper_centr_freq_seg0_idx = atoi(pos);
} else if (os_strcmp(buf, "he_oper_centr_freq_seg1_idx") == 0) {
conf->he_oper_centr_freq_seg1_idx = atoi(pos);
+ } else if (os_strcmp(buf, "he_6ghz_max_mpdu") == 0) {
+ conf->he_6ghz_max_mpdu = atoi(pos);
+ } else if (os_strcmp(buf, "he_6ghz_max_ampdu_len_exp") == 0) {
+ conf->he_6ghz_max_ampdu_len_exp = atoi(pos);
+ } else if (os_strcmp(buf, "he_6ghz_rx_ant_pat") == 0) {
+ conf->he_6ghz_rx_ant_pat = atoi(pos);
+ } else if (os_strcmp(buf, "he_6ghz_tx_ant_pat") == 0) {
+ conf->he_6ghz_tx_ant_pat = atoi(pos);
+ } else if (os_strcmp(buf, "unsol_bcast_probe_resp_interval") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 20) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid unsol_bcast_probe_resp_interval value",
+ line);
+ return 1;
+ }
+ bss->unsol_bcast_probe_resp_interval = val;
#endif /* CONFIG_IEEE80211AX */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@@ -4190,6 +4211,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->own_ie_override = tmp;
} else if (os_strcmp(buf, "sae_reflection_attack") == 0) {
bss->sae_reflection_attack = atoi(pos);
+ } else if (os_strcmp(buf, "sae_commit_status") == 0) {
+ bss->sae_commit_status = atoi(pos);
+ } else if (os_strcmp(buf, "sae_pk_omit") == 0) {
+ bss->sae_pk_omit = atoi(pos);
+ } else if (os_strcmp(buf, "sae_pk_password_check_skip") == 0) {
+ bss->sae_pk_password_check_skip = atoi(pos);
} else if (os_strcmp(buf, "sae_commit_override") == 0) {
wpabuf_free(bss->sae_commit_override);
bss->sae_commit_override = wpabuf_parse_bin(pos);
@@ -4217,6 +4244,24 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->skip_prune_assoc = atoi(pos);
} else if (os_strcmp(buf, "ft_rsnxe_used") == 0) {
bss->ft_rsnxe_used = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_eapol_m3") == 0) {
+ bss->oci_freq_override_eapol_m3 = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_eapol_g1") == 0) {
+ bss->oci_freq_override_eapol_g1 = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_saquery_req") == 0) {
+ bss->oci_freq_override_saquery_req = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_saquery_resp") == 0) {
+ bss->oci_freq_override_saquery_resp = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_ft_assoc") == 0) {
+ bss->oci_freq_override_ft_assoc = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_fils_assoc") == 0) {
+ bss->oci_freq_override_fils_assoc = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_wnm_sleep") == 0) {
+ bss->oci_freq_override_wnm_sleep = atoi(pos);
+ } else if (os_strcmp(buf, "skip_send_eapol") == 0) {
+ conf->skip_send_eapol = atoi(pos);
+ } else if (os_strcmp(buf, "enable_eapol_large_timeout") == 0) {
+ conf->enable_eapol_large_timeout = atoi(pos);
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_SAE
} else if (os_strcmp(buf, "sae_password") == 0) {
@@ -4392,11 +4437,17 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->dhcp_server_port = atoi(pos);
} else if (os_strcmp(buf, "dhcp_relay_port") == 0) {
bss->dhcp_relay_port = atoi(pos);
+ } else if (os_strcmp(buf, "fils_discovery_min_interval") == 0) {
+ bss->fils_discovery_min_int = atoi(pos);
+ } else if (os_strcmp(buf, "fils_discovery_max_interval") == 0) {
+ bss->fils_discovery_max_int = atoi(pos);
#endif /* CONFIG_FILS */
} else if (os_strcmp(buf, "multicast_to_unicast") == 0) {
bss->multicast_to_unicast = atoi(pos);
} else if (os_strcmp(buf, "broadcast_deauth") == 0) {
bss->broadcast_deauth = atoi(pos);
+ } else if (os_strcmp(buf, "notify_mgmt_frames") == 0) {
+ bss->notify_mgmt_frames = atoi(pos);
#ifdef CONFIG_DPP
} else if (os_strcmp(buf, "dpp_name") == 0) {
os_free(bss->dpp_name);
@@ -4483,6 +4534,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->rssi_reject_assoc_rssi = atoi(pos);
} else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) {
conf->rssi_reject_assoc_timeout = atoi(pos);
+ } else if (os_strcmp(buf, "rssi_ignore_probe_request") == 0) {
+ conf->rssi_ignore_probe_request = atoi(pos);
} else if (os_strcmp(buf, "pbss") == 0) {
bss->pbss = atoi(pos);
} else if (os_strcmp(buf, "transition_disable") == 0) {
@@ -4602,6 +4655,25 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
bss->mka_psk_set |= MKA_PSK_SET_CKN;
#endif /* CONFIG_MACSEC */
+ } else if (os_strcmp(buf, "disable_11n") == 0) {
+ bss->disable_11n = !!atoi(pos);
+ } else if (os_strcmp(buf, "disable_11ac") == 0) {
+ bss->disable_11ac = !!atoi(pos);
+ } else if (os_strcmp(buf, "disable_11ax") == 0) {
+ bss->disable_11ax = !!atoi(pos);
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strcmp(buf, "force_kdk_derivation") == 0) {
+ bss->force_kdk_derivation = atoi(pos);
+#endif /* CONFIG_TESTING_OPTIONS */
+ } else if (os_strcmp(buf, "pasn_groups") == 0) {
+ if (hostapd_parse_intlist(&bss->pasn_groups, pos)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid pasn_groups value '%s'",
+ line, pos);
+ return 1;
+ }
+#endif /* CONFIG_PASN */
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index edc69f47..55f3da72 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -37,6 +37,7 @@
#include "common/dpp.h"
#endif /* CONFIG_DPP */
#include "common/wpa_ctrl.h"
+#include "common/ptksa_cache.h"
#include "crypto/tls.h"
#include "drivers/driver.h"
#include "eapol_auth/eapol_auth_sm.h"
@@ -47,6 +48,7 @@
#include "ap/ap_config.h"
#include "ap/ieee802_1x.h"
#include "ap/wpa_auth.h"
+#include "ap/pmksa_cache_auth.h"
#include "ap/ieee802_11.h"
#include "ap/sta_info.h"
#include "ap/wps_hostapd.h"
@@ -1221,6 +1223,52 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
return pos - buf;
pos += ret;
}
+
+ if (hapd->conf->multi_ap) {
+ struct hostapd_ssid *ssid = &hapd->conf->multi_ap_backhaul_ssid;
+
+ ret = os_snprintf(pos, end - pos, "multi_ap=%d\n",
+ hapd->conf->multi_ap);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ if (ssid->ssid_len) {
+ ret = os_snprintf(pos, end - pos,
+ "multi_ap_backhaul_ssid=%s\n",
+ wpa_ssid_txt(ssid->ssid,
+ ssid->ssid_len));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (hapd->conf->wps_state && hapd->conf->wpa &&
+ ssid->wpa_passphrase) {
+ ret = os_snprintf(pos, end - pos,
+ "multi_ap_backhaul_wpa_passphrase=%s\n",
+ ssid->wpa_passphrase);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (hapd->conf->wps_state && hapd->conf->wpa &&
+ ssid->wpa_psk &&
+ ssid->wpa_psk->group) {
+ char hex[PMK_LEN * 2 + 1];
+
+ wpa_snprintf_hex(hex, sizeof(hex), ssid->wpa_psk->psk,
+ PMK_LEN);
+ ret = os_snprintf(pos, end - pos,
+ "multi_ap_backhaul_wpa_psk=%s\n",
+ hex);
+ forced_memzero(hex, sizeof(hex));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ }
#endif /* CONFIG_WPS */
if (hapd->conf->wpa) {
@@ -1346,21 +1394,29 @@ static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd,
- const char *band)
+ const char *bands)
{
union wpa_event_data event;
- enum set_band setband;
-
- if (os_strcmp(band, "AUTO") == 0)
- setband = WPA_SETBAND_AUTO;
- else if (os_strcmp(band, "5G") == 0)
- setband = WPA_SETBAND_5G;
- else if (os_strcmp(band, "2G") == 0)
- setband = WPA_SETBAND_2G;
- else
- return -1;
+ u32 setband_mask = WPA_SETBAND_AUTO;
+
+ /*
+ * For example:
+ * SET setband 2G,6G
+ * SET setband 5G
+ * SET setband AUTO
+ */
+ if (!os_strstr(bands, "AUTO")) {
+ if (os_strstr(bands, "5G"))
+ setband_mask |= WPA_SETBAND_5G;
+ if (os_strstr(bands, "6G"))
+ setband_mask |= WPA_SETBAND_6G;
+ if (os_strstr(bands, "2G"))
+ setband_mask |= WPA_SETBAND_2G;
+ if (setband_mask == WPA_SETBAND_AUTO)
+ return -1;
+ }
- if (hostapd_drv_set_band(hapd, setband) == 0) {
+ if (hostapd_drv_set_band(hapd, setband_mask) == 0) {
os_memset(&event, 0, sizeof(event));
event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
@@ -1478,12 +1534,35 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
os_strcmp(cmd, "sae_pwe") == 0) {
if (hapd->started)
hostapd_setup_sae_pt(hapd->conf);
+ } else if (os_strcasecmp(cmd, "transition_disable") == 0) {
+ wpa_auth_set_transition_disable(hapd->wpa_auth,
+ hapd->conf->transition_disable);
}
#ifdef CONFIG_TESTING_OPTIONS
if (os_strcmp(cmd, "ft_rsnxe_used") == 0)
wpa_auth_set_ft_rsnxe_used(hapd->wpa_auth,
hapd->conf->ft_rsnxe_used);
+ else if (os_strcmp(cmd, "oci_freq_override_eapol_m3") == 0)
+ wpa_auth_set_ocv_override_freq(
+ hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_M3,
+ atoi(value));
+ else if (os_strcmp(cmd, "oci_freq_override_eapol_g1") == 0)
+ wpa_auth_set_ocv_override_freq(
+ hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_G1,
+ atoi(value));
+ else if (os_strcmp(cmd, "oci_freq_override_ft_assoc") == 0)
+ wpa_auth_set_ocv_override_freq(
+ hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_FT_ASSOC,
+ atoi(value));
+ else if (os_strcmp(cmd, "oci_freq_override_fils_assoc") == 0)
+ wpa_auth_set_ocv_override_freq(
+ hapd->wpa_auth,
+ WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC, atoi(value));
+ else if (os_strcasecmp(cmd, "skip_send_eapol") == 0)
+ wpa_auth_set_skip_send_eapol(hapd->wpa_auth, atoi(value));
+ else if (os_strcasecmp(cmd, "enable_eapol_large_timeout") == 0)
+ wpa_auth_set_enable_eapol_large_timeout(hapd->wpa_auth, atoi(value));
#endif /* CONFIG_TESTING_OPTIONS */
}
@@ -1902,7 +1981,7 @@ static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
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");
+ "test data: RX - ignore unexpected IP header");
return;
}
@@ -2437,6 +2516,19 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
}
+static int hostapd_ctrl_get_pmksa_pmk(struct hostapd_data *hapd, const u8 *addr,
+ char *buf, size_t buflen)
+{
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, addr, NULL);
+ if (!pmksa)
+ return -1;
+
+ return wpa_snprintf_hex(buf, buflen, pmksa->pmk, pmksa->pmk_len);
+}
+
+
static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
char *buf, size_t buflen)
{
@@ -2452,13 +2544,13 @@ static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
if (!sta || !sta->wpa_sm) {
wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR,
MAC2STR(addr));
- return -1;
+ return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
}
pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
- if (!pmk) {
+ if (!pmk || !pmk_len) {
wpa_printf(MSG_DEBUG, "No PMK stored for " MACSTR,
MAC2STR(addr));
- return -1;
+ return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
}
return wpa_snprintf_hex(buf, buflen, pmk, pmk_len);
@@ -2638,9 +2730,9 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
for (i = 0; i < iface->num_bss; i++) {
- /* Save CHAN_SWITCH VHT config */
- hostapd_chan_switch_vht_config(
- iface->bss[i], settings.freq_params.vht_enabled);
+ /* Save CHAN_SWITCH VHT and HE config */
+ hostapd_chan_switch_config(iface->bss[i],
+ &settings.freq_params);
ret = hostapd_switch_channel(iface->bss[i], &settings);
if (ret) {
@@ -2674,13 +2766,17 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
char *buf, size_t buflen)
{
int ret;
- char *pos;
+ char *pos, *temp = NULL;
u8 *data = NULL;
unsigned int vendor_id, subcmd;
+ enum nested_attr nested_attr_flag = NESTED_ATTR_UNSPECIFIED;
struct wpabuf *reply;
size_t data_len = 0;
- /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
+ /**
+ * cmd: <vendor id> <subcommand id> [<hex formatted data>]
+ * [nested=<0|1>]
+ */
vendor_id = strtoul(cmd, &pos, 16);
if (!isblank((unsigned char) *pos))
return -EINVAL;
@@ -2690,7 +2786,9 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
if (*pos != '\0') {
if (!isblank((unsigned char) *pos++))
return -EINVAL;
- data_len = os_strlen(pos);
+
+ temp = os_strchr(pos, ' ');
+ data_len = temp ? (size_t) (temp - pos) : os_strlen(pos);
}
if (data_len) {
@@ -2707,6 +2805,11 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
}
}
+ pos = os_strstr(cmd, "nested=");
+ if (pos)
+ nested_attr_flag = atoi(pos + 7) ? NESTED_ATTR_USED :
+ NESTED_ATTR_NOT_USED;
+
reply = wpabuf_alloc((buflen - 1) / 2);
if (!reply) {
os_free(data);
@@ -2714,7 +2817,7 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
}
ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len,
- reply);
+ nested_attr_flag, reply);
if (ret == 0)
ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
@@ -3582,16 +3685,17 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
eloop_terminate();
} else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) {
- if (!hostapd_ctrl_iface_acl_add_mac(
+ if (hostapd_ctrl_iface_acl_add_mac(
+ &hapd->conf->accept_mac,
+ &hapd->conf->num_accept_mac, buf + 19))
+ reply_len = -1;
+ } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
+ if (!hostapd_ctrl_iface_acl_del_mac(
&hapd->conf->accept_mac,
&hapd->conf->num_accept_mac, buf + 19))
hostapd_disassoc_accept_mac(hapd);
else
reply_len = -1;
- } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
- hostapd_ctrl_iface_acl_del_mac(
- &hapd->conf->accept_mac,
- &hapd->conf->num_accept_mac, buf + 19);
} else if (os_strcmp(buf + 11, "SHOW") == 0) {
reply_len = hostapd_ctrl_iface_acl_show_mac(
hapd->conf->accept_mac,
@@ -3600,6 +3704,7 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
hostapd_ctrl_iface_acl_clear_list(
&hapd->conf->accept_mac,
&hapd->conf->num_accept_mac);
+ hostapd_disassoc_accept_mac(hapd);
}
} else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) {
if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) {
@@ -3607,10 +3712,13 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
&hapd->conf->deny_mac,
&hapd->conf->num_deny_mac, buf + 17))
hostapd_disassoc_deny_mac(hapd);
+ else
+ reply_len = -1;
} else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) {
- hostapd_ctrl_iface_acl_del_mac(
- &hapd->conf->deny_mac,
- &hapd->conf->num_deny_mac, buf + 17);
+ if (hostapd_ctrl_iface_acl_del_mac(
+ &hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac, buf + 17))
+ reply_len = -1;
} else if (os_strcmp(buf + 9, "SHOW") == 0) {
reply_len = hostapd_ctrl_iface_acl_show_mac(
hapd->conf->deny_mac,
@@ -3735,6 +3843,14 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0)
reply_len = -1;
#ifdef CONFIG_DPP2
+ } else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) {
+ if (hostapd_dpp_controller_start(hapd, buf + 20) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_CONTROLLER_START") == 0) {
+ if (hostapd_dpp_controller_start(hapd, NULL) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) {
+ dpp_controller_stop(hapd->iface->interfaces->dpp);
} else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) {
if (hostapd_dpp_chirp(hapd, buf + 9) < 0)
reply_len = -1;
@@ -3750,6 +3866,10 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
reply_len = hostapd_ctrl_iface_get_capability(
hapd, buf + 15, reply, reply_size);
+#ifdef CONFIG_PASN
+ } else if (os_strcmp(buf, "PTKSA_CACHE_LIST") == 0) {
+ reply_len = ptksa_cache_list(hapd->ptksa, reply, reply_size);
+#endif /* CONFIG_PASN */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 23417651..d7626a29 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -351,7 +351,7 @@ CONFIG_IPV6=y
#CONFIG_ACS=y
# Multiband Operation support
-# These extentions facilitate efficient use of multiple frequency bands
+# These extensions facilitate efficient use of multiple frequency bands
# available to the AP and the devices that may associate with it.
#CONFIG_MBO=y
@@ -400,3 +400,10 @@ CONFIG_IPV6=y
# build includes this to allow mixed mode WPA+WPA2 networks to be enabled, but
# that functionality is subject to be removed in the future.
#CONFIG_NO_TKIP=y
+
+# Pre-Association Security Negotiation (PASN)
+# Experimental implementation based on IEEE P802.11z/D2.6 and the protocol
+# design is still subject to change. As such, this should not yet be enabled in
+# production use.
+# This requires CONFIG_IEEE80211W=y to be enabled, too.
+#CONFIG_PASN=y
diff --git a/hostapd/hidl/1.2/hostapd.cpp b/hostapd/hidl/1.2/hostapd.cpp
deleted file mode 100644
index 7789ed69..00000000
--- a/hostapd/hidl/1.2/hostapd.cpp
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * hidl interface for wpa_hostapd daemon
- * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2018, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-#include <iomanip>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-
-#include "hostapd.h"
-#include "hidl_return_util.h"
-
-extern "C"
-{
-#include "utils/eloop.h"
-}
-
-// The HIDL implementation for hostapd creates a hostapd.conf dynamically for
-// each interface. This file can then be used to hook onto the normal config
-// file parsing logic in hostapd code. Helps us to avoid duplication of code
-// in the HIDL interface.
-// TOOD(b/71872409): Add unit tests for this.
-namespace {
-constexpr char kConfFileNameFmt[] = "/data/vendor/wifi/hostapd/hostapd_%s.conf";
-
-using android::base::RemoveFileIfExists;
-using android::base::StringPrintf;
-using android::base::WriteStringToFile;
-using android::hardware::wifi::hostapd::V1_2::IHostapd;
-
-std::string WriteHostapdConfig(
- const std::string& interface_name, const std::string& config)
-{
- const std::string file_path =
- StringPrintf(kConfFileNameFmt, interface_name.c_str());
- if (WriteStringToFile(
- config, file_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
- getuid(), getgid())) {
- return file_path;
- }
- // Diagnose failure
- int error = errno;
- wpa_printf(
- MSG_ERROR, "Cannot write hostapd config to %s, error: %s",
- file_path.c_str(), strerror(error));
- struct stat st;
- int result = stat(file_path.c_str(), &st);
- if (result == 0) {
- wpa_printf(
- MSG_ERROR, "hostapd config file uid: %d, gid: %d, mode: %d",
- st.st_uid, st.st_gid, st.st_mode);
- } else {
- wpa_printf(
- MSG_ERROR,
- "Error calling stat() on hostapd config file: %s",
- strerror(errno));
- }
- return "";
-}
-
-/*
- * Get the op_class for a channel/band
- * The logic here is based on Table E-4 in the 802.11 Specification
- */
-int getOpClassForChannel(int channel, int band, bool support11n, bool support11ac) {
- // 2GHz Band
- if ((band & IHostapd::BandMask::BAND_2_GHZ) != 0) {
- if (channel == 14) {
- return 82;
- }
- if (channel >= 1 && channel <= 13) {
- if (!support11n) {
- //20MHz channel
- return 81;
- }
- if (channel <= 9) {
- // HT40 with secondary channel above primary
- return 83;
- }
- // HT40 with secondary channel below primary
- return 84;
- }
- // Error
- return 0;
- }
-
- // 5GHz Band
- if ((band & IHostapd::BandMask::BAND_5_GHZ) != 0) {
- if (support11ac) {
- switch (channel) {
- case 42:
- case 58:
- case 106:
- case 122:
- case 138:
- case 155:
- // 80MHz channel
- return 128;
- case 50:
- case 114:
- // 160MHz channel
- return 129;
- }
- }
-
- if (!support11n) {
- if (channel >= 36 && channel <= 48) {
- return 115;
- }
- if (channel >= 52 && channel <= 64) {
- return 118;
- }
- if (channel >= 100 && channel <= 144) {
- return 121;
- }
- if (channel >= 149 && channel <= 161) {
- return 124;
- }
- if (channel >= 165 && channel <= 169) {
- return 125;
- }
- } else {
- switch (channel) {
- case 36:
- case 44:
- // HT40 with secondary channel above primary
- return 116;
- case 40:
- case 48:
- // HT40 with secondary channel below primary
- return 117;
- case 52:
- case 60:
- // HT40 with secondary channel above primary
- return 119;
- case 56:
- case 64:
- // HT40 with secondary channel below primary
- return 120;
- case 100:
- case 108:
- case 116:
- case 124:
- case 132:
- case 140:
- // HT40 with secondary channel above primary
- return 122;
- case 104:
- case 112:
- case 120:
- case 128:
- case 136:
- case 144:
- // HT40 with secondary channel below primary
- return 123;
- case 149:
- case 157:
- // HT40 with secondary channel above primary
- return 126;
- case 153:
- case 161:
- // HT40 with secondary channel below primary
- return 127;
- }
- }
- // Error
- return 0;
- }
-
- // 6GHz Band
- if ((band & IHostapd::BandMask::BAND_6_GHZ) != 0) {
- // Channels 1, 5. 9, 13, ...
- if ((channel & 0x03) == 0x01) {
- // 20MHz channel
- return 131;
- }
- // Channels 3, 11, 19, 27, ...
- if ((channel & 0x07) == 0x03) {
- // 40MHz channel
- return 132;
- }
- // Channels 7, 23, 39, 55, ...
- if ((channel & 0x0F) == 0x07) {
- // 80MHz channel
- return 133;
- }
- // Channels 15, 47, 69, ...
- if ((channel & 0x1F) == 0x0F) {
- // 160MHz channel
- return 134;
- }
- if (channel == 2) {
- // 20MHz channel
- return 136;
- }
- // Error
- return 0;
- }
-
- return 0;
-}
-
-bool validatePassphrase(int passphrase_len, int min_len, int max_len)
-{
- if (min_len != -1 && passphrase_len < min_len) return false;
- if (max_len != -1 && passphrase_len > max_len) return false;
- return true;
-}
-
-std::string CreateHostapdConfig(
- const IHostapd::IfaceParams& iface_params,
- const IHostapd::NetworkParams& nw_params)
-{
- if (nw_params.V1_0.ssid.size() >
- static_cast<uint32_t>(
- IHostapd::ParamSizeLimits::SSID_MAX_LEN_IN_BYTES)) {
- wpa_printf(
- MSG_ERROR, "Invalid SSID size: %zu", nw_params.V1_0.ssid.size());
- return "";
- }
-
- // SSID string
- std::stringstream ss;
- ss << std::hex;
- ss << std::setfill('0');
- for (uint8_t b : nw_params.V1_0.ssid) {
- ss << std::setw(2) << static_cast<unsigned int>(b);
- }
- const std::string ssid_as_string = ss.str();
-
- // Encryption config string
- std::string encryption_config_as_string;
- switch (nw_params.encryptionType) {
- case IHostapd::EncryptionType::NONE:
- // no security params
- break;
- case IHostapd::EncryptionType::WPA:
- if (!validatePassphrase(
- nw_params.passphrase.size(),
- static_cast<uint32_t>(IHostapd::ParamSizeLimits::
- WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
- static_cast<uint32_t>(IHostapd::ParamSizeLimits::
- WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
- return "";
- }
- encryption_config_as_string = StringPrintf(
- "wpa=3\n"
- "wpa_pairwise=TKIP CCMP\n"
- "wpa_passphrase=%s",
- nw_params.passphrase.c_str());
- break;
- case IHostapd::EncryptionType::WPA2:
- if (!validatePassphrase(
- nw_params.passphrase.size(),
- static_cast<uint32_t>(IHostapd::ParamSizeLimits::
- WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
- static_cast<uint32_t>(IHostapd::ParamSizeLimits::
- WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
- return "";
- }
- encryption_config_as_string = StringPrintf(
- "wpa=2\n"
- "rsn_pairwise=CCMP\n"
- "wpa_passphrase=%s",
- nw_params.passphrase.c_str());
- break;
- case IHostapd::EncryptionType::WPA3_SAE_TRANSITION:
- if (!validatePassphrase(
- nw_params.passphrase.size(),
- static_cast<uint32_t>(IHostapd::ParamSizeLimits::
- WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
- static_cast<uint32_t>(IHostapd::ParamSizeLimits::
- WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
- return "";
- }
- encryption_config_as_string = StringPrintf(
- "wpa=2\n"
- "rsn_pairwise=CCMP\n"
- "wpa_key_mgmt=WPA-PSK SAE\n"
- "ieee80211w=1\n"
- "sae_require_mfp=1\n"
- "wpa_passphrase=%s\n"
- "sae_password=%s",
- nw_params.passphrase.c_str(),
- nw_params.passphrase.c_str());
- break;
- case IHostapd::EncryptionType::WPA3_SAE:
- if (!validatePassphrase(nw_params.passphrase.size(), 1, -1)) {
- return "";
- }
- encryption_config_as_string = StringPrintf(
- "wpa=2\n"
- "rsn_pairwise=CCMP\n"
- "wpa_key_mgmt=SAE\n"
- "ieee80211w=2\n"
- "sae_require_mfp=2\n"
- "sae_password=%s",
- nw_params.passphrase.c_str());
- break;
- default:
- wpa_printf(MSG_ERROR, "Unknown encryption type");
- return "";
- }
-
- unsigned int band = 0;
- band |= iface_params.channelParams.bandMask;
-
- std::string channel_config_as_string;
- bool isFirst = true;
- if (iface_params.V1_1.V1_0.channelParams.enableAcs) {
- std::string freqList_as_string;
- for (const auto &range :
- iface_params.channelParams.acsChannelFreqRangesMhz) {
- if (!isFirst) {
- freqList_as_string += ",";
- }
- isFirst = false;
-
- if (range.start != range.end) {
- freqList_as_string +=
- StringPrintf("%d-%d", range.start, range.end);
- } else {
- freqList_as_string += StringPrintf("%d", range.start);
- }
- }
- channel_config_as_string = StringPrintf(
- "channel=0\n"
- "acs_exclude_dfs=%d\n"
- "freqlist=%s",
- iface_params.V1_1.V1_0.channelParams.acsShouldExcludeDfs,
- freqList_as_string.c_str());
- } else {
- int op_class = getOpClassForChannel(
- iface_params.V1_1.V1_0.channelParams.channel,
- band,
- iface_params.V1_1.V1_0.hwModeParams.enable80211N,
- iface_params.V1_1.V1_0.hwModeParams.enable80211AC);
- channel_config_as_string = StringPrintf(
- "channel=%d\n"
- "op_class=%d",
- iface_params.V1_1.V1_0.channelParams.channel, op_class);
- }
-
- std::string hw_mode_as_string;
- std::string ht_cap_vht_oper_chwidth_as_string;
-
- if ((band & IHostapd::BandMask::BAND_2_GHZ) != 0) {
- if (((band & IHostapd::BandMask::BAND_5_GHZ) != 0)
- || ((band & IHostapd::BandMask::BAND_6_GHZ) != 0)) {
- hw_mode_as_string = "hw_mode=any";
- if (iface_params.V1_1.V1_0.channelParams.enableAcs) {
- ht_cap_vht_oper_chwidth_as_string =
- "ht_capab=[HT40+]\n"
- "vht_oper_chwidth=1";
- }
- } else {
- hw_mode_as_string = "hw_mode=g";
- }
- } else {
- if (((band & IHostapd::BandMask::BAND_5_GHZ) != 0)
- || ((band & IHostapd::BandMask::BAND_6_GHZ) != 0)) {
- hw_mode_as_string = "hw_mode=a";
- if (iface_params.V1_1.V1_0.channelParams.enableAcs) {
- ht_cap_vht_oper_chwidth_as_string =
- "ht_capab=[HT40+]\n"
- "vht_oper_chwidth=1";
- }
- } else {
- wpa_printf(MSG_ERROR, "Invalid band");
- return "";
- }
- }
-
- std::string he_params_as_string;
-#ifdef CONFIG_IEEE80211AX
- if (iface_params.hwModeParams.enable80211AX) {
- he_params_as_string = StringPrintf(
- "ieee80211ax=1\n"
- "he_su_beamformer=%d\n"
- "he_su_beamformee=%d\n"
- "he_mu_beamformer=%d\n"
- "he_twt_required=%d\n",
- iface_params.hwModeParams.enableHeSingleUserBeamformer ? 1 : 0,
- iface_params.hwModeParams.enableHeSingleUserBeamformee ? 1 : 0,
- iface_params.hwModeParams.enableHeMultiUserBeamformer ? 1 : 0,
- iface_params.hwModeParams.enableHeTargetWakeTime ? 1 : 0);
- } else {
- he_params_as_string = "ieee80211ax=0";
- }
-#endif /* CONFIG_IEEE80211AX */
-
- return StringPrintf(
- "interface=%s\n"
- "driver=nl80211\n"
- "ctrl_interface=/data/vendor/wifi/hostapd/ctrl\n"
- // ssid2 signals to hostapd that the value is not a literal value
- // for use as a SSID. In this case, we're giving it a hex
- // std::string and hostapd needs to expect that.
- "ssid2=%s\n"
- "%s\n"
- "ieee80211n=%d\n"
- "ieee80211ac=%d\n"
- "%s\n"
- "%s\n"
- "%s\n"
- "ignore_broadcast_ssid=%d\n"
- "wowlan_triggers=any\n"
- "%s\n",
- iface_params.V1_1.V1_0.ifaceName.c_str(), ssid_as_string.c_str(),
- channel_config_as_string.c_str(),
- iface_params.V1_1.V1_0.hwModeParams.enable80211N ? 1 : 0,
- iface_params.V1_1.V1_0.hwModeParams.enable80211AC ? 1 : 0,
- he_params_as_string.c_str(),
- hw_mode_as_string.c_str(), ht_cap_vht_oper_chwidth_as_string.c_str(),
- nw_params.V1_0.isHidden ? 1 : 0, encryption_config_as_string.c_str());
-}
-
-// hostapd core functions accept "C" style function pointers, so use global
-// functions to pass to the hostapd core function and store the corresponding
-// std::function methods to be invoked.
-//
-// NOTE: Using the pattern from the vendor HAL (wifi_legacy_hal.cpp).
-//
-// Callback to be invoked once setup is complete
-std::function<void(struct hostapd_data*)> on_setup_complete_internal_callback;
-void onAsyncSetupCompleteCb(void* ctx)
-{
- struct hostapd_data* iface_hapd = (struct hostapd_data*)ctx;
- if (on_setup_complete_internal_callback) {
- on_setup_complete_internal_callback(iface_hapd);
- // Invalidate this callback since we don't want this firing
- // again.
- on_setup_complete_internal_callback = nullptr;
- }
-}
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace hostapd {
-namespace V1_2 {
-namespace implementation {
-using hidl_return_util::call;
-using namespace android::hardware::wifi::hostapd::V1_0;
-
-Hostapd::Hostapd(struct hapd_interfaces* interfaces) : interfaces_(interfaces)
-{}
-
-Return<void> Hostapd::addAccessPoint(
- const V1_0::IHostapd::IfaceParams& iface_params,
- const V1_0::IHostapd::NetworkParams& nw_params, addAccessPoint_cb _hidl_cb)
-{
- return call(
- this, &Hostapd::addAccessPointInternal, _hidl_cb, iface_params,
- nw_params);
-}
-
-Return<void> Hostapd::addAccessPoint_1_1(
- const V1_1::IHostapd::IfaceParams& iface_params,
- const V1_0::IHostapd::NetworkParams& nw_params, addAccessPoint_cb _hidl_cb)
-{
- return call(
- this, &Hostapd::addAccessPointInternal_1_1, _hidl_cb, iface_params,
- nw_params);
-}
-
-Return<void> Hostapd::addAccessPoint_1_2(
- const IfaceParams& iface_params, const NetworkParams& nw_params,
- addAccessPoint_1_2_cb _hidl_cb)
-{
- return call(
- this, &Hostapd::addAccessPointInternal_1_2, _hidl_cb, iface_params,
- nw_params);
-}
-
-Return<void> Hostapd::removeAccessPoint(
- const hidl_string& iface_name, removeAccessPoint_cb _hidl_cb)
-{
- return call(
- this, &Hostapd::removeAccessPointInternal, _hidl_cb, iface_name);
-}
-
-Return<void> Hostapd::terminate()
-{
- wpa_printf(MSG_INFO, "Terminating...");
- eloop_terminate();
- return Void();
-}
-
-Return<void> Hostapd::registerCallback(
- const sp<V1_1::IHostapdCallback>& callback, registerCallback_cb _hidl_cb)
-{
- return call(
- this, &Hostapd::registerCallbackInternal, _hidl_cb, callback);
-}
-
-Return<void> Hostapd::forceClientDisconnect(
- const hidl_string& iface_name, const hidl_array<uint8_t, 6>& client_address,
- V1_2::Ieee80211ReasonCode reason_code, forceClientDisconnect_cb _hidl_cb)
-{
- return call(
- this, &Hostapd::forceClientDisconnectInternal, _hidl_cb, iface_name,
- client_address, reason_code);
-}
-
-Return<void> Hostapd::setDebugParams(
- DebugLevel level, setDebugParams_cb _hidl_cb)
-{
- return call(
- this, &Hostapd::setDebugParamsInternal, _hidl_cb, level);
-}
-
-V1_0::HostapdStatus Hostapd::addAccessPointInternal(
- const V1_0::IHostapd::IfaceParams& iface_params,
- const V1_0::IHostapd::NetworkParams& nw_params)
-{
- return {V1_0::HostapdStatusCode::FAILURE_UNKNOWN, ""};
-}
-
-V1_0::HostapdStatus Hostapd::addAccessPointInternal_1_1(
- const V1_1::IHostapd::IfaceParams& iface_params,
- const V1_1::IHostapd::NetworkParams& nw_params)
-{
- return {V1_0::HostapdStatusCode::FAILURE_UNKNOWN, ""};
-}
-
-HostapdStatus Hostapd::addAccessPointInternal_1_2(
- const IfaceParams& iface_params, const NetworkParams& nw_params)
-{
- if (hostapd_get_iface(interfaces_, iface_params.V1_1.V1_0.ifaceName.c_str())) {
- wpa_printf(
- MSG_ERROR, "Interface %s already present",
- iface_params.V1_1.V1_0.ifaceName.c_str());
- return {HostapdStatusCode::FAILURE_IFACE_EXISTS, ""};
- }
- const auto conf_params = CreateHostapdConfig(iface_params, nw_params);
- if (conf_params.empty()) {
- wpa_printf(MSG_ERROR, "Failed to create config params");
- return {HostapdStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- const auto conf_file_path =
- WriteHostapdConfig(iface_params.V1_1.V1_0.ifaceName, conf_params);
- if (conf_file_path.empty()) {
- wpa_printf(MSG_ERROR, "Failed to write config file");
- return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
- }
- std::string add_iface_param_str = StringPrintf(
- "%s config=%s", iface_params.V1_1.V1_0.ifaceName.c_str(),
- conf_file_path.c_str());
- std::vector<char> add_iface_param_vec(
- add_iface_param_str.begin(), add_iface_param_str.end() + 1);
- if (hostapd_add_iface(interfaces_, add_iface_param_vec.data()) < 0) {
- wpa_printf(
- MSG_ERROR, "Adding interface %s failed",
- add_iface_param_str.c_str());
- return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
- }
- struct hostapd_data* iface_hapd =
- hostapd_get_iface(interfaces_, iface_params.V1_1.V1_0.ifaceName.c_str());
- WPA_ASSERT(iface_hapd != nullptr && iface_hapd->iface != nullptr);
- // Register the setup complete callbacks
- on_setup_complete_internal_callback =
- [this](struct hostapd_data* iface_hapd) {
- wpa_printf(
- MSG_DEBUG, "AP interface setup completed - state %s",
- hostapd_state_text(iface_hapd->iface->state));
- if (iface_hapd->iface->state == HAPD_IFACE_DISABLED) {
- // Invoke the failure callback on all registered
- // clients.
- for (const auto& callback : callbacks_) {
- callback->onFailure(
- iface_hapd->conf->iface);
- }
- }
- };
- iface_hapd->setup_complete_cb = onAsyncSetupCompleteCb;
- iface_hapd->setup_complete_cb_ctx = iface_hapd;
- if (hostapd_enable_iface(iface_hapd->iface) < 0) {
- wpa_printf(
- MSG_ERROR, "Enabling interface %s failed",
- iface_params.V1_1.V1_0.ifaceName.c_str());
- return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {HostapdStatusCode::SUCCESS, ""};
-}
-
-V1_0::HostapdStatus Hostapd::removeAccessPointInternal(const std::string& iface_name)
-{
- std::vector<char> remove_iface_param_vec(
- iface_name.begin(), iface_name.end() + 1);
- if (hostapd_remove_iface(interfaces_, remove_iface_param_vec.data()) <
- 0) {
- wpa_printf(
- MSG_ERROR, "Removing interface %s failed",
- iface_name.c_str());
- return {V1_0::HostapdStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {V1_0::HostapdStatusCode::SUCCESS, ""};
-}
-
-V1_0::HostapdStatus Hostapd::registerCallbackInternal(
- const sp<V1_1::IHostapdCallback>& callback)
-{
- callbacks_.push_back(callback);
- return {V1_0::HostapdStatusCode::SUCCESS, ""};
-}
-
-V1_2::HostapdStatus Hostapd::forceClientDisconnectInternal(const std::string& iface_name,
- const std::array<uint8_t, 6>& client_address, V1_2::Ieee80211ReasonCode reason_code)
-{
- struct hostapd_data *hapd = hostapd_get_iface(interfaces_, iface_name.c_str());
- struct sta_info *sta;
- if (!hapd) {
- wpa_printf(MSG_ERROR, "Interface %s doesn't exist", iface_name.c_str());
- return {V1_2::HostapdStatusCode::FAILURE_IFACE_UNKNOWN, ""};
- }
- for (sta = hapd->sta_list; sta; sta = sta->next) {
- int res;
- res = memcmp(sta->addr, client_address.data(), ETH_ALEN);
- if (res == 0) {
- wpa_printf(MSG_INFO, "Force client:" MACSTR " disconnect with reason: %d",
- MAC2STR(client_address.data()), (uint16_t) reason_code);
- ap_sta_disconnect(hapd, sta, sta->addr, (uint16_t) reason_code);
- return {V1_2::HostapdStatusCode::SUCCESS, ""};
- }
- }
- return {V1_2::HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, ""};
-}
-
-V1_2::HostapdStatus Hostapd::setDebugParamsInternal(DebugLevel level)
-{
- wpa_debug_level = static_cast<uint32_t>(level);
- return {V1_2::HostapdStatusCode::SUCCESS, ""};
-}
-
-} // namespace implementation
-} // namespace V1_2
-} // namespace hostapd
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/hostapd/hidl/1.2/hidl.cpp b/hostapd/hidl/1.3/hidl.cpp
index 4bde3124..84819089 100644
--- a/hostapd/hidl/1.2/hidl.cpp
+++ b/hostapd/hidl/1.3/hidl.cpp
@@ -22,8 +22,8 @@ extern "C"
using android::hardware::configureRpcThreadpool;
using android::hardware::IPCThreadState;
-using android::hardware::wifi::hostapd::V1_2::IHostapd;
-using android::hardware::wifi::hostapd::V1_2::implementation::Hostapd;
+using android::hardware::wifi::hostapd::V1_3::IHostapd;
+using android::hardware::wifi::hostapd::V1_3::implementation::Hostapd;
// This file is a bridge between the hostapd code written in 'C' and the HIDL
// interface in C++. So, using "C" style static globals here!
@@ -62,7 +62,9 @@ err:
void hostapd_hidl_deinit(struct hapd_interfaces *interfaces)
{
- wpa_printf(MSG_DEBUG, "Deiniting hidl control");
+ wpa_printf(MSG_INFO, "Deiniting hidl control");
+ // Before hidl init, make sure call terminate to clear callback_
+ service->terminate();
eloop_unregister_read_sock(hidl_fd);
IPCThreadState::shutdown();
hidl_fd = -1;
diff --git a/hostapd/hidl/1.2/hidl.h b/hostapd/hidl/1.3/hidl.h
index 5decf64e..5decf64e 100644
--- a/hostapd/hidl/1.2/hidl.h
+++ b/hostapd/hidl/1.3/hidl.h
diff --git a/hostapd/hidl/1.2/hidl_return_util.h b/hostapd/hidl/1.3/hidl_return_util.h
index 81742f8f..6d503487 100644
--- a/hostapd/hidl/1.2/hidl_return_util.h
+++ b/hostapd/hidl/1.3/hidl_return_util.h
@@ -16,7 +16,7 @@ namespace android {
namespace hardware {
namespace wifi {
namespace hostapd {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
namespace hidl_return_util {
@@ -35,7 +35,7 @@ Return<void> call(
}
} // namespace hidl_return_util
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace hostapd
} // namespace wifi
} // namespace hardware
diff --git a/hostapd/hidl/1.3/hostapd.cpp b/hostapd/hidl/1.3/hostapd.cpp
new file mode 100644
index 00000000..6add761e
--- /dev/null
+++ b/hostapd/hidl/1.3/hostapd.cpp
@@ -0,0 +1,1034 @@
+/*
+ * hidl interface for wpa_hostapd daemon
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <linux/if_bridge.h>
+
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+
+#include "hostapd.h"
+#include "hidl_return_util.h"
+
+extern "C"
+{
+#include "common/wpa_ctrl.h"
+#include "drivers/linux_ioctl.h"
+}
+
+// The HIDL implementation for hostapd creates a hostapd.conf dynamically for
+// each interface. This file can then be used to hook onto the normal config
+// file parsing logic in hostapd code. Helps us to avoid duplication of code
+// in the HIDL interface.
+// TOOD(b/71872409): Add unit tests for this.
+namespace {
+constexpr char kConfFileNameFmt[] = "/data/vendor/wifi/hostapd/hostapd_%s.conf";
+
+using android::base::RemoveFileIfExists;
+using android::base::StringPrintf;
+using android::base::WriteStringToFile;
+using android::hardware::wifi::hostapd::V1_3::IHostapd;
+using android::hardware::wifi::hostapd::V1_3::Generation;
+using android::hardware::wifi::hostapd::V1_3::Bandwidth;
+
+#define MAX_PORTS 1024
+bool GetInterfacesInBridge(std::string br_name,
+ std::vector<std::string>* interfaces) {
+ android::base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+ if (sock.get() < 0) {
+ wpa_printf(MSG_ERROR, "Failed to create sock (%s) in %s",
+ strerror(errno), __FUNCTION__);
+ return false;
+ }
+
+ struct ifreq request;
+ int i, ifindices[MAX_PORTS];
+ char if_name[IFNAMSIZ];
+ unsigned long args[3];
+
+ memset(ifindices, 0, MAX_PORTS * sizeof(int));
+
+ args[0] = BRCTL_GET_PORT_LIST;
+ args[1] = (unsigned long) ifindices;
+ args[2] = MAX_PORTS;
+
+ strlcpy(request.ifr_name, br_name.c_str(), IFNAMSIZ);
+ request.ifr_data = (char *)args;
+
+ if (ioctl(sock.get(), SIOCDEVPRIVATE, &request) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to ioctl SIOCDEVPRIVATE in %s",
+ __FUNCTION__);
+ return false;
+ }
+
+ for (i = 0; i < MAX_PORTS; i ++) {
+ memset(if_name, 0, IFNAMSIZ);
+ if (ifindices[i] == 0 || !if_indextoname(ifindices[i], if_name)) {
+ continue;
+ }
+ interfaces->push_back(if_name);
+ }
+ return true;
+}
+
+std::string WriteHostapdConfig(
+ const std::string& interface_name, const std::string& config)
+{
+ const std::string file_path =
+ StringPrintf(kConfFileNameFmt, interface_name.c_str());
+ if (WriteStringToFile(
+ config, file_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+ getuid(), getgid())) {
+ return file_path;
+ }
+ // Diagnose failure
+ int error = errno;
+ wpa_printf(
+ MSG_ERROR, "Cannot write hostapd config to %s, error: %s",
+ file_path.c_str(), strerror(error));
+ struct stat st;
+ int result = stat(file_path.c_str(), &st);
+ if (result == 0) {
+ wpa_printf(
+ MSG_ERROR, "hostapd config file uid: %d, gid: %d, mode: %d",
+ st.st_uid, st.st_gid, st.st_mode);
+ } else {
+ wpa_printf(
+ MSG_ERROR,
+ "Error calling stat() on hostapd config file: %s",
+ strerror(errno));
+ }
+ return "";
+}
+
+/*
+ * Get the op_class for a channel/band
+ * The logic here is based on Table E-4 in the 802.11 Specification
+ */
+int getOpClassForChannel(int channel, int band, bool support11n, bool support11ac) {
+ // 2GHz Band
+ if ((band & IHostapd::BandMask::BAND_2_GHZ) != 0) {
+ if (channel == 14) {
+ return 82;
+ }
+ if (channel >= 1 && channel <= 13) {
+ if (!support11n) {
+ //20MHz channel
+ return 81;
+ }
+ if (channel <= 9) {
+ // HT40 with secondary channel above primary
+ return 83;
+ }
+ // HT40 with secondary channel below primary
+ return 84;
+ }
+ // Error
+ return 0;
+ }
+
+ // 5GHz Band
+ if ((band & IHostapd::BandMask::BAND_5_GHZ) != 0) {
+ if (support11ac) {
+ switch (channel) {
+ case 42:
+ case 58:
+ case 106:
+ case 122:
+ case 138:
+ case 155:
+ // 80MHz channel
+ return 128;
+ case 50:
+ case 114:
+ // 160MHz channel
+ return 129;
+ }
+ }
+
+ if (!support11n) {
+ if (channel >= 36 && channel <= 48) {
+ return 115;
+ }
+ if (channel >= 52 && channel <= 64) {
+ return 118;
+ }
+ if (channel >= 100 && channel <= 144) {
+ return 121;
+ }
+ if (channel >= 149 && channel <= 161) {
+ return 124;
+ }
+ if (channel >= 165 && channel <= 169) {
+ return 125;
+ }
+ } else {
+ switch (channel) {
+ case 36:
+ case 44:
+ // HT40 with secondary channel above primary
+ return 116;
+ case 40:
+ case 48:
+ // HT40 with secondary channel below primary
+ return 117;
+ case 52:
+ case 60:
+ // HT40 with secondary channel above primary
+ return 119;
+ case 56:
+ case 64:
+ // HT40 with secondary channel below primary
+ return 120;
+ case 100:
+ case 108:
+ case 116:
+ case 124:
+ case 132:
+ case 140:
+ // HT40 with secondary channel above primary
+ return 122;
+ case 104:
+ case 112:
+ case 120:
+ case 128:
+ case 136:
+ case 144:
+ // HT40 with secondary channel below primary
+ return 123;
+ case 149:
+ case 157:
+ // HT40 with secondary channel above primary
+ return 126;
+ case 153:
+ case 161:
+ // HT40 with secondary channel below primary
+ return 127;
+ }
+ }
+ // Error
+ return 0;
+ }
+
+ // 6GHz Band
+ if ((band & IHostapd::BandMask::BAND_6_GHZ) != 0) {
+ // Channels 1, 5. 9, 13, ...
+ if ((channel & 0x03) == 0x01) {
+ // 20MHz channel
+ return 131;
+ }
+ // Channels 3, 11, 19, 27, ...
+ if ((channel & 0x07) == 0x03) {
+ // 40MHz channel
+ return 132;
+ }
+ // Channels 7, 23, 39, 55, ...
+ if ((channel & 0x0F) == 0x07) {
+ // 80MHz channel
+ return 133;
+ }
+ // Channels 15, 47, 69, ...
+ if ((channel & 0x1F) == 0x0F) {
+ // 160MHz channel
+ return 134;
+ }
+ if (channel == 2) {
+ // 20MHz channel
+ return 136;
+ }
+ // Error
+ return 0;
+ }
+
+ if ((band & IHostapd::BandMask::BAND_60_GHZ) != 0) {
+ if (1 <= channel && channel <= 8) {
+ return 180;
+ } else if (9 <= channel && channel <= 15) {
+ return 181;
+ } else if (17 <= channel && channel <= 22) {
+ return 182;
+ } else if (25 <= channel && channel <= 29) {
+ return 183;
+ }
+ // Error
+ return 0;
+ }
+
+ return 0;
+}
+
+bool validatePassphrase(int passphrase_len, int min_len, int max_len)
+{
+ if (min_len != -1 && passphrase_len < min_len) return false;
+ if (max_len != -1 && passphrase_len > max_len) return false;
+ return true;
+}
+
+std::string CreateHostapdConfig(
+ const android::hardware::wifi::hostapd::V1_3::IHostapd::IfaceParams& iface_params,
+ const android::hardware::wifi::hostapd::V1_3::IHostapd::ChannelParams& channelParams,
+ const IHostapd::NetworkParams& nw_params,
+ const std::string br_name)
+{
+ if (nw_params.V1_2.V1_0.ssid.size() >
+ static_cast<uint32_t>(
+ IHostapd::ParamSizeLimits::SSID_MAX_LEN_IN_BYTES)) {
+ wpa_printf(
+ MSG_ERROR, "Invalid SSID size: %zu", nw_params.V1_2.V1_0.ssid.size());
+ return "";
+ }
+
+ // SSID string
+ std::stringstream ss;
+ ss << std::hex;
+ ss << std::setfill('0');
+ for (uint8_t b : nw_params.V1_2.V1_0.ssid) {
+ ss << std::setw(2) << static_cast<unsigned int>(b);
+ }
+ const std::string ssid_as_string = ss.str();
+
+ // Encryption config string
+ uint32_t band = 0;
+ band |= channelParams.bandMask;
+ bool is_6Ghz_band_only = band == static_cast<uint32_t>(IHostapd::BandMask::BAND_6_GHZ);
+ bool is_60Ghz_band_only = band == static_cast<uint32_t>(IHostapd::BandMask::BAND_60_GHZ);
+ std::string encryption_config_as_string;
+ switch (nw_params.V1_2.encryptionType) {
+ case IHostapd::EncryptionType::NONE:
+ // no security params
+ break;
+ case IHostapd::EncryptionType::WPA:
+ if (!validatePassphrase(
+ nw_params.V1_2.passphrase.size(),
+ static_cast<uint32_t>(IHostapd::ParamSizeLimits::
+ WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
+ static_cast<uint32_t>(IHostapd::ParamSizeLimits::
+ WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
+ return "";
+ }
+ encryption_config_as_string = StringPrintf(
+ "wpa=3\n"
+ "wpa_pairwise=%s\n"
+ "wpa_passphrase=%s",
+ is_60Ghz_band_only ? "GCMP" : "TKIP CCMP",
+ nw_params.V1_2.passphrase.c_str());
+ break;
+ case IHostapd::EncryptionType::WPA2:
+ if (!validatePassphrase(
+ nw_params.V1_2.passphrase.size(),
+ static_cast<uint32_t>(IHostapd::ParamSizeLimits::
+ WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
+ static_cast<uint32_t>(IHostapd::ParamSizeLimits::
+ WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
+ return "";
+ }
+ encryption_config_as_string = StringPrintf(
+ "wpa=2\n"
+ "rsn_pairwise=%s\n"
+ "wpa_passphrase=%s",
+ is_60Ghz_band_only ? "GCMP" : "CCMP",
+ nw_params.V1_2.passphrase.c_str());
+ break;
+ case IHostapd::EncryptionType::WPA3_SAE_TRANSITION:
+ if (!validatePassphrase(
+ nw_params.V1_2.passphrase.size(),
+ static_cast<uint32_t>(IHostapd::ParamSizeLimits::
+ WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
+ static_cast<uint32_t>(IHostapd::ParamSizeLimits::
+ WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
+ return "";
+ }
+ encryption_config_as_string = StringPrintf(
+ "wpa=2\n"
+ "rsn_pairwise=%s\n"
+ "wpa_key_mgmt=WPA-PSK SAE\n"
+ "ieee80211w=1\n"
+ "sae_require_mfp=1\n"
+ "wpa_passphrase=%s\n"
+ "sae_password=%s",
+ is_60Ghz_band_only ? "GCMP" : "CCMP",
+ nw_params.V1_2.passphrase.c_str(),
+ nw_params.V1_2.passphrase.c_str());
+ break;
+ case IHostapd::EncryptionType::WPA3_SAE:
+ if (!validatePassphrase(nw_params.V1_2.passphrase.size(), 1, -1)) {
+ return "";
+ }
+ encryption_config_as_string = StringPrintf(
+ "wpa=2\n"
+ "rsn_pairwise=%s\n"
+ "wpa_key_mgmt=SAE\n"
+ "ieee80211w=2\n"
+ "sae_require_mfp=2\n"
+ "sae_pwe=%d\n"
+ "sae_password=%s",
+ is_60Ghz_band_only ? "GCMP" : "CCMP",
+ is_6Ghz_band_only ? 1 : 2,
+ nw_params.V1_2.passphrase.c_str());
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "Unknown encryption type");
+ return "";
+ }
+
+ std::string channel_config_as_string;
+ bool isFirst = true;
+ if (channelParams.enableAcs) {
+ std::string freqList_as_string;
+ for (const auto &range :
+ channelParams.V1_2.acsChannelFreqRangesMhz) {
+ if (!isFirst) {
+ freqList_as_string += ",";
+ }
+ isFirst = false;
+
+ if (range.start != range.end) {
+ freqList_as_string +=
+ StringPrintf("%d-%d", range.start, range.end);
+ } else {
+ freqList_as_string += StringPrintf("%d", range.start);
+ }
+ }
+ channel_config_as_string = StringPrintf(
+ "channel=0\n"
+ "acs_exclude_dfs=%d\n"
+ "freqlist=%s",
+ iface_params.V1_2.V1_1.V1_0.channelParams.acsShouldExcludeDfs,
+ freqList_as_string.c_str());
+ } else {
+ int op_class = getOpClassForChannel(
+ channelParams.channel,
+ band,
+ iface_params.V1_2.V1_1.V1_0.hwModeParams.enable80211N,
+ iface_params.V1_2.V1_1.V1_0.hwModeParams.enable80211AC);
+ channel_config_as_string = StringPrintf(
+ "channel=%d\n"
+ "op_class=%d",
+ channelParams.channel, op_class);
+ }
+
+ std::string hw_mode_as_string;
+ std::string ht_cap_vht_oper_chwidth_as_string;
+ std::string enable_edmg_as_string;
+ std::string edmg_channel_as_string;
+ bool is_60Ghz_used = false;
+
+ if (((band & IHostapd::BandMask::BAND_60_GHZ) != 0)) {
+ hw_mode_as_string = "hw_mode=ad";
+ if (iface_params.hwModeParams.enableEdmg) {
+ enable_edmg_as_string = "enable_edmg=1";
+ edmg_channel_as_string = StringPrintf(
+ "edmg_channel=%d",
+ channelParams.channel);
+ }
+ is_60Ghz_used = true;
+ } else if ((band & IHostapd::BandMask::BAND_2_GHZ) != 0) {
+ if (((band & IHostapd::BandMask::BAND_5_GHZ) != 0)
+ || ((band & IHostapd::BandMask::BAND_6_GHZ) != 0)) {
+ hw_mode_as_string = "hw_mode=any";
+ if (iface_params.V1_2.V1_1.V1_0.hwModeParams.enable80211AC) {
+ ht_cap_vht_oper_chwidth_as_string =
+ "ht_capab=[HT40+]\n"
+ "vht_oper_chwidth=1";
+ }
+ } else {
+ hw_mode_as_string = "hw_mode=g";
+ }
+ } else if (((band & IHostapd::BandMask::BAND_5_GHZ) != 0)
+ || ((band & IHostapd::BandMask::BAND_6_GHZ) != 0)) {
+ hw_mode_as_string = "hw_mode=a";
+ if (iface_params.V1_2.V1_1.V1_0.hwModeParams.enable80211AC) {
+ ht_cap_vht_oper_chwidth_as_string =
+ "ht_capab=[HT40+]\n"
+ "vht_oper_chwidth=1";
+ }
+ } else {
+ wpa_printf(MSG_ERROR, "Invalid band");
+ return "";
+ }
+
+ std::string he_params_as_string;
+#ifdef CONFIG_IEEE80211AX
+ if (iface_params.V1_2.hwModeParams.enable80211AX && !is_60Ghz_used) {
+ he_params_as_string = StringPrintf(
+ "ieee80211ax=1\n"
+ "he_oper_chwidth=1\n"
+ "he_su_beamformer=%d\n"
+ "he_su_beamformee=%d\n"
+ "he_mu_beamformer=%d\n"
+ "he_twt_required=%d\n",
+ iface_params.V1_2.hwModeParams.enableHeSingleUserBeamformer ? 1 : 0,
+ iface_params.V1_2.hwModeParams.enableHeSingleUserBeamformee ? 1 : 0,
+ iface_params.V1_2.hwModeParams.enableHeMultiUserBeamformer ? 1 : 0,
+ iface_params.V1_2.hwModeParams.enableHeTargetWakeTime ? 1 : 0);
+ } else {
+ he_params_as_string = "ieee80211ax=0";
+ }
+#endif /* CONFIG_IEEE80211AX */
+
+#ifdef CONFIG_INTERWORKING
+ std::string access_network_params_as_string;
+ if (nw_params.isMetered) {
+ access_network_params_as_string = StringPrintf(
+ "interworking=1\n"
+ "access_network_type=2\n"); // CHARGEABLE_PUBLIC_NETWORK
+ } else {
+ access_network_params_as_string = StringPrintf(
+ "interworking=0\n");
+ }
+#endif /* CONFIG_INTERWORKING */
+
+ std::string bridge_as_string;
+ if (!br_name.empty()) {
+ bridge_as_string = StringPrintf("bridge=%s", br_name.c_str());
+ }
+
+ return StringPrintf(
+ "interface=%s\n"
+ "driver=nl80211\n"
+ "ctrl_interface=/data/vendor/wifi/hostapd/ctrl\n"
+ // ssid2 signals to hostapd that the value is not a literal value
+ // for use as a SSID. In this case, we're giving it a hex
+ // std::string and hostapd needs to expect that.
+ "ssid2=%s\n"
+ "%s\n"
+ "ieee80211n=%d\n"
+ "ieee80211ac=%d\n"
+ "%s\n"
+ "%s\n"
+ "%s\n"
+ "ignore_broadcast_ssid=%d\n"
+ "wowlan_triggers=any\n"
+#ifdef CONFIG_INTERWORKING
+ "%s\n"
+#endif /* CONFIG_INTERWORKING */
+ "%s\n"
+ "%s\n"
+ "%s\n"
+ "%s\n",
+ iface_params.V1_2.V1_1.V1_0.ifaceName.c_str(), ssid_as_string.c_str(),
+ channel_config_as_string.c_str(),
+ iface_params.V1_2.V1_1.V1_0.hwModeParams.enable80211N ? 1 : 0,
+ iface_params.V1_2.V1_1.V1_0.hwModeParams.enable80211AC ? 1 : 0,
+ he_params_as_string.c_str(),
+ hw_mode_as_string.c_str(), ht_cap_vht_oper_chwidth_as_string.c_str(),
+ nw_params.V1_2.V1_0.isHidden ? 1 : 0,
+#ifdef CONFIG_INTERWORKING
+ access_network_params_as_string.c_str(),
+#endif /* CONFIG_INTERWORKING */
+ encryption_config_as_string.c_str(),
+ bridge_as_string.c_str(),
+ enable_edmg_as_string.c_str(),
+ edmg_channel_as_string.c_str());
+}
+
+Generation getGeneration(hostapd_hw_modes *current_mode)
+{
+ wpa_printf(MSG_DEBUG, "getGeneration hwmode=%d, ht_enabled=%d,"
+ " vht_enabled=%d, he_supported=%d",
+ current_mode->mode, current_mode->ht_capab != 0,
+ current_mode->vht_capab != 0, current_mode->he_capab->he_supported);
+ switch (current_mode->mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ return Generation::WIFI_STANDARD_LEGACY;
+ case HOSTAPD_MODE_IEEE80211G:
+ return current_mode->ht_capab == 0 ?
+ Generation::WIFI_STANDARD_LEGACY : Generation::WIFI_STANDARD_11N;
+ case HOSTAPD_MODE_IEEE80211A:
+ if (current_mode->he_capab->he_supported) {
+ return Generation::WIFI_STANDARD_11AX;
+ }
+ return current_mode->vht_capab == 0 ?
+ Generation::WIFI_STANDARD_11N : Generation::WIFI_STANDARD_11AC;
+ case HOSTAPD_MODE_IEEE80211AD:
+ return Generation::WIFI_STANDARD_11AD;
+ default:
+ return Generation::WIFI_STANDARD_UNKNOWN;
+ }
+}
+
+Bandwidth getBandwidth(struct hostapd_config *iconf)
+{
+ wpa_printf(MSG_DEBUG, "getBandwidth %d, isHT=%d, isHT40=%d",
+ iconf->vht_oper_chwidth, iconf->ieee80211n,
+ iconf->secondary_channel);
+ switch (iconf->vht_oper_chwidth) {
+ case CHANWIDTH_80MHZ:
+ return Bandwidth::WIFI_BANDWIDTH_80;
+ case CHANWIDTH_80P80MHZ:
+ return Bandwidth::WIFI_BANDWIDTH_80P80;
+ break;
+ case CHANWIDTH_160MHZ:
+ return Bandwidth::WIFI_BANDWIDTH_160;
+ break;
+ case CHANWIDTH_USE_HT:
+ if (iconf->ieee80211n) {
+ return iconf->secondary_channel != 0 ?
+ Bandwidth::WIFI_BANDWIDTH_40 : Bandwidth::WIFI_BANDWIDTH_20;
+ }
+ return Bandwidth::WIFI_BANDWIDTH_20_NOHT;
+ case CHANWIDTH_2160MHZ:
+ return Bandwidth::WIFI_BANDWIDTH_2160;
+ case CHANWIDTH_4320MHZ:
+ return Bandwidth::WIFI_BANDWIDTH_4320;
+ case CHANWIDTH_6480MHZ:
+ return Bandwidth::WIFI_BANDWIDTH_6480;
+ case CHANWIDTH_8640MHZ:
+ return Bandwidth::WIFI_BANDWIDTH_8640;
+ default:
+ return Bandwidth::WIFI_BANDWIDTH_INVALID;
+ }
+}
+
+bool forceStaDisconnection(struct hostapd_data* hapd,
+ const std::array<uint8_t, 6>& client_address,
+ const uint16_t reason_code) {
+ struct sta_info *sta;
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ int res;
+ res = memcmp(sta->addr, client_address.data(), ETH_ALEN);
+ if (res == 0) {
+ wpa_printf(MSG_INFO, "Force client:" MACSTR " disconnect with reason: %d",
+ MAC2STR(client_address.data()), reason_code);
+ ap_sta_disconnect(hapd, sta, sta->addr, reason_code);
+ return true;
+ }
+ }
+ return false;
+}
+
+// hostapd core functions accept "C" style function pointers, so use global
+// functions to pass to the hostapd core function and store the corresponding
+// std::function methods to be invoked.
+//
+// NOTE: Using the pattern from the vendor HAL (wifi_legacy_hal.cpp).
+//
+// Callback to be invoked once setup is complete
+std::function<void(struct hostapd_data*)> on_setup_complete_internal_callback;
+void onAsyncSetupCompleteCb(void* ctx)
+{
+ struct hostapd_data* iface_hapd = (struct hostapd_data*)ctx;
+ if (on_setup_complete_internal_callback) {
+ on_setup_complete_internal_callback(iface_hapd);
+ // Invalidate this callback since we don't want this firing
+ // again in single AP mode.
+ if (strlen(iface_hapd->conf->bridge) > 0) {
+ on_setup_complete_internal_callback = nullptr;
+ }
+ }
+}
+
+// Callback to be invoked on hotspot client connection/disconnection
+std::function<void(struct hostapd_data*, const u8 *mac_addr, int authorized,
+ const u8 *p2p_dev_addr)> on_sta_authorized_internal_callback;
+void onAsyncStaAuthorizedCb(void* ctx, const u8 *mac_addr, int authorized,
+ const u8 *p2p_dev_addr)
+{
+ struct hostapd_data* iface_hapd = (struct hostapd_data*)ctx;
+ if (on_sta_authorized_internal_callback) {
+ on_sta_authorized_internal_callback(iface_hapd, mac_addr,
+ authorized, p2p_dev_addr);
+ }
+}
+
+std::function<void(struct hostapd_data*, int level,
+ enum wpa_msg_type type, const char *txt,
+ size_t len)> on_wpa_msg_internal_callback;
+
+void onAsyncWpaEventCb(void *ctx, int level,
+ enum wpa_msg_type type, const char *txt,
+ size_t len)
+{
+ struct hostapd_data* iface_hapd = (struct hostapd_data*)ctx;
+ if (on_wpa_msg_internal_callback) {
+ on_wpa_msg_internal_callback(iface_hapd, level,
+ type, txt, len);
+ }
+}
+
+
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace hostapd {
+namespace V1_3 {
+namespace implementation {
+using hidl_return_util::call;
+using namespace android::hardware::wifi::hostapd::V1_0;
+
+Hostapd::Hostapd(struct hapd_interfaces* interfaces)
+ : interfaces_(interfaces), death_notifier_(sp<DeathNotifier>::make())
+{}
+
+Return<void> Hostapd::addAccessPoint(
+ const V1_0::IHostapd::IfaceParams& iface_params,
+ const V1_0::IHostapd::NetworkParams& nw_params, addAccessPoint_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::addAccessPointInternal, _hidl_cb, iface_params,
+ nw_params);
+}
+
+Return<void> Hostapd::addAccessPoint_1_1(
+ const V1_1::IHostapd::IfaceParams& iface_params,
+ const V1_0::IHostapd::NetworkParams& nw_params, addAccessPoint_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::addAccessPointInternal_1_1, _hidl_cb, iface_params,
+ nw_params);
+}
+
+Return<void> Hostapd::addAccessPoint_1_2(
+ const V1_2::IHostapd::IfaceParams& iface_params,
+ const V1_2::IHostapd::NetworkParams& nw_params,
+ addAccessPoint_1_2_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::addAccessPointInternal_1_2, _hidl_cb, iface_params,
+ nw_params);
+}
+
+Return<void> Hostapd::addAccessPoint_1_3(
+ const V1_3::IHostapd::IfaceParams& iface_params,
+ const V1_3::IHostapd::NetworkParams& nw_params,
+ addAccessPoint_1_3_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::addAccessPointInternal_1_3, _hidl_cb, iface_params,
+ nw_params);
+}
+
+Return<void> Hostapd::removeAccessPoint(
+ const hidl_string& iface_name, removeAccessPoint_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::removeAccessPointInternal, _hidl_cb, iface_name);
+}
+
+Return<void> Hostapd::terminate()
+{
+ wpa_printf(MSG_INFO, "Terminating...");
+ // Clear the callback to avoid IPCThreadState shutdown during the
+ // callback event.
+ callbacks_.clear();
+ eloop_terminate();
+ return Void();
+}
+
+Return<void> Hostapd::registerCallback(
+ const sp<V1_1::IHostapdCallback>& callback, registerCallback_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::registerCallbackInternal, _hidl_cb, callback);
+}
+
+Return<void> Hostapd::registerCallback_1_3(
+ const sp<V1_3::IHostapdCallback>& callback, registerCallback_1_3_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::registerCallbackInternal_1_3, _hidl_cb, callback);
+}
+
+Return<void> Hostapd::forceClientDisconnect(
+ const hidl_string& iface_name, const hidl_array<uint8_t, 6>& client_address,
+ V1_2::Ieee80211ReasonCode reason_code, forceClientDisconnect_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::forceClientDisconnectInternal, _hidl_cb, iface_name,
+ client_address, reason_code);
+}
+
+Return<void> Hostapd::setDebugParams(
+ V1_2::DebugLevel level, setDebugParams_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::setDebugParamsInternal, _hidl_cb, level);
+}
+
+V1_0::HostapdStatus Hostapd::addAccessPointInternal(
+ const V1_0::IHostapd::IfaceParams& iface_params,
+ const V1_0::IHostapd::NetworkParams& nw_params)
+{
+ return {V1_0::HostapdStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+V1_0::HostapdStatus Hostapd::addAccessPointInternal_1_1(
+ const V1_1::IHostapd::IfaceParams& iface_params,
+ const V1_1::IHostapd::NetworkParams& nw_params)
+{
+ return {V1_0::HostapdStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+V1_2::HostapdStatus Hostapd::addAccessPointInternal_1_2(
+ const V1_2::IHostapd::IfaceParams& iface_params,
+ const V1_2::IHostapd::NetworkParams& nw_params) {
+ return {V1_2::HostapdStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+V1_2::HostapdStatus Hostapd::addAccessPointInternal_1_3(
+ const V1_3::IHostapd::IfaceParams& iface_params,
+ const V1_3::IHostapd::NetworkParams& nw_params)
+{
+ int channelParamsListSize = iface_params.channelParamsList.size();
+ if (channelParamsListSize == 1) {
+ // Single AP
+ wpa_printf(MSG_INFO, "AddSingleAccessPoint, iface=%s",
+ iface_params.V1_2.V1_1.V1_0.ifaceName.c_str());
+ return addSingleAccessPoint(iface_params, iface_params.channelParamsList[0],
+ nw_params, "");
+ } else if (channelParamsListSize == 2) {
+ // Concurrent APs
+ wpa_printf(MSG_INFO, "AddDualAccessPoint, iface=%s",
+ iface_params.V1_2.V1_1.V1_0.ifaceName.c_str());
+ return addConcurrentAccessPoints(iface_params, nw_params);
+ }
+ return {V1_2::HostapdStatusCode::FAILURE_ARGS_INVALID, ""};
+}
+
+V1_2::HostapdStatus Hostapd::addConcurrentAccessPoints(
+ const V1_3::IHostapd::IfaceParams& iface_params, const V1_3::IHostapd::NetworkParams& nw_params)
+{
+ int channelParamsListSize = iface_params.channelParamsList.size();
+ // Get available interfaces in bridge
+ std::vector<std::string> managed_interfaces;
+ std::string br_name = StringPrintf(
+ "%s", iface_params.V1_2.V1_1.V1_0.ifaceName.c_str());
+ if (!GetInterfacesInBridge(br_name, &managed_interfaces)) {
+ return {V1_2::HostapdStatusCode::FAILURE_UNKNOWN,
+ "Get interfaces in bridge failed."};
+ }
+ if (managed_interfaces.size() < channelParamsListSize) {
+ return {V1_2::HostapdStatusCode::FAILURE_UNKNOWN,
+ "Available interfaces less than requested bands"};
+ }
+ // start BSS on specified bands
+ for (std::size_t i = 0; i < channelParamsListSize; i ++) {
+ V1_3::IHostapd::IfaceParams iface_params_new = iface_params;
+ iface_params_new.V1_2.V1_1.V1_0.ifaceName = managed_interfaces[i];
+ V1_2::HostapdStatus status = addSingleAccessPoint(
+ iface_params_new, iface_params.channelParamsList[i], nw_params, br_name);
+ if (status.code != V1_2::HostapdStatusCode::SUCCESS) {
+ wpa_printf(MSG_ERROR, "Failed to addAccessPoint %s",
+ managed_interfaces[i].c_str());
+ return status;
+ }
+ }
+ // Save bridge interface info
+ br_interfaces_[br_name] = managed_interfaces;
+ return {V1_2::HostapdStatusCode::SUCCESS, ""};
+}
+
+V1_2::HostapdStatus Hostapd::addSingleAccessPoint(
+ const V1_3::IHostapd::IfaceParams& iface_params,
+ const V1_3::IHostapd::ChannelParams& channelParams,
+ const V1_3::IHostapd::NetworkParams& nw_params,
+ const std::string br_name)
+{
+ if (hostapd_get_iface(interfaces_, iface_params.V1_2.V1_1.V1_0.ifaceName.c_str())) {
+ wpa_printf(
+ MSG_ERROR, "Interface %s already present",
+ iface_params.V1_2.V1_1.V1_0.ifaceName.c_str());
+ return {V1_2::HostapdStatusCode::FAILURE_IFACE_EXISTS, ""};
+ }
+ const auto conf_params = CreateHostapdConfig(iface_params, channelParams, nw_params, br_name);
+ if (conf_params.empty()) {
+ wpa_printf(MSG_ERROR, "Failed to create config params");
+ return {V1_2::HostapdStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ const auto conf_file_path =
+ WriteHostapdConfig(iface_params.V1_2.V1_1.V1_0.ifaceName, conf_params);
+ if (conf_file_path.empty()) {
+ wpa_printf(MSG_ERROR, "Failed to write config file");
+ return {V1_2::HostapdStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ std::string add_iface_param_str = StringPrintf(
+ "%s config=%s", iface_params.V1_2.V1_1.V1_0.ifaceName.c_str(),
+ conf_file_path.c_str());
+ std::vector<char> add_iface_param_vec(
+ add_iface_param_str.begin(), add_iface_param_str.end() + 1);
+ if (hostapd_add_iface(interfaces_, add_iface_param_vec.data()) < 0) {
+ wpa_printf(
+ MSG_ERROR, "Adding interface %s failed",
+ add_iface_param_str.c_str());
+ return {V1_2::HostapdStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ struct hostapd_data* iface_hapd =
+ hostapd_get_iface(interfaces_, iface_params.V1_2.V1_1.V1_0.ifaceName.c_str());
+ WPA_ASSERT(iface_hapd != nullptr && iface_hapd->iface != nullptr);
+ // Register the setup complete callbacks
+ on_setup_complete_internal_callback =
+ [this](struct hostapd_data* iface_hapd) {
+ wpa_printf(
+ MSG_INFO, "AP interface setup completed - state %s",
+ hostapd_state_text(iface_hapd->iface->state));
+ if (iface_hapd->iface->state == HAPD_IFACE_DISABLED) {
+ // Invoke the failure callback on all registered
+ // clients.
+ for (const auto& callback : callbacks_) {
+ callback->onFailure(
+ iface_hapd->conf->iface);
+ }
+ }
+ };
+
+ // Rgegister for new client connect/disconnect indication.
+ on_sta_authorized_internal_callback =
+ [this](struct hostapd_data* iface_hapd, const u8 *mac_addr,
+ int authorized, const u8 *p2p_dev_addr) {
+ wpa_printf(MSG_DEBUG, "notify client " MACSTR " %s",
+ MAC2STR(mac_addr),
+ (authorized) ? "Connected" : "Disconnected");
+ for (const auto &callback : callbacks_) {
+ callback->onConnectedClientsChanged(strlen(iface_hapd->conf->bridge) > 0 ?
+ iface_hapd->conf->bridge : iface_hapd->conf->iface,
+ iface_hapd->conf->iface, mac_addr, authorized);
+ }
+ };
+
+ // Register for wpa_event which used to get channel switch event
+ on_wpa_msg_internal_callback =
+ [this](struct hostapd_data* iface_hapd, int level,
+ enum wpa_msg_type type, const char *txt,
+ size_t len) {
+ wpa_printf(MSG_DEBUG, "Receive wpa msg : %s", txt);
+ if (os_strncmp(txt, AP_EVENT_ENABLED,
+ strlen(AP_EVENT_ENABLED)) == 0 ||
+ os_strncmp(txt, WPA_EVENT_CHANNEL_SWITCH,
+ strlen(WPA_EVENT_CHANNEL_SWITCH)) == 0) {
+ for (const auto &callback : callbacks_) {
+ callback->onApInstanceInfoChanged(
+ strlen(iface_hapd->conf->bridge) > 0 ?
+ iface_hapd->conf->bridge : iface_hapd->conf->iface,
+ iface_hapd->conf->iface, iface_hapd->iface->freq,
+ getBandwidth(iface_hapd->iconf),
+ getGeneration(iface_hapd->iface->current_mode),
+ iface_hapd->own_addr);
+ }
+ }
+ };
+
+ // Setup callback
+ iface_hapd->setup_complete_cb = onAsyncSetupCompleteCb;
+ iface_hapd->setup_complete_cb_ctx = iface_hapd;
+ iface_hapd->sta_authorized_cb = onAsyncStaAuthorizedCb;
+ iface_hapd->sta_authorized_cb_ctx = iface_hapd;
+ wpa_msg_register_cb(onAsyncWpaEventCb);
+
+ if (hostapd_enable_iface(iface_hapd->iface) < 0) {
+ wpa_printf(
+ MSG_ERROR, "Enabling interface %s failed",
+ iface_params.V1_2.V1_1.V1_0.ifaceName.c_str());
+ return {V1_2::HostapdStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {V1_2::HostapdStatusCode::SUCCESS, ""};
+}
+
+V1_0::HostapdStatus Hostapd::removeAccessPointInternal(const std::string& iface_name)
+{
+ // interfaces to be removed
+ std::vector<std::string> interfaces;
+ bool is_error = false;
+
+ const auto it = br_interfaces_.find(iface_name);
+ if (it != br_interfaces_.end()) {
+ // In case bridge, remove managed interfaces
+ interfaces = it->second;
+ br_interfaces_.erase(iface_name);
+ } else {
+ // else remove current interface
+ interfaces.push_back(iface_name);
+ }
+
+ for (auto& iface : interfaces) {
+ std::vector<char> remove_iface_param_vec(
+ iface.begin(), iface.end() + 1);
+ if (hostapd_remove_iface(interfaces_, remove_iface_param_vec.data()) <
+ 0) {
+ wpa_printf(MSG_INFO, "Remove interface %s failed",
+ iface.c_str());
+ is_error = true;
+ }
+ }
+ if (is_error) {
+ return {V1_0::HostapdStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {V1_0::HostapdStatusCode::SUCCESS, ""};
+}
+
+V1_0::HostapdStatus Hostapd::registerCallbackInternal(
+ const sp<V1_1::IHostapdCallback>& callback)
+{
+ return {V1_0::HostapdStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+V1_2::HostapdStatus Hostapd::registerCallbackInternal_1_3(
+ const sp<V1_3::IHostapdCallback>& callback)
+{
+ if (!callback->linkToDeath(death_notifier_, 0)) {
+ wpa_printf(
+ MSG_ERROR,
+ "Error registering for death notification for "
+ "hostapd callback object");
+ return {V1_2::HostapdStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ callbacks_.push_back(callback);
+ return {V1_2::HostapdStatusCode::SUCCESS, ""};
+}
+
+V1_2::HostapdStatus Hostapd::forceClientDisconnectInternal(const std::string& iface_name,
+ const std::array<uint8_t, 6>& client_address, V1_2::Ieee80211ReasonCode reason_code)
+{
+ struct hostapd_data *hapd = hostapd_get_iface(interfaces_, iface_name.c_str());
+ bool result;
+ if (!hapd) {
+ for (auto const& iface : br_interfaces_) {
+ if (iface.first == iface_name) {
+ for (auto const& instance : iface.second) {
+ hapd = hostapd_get_iface(interfaces_, instance.c_str());
+ if (hapd) {
+ result = forceStaDisconnection(hapd, client_address,
+ (uint16_t) reason_code);
+ if (result) break;
+ }
+ }
+ }
+ }
+ } else {
+ result = forceStaDisconnection(hapd, client_address, (uint16_t) reason_code);
+ }
+ if (!hapd) {
+ wpa_printf(MSG_ERROR, "Interface %s doesn't exist", iface_name.c_str());
+ return {V1_2::HostapdStatusCode::FAILURE_IFACE_UNKNOWN, ""};
+ }
+ if (result) {
+ return {V1_2::HostapdStatusCode::SUCCESS, ""};
+ }
+ return {V1_2::HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, ""};
+}
+
+V1_2::HostapdStatus Hostapd::setDebugParamsInternal(V1_2::DebugLevel level)
+{
+ wpa_debug_level = static_cast<uint32_t>(level);
+ return {V1_2::HostapdStatusCode::SUCCESS, ""};
+}
+
+} // namespace implementation
+} // namespace V1_3
+} // namespace hostapd
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/hostapd/hidl/1.2/hostapd.h b/hostapd/hidl/1.3/hostapd.h
index ca6c32e0..dc45932f 100644
--- a/hostapd/hidl/1.2/hostapd.h
+++ b/hostapd/hidl/1.3/hostapd.h
@@ -14,23 +14,37 @@
#include <android-base/macros.h>
-#include <android/hardware/wifi/hostapd/1.2/IHostapd.h>
-#include <android/hardware/wifi/hostapd/1.1/IHostapdCallback.h>
+#include <android/hardware/wifi/hostapd/1.3/IHostapd.h>
+#include <android/hardware/wifi/hostapd/1.3/IHostapdCallback.h>
extern "C"
{
#include "utils/common.h"
+#include "utils/eloop.h"
#include "utils/includes.h"
#include "utils/wpa_debug.h"
#include "ap/hostapd.h"
#include "ap/sta_info.h"
}
+class DeathNotifier : public android::hardware::hidl_death_recipient
+{
+public:
+ void serviceDied(
+ uint64_t /*cookie*/,
+ const android::wp<android::hidl::base::V1_0::IBase>
+ & /* who */) override
+ {
+ wpa_printf(MSG_ERROR, "Client died. Terminating...");
+ eloop_terminate();
+ }
+};
+
namespace android {
namespace hardware {
namespace wifi {
namespace hostapd {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
using namespace android::hardware::wifi::hostapd::V1_0;
@@ -39,7 +53,7 @@ using namespace android::hardware::wifi::hostapd::V1_0;
* object is used core for global control operations on
* hostapd.
*/
-class Hostapd : public V1_2::IHostapd
+class Hostapd : public V1_3::IHostapd
{
public:
Hostapd(hapd_interfaces* interfaces);
@@ -53,8 +67,13 @@ public:
const V1_1::IHostapd::IfaceParams& iface_params,
const V1_0::IHostapd::NetworkParams& nw_params, addAccessPoint_cb _hidl_cb) override;
Return<void> addAccessPoint_1_2(
- const V1_2::IHostapd::IfaceParams& iface_params, const NetworkParams& nw_params,
+ const V1_2::IHostapd::IfaceParams& iface_params,
+ const V1_2::IHostapd::NetworkParams& nw_params,
addAccessPoint_1_2_cb _hidl_cb) override;
+ Return<void> addAccessPoint_1_3(
+ const V1_3::IHostapd::IfaceParams& iface_params,
+ const V1_3::IHostapd::NetworkParams& nw_params,
+ addAccessPoint_1_3_cb _hidl_cb) override;
Return<void> removeAccessPoint(
const hidl_string& iface_name,
removeAccessPoint_cb _hidl_cb) override;
@@ -62,12 +81,15 @@ public:
Return<void> registerCallback(
const sp<V1_1::IHostapdCallback>& callback,
registerCallback_cb _hidl_cb) override;
+ Return<void> registerCallback_1_3(
+ const sp<V1_3::IHostapdCallback>& callback,
+ registerCallback_1_3_cb _hidl_cb) override;
Return<void>forceClientDisconnect(
const hidl_string& iface_name,
const hidl_array<uint8_t, 6>& client_address,
V1_2::Ieee80211ReasonCode reason_code, forceClientDisconnect_cb _hidl_cb) override;
Return<void> setDebugParams(
- DebugLevel level, setDebugParams_cb _hidl_cb) override;
+ V1_2::DebugLevel level, setDebugParams_cb _hidl_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
V1_0::HostapdStatus addAccessPointInternal(
@@ -79,22 +101,39 @@ private:
V1_2::HostapdStatus addAccessPointInternal_1_2(
const V1_2::IHostapd::IfaceParams& IfaceParams,
const V1_2::IHostapd::NetworkParams& nw_params);
+ V1_2::HostapdStatus addAccessPointInternal_1_3(
+ const V1_3::IHostapd::IfaceParams& IfaceParams,
+ const V1_3::IHostapd::NetworkParams& nw_params);
+ V1_2::HostapdStatus addSingleAccessPoint(
+ const V1_3::IHostapd::IfaceParams& IfaceParams,
+ const V1_3::IHostapd::ChannelParams& channelParams,
+ const V1_3::IHostapd::NetworkParams& nw_params,
+ std::string br_name);
+ V1_2::HostapdStatus addConcurrentAccessPoints(
+ const V1_3::IHostapd::IfaceParams& IfaceParams,
+ const V1_3::IHostapd::NetworkParams& nw_params);
V1_0::HostapdStatus removeAccessPointInternal(const std::string& iface_name);
V1_0::HostapdStatus registerCallbackInternal(
const sp<V1_1::IHostapdCallback>& callback);
+ V1_2::HostapdStatus registerCallbackInternal_1_3(
+ const sp<V1_3::IHostapdCallback>& callback);
V1_2::HostapdStatus forceClientDisconnectInternal(
const std::string& iface_name,
const std::array<uint8_t, 6>& client_address,
V1_2::Ieee80211ReasonCode reason_code);
- V1_2::HostapdStatus setDebugParamsInternal(DebugLevel level);
+ V1_2::HostapdStatus setDebugParamsInternal(V1_2::DebugLevel level);
// Raw pointer to the global structure maintained by the core.
struct hapd_interfaces* interfaces_;
// Callbacks registered.
- std::vector<sp<V1_1::IHostapdCallback>> callbacks_;
+ std::vector<sp<V1_3::IHostapdCallback>> callbacks_;
+ // Death notifier.
+ android::sp<DeathNotifier> death_notifier_;
+ // Bridge and its managed interfaces.
+ std::map<std::string, std::vector<std::string>> br_interfaces_;
DISALLOW_COPY_AND_ASSIGN(Hostapd);
};
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace hostapd
} // namespace wifi
} // namespace hardware
diff --git a/hostapd/hostapd.android.rc b/hostapd/hostapd.android.rc
index 512ca0d7..7cc45bde 100644
--- a/hostapd/hostapd.android.rc
+++ b/hostapd/hostapd.android.rc
@@ -15,6 +15,7 @@ service hostapd /vendor/bin/hw/hostapd
interface android.hardware.wifi.hostapd@1.0::IHostapd default
interface android.hardware.wifi.hostapd@1.1::IHostapd default
interface android.hardware.wifi.hostapd@1.2::IHostapd default
+ interface android.hardware.wifi.hostapd@1.3::IHostapd default
class main
capabilities NET_ADMIN NET_RAW
user wifi
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 9fae06dc..a3d28efe 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -279,6 +279,8 @@ fragm_threshold=-1
# beacon_rate=ht:<HT MCS>
# VHT:
# beacon_rate=vht:<VHT MCS>
+# HE:
+# beacon_rate=he:<HE MCS>
#
# For example, beacon_rate=10 for 1 Mbps or beacon_rate=60 for 6 Mbps (OFDM).
#beacon_rate=10
@@ -571,6 +573,10 @@ wmm_ac_vo_acm=0
# Default: 1 (enabled)
#broadcast_deauth=1
+# Get notifications for received Management frames on control interface
+# Default: 0 (disabled)
+#notify_mgmt_frames=0
+
##### IEEE 802.11n related configuration ######################################
# ieee80211n: Whether IEEE 802.11n (HT) is enabled
@@ -580,6 +586,9 @@ wmm_ac_vo_acm=0
# Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band.
#ieee80211n=1
+# disable_11n: Boolean (0/1) to disable HT for a specific BSS
+#disable_11n=0
+
# ht_capab: HT capabilities (list of flags)
# LDPC coding capability: [LDPC] = supported
# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
@@ -632,6 +641,9 @@ wmm_ac_vo_acm=0
# Note: hw_mode=a is used to specify that 5 GHz band is used with VHT.
#ieee80211ac=1
+# disable_11ac: Boolean (0/1) to disable VHT for a specific BSS
+#disable_11ac=0
+
# vht_capab: VHT capabilities (list of flags)
#
# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
@@ -786,6 +798,9 @@ wmm_ac_vo_acm=0
# 1 = enabled
#ieee80211ax=1
+# disable_11ax: Boolean (0/1) to disable HE for a specific BSS
+#disable_11ax=0
+
#he_su_beamformer: HE single user beamformer support
# 0 = not supported (default)
# 1 = supported
@@ -866,6 +881,65 @@ wmm_ac_vo_acm=0
#he_spr_non_srg_obss_pd_max_offset
#he_spr_srg_obss_pd_min_offset
#he_spr_srg_obss_pd_max_offset
+#
+# SPR SRG BSS Color
+# This config represents SRG BSS Color Bitmap field of Spatial Reuse Parameter
+# Set element that indicates the BSS color values used by members of the
+# SRG of which the transmitting STA is a member. The value is in range of 0-63.
+#he_spr_srg_bss_colors=1 2 10 63
+#
+# SPR SRG Partial BSSID
+# This config represents SRG Partial BSSID Bitmap field of Spatial Reuse
+# Parameter Set element that indicates the Partial BSSID values used by members
+# of the SRG of which the transmitting STA is a member. The value range
+# corresponds to one of the 64 possible values of BSSID[39:44], where the lowest
+# numbered bit corresponds to Partial BSSID value 0 and the highest numbered bit
+# corresponds to Partial BSSID value 63.
+#he_spr_srg_partial_bssid=0 1 3 63
+#
+#he_6ghz_max_mpdu: Maximum MPDU Length of HE 6 GHz band capabilities.
+# Indicates maximum MPDU length
+# 0 = 3895 octets
+# 1 = 7991 octets
+# 2 = 11454 octets (default)
+#he_6ghz_max_mpdu=2
+#
+#he_6ghz_max_ampdu_len_exp: Maximum A-MPDU Length Exponent of HE 6 GHz band
+# capabilities. Indicates the maximum length of A-MPDU pre-EOF padding that
+# the STA can receive. This field is an integer in the range of 0 to 7.
+# The length defined by this field is equal to
+# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets
+# 0 = AMPDU length of 8k
+# 1 = AMPDU length of 16k
+# 2 = AMPDU length of 32k
+# 3 = AMPDU length of 65k
+# 4 = AMPDU length of 131k
+# 5 = AMPDU length of 262k
+# 6 = AMPDU length of 524k
+# 7 = AMPDU length of 1048k (default)
+#he_6ghz_max_ampdu_len_exp=7
+#
+#he_6ghz_rx_ant_pat: Rx Antenna Pattern Consistency of HE 6 GHz capability.
+# Indicates the possibility of Rx antenna pattern change
+# 0 = Rx antenna pattern might change during the lifetime of an association
+# 1 = Rx antenna pattern does not change during the lifetime of an association
+# (default)
+#he_6ghz_rx_ant_pat=1
+#
+#he_6ghz_tx_ant_pat: Tx Antenna Pattern Consistency of HE 6 GHz capability.
+# Indicates the possibility of Tx antenna pattern change
+# 0 = Tx antenna pattern might change during the lifetime of an association
+# 1 = Tx antenna pattern does not change during the lifetime of an association
+# (default)
+#he_6ghz_tx_ant_pat=1
+
+# Unsolicited broadcast Probe Response transmission settings
+# This is for the 6 GHz band only. If the interval is set to a non-zero value,
+# the AP schedules unsolicited broadcast Probe Response frames to be
+# transmitted for in-band discovery. Refer to
+# IEEE P802.11ax/D8.0 26.17.2.3.2, AP behavior for fast passive scanning.
+# Valid range: 0..20 TUs; default is 0 (disabled)
+#unsol_bcast_probe_resp_interval=0
##### IEEE 802.1X-2004 related configuration ##################################
@@ -1202,7 +1276,7 @@ eap_server=0
# should be unique across all issuing servers. In theory, this is a variable
# length field, but due to some existing implementations requiring A-ID to be
# 16 octets in length, it is strongly recommended to use that length for the
-# field to provid interoperability with deployed peer implementations. This
+# field to provide interoperability with deployed peer implementations. This
# field is configured in hex format.
#eap_fast_a_id=101112131415161718191a1b1c1d1e1f
@@ -1229,6 +1303,8 @@ eap_server=0
# EAP-TEAP authentication type
# 0 = inner EAP (default)
# 1 = Basic-Password-Auth
+# 2 = Do not require Phase 2 authentication if client can be authenticated
+# during Phase 1
#eap_teap_auth=0
# EAP-TEAP authentication behavior when using PAC
@@ -1710,7 +1786,8 @@ own_ip_addr=127.0.0.1
#group_mgmt_cipher=AES-128-CMAC
# Beacon Protection (management frame protection for Beacon frames)
-# This depends on management frame protection being enabled (ieee80211w != 0).
+# This depends on management frame protection being enabled (ieee80211w != 0)
+# and beacon protection support indication from the driver.
# 0 = disabled (default)
# 1 = enabled
#beacon_prot=0
@@ -1727,9 +1804,25 @@ own_ip_addr=127.0.0.1
# ocv: Operating Channel Validation
# This is a countermeasure against multi-channel man-in-the-middle attacks.
+# Enabling this depends on the driver's support for OCV when the driver SME is
+# used. If hostapd SME is used, this will be enabled just based on this
+# configuration.
# Enabling this automatically also enables ieee80211w, if not yet enabled.
# 0 = disabled (default)
# 1 = enabled
+# 2 = enabled in workaround mode - Allow STA that claims OCV capability to
+# connect even if the STA doesn't send OCI or negotiate PMF. This
+# workaround is to improve interoperability with legacy STAs which are
+# wrongly copying reserved bits of RSN capabilities from the AP's
+# RSNE into (Re)Association Request frames. When this configuration is
+# enabled, the AP considers STA is OCV capable only when the STA indicates
+# MFP capability in (Re)Association Request frames and sends OCI in
+# EAPOL-Key msg 2/4/FT Reassociation Request frame/FILS (Re)Association
+# Request frame; otherwise, the AP disables OCV for the current connection
+# with the STA. Enabling this workaround mode reduced OCV protection to
+# some extend since it allows misbehavior to go through. As such, this
+# should be enabled only if interoperability with misbehaving STAs is
+# needed.
#ocv=1
# disable_pmksa_caching: Disable PMKSA caching
@@ -1761,7 +1854,7 @@ own_ip_addr=127.0.0.1
# be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and
# by optional password identifier (dot11RSNAConfigPasswordIdentifier). In
# addition, an optional VLAN ID specification can be used to bind the station
-# to the specified VLAN whenver the specific SAE password entry is used.
+# to the specified VLAN whenever the specific SAE password entry is used.
#
# If the peer MAC address is not included or is set to the wildcard address
# (ff:ff:ff:ff:ff:ff), the entry is available for any station to use. If a
@@ -1776,7 +1869,8 @@ own_ip_addr=127.0.0.1
# special meaning of removing all previously added entries.
#
# sae_password uses the following encoding:
-#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>][|id=<identifier>]
+#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>]
+#[|pk=<m:ECPrivateKey-base64>][|id=<identifier>]
# Examples:
#sae_password=secret
#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff
@@ -1905,6 +1999,13 @@ own_ip_addr=127.0.0.1
# default: 30 TUs (= 30.72 milliseconds)
#fils_hlp_wait_time=30
+# FILS Discovery frame transmission minimum and maximum interval settings.
+# If fils_discovery_max_interval is non-zero, the AP enables FILS Discovery
+# frame transmission. These values use TUs as the unit and have allowed range
+# of 0-10000. fils_discovery_min_interval defaults to 20.
+#fils_discovery_min_interval=20
+#fils_discovery_max_interval=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
@@ -1922,6 +2023,14 @@ own_ip_addr=127.0.0.1
# (default: 0 = do not include Transition Disable KDE)
#transition_disable=0x01
+# PASN ECDH groups
+# PASN implementations are required to support group 19 (NIST P-256). If this
+# parameter is not set, only group 19 is supported by default. This
+# configuration parameter can be used to specify a limited set of allowed
+# groups. The group values are listed in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
+#pasn_groups=19 20 21
+
##### IEEE 802.11r configuration ##############################################
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
@@ -1965,7 +2074,7 @@ own_ip_addr=127.0.0.1
# Wildcard entry:
# Upon receiving a response from R0KH, it will be added to this list, so
# subsequent requests won't be broadcast. If R0KH does not reply, it will be
-# blacklisted.
+# temporarily blocked (see rkh_neg_timeout).
#r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff
# List of R1KHs in the same Mobility Domain
@@ -2021,7 +2130,7 @@ own_ip_addr=127.0.0.1
#ft_psk_generate_local=0
##### Neighbor table ##########################################################
-# Maximum number of entries kept in AP table (either for neigbor table or for
+# Maximum number of entries kept in AP table (either for neighbor table or for
# detecting Overlapping Legacy BSS Condition). The oldest entry will be
# removed when adding a new entry that would make the list grow over this
# limit. Note! WFA certification for IEEE 802.11g requires that OLBC is
@@ -2710,6 +2819,10 @@ own_ip_addr=127.0.0.1
# threshold (range: 0..255, default=30).
#rssi_reject_assoc_timeout=30
+# Ignore Probe Request frames if RSSI is below given threshold (in dBm)
+# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
+#rssi_ignore_probe_request=-75
+
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 440664e9..249e4669 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -975,7 +975,7 @@ static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
dir = opendir(ctrl_iface_dir);
if (dir == NULL) {
printf("Control interface directory '%s' could not be "
- "openned.\n", ctrl_iface_dir);
+ "opened.\n", ctrl_iface_dir);
return;
}
@@ -1227,14 +1227,15 @@ static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
char cmd[256];
int res;
- if (argc < 2 || argc > 3) {
+ if (argc < 2 || argc > 4) {
printf("Invalid vendor command\n"
- "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
+ "usage: <vendor id> <command id> [<hex formatted command argument>] [nested=<0|1>]\n");
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
- argc == 3 ? argv[2] : "");
+ res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s%s%s", argv[0],
+ argv[1], argc >= 3 ? argv[2] : "",
+ argc == 4 ? " " : "", argc == 4 ? argv[3] : "");
if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long VENDOR command.\n");
return -1;
@@ -1402,6 +1403,13 @@ static int hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc,
}
+static int hostapd_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_SET", 1, argc, argv);
+}
+
+
static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1464,6 +1472,37 @@ static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
}
+
+#ifdef CONFIG_DPP2
+
+static int hostapd_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_CONTROLLER_START", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_controller_stop(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_CONTROLLER_STOP");
+}
+
+
+static int hostapd_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_CHIRP", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_STOP_CHIRP");
+}
+
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
@@ -1650,6 +1689,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
"<id> = get DPP bootstrap URI" },
{ "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL,
"<id> = show DPP bootstrap information" },
+ { "dpp_bootstrap_set", hostapd_cli_cmd_dpp_bootstrap_set, NULL,
+ "<id> [conf=..] [ssid=<SSID>] [ssid_charset=#] [psk=<PSK>] [pass=<passphrase>] [configurator=<id>] [conn_status=#] [akm_use_selector=<0|1>] [group_id=..] [expiry=#] [csrattrs=..] = set DPP configurator parameters" },
{ "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL,
"peer=<id> [own=<id>] = initiate DPP bootstrapping" },
{ "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL,
@@ -1670,6 +1711,16 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
"add PKEX code" },
{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
"*|<id> = remove DPP pkex information" },
+#ifdef CONFIG_DPP2
+ { "dpp_controller_start", hostapd_cli_cmd_dpp_controller_start, NULL,
+ "[tcp_port=<port>] [role=..] = start DPP controller" },
+ { "dpp_controller_stop", hostapd_cli_cmd_dpp_controller_stop, NULL,
+ "= stop DPP controller" },
+ { "dpp_chirp", hostapd_cli_cmd_dpp_chirp, NULL,
+ "own=<BI ID> iter=<count> = start DPP chirp" },
+ { "dpp_stop_chirp", hostapd_cli_cmd_dpp_stop_chirp, NULL,
+ "= stop DPP chirp" },
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
{ "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
"=Add/Delete/Show/Clear accept MAC ACL" },
diff --git a/hostapd/main.c b/hostapd/main.c
index cdcb692c..346df483 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -677,7 +677,6 @@ int main(int argc, char *argv[])
#ifdef CONFIG_DPP
os_memset(&dpp_conf, 0, sizeof(dpp_conf));
dpp_conf.cb_ctx = &interfaces;
- /* TODO: dpp_conf.msg_ctx? */
#ifdef CONFIG_DPP2
dpp_conf.remove_bi = hostapd_dpp_remove_bi;
#endif /* CONFIG_DPP2 */
diff --git a/hostapd/sae_pk_gen.c b/hostapd/sae_pk_gen.c
new file mode 100644
index 00000000..c31eff75
--- /dev/null
+++ b/hostapd/sae_pk_gen.c
@@ -0,0 +1,196 @@
+/*
+ * SAE-PK password/modifier generator
+ * 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 "utils/base64.h"
+#include "crypto/crypto.h"
+#include "common/sae.h"
+
+
+int main(int argc, char *argv[])
+{
+ char *der = NULL;
+ size_t der_len;
+ struct crypto_ec_key *key = NULL;
+ struct wpabuf *pub = NULL;
+ u8 *data = NULL, *m;
+ size_t data_len;
+ char *b64 = NULL, *pw = NULL, *pos, *src;
+ int sec, j;
+ int ret = -1;
+ u8 hash[SAE_MAX_HASH_LEN];
+ char hash_hex[2 * SAE_MAX_HASH_LEN + 1];
+ u8 pw_base_bin[SAE_MAX_HASH_LEN];
+ u8 *dst;
+ int group;
+ size_t hash_len;
+ unsigned long long i, expected;
+ char m_hex[2 * SAE_PK_M_LEN + 1];
+ u32 sec_1b, val20;
+
+ wpa_debug_level = MSG_INFO;
+ if (os_program_init() < 0)
+ goto fail;
+
+ if (argc != 4) {
+ fprintf(stderr,
+ "usage: sae_pk_gen <DER ECPrivateKey file> <Sec:3|5> <SSID>\n");
+ goto fail;
+ }
+
+ sec = atoi(argv[2]);
+ if (sec != 3 && sec != 5) {
+ fprintf(stderr,
+ "Invalid Sec value (allowed values: 3 and 5)\n");
+ goto fail;
+ }
+ sec_1b = sec == 3;
+ expected = 1;
+ for (j = 0; j < sec; j++)
+ expected *= 256;
+
+ der = os_readfile(argv[1], &der_len);
+ if (!der) {
+ fprintf(stderr, "Could not read %s: %s\n",
+ argv[1], strerror(errno));
+ goto fail;
+ }
+
+ key = crypto_ec_key_parse_priv((u8 *) der, der_len);
+ if (!key) {
+ fprintf(stderr, "Could not parse ECPrivateKey\n");
+ goto fail;
+ }
+
+ pub = crypto_ec_key_get_subject_public_key(key);
+ if (!pub) {
+ fprintf(stderr, "Failed to build SubjectPublicKey\n");
+ goto fail;
+ }
+
+ group = crypto_ec_key_group(key);
+ switch (group) {
+ case 19:
+ hash_len = 32;
+ break;
+ case 20:
+ hash_len = 48;
+ break;
+ case 21:
+ hash_len = 64;
+ break;
+ default:
+ fprintf(stderr, "Unsupported private key group\n");
+ goto fail;
+ }
+
+ data_len = os_strlen(argv[3]) + SAE_PK_M_LEN + wpabuf_len(pub);
+ data = os_malloc(data_len);
+ if (!data) {
+ fprintf(stderr, "No memory for data buffer\n");
+ goto fail;
+ }
+ os_memcpy(data, argv[3], os_strlen(argv[3]));
+ m = data + os_strlen(argv[3]);
+ if (os_get_random(m, SAE_PK_M_LEN) < 0) {
+ fprintf(stderr, "Could not generate random Modifier M\n");
+ goto fail;
+ }
+ os_memcpy(m + SAE_PK_M_LEN, wpabuf_head(pub), wpabuf_len(pub));
+
+ fprintf(stderr, "Searching for a suitable Modifier M value\n");
+ for (i = 0;; i++) {
+ if (sae_hash(hash_len, data, data_len, hash) < 0) {
+ fprintf(stderr, "Hash failed\n");
+ goto fail;
+ }
+ if (hash[0] == 0 && hash[1] == 0) {
+ if ((hash[2] & 0xf0) == 0)
+ fprintf(stderr, "\r%3.2f%%",
+ 100.0 * (double) i / (double) expected);
+ for (j = 2; j < sec; j++) {
+ if (hash[j])
+ break;
+ }
+ if (j == sec)
+ break;
+ }
+ inc_byte_array(m, SAE_PK_M_LEN);
+ }
+
+ if (wpa_snprintf_hex(m_hex, sizeof(m_hex), m, SAE_PK_M_LEN) < 0 ||
+ wpa_snprintf_hex(hash_hex, sizeof(hash_hex), hash, hash_len) < 0)
+ goto fail;
+ fprintf(stderr, "\nFound a valid hash in %llu iterations: %s\n",
+ i + 1, hash_hex);
+
+ b64 = base64_encode(der, der_len, NULL);
+ if (!b64)
+ goto fail;
+ src = pos = b64;
+ while (*src) {
+ if (*src != '\n')
+ *pos++ = *src;
+ src++;
+ }
+ *pos = '\0';
+
+ /* Skip 8*Sec bits and add Sec_1b as the every 20th bit starting with
+ * one. */
+ os_memset(pw_base_bin, 0, sizeof(pw_base_bin));
+ dst = pw_base_bin;
+ for (j = 0; j < 8 * (int) hash_len / 20; j++) {
+ val20 = sae_pk_get_be19(hash + sec);
+ val20 |= sec_1b << 19;
+ sae_pk_buf_shift_left_19(hash + sec, hash_len - sec);
+
+ if (j & 1) {
+ *dst |= (val20 >> 16) & 0x0f;
+ dst++;
+ *dst++ = (val20 >> 8) & 0xff;
+ *dst++ = val20 & 0xff;
+ } else {
+ *dst++ = (val20 >> 12) & 0xff;
+ *dst++ = (val20 >> 4) & 0xff;
+ *dst = (val20 << 4) & 0xf0;
+ }
+ }
+ if (wpa_snprintf_hex(hash_hex, sizeof(hash_hex),
+ pw_base_bin, hash_len - sec) >= 0)
+ fprintf(stderr, "PasswordBase binary data for base32: %s",
+ hash_hex);
+
+ pw = sae_pk_base32_encode(pw_base_bin, 20 * 3 - 5);
+ if (!pw)
+ goto fail;
+
+ printf("# SAE-PK password/M/private key for Sec=%d.\n", sec);
+ printf("sae_password=%s|pk=%s:%s\n", pw, m_hex, b64);
+ printf("# Longer passwords can be used for improved security at the cost of usability:\n");
+ for (j = 4; j <= ((int) hash_len * 8 + 5 - 8 * sec) / 19; j++) {
+ os_free(pw);
+ pw = sae_pk_base32_encode(pw_base_bin, 20 * j - 5);
+ if (pw)
+ printf("# %s\n", pw);
+ }
+
+ ret = 0;
+fail:
+ os_free(der);
+ wpabuf_free(pub);
+ crypto_ec_key_deinit(key);
+ os_free(data);
+ os_free(b64);
+ os_free(pw);
+
+ os_program_deinit();
+
+ return ret;
+}
diff --git a/hs20/client/Makefile b/hs20/client/Makefile
index cc2af03f..4dcfe2d3 100644
--- a/hs20/client/Makefile
+++ b/hs20/client/Makefile
@@ -1,28 +1,6 @@
-all: hs20-osu-client
+ALL=hs20-osu-client
-ifndef CC
-CC=gcc
-endif
-
-ifndef LDO
-LDO=$(CC)
-endif
-
-ifeq ($(QUIET), 1)
-Q=@
-E=true
-else
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-endif
-
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
-endif
+include ../../src/build.rules
CFLAGS += -I../../src/utils
CFLAGS += -I../../src/common
@@ -93,23 +71,11 @@ CFLAGS += -DEAP_TLS_OPENSSL
OBJS += ../../src/crypto/tls_openssl_ocsp.o
LIBS += -lssl -lcrypto
+_OBJS_VAR := OBJS
+include ../../src/objs.mk
hs20-osu-client: $(OBJS)
$(Q)$(LDO) $(LDFLAGS) -o hs20-osu-client $(OBJS) $(LIBS)
@$(E) " LD " $@
-%.o: %.c
- $(Q)$(CC) -c -o $@ $(CFLAGS) $<
- @$(E) " CC " $<
-
-clean:
- rm -f core *~ *.o *.d hs20-osu-client
- rm -f ../../src/utils/*.o
- rm -f ../../src/utils/*.d
- rm -f ../../src/common/*.o
- rm -f ../../src/common/*.d
- rm -f ../../src/crypto/*.o
- rm -f ../../src/crypto/*.d
- rm -f ../../src/wps/*.o
- rm -f ../../src/wps/*.d
-
--include $(OBJS:%.o=%.d)
+clean: common-clean
+ rm -f core *~
diff --git a/hs20/server/.gitignore b/hs20/server/.gitignore
new file mode 100644
index 00000000..fecb096c
--- /dev/null
+++ b/hs20/server/.gitignore
@@ -0,0 +1 @@
+hs20_spp_server
diff --git a/hs20/server/Makefile b/hs20/server/Makefile
index 9b737279..0cab6d6b 100644
--- a/hs20/server/Makefile
+++ b/hs20/server/Makefile
@@ -1,16 +1,6 @@
-all: hs20_spp_server
+ALL=hs20_spp_server
-ifndef CC
-CC=gcc
-endif
-
-ifndef LDO
-LDO=$(CC)
-endif
-
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
-endif
+include ../../src/build.rules
CFLAGS += -I../../src
CFLAGS += -I../../src/utils
@@ -43,14 +33,10 @@ CFLAGS += $(shell xml2-config --cflags)
LIBS += $(shell xml2-config --libs)
OBJS += ../../src/utils/xml_libxml2.o
+_OBJS_VAR := OBJS
+include ../../src/objs.mk
hs20_spp_server: $(OBJS)
$(LDO) $(LDFLAGS) -o hs20_spp_server $(OBJS) $(LIBS)
-clean:
- rm -f core *~ *.o *.d hs20_spp_server
- rm -f ../../src/utils/*.o
- rm -f ../../src/utils/*.d
- rm -f ../../src/crypto/*.o
- rm -f ../../src/crypto/*.d
-
--include $(OBJS:%.o=%.d)
+clean: common-clean
+ rm -f core *~
diff --git a/src/Makefile b/src/Makefile
index c9e84c11..6eb7f2ac 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -5,8 +5,8 @@ all:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done
clean:
- for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
- rm -f *~
+ $(Q)for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
+ $(Q)rm -f *~
install:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d install; done
diff --git a/src/ap/Makefile b/src/ap/Makefile
index 54e48a0d..a1e9b7c4 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -1,13 +1,3 @@
-all: libap.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libap.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DHOSTAPD
CFLAGS += -DNEED_AP_MLME
CFLAGS += -DCONFIG_ETH_P_OUI
@@ -67,7 +57,4 @@ LIB_OBJS= \
wps_hostapd.o \
x_snoop.o
-libap.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 35a32a13..b0d8ec86 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -131,6 +131,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->fils_hlp_wait_time = 30;
bss->dhcp_server_port = DHCP_SERVER_PORT;
bss->dhcp_relay_port = DHCP_SERVER_PORT;
+ bss->fils_discovery_min_int = 20;
#endif /* CONFIG_FILS */
bss->broadcast_deauth = 1;
@@ -160,6 +161,10 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
/* Default to strict CRL checking. */
bss->check_crl_strict = 1;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ bss->sae_commit_status = -1;
+#endif /* CONFIG_TESTING_OPTIONS */
}
@@ -248,6 +253,8 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->ignore_reassoc_probability = 0.0;
conf->corrupt_gtk_rekey_mic_probability = 0.0;
conf->ecsa_ie_only = 0;
+ conf->skip_send_eapol = 0;
+ conf->enable_eapol_large_timeout = 0;
#endif /* CONFIG_TESTING_OPTIONS */
conf->acs = 0;
@@ -264,6 +271,10 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->he_op.he_bss_color_disabled = 1;
conf->he_op.he_bss_color_partial = 0;
conf->he_op.he_bss_color = 1;
+ conf->he_6ghz_max_mpdu = 2;
+ conf->he_6ghz_max_ampdu_len_exp = 7;
+ conf->he_6ghz_rx_ant_pat = 1;
+ conf->he_6ghz_tx_ant_pat = 1;
#endif /* CONFIG_IEEE80211AX */
/* The third octet of the country string uses an ASCII space character
@@ -461,7 +472,8 @@ int hostapd_setup_sae_pt(struct hostapd_bss_config *conf)
struct hostapd_ssid *ssid = &conf->ssid;
struct sae_password_entry *pw;
- if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf)) ||
+ if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf) &&
+ !hostapd_sae_pk_in_use(conf)) ||
conf->sae_pwe == 3 ||
!wpa_key_mgmt_sae(conf->wpa_key_mgmt))
return 0; /* PT not needed */
@@ -711,6 +723,9 @@ static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf)
#ifdef CONFIG_SAE
sae_deinit_pt(tmp->pt);
#endif /* CONFIG_SAE */
+#ifdef CONFIG_SAE_PK
+ sae_deinit_pk(tmp->pk);
+#endif /* CONFIG_SAE_PK */
os_free(tmp);
}
}
@@ -947,6 +962,10 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
}
#endif /* CONFIG_AIRTIME_POLICY */
+#ifdef CONFIG_PASN
+ os_free(conf->pasn_groups);
+#endif /* CONFIG_PASN */
+
os_free(conf);
}
@@ -1111,10 +1130,85 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
}
+#ifdef CONFIG_SAE_PK
+static bool hostapd_sae_pk_password_without_pk(struct hostapd_bss_config *bss)
+{
+ struct sae_password_entry *pw;
+ bool res = false;
+
+ if (bss->ssid.wpa_passphrase &&
+#ifdef CONFIG_TESTING_OPTIONS
+ !bss->sae_pk_password_check_skip &&
+#endif /* CONFIG_TESTING_OPTIONS */
+ sae_pk_valid_password(bss->ssid.wpa_passphrase))
+ res = true;
+
+ for (pw = bss->sae_passwords; pw; pw = pw->next) {
+ if (!pw->pk &&
+#ifdef CONFIG_TESTING_OPTIONS
+ !bss->sae_pk_password_check_skip &&
+#endif /* CONFIG_TESTING_OPTIONS */
+ sae_pk_valid_password(pw->password))
+ return true;
+
+ if (bss->ssid.wpa_passphrase && res && pw->pk &&
+ os_strcmp(bss->ssid.wpa_passphrase, pw->password) == 0)
+ res = false;
+ }
+
+ return res;
+}
+#endif /* CONFIG_SAE_PK */
+
+
+static bool hostapd_config_check_bss_6g(struct hostapd_bss_config *bss)
+{
+ if (bss->wpa != WPA_PROTO_RSN) {
+ wpa_printf(MSG_ERROR,
+ "Pre-RSNA security methods are not allowed in 6 GHz");
+ return false;
+ }
+
+ if (bss->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED) {
+ wpa_printf(MSG_ERROR,
+ "Management frame protection is required in 6 GHz");
+ return false;
+ }
+
+ if (bss->wpa_key_mgmt & (WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256)) {
+ wpa_printf(MSG_ERROR, "Invalid AKM suite for 6 GHz");
+ return false;
+ }
+
+ if (bss->rsn_pairwise & (WPA_CIPHER_WEP40 |
+ WPA_CIPHER_WEP104 |
+ WPA_CIPHER_TKIP)) {
+ wpa_printf(MSG_ERROR,
+ "Invalid pairwise cipher suite for 6 GHz");
+ return false;
+ }
+
+ if (bss->wpa_group & (WPA_CIPHER_WEP40 |
+ WPA_CIPHER_WEP104 |
+ WPA_CIPHER_TKIP)) {
+ wpa_printf(MSG_ERROR, "Invalid group cipher suite for 6 GHz");
+ return false;
+ }
+
+ return true;
+}
+
+
static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
struct hostapd_config *conf,
int full_config)
{
+ if (full_config && is_6ghz_op_class(conf->op_class) &&
+ !hostapd_config_check_bss_6g(bss))
+ return -1;
+
if (full_config && bss->ieee802_1x && !bss->eap_server &&
!bss->radius->auth_servers) {
wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
@@ -1190,7 +1284,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
if (full_config && conf->ieee80211n &&
conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
- bss->disable_11n = 1;
+ bss->disable_11n = true;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
"allowed, disabling HT capabilities");
}
@@ -1198,7 +1292,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
#ifdef CONFIG_WEP
if (full_config && conf->ieee80211n &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
- bss->disable_11n = 1;
+ bss->disable_11n = true;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
"allowed, disabling HT capabilities");
}
@@ -1209,7 +1303,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
{
- bss->disable_11n = 1;
+ bss->disable_11n = true;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
"requires CCMP/GCMP to be enabled, disabling HT "
"capabilities");
@@ -1219,7 +1313,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
#ifdef CONFIG_WEP
if (full_config && conf->ieee80211ac &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
- bss->disable_11ac = 1;
+ bss->disable_11ac = true;
wpa_printf(MSG_ERROR,
"VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
}
@@ -1230,12 +1324,33 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
{
- bss->disable_11ac = 1;
+ bss->disable_11ac = true;
wpa_printf(MSG_ERROR,
"VHT (IEEE 802.11ac) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling VHT capabilities");
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+#ifdef CONFIG_WEP
+ if (full_config && conf->ieee80211ax &&
+ bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+ bss->disable_11ax = true;
+ wpa_printf(MSG_ERROR,
+ "HE (IEEE 802.11ax) with WEP is not allowed, disabling HE capabilities");
+ }
+#endif /* CONFIG_WEP */
+
+ if (full_config && conf->ieee80211ax && bss->wpa &&
+ !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+ WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
+ {
+ bss->disable_11ax = true;
+ wpa_printf(MSG_ERROR,
+ "HE (IEEE 802.11ax) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling HE capabilities");
+ }
+#endif /* CONFIG_IEEE80211AX */
+
#ifdef CONFIG_WPS
if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
@@ -1294,6 +1409,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
#endif /* CONFIG_OCV */
+#ifdef CONFIG_SAE_PK
+ if (full_config && hostapd_sae_pk_in_use(bss) &&
+ hostapd_sae_pk_password_without_pk(bss)) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: SAE password uses SAE-PK style, but does not have PK configured");
+ return -1;
+ }
+#endif /* CONFIG_SAE_PK */
+
return 0;
}
@@ -1473,3 +1597,38 @@ int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf)
return 2;
return with_id;
}
+
+
+bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf)
+{
+#ifdef CONFIG_SAE_PK
+ struct sae_password_entry *pw;
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ if (pw->pk)
+ return true;
+ }
+#endif /* CONFIG_SAE_PK */
+
+ return false;
+}
+
+
+#ifdef CONFIG_SAE_PK
+bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf)
+{
+ bool with_pk = false;
+ struct sae_password_entry *pw;
+
+ if (conf->ssid.wpa_passphrase)
+ return false;
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ if (!pw->pk)
+ return false;
+ with_pk = true;
+ }
+
+ return with_pk;
+}
+#endif /* CONFIG_SAE_PK */
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index cffa636c..e1b17f50 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -197,15 +197,6 @@ struct hostapd_radius_attr {
#define NUM_TX_QUEUES 4
-
-struct hostapd_tx_queue_params {
- int aifs;
- int cwmin;
- int cwmax;
- int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
-};
-
-
#define MAX_ROAMING_CONSORTIUM_LEN 15
struct hostapd_roaming_consortium {
@@ -261,6 +252,7 @@ struct sae_password_entry {
u8 peer_addr[ETH_ALEN];
int vlan_id;
struct sae_pt *pt;
+ struct sae_pk *pk;
};
struct dpp_controller_conf {
@@ -539,8 +531,9 @@ struct hostapd_bss_config {
#define TDLS_PROHIBIT BIT(0)
#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
int tdls;
- int disable_11n;
- int disable_11ac;
+ bool disable_11n;
+ bool disable_11ac;
+ bool disable_11ax;
/* IEEE 802.11v */
int time_advertisement;
@@ -677,6 +670,9 @@ struct hostapd_bss_config {
u8 bss_load_test_set;
struct wpabuf *own_ie_override;
int sae_reflection_attack;
+ int sae_commit_status;
+ int sae_pk_omit;
+ int sae_pk_password_check_skip;
struct wpabuf *sae_commit_override;
struct wpabuf *rsne_override_eapol;
struct wpabuf *rsnxe_override_eapol;
@@ -687,6 +683,13 @@ struct hostapd_bss_config {
int no_beacon_rsnxe;
int skip_prune_assoc;
int ft_rsnxe_used;
+ unsigned int oci_freq_override_eapol_m3;
+ unsigned int oci_freq_override_eapol_g1;
+ unsigned int oci_freq_override_saquery_req;
+ unsigned int oci_freq_override_saquery_resp;
+ 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 */
#define MESH_ENABLED BIT(0)
@@ -727,12 +730,16 @@ struct hostapd_bss_config {
unsigned int fils_hlp_wait_time;
u16 dhcp_server_port;
u16 dhcp_relay_port;
+ u32 fils_discovery_min_int;
+ u32 fils_discovery_max_int;
#endif /* CONFIG_FILS */
int multicast_to_unicast;
int broadcast_deauth;
+ int notify_mgmt_frames;
+
#ifdef CONFIG_DPP
char *dpp_name;
char *dpp_mud_url;
@@ -859,6 +866,20 @@ struct hostapd_bss_config {
*/
u8 mka_psk_set;
#endif /* CONFIG_MACSEC */
+
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ /*
+ * Normally, KDK should be derived if and only if both sides support
+ * secure LTF. Allow forcing KDK derivation for testing purposes.
+ */
+ int force_kdk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ int *pasn_groups;
+#endif /* CONFIG_PASN */
+
+ unsigned int unsol_bcast_probe_resp_interval;
};
/**
@@ -891,8 +912,8 @@ struct spatial_reuse {
u8 non_srg_obss_pd_max_offset;
u8 srg_obss_pd_min_offset;
u8 srg_obss_pd_max_offset;
- u8 srg_obss_color_bitmap;
- u8 srg_obss_color_partial_bitmap;
+ u8 srg_bss_color_bitmap[8];
+ u8 srg_partial_bssid_bitmap[8];
};
/**
@@ -1003,6 +1024,8 @@ struct hostapd_config {
double ignore_reassoc_probability;
double corrupt_gtk_rekey_mic_probability;
int ecsa_ie_only;
+ unsigned int skip_send_eapol;
+ unsigned int enable_eapol_large_timeout;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_ACS
@@ -1027,6 +1050,10 @@ struct hostapd_config {
u8 he_oper_chwidth;
u8 he_oper_centr_freq_seg0_idx;
u8 he_oper_centr_freq_seg1_idx;
+ u8 he_6ghz_max_mpdu;
+ u8 he_6ghz_max_ampdu_len_exp;
+ u8 he_6ghz_rx_ant_pat;
+ u8 he_6ghz_tx_ant_pat;
#endif /* CONFIG_IEEE80211AX */
/* VHT enable/disable config from CHAN_SWITCH */
@@ -1034,8 +1061,14 @@ struct hostapd_config {
#define CH_SWITCH_VHT_DISABLED BIT(1)
unsigned int ch_switch_vht_config;
+ /* HE enable/disable config from CHAN_SWITCH */
+#define CH_SWITCH_HE_ENABLED BIT(0)
+#define CH_SWITCH_HE_DISABLED BIT(1)
+ unsigned int ch_switch_he_config;
+
int rssi_reject_assoc_rssi;
int rssi_reject_assoc_timeout;
+ int rssi_ignore_probe_request;
#ifdef CONFIG_AIRTIME_POLICY
enum {
@@ -1140,6 +1173,8 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config);
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config);
int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf);
+bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf);
+bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf);
int hostapd_setup_sae_pt(struct hostapd_bss_config *conf);
#endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index f1576594..d1642d7d 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -988,3 +988,11 @@ int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
return hapd->driver->update_dh_ie(hapd->drv_priv, peer, reason_code,
ie, ielen);
}
+
+
+int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable)
+{
+ if (!hapd->driver || !hapd->driver->dpp_listen || !hapd->drv_priv)
+ return 0;
+ return hapd->driver->dpp_listen(hapd->drv_priv, enable);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 5738c1c9..582ab61d 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -134,6 +134,7 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
int hostapd_drv_do_acs(struct hostapd_data *hapd);
int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
u16 reason_code, const u8 *ie, size_t ielen);
+int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable);
#include "drivers/driver.h"
@@ -350,12 +351,13 @@ static inline int hostapd_drv_br_set_net_param(struct hostapd_data *hapd,
static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
int vendor_id, int subcmd,
const u8 *data, size_t data_len,
+ enum nested_attr nested_attr_flag,
struct wpabuf *buf)
{
if (hapd->driver == NULL || hapd->driver->vendor_cmd == NULL)
return -1;
return hapd->driver->vendor_cmd(hapd->drv_priv, vendor_id, subcmd, data,
- data_len, buf);
+ data_len, nested_attr_flag, buf);
}
static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
@@ -384,11 +386,11 @@ hostapd_drv_send_external_auth_status(struct hostapd_data *hapd,
}
static inline int
-hostapd_drv_set_band(struct hostapd_data *hapd, enum set_band band)
+hostapd_drv_set_band(struct hostapd_data *hapd, u32 band_mask)
{
if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_band)
return -1;
- return hapd->driver->set_band(hapd->drv_priv, band);
+ return hapd->driver->set_band(hapd->drv_priv, band_mask);
}
#endif /* AP_DRV_OPS */
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 22e672c8..7d9e8b92 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -266,7 +266,7 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
}
-static const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
+const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
{
const u8 *ies;
size_t ies_len;
@@ -458,7 +458,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
}
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
@@ -560,15 +560,24 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
pos = hostapd_eid_txpower_envelope(hapd, pos);
- pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax &&
+ is_6ghz_op_class(hapd->iconf->op_class))
+ pos = hostapd_eid_txpower_envelope(hapd, pos);
+#endif /* CONFIG_IEEE80211AX */
+
+ if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
+ (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax))
+ pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
+
pos = hostapd_eid_fils_indic(hapd, pos, 0);
pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
pos = hostapd_eid_he_operation(hapd, pos);
pos = hostapd_eid_spatial_reuse(hapd, pos);
@@ -815,6 +824,10 @@ void handle_probe_req(struct hostapd_data *hapd,
size_t csa_offs_len;
struct radius_sta rad_info;
+ if (hapd->iconf->rssi_ignore_probe_request && ssi_signal &&
+ ssi_signal < hapd->iconf->rssi_ignore_probe_request)
+ return;
+
if (len < IEEE80211_HDRLEN)
return;
ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
@@ -1111,6 +1124,23 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
+#ifdef CONFIG_IEEE80211AX
+/* Unsolicited broadcast Probe Response transmission, 6 GHz only */
+static u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
+ struct wpa_driver_ap_params *params)
+{
+ if (!is_6ghz_op_class(hapd->iconf->op_class))
+ return NULL;
+
+ params->unsol_bcast_probe_resp_interval =
+ hapd->conf->unsol_bcast_probe_resp_interval;
+
+ return hostapd_gen_probe_resp(hapd, NULL, 0,
+ &params->unsol_bcast_probe_resp_tmpl_len);
+}
+#endif /* CONFIG_IEEE80211AX */
+
+
void sta_track_del(struct hostapd_sta_info *info)
{
#ifdef CONFIG_TAXONOMY
@@ -1121,6 +1151,243 @@ void sta_track_del(struct hostapd_sta_info *info)
}
+#ifdef CONFIG_FILS
+
+static u16 hostapd_fils_discovery_cap(struct hostapd_data *hapd)
+{
+ u16 cap_info, phy_index = 0;
+ u8 chwidth = FD_CAP_BSS_CHWIDTH_20, mcs_nss_size = 4;
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+
+ cap_info = FD_CAP_ESS;
+ if (hapd->conf->wpa)
+ cap_info |= FD_CAP_PRIVACY;
+
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ phy_index = FD_CAP_PHY_INDEX_HE;
+
+ switch (hapd->iconf->op_class) {
+ case 135:
+ mcs_nss_size += 4;
+ /* fallthrough */
+ case 134:
+ mcs_nss_size += 4;
+ chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
+ break;
+ case 133:
+ chwidth = FD_CAP_BSS_CHWIDTH_80;
+ break;
+ case 132:
+ chwidth = FD_CAP_BSS_CHWIDTH_40;
+ break;
+ }
+ } else {
+ switch (hostapd_get_oper_chwidth(hapd->iconf)) {
+ case CHANWIDTH_80P80MHZ:
+ mcs_nss_size += 4;
+ /* fallthrough */
+ case CHANWIDTH_160MHZ:
+ mcs_nss_size += 4;
+ chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
+ break;
+ case CHANWIDTH_80MHZ:
+ chwidth = FD_CAP_BSS_CHWIDTH_80;
+ break;
+ case CHANWIDTH_USE_HT:
+ if (hapd->iconf->secondary_channel)
+ chwidth = FD_CAP_BSS_CHWIDTH_40;
+ else
+ chwidth = FD_CAP_BSS_CHWIDTH_20;
+ break;
+ }
+
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax)
+ phy_index = FD_CAP_PHY_INDEX_HE;
+#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211AC
+ if (!phy_index &&
+ hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac)
+ phy_index = FD_CAP_PHY_INDEX_VHT;
+#endif /* CONFIG_IEEE80211AC */
+ if (!phy_index &&
+ hapd->iconf->ieee80211n && !hapd->conf->disable_11n)
+ phy_index = FD_CAP_PHY_INDEX_HT;
+ }
+
+ cap_info |= phy_index << FD_CAP_PHY_INDEX_SHIFT;
+ cap_info |= chwidth << FD_CAP_BSS_CHWIDTH_SHIFT;
+
+ if (mode) {
+ u16 *mcs = (u16 *) mode->he_capab[IEEE80211_MODE_AP].mcs;
+ int i;
+ u16 nss = 0;
+
+ for (i = 0; i < HE_NSS_MAX_STREAMS; i++) {
+ u16 nss_mask = 0x3 << (i * 2);
+
+ if (mcs_nss_size == 4 &&
+ (((mcs[0] & nss_mask) == nss_mask) ||
+ ((mcs[1] & nss_mask) == nss_mask)))
+ continue;
+
+ if (mcs_nss_size == 8 &&
+ (((mcs[2] & nss_mask) == nss_mask) ||
+ ((mcs[3] & nss_mask) == nss_mask)))
+ continue;
+
+ if (mcs_nss_size == 12 &&
+ (((mcs[4] & nss_mask) == nss_mask) ||
+ ((mcs[5] & nss_mask) == nss_mask)))
+ continue;
+
+ nss++;
+ }
+
+ if (nss > 4)
+ cap_info |= FD_CAP_NSS_5_8 << FD_CAP_NSS_SHIFT;
+ else if (nss)
+ cap_info |= (nss - 1) << FD_CAP_NSS_SHIFT;
+ }
+
+ return cap_info;
+}
+
+
+static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len)
+{
+ struct ieee80211_mgmt *head;
+ const u8 *mobility_domain;
+ u8 *pos, *length_pos, buf[200];
+ u16 ctl = 0;
+ u8 fd_rsn_info[5];
+ size_t total_len, buf_len;
+
+ total_len = 24 + 2 + 12;
+
+ /* FILS Discovery Frame Control */
+ ctl = (sizeof(hapd->conf->ssid.short_ssid) - 1) |
+ FD_FRAME_CTL_SHORT_SSID_PRESENT |
+ FD_FRAME_CTL_LENGTH_PRESENT |
+ FD_FRAME_CTL_CAP_PRESENT;
+ total_len += 4 + 1 + 2;
+
+ /* Check for optional subfields and calculate length */
+ if (wpa_auth_write_fd_rsn_info(hapd->wpa_auth, fd_rsn_info)) {
+ ctl |= FD_FRAME_CTL_RSN_INFO_PRESENT;
+ total_len += sizeof(fd_rsn_info);
+ }
+
+ mobility_domain = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
+ if (mobility_domain) {
+ ctl |= FD_FRAME_CTL_MD_PRESENT;
+ total_len += 3;
+ }
+
+ pos = hostapd_eid_fils_indic(hapd, buf, 0);
+ buf_len = pos - buf;
+ total_len += buf_len;
+
+ head = os_zalloc(total_len);
+ if (!head)
+ return NULL;
+
+ head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memset(head->da, 0xff, ETH_ALEN);
+ os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
+
+ head->u.action.category = WLAN_ACTION_PUBLIC;
+ head->u.action.u.public_action.action = WLAN_PA_FILS_DISCOVERY;
+
+ pos = &head->u.action.u.public_action.variable[0];
+
+ /* FILS Discovery Information field */
+
+ /* FILS Discovery Frame Control */
+ WPA_PUT_LE16(pos, ctl);
+ pos += 2;
+
+ /* Hardware or low-level driver will fill in the Timestamp value */
+ pos += 8;
+
+ /* Beacon Interval */
+ WPA_PUT_LE16(pos, hapd->iconf->beacon_int);
+ pos += 2;
+
+ /* Short SSID */
+ WPA_PUT_LE32(pos, hapd->conf->ssid.short_ssid);
+ pos += sizeof(hapd->conf->ssid.short_ssid);
+
+ /* Store position of FILS discovery information element Length field */
+ length_pos = pos++;
+
+ /* FD Capability */
+ WPA_PUT_LE16(pos, hostapd_fils_discovery_cap(hapd));
+ pos += 2;
+
+ /* Operating Class - not present */
+
+ /* Primary Channel - not present */
+
+ /* AP Configuration Sequence Number - not present */
+
+ /* Access Network Options - not present */
+
+ /* FD RSN Information */
+ if (ctl & FD_FRAME_CTL_RSN_INFO_PRESENT) {
+ os_memcpy(pos, fd_rsn_info, sizeof(fd_rsn_info));
+ pos += sizeof(fd_rsn_info);
+ }
+
+ /* Channel Center Frequency Segment 1 - not present */
+
+ /* Mobility Domain */
+ if (ctl & FD_FRAME_CTL_MD_PRESENT) {
+ os_memcpy(pos, &mobility_domain[2], 3);
+ pos += 3;
+ }
+
+ /* Fill in the Length field value */
+ *length_pos = pos - (length_pos + 1);
+
+ /* FILS Indication element */
+ if (buf_len) {
+ os_memcpy(pos, buf, buf_len);
+ pos += buf_len;
+ }
+
+ *len = pos - (u8 *) head;
+ wpa_hexdump(MSG_DEBUG, "FILS Discovery frame template",
+ head, pos - (u8 *) head);
+ return (u8 *) head;
+}
+
+
+/* Configure FILS Discovery frame transmission parameters */
+static u8 * hostapd_fils_discovery(struct hostapd_data *hapd,
+ struct wpa_driver_ap_params *params)
+{
+ params->fd_max_int = hapd->conf->fils_discovery_max_int;
+ if (is_6ghz_op_class(hapd->iconf->op_class) &&
+ params->fd_max_int > FD_MAX_INTERVAL_6GHZ)
+ params->fd_max_int = FD_MAX_INTERVAL_6GHZ;
+
+ params->fd_min_int = hapd->conf->fils_discovery_min_int;
+ if (params->fd_min_int > params->fd_max_int)
+ params->fd_min_int = params->fd_max_int;
+
+ if (params->fd_max_int)
+ return hostapd_gen_fils_discovery(hapd,
+ &params->fd_frame_tmpl_len);
+
+ return NULL;
+}
+
+#endif /* CONFIG_FILS */
+
+
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
@@ -1160,7 +1427,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
@@ -1277,19 +1544,29 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#endif /* CONFIG_FST */
#ifdef CONFIG_IEEE80211AC
- if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
+ !is_6ghz_op_class(hapd->iconf->op_class)) {
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
- tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax &&
+ is_6ghz_op_class(hapd->iconf->op_class))
+ tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
+#endif /* CONFIG_IEEE80211AX */
+
+ if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
+ (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax))
+ tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
+
tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
tailpos = hostapd_eid_he_capab(hapd, tailpos,
IEEE80211_MODE_AP);
tailpos = hostapd_eid_he_operation(hapd, tailpos);
@@ -1455,6 +1732,14 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
params->head = NULL;
os_free(params->proberesp);
params->proberesp = NULL;
+#ifdef CONFIG_FILS
+ os_free(params->fd_frame_tmpl);
+ params->fd_frame_tmpl = NULL;
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211AX
+ os_free(params->unsol_bcast_probe_resp_tmpl);
+ params->unsol_bcast_probe_resp_tmpl = NULL;
+#endif /* CONFIG_IEEE80211AX */
}
@@ -1487,11 +1772,17 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
params.assocresp_ies = assocresp;
params.reenable = hapd->reenable_beacon;
#ifdef CONFIG_IEEE80211AX
- params.he_spr = !!hapd->iface->conf->spr.sr_control;
+ params.he_spr_ctrl = hapd->iface->conf->spr.sr_control;
+ params.he_spr_non_srg_obss_pd_max_offset =
+ hapd->iface->conf->spr.non_srg_obss_pd_max_offset;
params.he_spr_srg_obss_pd_min_offset =
hapd->iface->conf->spr.srg_obss_pd_min_offset;
params.he_spr_srg_obss_pd_max_offset =
hapd->iface->conf->spr.srg_obss_pd_max_offset;
+ os_memcpy(params.he_spr_bss_color_bitmap,
+ hapd->iface->conf->spr.srg_bss_color_bitmap, 8);
+ os_memcpy(params.he_spr_partial_bssid_bitmap,
+ hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8);
params.he_bss_color_disabled =
hapd->iface->conf->he_op.he_bss_color_disabled;
params.he_bss_color_partial =
@@ -1499,8 +1790,17 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
params.he_bss_color = hapd->iface->conf->he_op.he_bss_color;
params.twt_responder = hostapd_get_he_twt_responder(hapd,
IEEE80211_MODE_AP);
+ params.unsol_bcast_probe_resp_tmpl =
+ hostapd_unsol_bcast_probe_resp(hapd, &params);
#endif /* CONFIG_IEEE80211AX */
hapd->reenable_beacon = 0;
+#ifdef CONFIG_SAE
+ params.sae_pwe = hapd->conf->sae_pwe;
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_FILS
+ params.fd_frame_tmpl = hostapd_fils_discovery(hapd, &params);
+#endif /* CONFIG_FILS */
if (cmode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index a26e3087..c320825f 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -30,4 +30,6 @@ sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
struct wpabuf **probe_ie_taxonomy);
+const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid);
+
#endif /* BEACON_H */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index ef53a825..28e40ba9 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -748,7 +748,8 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
iface->conf->ieee80211n && !hapd->conf->disable_11n,
iface->conf->ieee80211ac &&
!hapd->conf->disable_11ac,
- iface->conf->ieee80211ax,
+ iface->conf->ieee80211ax &&
+ !hapd->conf->disable_11ax,
iface->conf->beacon_int,
hapd->conf->dtim_period);
if (os_snprintf_error(buflen - len, ret))
@@ -756,7 +757,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
len += ret;
#ifdef CONFIG_IEEE80211AX
- if (iface->conf->ieee80211ax) {
+ if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
ret = os_snprintf(buf + len, buflen - len,
"he_oper_chwidth=%d\n"
"he_oper_centr_freq_seg0_idx=%d\n"
@@ -908,6 +909,7 @@ int hostapd_parse_csa_settings(const char *pos,
SET_CSA_SETTING(sec_channel_offset);
settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
+ settings->freq_params.he_enabled = !!os_strstr(pos, " he");
settings->block_tx = !!os_strstr(pos, " blocktx");
#undef SET_CSA_SETTING
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 3c078b9c..b990fb34 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -81,17 +81,17 @@ static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
* We will also choose this first channel as the control one.
*/
int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
- 184, 192 };
+ 165, 173, 184, 192 };
/*
* VHT80, valid channels based on center frequency:
- * 42, 58, 106, 122, 138, 155
+ * 42, 58, 106, 122, 138, 155, 171
*/
- int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
+ int allowed_80[] = { 36, 52, 100, 116, 132, 149, 165 };
/*
* VHT160 valid channels based on center frequency:
- * 50, 114
+ * 50, 114, 163
*/
- int allowed_160[] = { 36, 100 };
+ int allowed_160[] = { 36, 100, 149 };
int *allowed = allowed_40;
unsigned int i, allowed_no = 0;
@@ -955,10 +955,13 @@ dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
if (*skip_radar) {
*skip_radar = 0;
} else {
- if (iface->conf->vht_oper_chwidth == CHANWIDTH_USE_HT)
+ int oper_chwidth;
+
+ oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+ if (oper_chwidth == CHANWIDTH_USE_HT)
break;
*skip_radar = 1;
- iface->conf->vht_oper_chwidth--;
+ hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
}
}
@@ -1028,7 +1031,8 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
unsigned int i;
int err = 1;
struct hostapd_hw_modes *cmode = iface->current_mode;
- u8 current_vht_oper_chwidth = iface->conf->vht_oper_chwidth;
+ u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+ int ieee80211_mode = IEEE80211_MODE_AP;
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no",
@@ -1066,8 +1070,16 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
&skip_radar);
- if (!channel)
- return err;
+ if (!channel) {
+ /*
+ * Toggle interface state to enter DFS state
+ * until NOP is finished.
+ */
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+ return 0;
+ }
+
if (!skip_radar) {
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
@@ -1089,13 +1101,17 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
"freq=%d chan=%d sec_chan=%d", channel->freq,
channel->chan, secondary_channel);
- new_vht_oper_chwidth = iface->conf->vht_oper_chwidth;
- iface->conf->vht_oper_chwidth = current_vht_oper_chwidth;
+ new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+ hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
/* Setup CSA request */
os_memset(&csa_settings, 0, sizeof(csa_settings));
csa_settings.cs_count = 5;
csa_settings.block_tx = 1;
+#ifdef CONFIG_MESH
+ if (iface->mconf)
+ ieee80211_mode = IEEE80211_MODE_MESH;
+#endif /* CONFIG_MESH */
err = hostapd_set_freq_params(&csa_settings.freq_params,
iface->conf->hw_mode,
channel->freq,
@@ -1110,7 +1126,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx,
cmode->vht_capab,
- &cmode->he_capab[IEEE80211_MODE_AP]);
+ &cmode->he_capab[ieee80211_mode]);
if (err) {
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
@@ -1130,7 +1146,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
- iface->conf->vht_oper_chwidth = new_vht_oper_chwidth;
+ hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
oper_centr_freq_seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
@@ -1332,12 +1348,16 @@ int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
if (!(chan->flag & HOSTAPD_CHAN_RADAR))
continue;
+ if ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
+ HOSTAPD_CHAN_DFS_AVAILABLE)
+ continue;
+
if (center_freq - chan->freq < half_width &&
chan->freq - center_freq < half_width)
res++;
}
- wpa_printf(MSG_DEBUG, "DFS: (%d, %d): in range: %s",
+ wpa_printf(MSG_DEBUG, "DFS CAC required: (%d, %d): in range: %s",
center_freq - half_width, center_freq + half_width,
res ? "yes" : "no");
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 178fd126..e1e5a3ac 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -23,12 +23,17 @@
static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
+static void hostapd_dpp_auth_conf_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx);
static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator);
static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
#ifdef CONFIG_DPP2
static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
void *timeout_ctx);
+static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf);
#endif /* CONFIG_DPP2 */
static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -63,6 +68,10 @@ int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd)
wpabuf_len(hapd->dpp_auth->resp_msg));
}
+#ifdef CONFIG_DPP2
+ dpp_controller_new_qr_code(hapd->iface->interfaces->dpp, bi);
+#endif /* CONFIG_DPP2 */
+
return bi->id;
}
@@ -239,6 +248,8 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout,
+ hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
NULL);
#ifdef CONFIG_DPP2
@@ -270,6 +281,17 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
}
}
+ if (auth->waiting_auth_conf &&
+ auth->auth_resp_status == DPP_STATUS_OK) {
+ /* Make sure we do not get stuck waiting for Auth Confirm
+ * indefinitely after successfully transmitted Auth Response to
+ * allow new authentication exchanges to be started. */
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd,
+ NULL);
+ eloop_register_timeout(1, 0, hostapd_dpp_auth_conf_wait_timeout,
+ hapd, NULL);
+ }
+
if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp && ok) {
/* Allow timeout handling to stop iteration if no response is
* received from a peer that has ACKed a request. */
@@ -370,6 +392,25 @@ static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
}
+static void hostapd_dpp_auth_conf_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth || !auth->waiting_auth_conf)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Terminate authentication exchange due to Auth Confirm timeout");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "No Auth Confirm received");
+ hostapd_drv_send_action_cancel_wait(hapd);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+}
+
+
static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd,
struct dpp_authentication *auth)
{
@@ -454,7 +495,9 @@ static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd)
freq = auth->freq[auth->freq_idx++];
auth->curr_freq = freq;
- if (is_zero_ether_addr(auth->peer_bi->mac_addr))
+ if (!is_zero_ether_addr(auth->peer_mac_addr))
+ dst = auth->peer_mac_addr;
+ else if (is_zero_ether_addr(auth->peer_bi->mac_addr))
dst = broadcast;
else
dst = auth->peer_bi->mac_addr;
@@ -486,12 +529,35 @@ static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd)
}
+#ifdef CONFIG_DPP2
+static int hostapd_dpp_process_conf_obj(void *ctx,
+ struct dpp_authentication *auth)
+{
+ struct hostapd_data *hapd = ctx;
+ unsigned int i;
+
+ for (i = 0; i < auth->num_conf_obj; i++)
+ hostapd_dpp_handle_config_obj(hapd, auth,
+ &auth->conf_obj[i]);
+
+ return 0;
+}
+#endif /* CONFIG_DPP2 */
+
+
int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
{
const char *pos;
struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
+ struct dpp_authentication *auth;
u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
unsigned int neg_freq = 0;
+ int tcp = 0;
+#ifdef CONFIG_DPP2
+ int tcp_port = DPP_TCP_PORT;
+ struct hostapd_ip_addr ipaddr;
+ char *addr;
+#endif /* CONFIG_DPP2 */
pos = os_strstr(cmd, " peer=");
if (!pos)
@@ -504,6 +570,25 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
return -1;
}
+#ifdef CONFIG_DPP2
+ pos = os_strstr(cmd, " tcp_port=");
+ if (pos) {
+ pos += 10;
+ tcp_port = atoi(pos);
+ }
+
+ addr = get_param(cmd, " tcp_addr=");
+ if (addr) {
+ int res;
+
+ res = hostapd_parse_ip_addr(addr, &ipaddr);
+ os_free(addr);
+ if (res)
+ return -1;
+ tcp = 1;
+ }
+#endif /* CONFIG_DPP2 */
+
pos = os_strstr(cmd, " own=");
if (pos) {
pos += 5;
@@ -541,10 +626,12 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
if (pos)
neg_freq = atoi(pos + 10);
- if (hapd->dpp_auth) {
+ if (!tcp && hapd->dpp_auth) {
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout,
+ hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
NULL);
#ifdef CONFIG_DPP2
@@ -555,26 +642,32 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
dpp_auth_deinit(hapd->dpp_auth);
}
- hapd->dpp_auth = dpp_auth_init(hapd->iface->interfaces->dpp,
- hapd->msg_ctx, peer_bi, own_bi,
- allowed_roles, neg_freq,
- hapd->iface->hw_features,
- hapd->iface->num_hw_features);
- if (!hapd->dpp_auth)
+ auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ peer_bi, own_bi, allowed_roles, neg_freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
+ if (!auth)
goto fail;
- hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- if (dpp_set_configurator(hapd->dpp_auth, cmd) < 0) {
- dpp_auth_deinit(hapd->dpp_auth);
- hapd->dpp_auth = NULL;
+ hostapd_dpp_set_testing_options(hapd, auth);
+ if (dpp_set_configurator(auth, cmd) < 0) {
+ dpp_auth_deinit(auth);
goto fail;
}
- hapd->dpp_auth->neg_freq = neg_freq;
+ auth->neg_freq = neg_freq;
if (!is_zero_ether_addr(peer_bi->mac_addr))
- os_memcpy(hapd->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
- ETH_ALEN);
+ os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+
+#ifdef CONFIG_DPP2
+ if (tcp)
+ return dpp_tcp_init(hapd->iface->interfaces->dpp, auth,
+ &ipaddr, tcp_port, hapd->conf->dpp_name,
+ DPP_NETROLE_AP, hapd->msg_ctx, hapd,
+ hostapd_dpp_process_conf_obj);
+#endif /* CONFIG_DPP2 */
+ hapd->dpp_auth = auth;
return hostapd_dpp_auth_init_next(hapd);
fail:
return -1;
@@ -606,12 +699,14 @@ int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd)
return -1;
}
+ hostapd_drv_dpp_listen(hapd, true);
return 0;
}
void hostapd_dpp_listen_stop(struct hostapd_data *hapd)
{
+ hostapd_drv_dpp_listen(hapd, false);
/* TODO: Stop listen operation on non-operating channel */
}
@@ -1173,6 +1268,9 @@ hostapd_dpp_rx_presence_announcement(struct hostapd_data *hapd, const u8 *src,
r_bootstrap, r_bootstrap_len);
peer_bi = dpp_bootstrap_find_chirp(hapd->iface->interfaces->dpp,
r_bootstrap);
+ dpp_notify_chirp_received(hapd->msg_ctx,
+ peer_bi ? (int) peer_bi->id : -1,
+ src, freq, r_bootstrap);
if (!peer_bi) {
if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
src, hdr, buf, len, freq, NULL,
@@ -1194,8 +1292,8 @@ hostapd_dpp_rx_presence_announcement(struct hostapd_data *hapd, const u8 *src,
0);
if (!auth)
return;
- hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- if (dpp_set_configurator(hapd->dpp_auth,
+ hostapd_dpp_set_testing_options(hapd, auth);
+ if (dpp_set_configurator(auth,
hapd->dpp_configurator_params) < 0) {
dpp_auth_deinit(auth);
return;
@@ -1203,8 +1301,9 @@ hostapd_dpp_rx_presence_announcement(struct hostapd_data *hapd, const u8 *src,
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);
+ /* The source address of the Presence Announcement frame overrides any
+ * MAC address information from the bootstrapping information. */
+ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
hapd->dpp_auth = auth;
if (hostapd_dpp_auth_init_next(hapd) < 0) {
@@ -1235,11 +1334,12 @@ hostapd_dpp_rx_reconfig_announcement(struct hostapd_data *hapd, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len,
unsigned int freq)
{
- const u8 *csign_hash;
- u16 csign_hash_len;
+ 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 (hapd->dpp_auth) {
wpa_printf(MSG_DEBUG,
@@ -1271,8 +1371,22 @@ hostapd_dpp_rx_reconfig_announcement(struct hostapd_data *hapd, const u8 *src,
return;
}
+ fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &fcgroup_len);
+ if (!fcgroup || fcgroup_len != 2) {
+ wpa_msg(hapd->msg_ctx, 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(hapd->iface->interfaces->dpp, hapd->msg_ctx,
- conf, freq);
+ conf, freq, group, a_nonce, a_nonce_len,
+ e_id, e_id_len);
if (!auth)
return;
hostapd_dpp_set_testing_options(hapd, auth);
@@ -1889,6 +2003,7 @@ void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
#ifdef CONFIG_DPP2
eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
@@ -2134,6 +2249,7 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
if (!hapd->dpp_init_done)
return;
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
#ifdef CONFIG_DPP2
@@ -2156,6 +2272,45 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
#ifdef CONFIG_DPP2
+int hostapd_dpp_controller_start(struct hostapd_data *hapd, 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_AP;
+ config.msg_ctx = hapd->msg_ctx;
+ config.cb_ctx = hapd;
+ config.process_conf_obj = hostapd_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 = hapd->dpp_configurator_params;
+ return dpp_controller_start(hapd->iface->interfaces->dpp, &config);
+}
+
+
static void hostapd_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx);
static void hostapd_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx)
diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h
index 7e74185c..264d3e4c 100644
--- a/src/ap/dpp_hostapd.h
+++ b/src/ap/dpp_hostapd.h
@@ -41,6 +41,7 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd);
void hostapd_dpp_init_global(struct hapd_interfaces *ifaces);
void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces);
+int hostapd_dpp_controller_start(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_chirp(struct hostapd_data *hapd, const char *cmd);
void hostapd_dpp_chirp_stop(struct hostapd_data *hapd);
void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 524a1513..53082f53 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -105,6 +105,32 @@ void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
#endif /* CONFIG_FILS */
+static bool check_sa_query_need(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ if ((sta->flags &
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
+ return false;
+
+ if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
+ ap_check_sa_query_timeout(hapd, sta);
+
+ if (!sta->sa_query_timed_out && (sta->auth_alg != WLAN_AUTH_FT)) {
+ /*
+ * STA has already been associated with MFP and SA Query timeout
+ * has not been reached. Reject the association attempt
+ * temporarily and start SA Query, if one is not pending.
+ */
+ if (sta->sa_query_count == 0)
+ ap_sta_start_sa_query(hapd, sta);
+
+ return true;
+ }
+
+ return false;
+}
+
+
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *req_ies, size_t req_ies_len, int reassoc)
{
@@ -293,6 +319,17 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
struct wpabuf *wps;
+ if (check_sa_query_need(hapd, sta)) {
+ status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
+
+ p = hostapd_eid_assoc_comeback_time(hapd, sta,
+ p);
+
+ hostapd_sta_assoc(hapd, addr, reassoc, status,
+ buf, p - buf);
+ return 0;
+ }
+
sta->flags |= WLAN_STA_WPS;
wps = ieee802_11_vendor_ie_concat(ie, ielen,
WPS_IE_VENDOR_TYPE);
@@ -388,25 +425,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
goto fail;
}
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- sta->sa_query_count > 0)
- ap_check_sa_query_timeout(hapd, sta);
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- (sta->auth_alg != WLAN_AUTH_FT)) {
- /*
- * STA has already been associated with MFP and SA
- * Query timeout has not been reached. Reject the
- * association attempt temporarily and start SA Query,
- * if one is not pending.
- */
-
- if (sta->sa_query_count == 0)
- ap_sta_start_sa_query(hapd, sta);
-
+ if (check_sa_query_need(hapd, sta)) {
status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
@@ -439,7 +458,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
#ifdef CONFIG_SAE
if (hapd->conf->sae_pwe == 2 &&
sta->auth_alg == WLAN_AUTH_SAE &&
- sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
+ sta->sae && !sta->sae->h2e &&
elems.rsnxe && elems.rsnxe_len >= 1 &&
(elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
wpa_printf(MSG_INFO, "SAE: " MACSTR
@@ -844,8 +863,6 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2,
int finished)
{
- /* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
-
#ifdef NEED_AP_MLME
int channel, chwidth, is_dfs;
u8 seg0_idx = 0, seg1_idx = 0;
@@ -853,9 +870,10 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
- "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+ "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
finished ? "had" : "starting",
- freq, ht, hapd->iconf->ch_switch_vht_config, offset,
+ freq, ht, hapd->iconf->ch_switch_vht_config,
+ hapd->iconf->ch_switch_he_config, offset,
width, channel_width_to_string(width), cf1, cf2);
if (!hapd->iface->current_mode) {
@@ -895,9 +913,18 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
switch (hapd->iface->current_mode->mode) {
case HOSTAPD_MODE_IEEE80211A:
- if (cf1 > 5000)
+ if (cf1 == 5935)
+ seg0_idx = (cf1 - 5925) / 5;
+ else if (cf1 > 5950)
+ seg0_idx = (cf1 - 5950) / 5;
+ else if (cf1 > 5000)
seg0_idx = (cf1 - 5000) / 5;
- if (cf2 > 5000)
+
+ if (cf2 == 5935)
+ seg1_idx = (cf2 - 5925) / 5;
+ else if (cf2 > 5950)
+ seg1_idx = (cf2 - 5950) / 5;
+ else if (cf2 > 5000)
seg1_idx = (cf2 - 5000) / 5;
break;
default:
@@ -918,8 +945,17 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
else if (hapd->iconf->ch_switch_vht_config &
CH_SWITCH_VHT_DISABLED)
hapd->iconf->ieee80211ac = 0;
+ } else if (hapd->iconf->ch_switch_he_config) {
+ /* CHAN_SWITCH HE config */
+ if (hapd->iconf->ch_switch_he_config &
+ CH_SWITCH_HE_ENABLED)
+ hapd->iconf->ieee80211ax = 1;
+ else if (hapd->iconf->ch_switch_he_config &
+ CH_SWITCH_HE_DISABLED)
+ hapd->iconf->ieee80211ax = 0;
}
hapd->iconf->ch_switch_vht_config = 0;
+ hapd->iconf->ch_switch_he_config = 0;
hapd->iconf->secondary_channel = offset;
hostapd_set_oper_chwidth(hapd->iconf, chwidth);
@@ -958,6 +994,29 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
for (i = 0; i < hapd->iface->num_bss; i++)
hostapd_neighbor_set_own_report(hapd->iface->bss[i]);
+
+#ifdef CONFIG_OCV
+ if (hapd->conf->ocv) {
+ struct sta_info *sta;
+ bool check_sa_query = false;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (wpa_auth_uses_ocv(sta->wpa_sm) &&
+ !(sta->flags & WLAN_STA_WNM_SLEEP_MODE)) {
+ sta->post_csa_sa_query = 1;
+ check_sa_query = true;
+ }
+ }
+
+ if (check_sa_query) {
+ wpa_printf(MSG_DEBUG,
+ "OCV: Check post-CSA SA Query initiation in 15 seconds");
+ eloop_register_timeout(15, 0,
+ hostapd_ocv_check_csa_sa_query,
+ hapd, NULL);
+ }
+ }
+#endif /* CONFIG_OCV */
#endif /* NEED_AP_MLME */
}
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 9567e202..90f15778 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -1555,11 +1555,14 @@ void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
di->prot = prot;
di->sd_resp = buf;
di->sd_resp_pos = 0;
+ di->dpp = 1;
tx_buf = gas_build_initial_resp(
dialog_token, WLAN_STATUS_SUCCESS,
- comeback_delay, 10);
- if (tx_buf)
+ comeback_delay, 10 + 2);
+ if (tx_buf) {
gas_serv_write_dpp_adv_proto(tx_buf);
+ wpabuf_put_le16(tx_buf, 0);
+ }
}
} else {
wpa_printf(MSG_DEBUG,
@@ -1782,9 +1785,10 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
tx_buf = gas_build_comeback_resp(dialog_token,
WLAN_STATUS_SUCCESS,
dialog->sd_frag_id, more, 0,
- 10 + frag_len);
+ 10 + 2 + frag_len);
if (tx_buf) {
gas_serv_write_dpp_adv_proto(tx_buf);
+ wpabuf_put_le16(tx_buf, frag_len);
wpabuf_put_buf(tx_buf, buf);
}
} else
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index f9af038b..e2571746 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -354,7 +354,7 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
#endif /* CONFIG_WEP */
-static void hostapd_free_hapd_data(struct hostapd_data *hapd)
+void hostapd_free_hapd_data(struct hostapd_data *hapd)
{
os_free(hapd->probereq_cb);
hapd->probereq_cb = NULL;
@@ -434,11 +434,17 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
#ifdef CONFIG_MESH
wpabuf_free(hapd->mesh_pending_auth);
hapd->mesh_pending_auth = NULL;
+ /* handling setup failure is already done */
+ hapd->setup_complete_cb = NULL;
#endif /* CONFIG_MESH */
hostapd_clean_rrm(hapd);
fils_hlp_deinit(hapd);
+#ifdef CONFIG_OCV
+ eloop_cancel_timeout(hostapd_ocv_check_csa_sa_query, hapd, NULL);
+#endif /* CONFIG_OCV */
+
#ifdef CONFIG_SAE
{
struct hostapd_sae_commit_queue *q;
@@ -492,7 +498,7 @@ static void sta_track_deinit(struct hostapd_iface *iface)
}
-static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
+void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
#ifdef NEED_AP_MLME
@@ -620,7 +626,7 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
}
-static void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
+void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
{
hostapd_free_stas(hapd);
hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
@@ -1697,6 +1703,9 @@ static int setup_interface2(struct hostapd_iface *iface)
ret = hostapd_check_edmg_capab(iface);
if (ret < 0)
goto fail;
+ ret = hostapd_check_he_6ghz_capab(iface);
+ if (ret < 0)
+ goto fail;
ret = hostapd_check_ht_capab(iface);
if (ret < 0)
goto fail;
@@ -1911,6 +1920,13 @@ static int hostapd_owe_iface_iter2(struct hostapd_iface *iface, void *ctx)
if (!bss->conf->owe_transition_ifname[0])
continue;
+ if (bss->iface->state != HAPD_IFACE_ENABLED) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Interface %s state %s - defer beacon update",
+ bss->conf->iface,
+ hostapd_state_text(bss->iface->state));
+ continue;
+ }
res = hostapd_owe_trans_get_info(bss);
if (res == 0)
continue;
@@ -2145,6 +2161,13 @@ dfs_offload:
if (hapd->setup_complete_cb)
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
+#ifdef CONFIG_MESH
+ if (delay_apply_cfg && !iface->mconf) {
+ wpa_printf(MSG_ERROR, "Error while completing mesh init");
+ goto fail;
+ }
+#endif /* CONFIG_MESH */
+
wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
iface->bss[0]->conf->iface);
if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
@@ -2288,7 +2311,7 @@ int hostapd_setup_interface(struct hostapd_iface *iface)
ret = setup_interface(iface);
if (ret) {
wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
- iface->bss[0]->conf->iface);
+ iface->conf ? iface->conf->bss[0]->iface : "N/A");
return -1;
}
@@ -2670,6 +2693,12 @@ int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
{
size_t j;
+ if (!hapd_iface)
+ return -1;
+
+ if (hapd_iface->enable_iface_cb)
+ return hapd_iface->enable_iface_cb(hapd_iface);
+
if (hapd_iface->bss[0]->drv_priv != NULL) {
wpa_printf(MSG_ERROR, "Interface %s already enabled",
hapd_iface->conf->bss[0]->iface);
@@ -2731,6 +2760,9 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
if (hapd_iface == NULL)
return -1;
+ if (hapd_iface->disable_iface_cb)
+ return hapd_iface->disable_iface_cb(hapd_iface);
+
if (hapd_iface->bss[0]->drv_priv == NULL) {
wpa_printf(MSG_INFO, "Interface %s already disabled",
hapd_iface->conf->bss[0]->iface);
@@ -3151,6 +3183,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
hostapd_prune_associations(hapd, sta->addr);
ap_sta_clear_disconnect_timeouts(hapd, sta);
+ sta->post_csa_sa_query = 0;
#ifdef CONFIG_P2P
if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
@@ -3527,15 +3560,23 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
}
-void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled)
+void hostapd_chan_switch_config(struct hostapd_data *hapd,
+ struct hostapd_freq_params *freq_params)
{
- if (vht_enabled)
+ if (freq_params->he_enabled)
+ hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_ENABLED;
+ else
+ hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_DISABLED;
+
+ if (freq_params->vht_enabled)
hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED;
else
hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_INFO, "CHAN_SWITCH VHT CONFIG 0x%x",
+ HOSTAPD_LEVEL_INFO,
+ "CHAN_SWITCH HE config 0x%x VHT config 0x%x",
+ hapd->iconf->ch_switch_he_config,
hapd->iconf->ch_switch_vht_config);
}
@@ -3662,3 +3703,25 @@ void hostapd_periodic_iface(struct hostapd_iface *iface)
#endif /* CONFIG_NO_RADIUS */
}
}
+
+
+#ifdef CONFIG_OCV
+void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta;
+
+ wpa_printf(MSG_DEBUG, "OCV: Post-CSA SA Query initiation check");
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!sta->post_csa_sa_query)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "OCV: OCVC STA " MACSTR
+ " did not start SA Query after CSA - disconnect",
+ MAC2STR(sta->addr));
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ }
+}
+#endif /* CONFIG_OCV */
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index a6161360..591996aa 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -370,6 +370,8 @@ struct hostapd_data {
int dhcp_sock; /* UDP socket used with the DHCP server */
+ struct ptksa_cache *ptksa;
+
#ifdef CONFIG_DPP
int dpp_init_done;
struct dpp_authentication *dpp_auth;
@@ -590,6 +592,9 @@ struct hostapd_iface {
/* Previous WMM element information */
struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
+
+ int (*enable_iface_cb)(struct hostapd_iface *iface);
+ int (*disable_iface_cb)(struct hostapd_iface *iface);
};
/* hostapd.c */
@@ -618,13 +623,17 @@ void hostapd_interface_deinit_free(struct hostapd_iface *iface);
int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
+void hostapd_bss_deinit_no_free(struct hostapd_data *hapd);
+void hostapd_free_hapd_data(struct hostapd_data *hapd);
+void hostapd_cleanup_iface_partial(struct hostapd_iface *iface);
int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
const char * hostapd_state_text(enum hostapd_iface_state s);
int hostapd_csa_in_progress(struct hostapd_iface *iface);
-void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled);
+void hostapd_chan_switch_config(struct hostapd_data *hapd,
+ struct hostapd_freq_params *freq_params);
int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings);
void
@@ -633,6 +642,7 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
void hostapd_periodic_iface(struct hostapd_iface *iface);
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
+void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
diff --git a/src/ap/hs20.c b/src/ap/hs20.c
index 543fa335..05e9b9d2 100644
--- a/src/ap/hs20.c
+++ b/src/ap/hs20.c
@@ -86,7 +86,9 @@ u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid)
capab |= WPA_CAPABILITY_MFPR;
}
#ifdef CONFIG_OCV
- if (hapd->conf->ocv)
+ if (hapd->conf->ocv &&
+ (hapd->iface->drv_flags2 &
+ (WPA_DRIVER_FLAGS2_AP_SME | WPA_DRIVER_FLAGS2_OCV)))
capab |= WPA_CAPABILITY_OCVC;
#endif /* CONFIG_OCV */
WPA_PUT_LE16(eid, capab);
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index f6e69030..7849be18 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -313,7 +313,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
{
struct wpa_scan_results *scan_res;
int oper40;
- int res;
+ int res = 0;
/* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
* allowed per IEEE Std 802.11-2012, 10.15.3.2 */
@@ -349,7 +349,24 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
}
}
- res = ieee80211n_allowed_ht40_channel_pair(iface);
+#ifdef CONFIG_IEEE80211AX
+ if (iface->conf->secondary_channel &&
+ iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
+ iface->conf->ieee80211ax) {
+ struct he_capabilities *he_cap;
+
+ he_cap = &iface->current_mode->he_capab[IEEE80211_MODE_AP];
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
+ wpa_printf(MSG_DEBUG,
+ "HE: 40 MHz channel width is not supported in 2.4 GHz; clear secondary channel configuration");
+ iface->conf->secondary_channel = 0;
+ }
+ }
+#endif /* CONFIG_IEEE80211AX */
+
+ if (iface->conf->secondary_channel)
+ res = ieee80211n_allowed_ht40_channel_pair(iface);
if (!res) {
iface->conf->secondary_channel = 0;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 0);
@@ -732,6 +749,51 @@ int hostapd_check_edmg_capab(struct hostapd_iface *iface)
}
+int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
+{
+#ifdef CONFIG_IEEE80211AX
+ struct he_capabilities *he_cap;
+ u16 hw;
+
+ if (!iface->current_mode || !is_6ghz_freq(iface->freq))
+ return 0;
+
+ he_cap = &iface->current_mode->he_capab[IEEE80211_MODE_AP];
+ hw = he_cap->he_6ghz_capa;
+ if (iface->conf->he_6ghz_max_mpdu >
+ ((hw & HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK) >>
+ HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT)) {
+ wpa_printf(MSG_ERROR,
+ "The driver does not support the configured HE 6 GHz Max MPDU length");
+ return -1;
+ }
+
+ if (iface->conf->he_6ghz_max_ampdu_len_exp >
+ ((hw & HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK) >>
+ HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT)) {
+ wpa_printf(MSG_ERROR,
+ "The driver does not support the configured HE 6 GHz Max AMPDU Length Exponent");
+ return -1;
+ }
+
+ if (iface->conf->he_6ghz_rx_ant_pat &&
+ !(hw & HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS)) {
+ wpa_printf(MSG_ERROR,
+ "The driver does not support the configured HE 6 GHz Rx Antenna Pattern");
+ return -1;
+ }
+
+ if (iface->conf->he_6ghz_tx_ant_pat &&
+ !(hw & HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS)) {
+ wpa_printf(MSG_ERROR,
+ "The driver does not support the configured HE 6 GHz Tx Antenna Pattern");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211AX */
+ return 0;
+}
+
+
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
int frequency, int primary)
{
@@ -949,9 +1011,9 @@ static void hostapd_notify_bad_chans(struct hostapd_iface *iface)
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
- "Configured channel (%d) or frequency (%d) not found from the channel list of the current mode (%d) %s",
+ "Configured channel (%d) or frequency (%d) (secondary_channel=%d) not found from the channel list of the current mode (%d) %s",
iface->conf->channel,
- iface->freq,
+ iface->freq, iface->conf->secondary_channel,
iface->current_mode->mode,
hostapd_hw_mode_txt(iface->current_mode->mode));
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
@@ -1029,12 +1091,13 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
iface->current_mode = NULL;
for (i = 0; i < iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode = &iface->hw_features[i];
+ int chan;
+
if (mode->mode == iface->conf->hw_mode) {
if (iface->freq > 0 &&
- !hw_get_chan(mode->mode, iface->freq,
- iface->hw_features,
- iface->num_hw_features))
+ !hw_mode_get_channel(mode, iface->freq, &chan))
continue;
+
iface->current_mode = mode;
break;
}
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index dd24f95b..ad0ddf7f 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -22,6 +22,7 @@ int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
int hostapd_check_edmg_capab(struct hostapd_iface *iface);
+int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
void hostapd_stop_setup_timers(struct hostapd_iface *iface);
@@ -85,6 +86,11 @@ static inline int hostapd_hw_skip_mode(struct hostapd_iface *iface,
return 0;
}
+static inline int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
+{
+ return 0;
+}
+
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 565e9afc..40d4a338 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -24,6 +24,8 @@
#include "common/dpp.h"
#include "common/ocv.h"
#include "common/wpa_common.h"
+#include "common/wpa_ctrl.h"
+#include "common/ptksa_cache.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -64,6 +66,23 @@ prepare_auth_resp_fils(struct hostapd_data *hapd,
const u8 *msk, size_t msk_len,
int *is_pub);
#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_PASN
+
+static int handle_auth_pasn_resp(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct rsn_pmksa_cache_entry *pmksa,
+ u16 status);
+#ifdef CONFIG_FILS
+
+static void pasn_fils_auth_resp(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 status,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len);
+
+#endif /* CONFIG_FILS */
+#endif /* CONFIG_PASN */
+
static void handle_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int rssi, int from_queue);
@@ -385,7 +404,8 @@ static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
auth_alg == WLAN_AUTH_SAE) {
if (auth_transaction == 1 && sta &&
(resp == WLAN_STATUS_SUCCESS ||
- resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT)) {
+ resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ resp == WLAN_STATUS_SAE_PK)) {
wpa_printf(MSG_DEBUG,
"TESTING: Postpone SAE Commit transmission until Confirm is ready");
os_free(sta->sae_postponed_commit);
@@ -467,28 +487,17 @@ static void sae_set_state(struct sta_info *sta, enum sae_state state,
}
-static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
- struct sta_info *sta, int update,
- int status_code)
+static const char * sae_get_password(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const char *rx_id,
+ struct sae_password_entry **pw_entry,
+ struct sae_pt **s_pt,
+ const struct sae_pk **s_pk)
{
- struct wpabuf *buf;
const char *password = NULL;
struct sae_password_entry *pw;
- const char *rx_id = NULL;
- int use_pt = 0;
struct sae_pt *pt = NULL;
-
- if (sta->sae->tmp) {
- rx_id = sta->sae->tmp->pw_id;
- use_pt = sta->sae->tmp->h2e;
- }
-
- if (rx_id && hapd->conf->sae_pwe != 3)
- use_pt = 1;
- else if (status_code == WLAN_STATUS_SUCCESS)
- use_pt = 0;
- else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
- use_pt = 1;
+ const struct sae_pk *pk = NULL;
for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
if (!is_broadcast_ether_addr(pw->peer_addr) &&
@@ -501,12 +510,56 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
continue;
password = pw->password;
pt = pw->pt;
+ if (!(hapd->conf->mesh & MESH_ENABLED))
+ pk = pw->pk;
break;
}
if (!password) {
password = hapd->conf->ssid.wpa_passphrase;
pt = hapd->conf->ssid.pt;
}
+
+ if (pw_entry)
+ *pw_entry = pw;
+ if (s_pt)
+ *s_pt = pt;
+ if (s_pk)
+ *s_pk = pk;
+
+ return password;
+}
+
+
+static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
+ struct sta_info *sta, int update,
+ int status_code)
+{
+ struct wpabuf *buf;
+ const char *password = NULL;
+ struct sae_password_entry *pw;
+ const char *rx_id = NULL;
+ int use_pt = 0;
+ struct sae_pt *pt = NULL;
+ const struct sae_pk *pk = NULL;
+
+ if (sta->sae->tmp) {
+ rx_id = sta->sae->tmp->pw_id;
+ use_pt = sta->sae->h2e;
+#ifdef CONFIG_SAE_PK
+ os_memcpy(sta->sae->tmp->own_addr, hapd->own_addr, ETH_ALEN);
+ os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
+#endif /* CONFIG_SAE_PK */
+ }
+
+ if (rx_id && hapd->conf->sae_pwe != 3)
+ use_pt = 1;
+ else if (status_code == WLAN_STATUS_SUCCESS)
+ use_pt = 0;
+ else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK)
+ use_pt = 1;
+
+ password = sae_get_password(hapd, sta, rx_id, &pw, &pt, &pk);
if (!password || (use_pt && !pt)) {
wpa_printf(MSG_DEBUG, "SAE: No password available");
return NULL;
@@ -514,7 +567,7 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
if (update && use_pt &&
sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
- NULL) < 0)
+ NULL, pk) < 0)
return NULL;
if (update && !use_pt &&
@@ -557,7 +610,17 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
if (buf == NULL)
return NULL;
- sae_write_confirm(sta->sae, buf);
+#ifdef CONFIG_SAE_PK
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sta->sae->tmp)
+ sta->sae->tmp->omit_pk_elem = hapd->conf->sae_pk_omit;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_SAE_PK */
+
+ if (sae_write_confirm(sta->sae, buf) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
return buf;
}
@@ -577,8 +640,21 @@ static int auth_sae_send_commit(struct hostapd_data *hapd,
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- status = (sta->sae->tmp && sta->sae->tmp->h2e) ?
- WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS;
+ if (sta->sae->tmp && sta->sae->pk)
+ status = WLAN_STATUS_SAE_PK;
+ else if (sta->sae->tmp && sta->sae->h2e)
+ status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
+ else
+ status = WLAN_STATUS_SUCCESS;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->sae_commit_status >= 0 &&
+ hapd->conf->sae_commit_status != status) {
+ wpa_printf(MSG_INFO,
+ "TESTING: Override SAE commit status code %u --> %d",
+ status, hapd->conf->sae_commit_status);
+ status = hapd->conf->sae_commit_status;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
WLAN_AUTH_SAE, 1,
status, wpabuf_head(data),
@@ -899,9 +975,14 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
switch (sta->sae->state) {
case SAE_NOTHING:
if (auth_transaction == 1) {
- if (sta->sae->tmp)
- sta->sae->tmp->h2e = status_code ==
- WLAN_STATUS_SAE_HASH_TO_ELEMENT;
+ if (sta->sae->tmp) {
+ sta->sae->h2e =
+ (status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK);
+ sta->sae->pk =
+ status_code == WLAN_STATUS_SAE_PK;
+ }
ret = auth_sae_send_commit(hapd, sta, bssid,
!allow_reuse, status_code);
if (ret)
@@ -1111,20 +1192,28 @@ static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
{
int sae_pwe = hapd->conf->sae_pwe;
int id_in_use;
+ bool sae_pk = false;
id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
if (id_in_use == 2 && sae_pwe != 3)
sae_pwe = 1;
else if (id_in_use == 1 && sae_pwe == 0)
sae_pwe = 2;
+#ifdef CONFIG_SAE_PK
+ sae_pk = hostapd_sae_pk_in_use(hapd->conf);
+ if (sae_pwe == 0 && sae_pk)
+ sae_pwe = 2;
+#endif /* CONFIG_SAE_PK */
return ((sae_pwe == 0 || sae_pwe == 3) &&
status_code == WLAN_STATUS_SUCCESS) ||
(sae_pwe == 1 &&
- status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) ||
+ (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ (sae_pk && status_code == WLAN_STATUS_SAE_PK))) ||
(sae_pwe == 2 &&
(status_code == WLAN_STATUS_SUCCESS ||
- status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT));
+ status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ (sae_pk && status_code == WLAN_STATUS_SAE_PK)));
}
@@ -1147,11 +1236,15 @@ static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
static int check_sae_rejected_groups(struct hostapd_data *hapd,
- const struct wpabuf *groups)
+ struct sae_data *sae)
{
+ const struct wpabuf *groups;
size_t i, count;
const u8 *pos;
+ if (!sae->tmp)
+ return 0;
+ groups = sae->tmp->peer_rejected_groups;
if (!groups)
return 0;
@@ -1184,6 +1277,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
int default_groups[] = { 19, 0 };
const u8 *pos, *end;
int sta_removed = 0;
+ bool success_status;
if (!groups)
groups = default_groups;
@@ -1193,6 +1287,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
pos = mgmt->u.auth.variable;
end = ((const u8 *) mgmt) + len;
+ resp = status_code;
send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp, pos, end - pos,
"auth-sae-reflection-attack");
@@ -1338,7 +1433,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
&token_len, groups, status_code ==
- WLAN_STATUS_SAE_HASH_TO_ELEMENT);
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK);
if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack",
@@ -1368,9 +1464,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
if (resp != WLAN_STATUS_SUCCESS)
goto reply;
- if (sta->sae->tmp &&
- check_sae_rejected_groups(
- hapd, sta->sae->tmp->peer_rejected_groups)) {
+ if (check_sae_rejected_groups(hapd, sta->sae)) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto reply;
}
@@ -1382,8 +1476,9 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
"SAE: Request anti-clogging token from "
MACSTR, MAC2STR(sta->addr));
if (sta->sae->tmp)
- h2e = sta->sae->tmp->h2e;
- if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+ h2e = sta->sae->h2e;
+ if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK)
h2e = 1;
data = auth_build_token_req(hapd, sta->sae->group,
sta->addr, h2e);
@@ -1468,9 +1563,12 @@ reply:
}
remove_sta:
+ if (auth_transaction == 1)
+ success_status = sae_status_success(hapd, status_code);
+ else
+ success_status = status_code == WLAN_STATUS_SUCCESS;
if (!sta_removed && sta->added_unassoc &&
- (resp != WLAN_STATUS_SUCCESS ||
- status_code != WLAN_STATUS_SUCCESS)) {
+ (resp != WLAN_STATUS_SUCCESS || !success_status)) {
hostapd_drv_sta_remove(hapd, sta->addr);
sta->added_unassoc = 0;
}
@@ -2134,23 +2232,35 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
struct wpabuf *erp_resp,
const u8 *msk, size_t msk_len)
{
- struct wpabuf *data;
- int pub = 0;
u16 resp;
+ u32 flags = sta->flags;
- sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
+ sta->flags &= ~(WLAN_STA_PENDING_FILS_ERP |
+ WLAN_STA_PENDING_PASN_FILS_ERP);
- if (!sta->fils_pending_cb)
- return;
resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
- data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
- msk, msk_len, &pub);
- if (!data) {
- wpa_printf(MSG_DEBUG,
- "%s: prepare_auth_resp_fils() returned failure",
- __func__);
+
+ if (flags & WLAN_STA_PENDING_FILS_ERP) {
+ struct wpabuf *data;
+ int pub = 0;
+
+ if (!sta->fils_pending_cb)
+ return;
+
+ data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
+ msk, msk_len, &pub);
+ if (!data) {
+ wpa_printf(MSG_DEBUG,
+ "%s: prepare_auth_resp_fils() failure",
+ __func__);
+ }
+ sta->fils_pending_cb(hapd, sta, resp, data, pub);
+#ifdef CONFIG_PASN
+ } else if (flags & WLAN_STA_PENDING_PASN_FILS_ERP) {
+ pasn_fils_auth_resp(hapd, sta, resp, erp_resp,
+ msk, msk_len);
+#endif /* CONFIG_PASN */
}
- sta->fils_pending_cb(hapd, sta, resp, data, pub);
}
#endif /* CONFIG_FILS */
@@ -2245,6 +2355,1065 @@ ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
}
+#ifdef CONFIG_PASN
+#ifdef CONFIG_SAE
+
+static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct wpabuf *wd)
+{
+ struct pasn_data *pasn = sta->pasn;
+ const char *password = NULL;
+ const u8 *data;
+ size_t buf_len;
+ u16 res, alg, seq, status;
+ int groups[] = { pasn->group, 0 };
+ int ret;
+
+ if (!wd)
+ return -1;
+
+ data = wpabuf_head_u8(wd);
+ buf_len = wpabuf_len(wd);
+
+ if (buf_len < 6) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%lu",
+ buf_len);
+ return -1;
+ }
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: SAE commit: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ /* TODO: SAE H2E */
+ if (alg != WLAN_AUTH_SAE || seq != 1 || status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE commit");
+ return -1;
+ }
+
+ sae_clear_data(&pasn->sae);
+ pasn->sae.state = SAE_NOTHING;
+
+ ret = sae_set_group(&pasn->sae, pasn->group);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group");
+ return -1;
+ }
+
+ password = sae_get_password(hapd, sta, NULL, NULL, NULL, NULL);
+ if (!password) {
+ wpa_printf(MSG_DEBUG, "PASN: No SAE password found");
+ return -1;
+ }
+
+ ret = sae_prepare_commit(hapd->own_addr, sta->addr,
+ (const u8 *) password, os_strlen(password), 0,
+ &pasn->sae);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit");
+ return -1;
+ }
+
+ res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, 0,
+ groups, 0);
+ if (res != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed parsing SAE commit");
+ return -1;
+ }
+
+ /* Process the commit message and derive the PMK */
+ ret = sae_process_commit(&pasn->sae);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
+ return -1;
+ }
+
+ pasn->sae.state = SAE_COMMITTED;
+
+ return 0;
+}
+
+
+static int pasn_wd_handle_sae_confirm(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct wpabuf *wd)
+{
+ struct pasn_data *pasn = sta->pasn;
+ const u8 *data;
+ size_t buf_len;
+ u16 res, alg, seq, status;
+
+ if (!wd)
+ return -1;
+
+ data = wpabuf_head_u8(wd);
+ buf_len = wpabuf_len(wd);
+
+ if (buf_len < 6) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%lu",
+ buf_len);
+ return -1;
+ }
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: SAE confirm: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ if (alg != WLAN_AUTH_SAE || seq != 2 || status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE confirm");
+ return -1;
+ }
+
+ res = sae_check_confirm(&pasn->sae, data + 6, buf_len - 6);
+ if (res != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm");
+ return -1;
+ }
+
+ pasn->sae.state = SAE_ACCEPTED;
+
+ /*
+ * TODO: Based on on IEEE P802.11az/D2.6, the PMKSA derived with
+ * PASN/SAE should only be allowed with future PASN only. For now do not
+ * restrict this only for PASN.
+ */
+ wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
+ pasn->sae.pmk, pasn->sae.pmkid);
+ return 0;
+}
+
+
+static struct wpabuf * pasn_get_sae_wd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct pasn_data *pasn = sta->pasn;
+ struct wpabuf *buf = NULL;
+ u8 *len_ptr;
+ size_t len;
+
+ /* Need to add the entire Authentication frame body */
+ buf = wpabuf_alloc(8 + SAE_COMMIT_MAX_LEN + 8 + SAE_CONFIRM_MAX_LEN);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
+ return NULL;
+ }
+
+ /* Need to add the entire authentication frame body for the commit */
+ len_ptr = wpabuf_put(buf, 2);
+ wpabuf_put_le16(buf, WLAN_AUTH_SAE);
+ wpabuf_put_le16(buf, 1);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ /* Write the actual commit and update the length accordingly */
+ sae_write_commit(&pasn->sae, buf, NULL, 0);
+ len = wpabuf_len(buf);
+ WPA_PUT_LE16(len_ptr, len - 2);
+
+ /* Need to add the entire Authentication frame body for the confirm */
+ len_ptr = wpabuf_put(buf, 2);
+ wpabuf_put_le16(buf, WLAN_AUTH_SAE);
+ wpabuf_put_le16(buf, 2);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ sae_write_confirm(&pasn->sae, buf);
+ WPA_PUT_LE16(len_ptr, wpabuf_len(buf) - len - 2);
+
+ pasn->sae.state = SAE_CONFIRMED;
+
+ return buf;
+}
+
+#endif /* CONFIG_SAE */
+
+
+#ifdef CONFIG_FILS
+
+static struct wpabuf * pasn_get_fils_wd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct pasn_data *pasn = sta->pasn;
+ struct pasn_fils_data *fils = &pasn->fils;
+ struct wpabuf *buf = NULL;
+
+ if (!fils->erp_resp) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing erp_resp");
+ return NULL;
+ }
+
+ buf = wpabuf_alloc(1500);
+ if (!buf)
+ return NULL;
+
+ /* Add the authentication algorithm */
+ wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK);
+
+ /* Authentication Transaction seq# */
+ wpabuf_put_le16(buf, 2);
+
+ /* Status Code */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ /* Own RSNE */
+ wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
+
+ /* FILS Nonce */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
+ wpabuf_put_data(buf, fils->anonce, FILS_NONCE_LEN);
+
+ /* FILS Session */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
+ wpabuf_put_data(buf, fils->session, FILS_SESSION_LEN);
+
+ /* Wrapped Data */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(fils->erp_resp));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
+ wpabuf_put_buf(buf, fils->erp_resp);
+
+ return buf;
+}
+
+
+static void pasn_fils_auth_resp(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 status,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len)
+{
+ struct pasn_data *pasn = sta->pasn;
+ struct pasn_fils_data *fils = &pasn->fils;
+ u8 pmk[PMK_LEN_MAX];
+ size_t pmk_len;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Handle AS response - status=%u",
+ status);
+
+ if (status != WLAN_STATUS_SUCCESS)
+ goto fail;
+
+ if (!pasn->secret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing secret");
+ goto fail;
+ }
+
+ if (random_get_bytes(fils->anonce, FILS_NONCE_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ANonce");
+ goto fail;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce",
+ fils->anonce, FILS_NONCE_LEN);
+
+ ret = fils_rmsk_to_pmk(pasn->akmp, msk, msk_len, fils->nonce,
+ fils->anonce, NULL, 0, pmk, &pmk_len);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
+ goto fail;
+ }
+
+ ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
+ wpabuf_head(pasn->secret),
+ wpabuf_len(pasn->secret),
+ &sta->pasn->ptk, sta->pasn->akmp,
+ sta->pasn->cipher, WPA_KDK_MAX_LEN);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
+
+ wpabuf_free(pasn->secret);
+ pasn->secret = NULL;
+
+ fils->erp_resp = erp_resp;
+ ret = handle_auth_pasn_resp(hapd, sta, NULL, WLAN_STATUS_SUCCESS);
+ fils->erp_resp = NULL;
+
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to send response");
+ goto fail;
+ }
+
+ fils->state = PASN_FILS_STATE_COMPLETE;
+ return;
+fail:
+ ap_free_sta(hapd, sta);
+}
+
+
+static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
+ struct wpabuf *wd)
+{
+ struct pasn_data *pasn = sta->pasn;
+ struct pasn_fils_data *fils = &pasn->fils;
+ struct ieee802_11_elems elems;
+ struct wpa_ie_data rsne_data;
+ struct wpabuf *fils_wd;
+ const u8 *data;
+ size_t buf_len;
+ u16 alg, seq, status;
+ int ret;
+
+ if (fils->state != PASN_FILS_STATE_NONE) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Not expecting wrapped data");
+ return -1;
+ }
+
+ if (!wd) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: No wrapped data");
+ return -1;
+ }
+
+ data = wpabuf_head_u8(wd);
+ buf_len = wpabuf_len(wd);
+
+ if (buf_len < 6) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%lu",
+ buf_len);
+ return -1;
+ }
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ if (alg != WLAN_AUTH_FILS_SK || seq != 1 ||
+ status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Dropping peer authentication");
+ return -1;
+ }
+
+ data += 6;
+ buf_len -= 6;
+
+ if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
+ return -1;
+ }
+
+ if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
+ !elems.wrapped_data) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
+ return -1;
+ }
+
+ ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RNSE");
+ return -1;
+ }
+
+ ret = wpa_pasn_validate_rsne(&rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
+ return -1;
+ }
+
+ if (rsne_data.num_pmkid) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Not expecting PMKID in RSNE");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", elems.fils_nonce,
+ FILS_NONCE_LEN);
+ os_memcpy(fils->nonce, elems.fils_nonce, FILS_NONCE_LEN);
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", elems.fils_session,
+ FILS_SESSION_LEN);
+ os_memcpy(fils->session, elems.fils_session, FILS_SESSION_LEN);
+
+#ifdef CONFIG_NO_RADIUS
+ wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail");
+ return -1;
+#endif /* CONFIG_NO_RADIUS */
+
+ fils_wd = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
+ WLAN_EID_EXT_WRAPPED_DATA);
+
+ if (!fils_wd) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing wrapped data");
+ return -1;
+ }
+
+ if (!sta->eapol_sm)
+ sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Forward EAP-Initiate/Re-auth to AS");
+
+ ieee802_1x_encapsulate_radius(hapd, sta, wpabuf_head(fils_wd),
+ wpabuf_len(fils_wd));
+
+ sta->flags |= WLAN_STA_PENDING_PASN_FILS_ERP;
+
+ fils->state = PASN_FILS_STATE_PENDING_AS;
+
+ /*
+ * Calculate pending PMKID here so that we do not need to maintain a
+ * copy of the EAP-Initiate/Reautt message.
+ */
+ fils_pmkid_erp(pasn->akmp, wpabuf_head(fils_wd), wpabuf_len(fils_wd),
+ fils->erp_pmkid);
+
+ wpabuf_free(fils_wd);
+ return 0;
+}
+
+#endif /* CONFIG_FILS */
+
+
+static struct wpabuf * pasn_get_wrapped_data(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ switch (sta->pasn->akmp) {
+ case WPA_KEY_MGMT_PASN:
+ /* no wrapped data */
+ return NULL;
+ case WPA_KEY_MGMT_SAE:
+#ifdef CONFIG_SAE
+ return pasn_get_sae_wd(hapd, sta);
+#else /* CONFIG_SAE */
+ wpa_printf(MSG_ERROR,
+ "PASN: SAE: Cannot derive wrapped data");
+ return NULL;
+#endif /* CONFIG_SAE */
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+#ifdef CONFIG_FILS
+ return pasn_get_fils_wd(hapd, sta);
+#endif /* CONFIG_FILS */
+ /* fall through */
+ case WPA_KEY_MGMT_FT_PSK:
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ default:
+ wpa_printf(MSG_ERROR,
+ "PASN: TODO: Wrapped data for akmp=0x%x",
+ sta->pasn->akmp);
+ return NULL;
+ }
+}
+
+
+static int
+pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *cached_pmk, size_t cached_pmk_len,
+ struct wpa_pasn_params_data *pasn_data,
+ struct wpabuf *wrapped_data,
+ struct wpabuf *secret)
+{
+ static const u8 pasn_default_pmk[] = {'P', 'M', 'K', 'z'};
+ u8 pmk[PMK_LEN_MAX];
+ u8 pmk_len;
+ int ret;
+
+ os_memset(pmk, 0, sizeof(pmk));
+ pmk_len = 0;
+
+ if (!cached_pmk || !cached_pmk_len)
+ wpa_printf(MSG_DEBUG, "PASN: No valid PMKSA entry");
+
+ if (sta->pasn->akmp == WPA_KEY_MGMT_PASN) {
+ wpa_printf(MSG_DEBUG, "PASN: Using default PMK");
+
+ pmk_len = WPA_PASN_PMK_LEN;
+ os_memcpy(pmk, pasn_default_pmk, sizeof(pasn_default_pmk));
+ } else if (cached_pmk && cached_pmk_len) {
+ wpa_printf(MSG_DEBUG, "PASN: Using PMKSA entry");
+
+ pmk_len = cached_pmk_len;
+ os_memcpy(pmk, cached_pmk, cached_pmk_len);
+ } else {
+ switch (sta->pasn->akmp) {
+#ifdef CONFIG_SAE
+ case WPA_KEY_MGMT_SAE:
+ if (sta->pasn->sae.state == SAE_COMMITTED) {
+ pmk_len = PMK_LEN;
+ os_memcpy(pmk, sta->pasn->sae.pmk, PMK_LEN);
+ break;
+ }
+#endif /* CONFIG_SAE */
+ /* fall through */
+ default:
+ /* TODO: Derive PMK based on wrapped data */
+ wpa_printf(MSG_DEBUG,
+ "PASN: Missing PMK derivation");
+ return -1;
+ }
+ }
+
+ ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
+ wpabuf_head(secret), wpabuf_len(secret),
+ &sta->pasn->ptk, sta->pasn->akmp,
+ sta->pasn->cipher, WPA_KDK_MAX_LEN);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
+ return 0;
+}
+
+
+static int handle_auth_pasn_resp(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct rsn_pmksa_cache_entry *pmksa,
+ u16 status)
+{
+ struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
+ u8 mic[WPA_PASN_MAX_MIC_LEN];
+ u8 mic_len, frame_len, data_len;
+ u8 *ptr;
+ const u8 *frame, *data, *rsn_ie, *rsnxe_ie;
+ u8 *data_buf = NULL;
+ size_t rsn_ie_len;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "PASN: Building frame 2: status=%u", status);
+
+ buf = wpabuf_alloc(1500);
+ if (!buf)
+ goto fail;
+
+ wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr,
+ sta->addr, 2, status);
+
+ if (status != WLAN_STATUS_SUCCESS)
+ goto done;
+
+ if (wpa_pasn_add_rsne(buf, pmksa ? pmksa->pmkid : NULL,
+ sta->pasn->akmp, sta->pasn->cipher) < 0)
+ goto fail;
+
+ /* No need to derive PMK if PMKSA is given */
+ if (!pmksa)
+ wrapped_data_buf = pasn_get_wrapped_data(hapd, sta);
+ else
+ sta->pasn->wrapped_data_format = WPA_PASN_WRAPPED_DATA_NO;
+
+ /* Get public key */
+ pubkey = crypto_ecdh_get_pubkey(sta->pasn->ecdh, 0);
+ pubkey = wpabuf_zeropad(pubkey,
+ crypto_ecdh_prime_len(sta->pasn->ecdh));
+ if (!pubkey) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to get pubkey");
+ goto fail;
+ }
+
+ wpa_pasn_add_parameter_ie(buf, sta->pasn->group,
+ sta->pasn->wrapped_data_format,
+ pubkey, NULL, 0);
+
+ if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
+ goto fail;
+
+ wpabuf_free(wrapped_data_buf);
+ wrapped_data_buf = NULL;
+ wpabuf_free(pubkey);
+ pubkey = NULL;
+
+ /* Add RSNXE if needed */
+ rsnxe_ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
+ if (rsnxe_ie)
+ wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]);
+
+ /* Add the mic */
+ mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
+ wpabuf_put_u8(buf, WLAN_EID_MIC);
+ wpabuf_put_u8(buf, mic_len);
+ ptr = wpabuf_put(buf, mic_len);
+
+ os_memset(ptr, 0, mic_len);
+
+ frame = wpabuf_head_u8(buf) + IEEE80211_HDRLEN;
+ frame_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
+
+ rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &rsn_ie_len);
+ if (!rsn_ie || !rsn_ie_len)
+ goto fail;
+
+ /*
+ * Note: wpa_auth_get_wpa_ie() might return not only the RSNE but also
+ * MDE, etc. Thus, do not use the returned length but instead use the
+ * length specified in the IE header.
+ */
+ data_len = rsn_ie[1] + 2;
+ if (rsnxe_ie) {
+ data_buf = os_zalloc(rsn_ie[1] + 2 + rsnxe_ie[1] + 2);
+ if (!data_buf)
+ goto fail;
+
+ os_memcpy(data_buf, rsn_ie, rsn_ie[1] + 2);
+ os_memcpy(data_buf + rsn_ie[1] + 2, rsnxe_ie, rsnxe_ie[1] + 2);
+ data_len += rsnxe_ie[1] + 2;
+ data = data_buf;
+ } else {
+ data = rsn_ie;
+ }
+
+ ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
+ hapd->own_addr, sta->addr, data, data_len,
+ frame, frame_len, mic);
+ os_free(data_buf);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Frame 3: Failed MIC calculation");
+ goto fail;
+ }
+
+ os_memcpy(ptr, mic, mic_len);
+
+done:
+ wpa_printf(MSG_DEBUG,
+ "PASN: Building frame 2: success; resp STA=" MACSTR,
+ MAC2STR(sta->addr));
+
+ ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0,
+ NULL, 0, 0);
+ if (ret)
+ wpa_printf(MSG_INFO, "send_auth_reply: Send failed");
+
+ wpabuf_free(buf);
+ return ret;
+fail:
+ wpabuf_free(wrapped_data_buf);
+ wpabuf_free(pubkey);
+ wpabuf_free(buf);
+ return -1;
+}
+
+
+static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct ieee802_11_elems elems;
+ struct wpa_ie_data rsn_data;
+ struct wpa_pasn_params_data pasn_params;
+ struct rsn_pmksa_cache_entry *pmksa = NULL;
+ const u8 *cached_pmk = NULL;
+ size_t cached_pmk_len = 0;
+#ifdef CONFIG_IEEE80211R_AP
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t pmk_r1_len;
+#endif /* CONFIG_IEEE80211R_AP */
+ struct wpabuf *wrapped_data = NULL, *secret = NULL;
+ const int *groups = hapd->conf->pasn_groups;
+ static const int default_groups[] = { 19, 0 };
+ u16 status = WLAN_STATUS_SUCCESS;
+ int ret;
+ bool derive_keys;
+ u32 i;
+
+ if (!groups)
+ groups = default_groups;
+
+ if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable),
+ &elems, 0) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed parsing Authentication frame");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsn_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed parsing RNSE");
+ status = WLAN_STATUS_INVALID_RSNIE;
+ goto send_resp;
+ }
+
+ ret = wpa_pasn_validate_rsne(&rsn_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE");
+ status = WLAN_STATUS_INVALID_RSNIE;
+ goto send_resp;
+ }
+
+ if (!(rsn_data.key_mgmt & hapd->conf->wpa_key_mgmt) ||
+ !(rsn_data.pairwise_cipher & hapd->conf->rsn_pairwise)) {
+ wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
+ status = WLAN_STATUS_INVALID_RSNIE;
+ goto send_resp;
+ }
+
+ sta->pasn->akmp = rsn_data.key_mgmt;
+ sta->pasn->cipher = rsn_data.pairwise_cipher;
+
+ if (!elems.pasn_params || !elems.pasn_params_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: No PASN Parameters element found");
+ status = WLAN_STATUS_INVALID_PARAMETERS;
+ goto send_resp;
+ }
+
+ ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
+ elems.pasn_params_len + 3,
+ false, &pasn_params);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed validation of PASN Parameters IE");
+ status = WLAN_STATUS_INVALID_PARAMETERS;
+ goto send_resp;
+ }
+
+ for (i = 0; groups[i] > 0 && groups[i] != pasn_params.group; i++)
+ ;
+
+ if (!pasn_params.group || groups[i] != pasn_params.group) {
+ wpa_printf(MSG_DEBUG, "PASN: Requested group=%hu not allowed",
+ pasn_params.group);
+ status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ goto send_resp;
+ }
+
+ if (!pasn_params.pubkey || !pasn_params.pubkey_len) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid public key");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group);
+ if (!sta->pasn->ecdh) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ sta->pasn->group = pasn_params.group;
+
+ secret = crypto_ecdh_set_peerkey(sta->pasn->ecdh, 0,
+ pasn_params.pubkey,
+ pasn_params.pubkey_len);
+ if (!secret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ derive_keys = true;
+ if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
+ wrapped_data = ieee802_11_defrag(&elems,
+ WLAN_EID_EXTENSION,
+ WLAN_EID_EXT_WRAPPED_DATA);
+ if (!wrapped_data) {
+ wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+#ifdef CONFIG_SAE
+ if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
+ ret = pasn_wd_handle_sae_commit(hapd, sta,
+ wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed processing SAE commit");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+ }
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+ sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+ ret = pasn_wd_handle_fils(hapd, sta, wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed processing FILS wrapped data");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Pending AS response");
+
+ /*
+ * With PASN/FILS, keys can be derived only after a
+ * response from the AS is processed.
+ */
+ derive_keys = false;
+ }
+#endif /* CONFIG_FILS */
+ }
+
+ sta->pasn->wrapped_data_format = pasn_params.wrapped_data_format;
+
+ ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
+ ((const u8 *) mgmt) + IEEE80211_HDRLEN,
+ len - IEEE80211_HDRLEN, sta->pasn->hash);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ if (!derive_keys) {
+ wpa_printf(MSG_DEBUG, "PASN: Storing secret");
+ sta->pasn->secret = secret;
+ wpabuf_free(wrapped_data);
+ return;
+ }
+
+ if (rsn_data.num_pmkid) {
+ if (wpa_key_mgmt_ft(sta->pasn->akmp)) {
+#ifdef CONFIG_IEEE80211R_AP
+ wpa_printf(MSG_DEBUG, "PASN: FT: Fetch PMK-R1");
+
+ ret = wpa_ft_fetch_pmk_r1(hapd->wpa_auth, sta->addr,
+ rsn_data.pmkid,
+ pmk_r1, &pmk_r1_len, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FT: Failed getting PMK-R1");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+ cached_pmk = pmk_r1;
+ cached_pmk_len = pmk_r1_len;
+#else /* CONFIG_IEEE80211R_AP */
+ wpa_printf(MSG_DEBUG, "PASN: FT: Not supported");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+#endif /* CONFIG_IEEE80211R_AP */
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: Try to find PMKSA entry");
+
+ pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
+ rsn_data.pmkid);
+ if (pmksa) {
+ cached_pmk = pmksa->pmk;
+ cached_pmk_len = pmksa->pmk_len;
+ }
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: No PMKID specified");
+ }
+
+ ret = pasn_derive_keys(hapd, sta, cached_pmk, cached_pmk_len,
+ &pasn_params, wrapped_data, secret);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive keys");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
+ ((const u8 *) mgmt) + IEEE80211_HDRLEN,
+ len - IEEE80211_HDRLEN, sta->pasn->hash);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+send_resp:
+ ret = handle_auth_pasn_resp(hapd, sta, pmksa, status);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to send response");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Success handling transaction == 1");
+ }
+
+ wpabuf_free(secret);
+ wpabuf_free(wrapped_data);
+
+ if (status != WLAN_STATUS_SUCCESS)
+ ap_free_sta(hapd, sta);
+}
+
+
+static void handle_auth_pasn_3(struct hostapd_data *hapd, struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct ieee802_11_elems elems;
+ struct wpa_pasn_params_data pasn_params;
+ struct wpabuf *wrapped_data = NULL;
+ u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
+ u8 mic_len;
+ int ret;
+
+ if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable),
+ &elems, 0) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed parsing Authentication frame");
+ goto fail;
+ }
+
+ /* Check that the MIC IE exists. Save it and zero out the memory. */
+ mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
+ if (!elems.mic || elems.mic_len != mic_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid MIC. Expecting len=%u", mic_len);
+ goto fail;
+ } else {
+ os_memcpy(mic, elems.mic, mic_len);
+ /* TODO: Clean this up.. Should not modify received frame
+ * buffer. */
+ os_memset((u8 *) elems.mic, 0, mic_len);
+ }
+
+ if (!elems.pasn_params || !elems.pasn_params_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: No PASN Parameters element found");
+ goto fail;
+ }
+
+ ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
+ elems.pasn_params_len + 3,
+ false, &pasn_params);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed validation of PASN Parameters IE");
+ goto fail;
+ }
+
+ if (pasn_params.pubkey || pasn_params.pubkey_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Public key should not be included");
+ goto fail;
+ }
+
+ /* Verify the MIC */
+ ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
+ sta->addr, hapd->own_addr,
+ sta->pasn->hash, mic_len * 2,
+ (u8 *) &mgmt->u.auth,
+ len - offsetof(struct ieee80211_mgmt, u.auth),
+ out_mic);
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: Frame MIC", mic, mic_len);
+ if (ret || os_memcmp(mic, out_mic, mic_len) != 0) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed MIC verification");
+ goto fail;
+ }
+
+ if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
+ wrapped_data = ieee802_11_defrag(&elems,
+ WLAN_EID_EXTENSION,
+ WLAN_EID_EXT_WRAPPED_DATA);
+
+ if (!wrapped_data) {
+ wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
+ goto fail;
+ }
+
+#ifdef CONFIG_SAE
+ if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
+ ret = pasn_wd_handle_sae_confirm(hapd, sta,
+ wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed processing SAE confirm");
+ wpabuf_free(wrapped_data);
+ goto fail;
+ }
+ }
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+ sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+ if (wrapped_data) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Ignore wrapped data");
+ }
+ }
+#endif /* CONFIG_FILS */
+ wpabuf_free(wrapped_data);
+ }
+
+ wpa_printf(MSG_INFO,
+ "PASN: Success handling transaction == 3. Store PTK");
+
+ ptksa_cache_add(hapd->ptksa, sta->addr, sta->pasn->cipher, 43200,
+ &sta->pasn->ptk);
+fail:
+ ap_free_sta(hapd, sta);
+}
+
+
+static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ u16 trans_seq, u16 status)
+{
+ if (hapd->conf->wpa != WPA_PROTO_RSN) {
+ wpa_printf(MSG_INFO, "PASN: RSN is not configured");
+ return;
+ }
+
+ wpa_printf(MSG_INFO, "PASN authentication: sta=" MACSTR,
+ MAC2STR(sta->addr));
+
+ if (trans_seq == 1) {
+ if (sta->pasn) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Not expecting transaction == 1");
+ return;
+ }
+
+ if (status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failure status in transaction == 1");
+ return;
+ }
+
+ sta->pasn = os_zalloc(sizeof(*sta->pasn));
+ if (!sta->pasn) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed to allocate PASN context");
+ return;
+ }
+
+ handle_auth_pasn_1(hapd, sta, mgmt, len);
+ } else if (trans_seq == 3) {
+ if (!sta->pasn) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Not expecting transaction == 3");
+ return;
+ }
+
+ if (status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failure status in transaction == 3");
+ ap_free_sta_pasn(hapd, sta);
+ return;
+ }
+
+ handle_auth_pasn_3(hapd, sta, mgmt, len);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid transaction %u - ignore", trans_seq);
+ }
+}
+
+#endif /* CONFIG_PASN */
+
+
static void handle_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int rssi, int from_queue)
@@ -2331,6 +3500,11 @@ static void handle_auth(struct hostapd_data *hapd,
hapd->conf->fils_dh_group &&
auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
#endif /* CONFIG_FILS */
+#ifdef CONFIG_PASN
+ (hapd->conf->wpa &&
+ (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) &&
+ auth_alg == WLAN_AUTH_PASN) ||
+#endif /* CONFIG_PASN */
((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
auth_alg == WLAN_AUTH_SHARED_KEY))) {
wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
@@ -2340,6 +3514,9 @@ static void handle_auth(struct hostapd_data *hapd,
}
if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
+#ifdef CONFIG_PASN
+ (auth_alg == WLAN_AUTH_PASN && auth_transaction == 3) ||
+#endif /* CONFIG_PASN */
(auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
auth_transaction);
@@ -2461,6 +3638,15 @@ static void handle_auth(struct hostapd_data *hapd,
return;
}
#endif /* CONFIG_MESH */
+#ifdef CONFIG_PASN
+ if (auth_alg == WLAN_AUTH_PASN &&
+ (sta->flags & WLAN_STA_ASSOC)) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: auth: Existing station: " MACSTR,
+ MAC2STR(sta->addr));
+ return;
+ }
+#endif /* CONFIG_PASN */
} else {
#ifdef CONFIG_MESH
if (hapd->conf->mesh & MESH_ENABLED) {
@@ -2521,11 +3707,14 @@ static void handle_auth(struct hostapd_data *hapd,
* to allow the original connection work until the attempt can complete
* (re)association, so that unprotected Authentication frame cannot be
* used to bypass PMF protection.
+ *
+ * PASN authentication does not require adding/removing station to the
+ * driver so skip this flow in case of PASN authentication.
*/
if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
(!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
!(hapd->conf->mesh & MESH_ENABLED) &&
- !(sta->added_unassoc)) {
+ !(sta->added_unassoc) && auth_alg != WLAN_AUTH_PASN) {
if (ap_sta_re_add(hapd, sta) < 0) {
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto fail;
@@ -2612,6 +3801,12 @@ static void handle_auth(struct hostapd_data *hapd,
handle_auth_fils_finish);
return;
#endif /* CONFIG_FILS */
+#ifdef CONFIG_PASN
+ case WLAN_AUTH_PASN:
+ handle_auth_pasn(hapd, sta, mgmt, len, auth_transaction,
+ status_code);
+ return;
+#endif /* CONFIG_PASN */
}
fail:
@@ -3104,6 +4299,34 @@ end:
#endif /* CONFIG_OWE */
+static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
+ int reassoc)
+{
+ if ((sta->flags &
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
+ return false;
+
+ if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
+ ap_check_sa_query_timeout(hapd, sta);
+
+ if (!sta->sa_query_timed_out &&
+ (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
+ /*
+ * STA has already been associated with MFP and SA Query timeout
+ * has not been reached. Reject the association attempt
+ * temporarily and start SA Query, if one is not pending.
+ */
+ if (sta->sa_query_count == 0)
+ ap_sta_start_sa_query(hapd, sta);
+
+ return true;
+ }
+
+ return false;
+}
+
+
static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ies, size_t ies_len, int reassoc)
{
@@ -3175,13 +4398,20 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
elems.he_capabilities,
elems.he_capabilities_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ if (!(sta->flags & WLAN_STA_HE)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Station does not support mandatory HE PHY - reject association");
+ return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
+ }
resp = copy_sta_he_6ghz_capab(hapd, sta,
elems.he_6ghz_band_cap);
if (resp != WLAN_STATUS_SUCCESS)
@@ -3220,6 +4450,8 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (hapd->conf->wps_state && elems.wps_ie) {
wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
"Request - assume WPS is used");
+ if (check_sa_query(hapd, sta, reassoc))
+ return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
sta->flags |= WLAN_STA_WPS;
wpabuf_free(sta->wps_ie);
sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
@@ -3273,27 +4505,9 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- sta->sa_query_count > 0)
- ap_check_sa_query_timeout(hapd, sta);
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
- /*
- * STA has already been associated with MFP and SA
- * Query timeout has not been reached. Reject the
- * association attempt temporarily and start SA Query,
- * if one is not pending.
- */
-
- if (sta->sa_query_count == 0)
- ap_sta_start_sa_query(hapd, sta);
+ if (check_sa_query(hapd, sta, reassoc))
return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
- }
if (wpa_auth_uses_mfp(sta->wpa_sm))
sta->flags |= WLAN_STA_MFP;
@@ -3346,7 +4560,7 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (hapd->conf->sae_pwe == 2 &&
sta->auth_alg == WLAN_AUTH_SAE &&
- sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
+ sta->sae && !sta->sae->h2e &&
elems.rsnxe && elems.rsnxe_len >= 1 &&
(elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
wpa_printf(MSG_INFO, "SAE: " MACSTR
@@ -3494,6 +4708,7 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
struct wpa_channel_info ci;
int tx_chanwidth;
int tx_seg1_idx;
+ enum oci_verify_result res;
if (hostapd_drv_channel_info(hapd, &ci) != 0) {
wpa_printf(MSG_WARNING,
@@ -3507,9 +4722,20 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
&tx_seg1_idx) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr);
+ res = ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx);
+ if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
+ res == OCI_NOT_FOUND) {
+ /* Work around misbehaving STAs */
+ wpa_printf(MSG_INFO,
+ "FILS: Disable OCV with a STA that does not send OCI");
+ wpa_auth_set_ocv(sta->wpa_sm, 0);
+ } else if (res != OCI_SUCCESS) {
+ wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
+ ocv_errorstr);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
+ MACSTR " frame=fils-reassoc-req error=%s",
+ MAC2STR(sta->addr), ocv_errorstr);
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
}
@@ -3788,7 +5014,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
p = hostapd_eid_he_operation(hapd, p);
p = hostapd_eid_spatial_reuse(hapd, p);
@@ -3831,7 +5057,8 @@ rsnxe_done:
#ifdef CONFIG_OWE
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
- wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) {
+ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
+ !wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
struct wpabuf *pub;
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
@@ -4085,7 +5312,7 @@ static void handle_assoc(struct hostapd_data *hapd,
{
u16 capab_info, listen_interval, seq_ctrl, fc;
int resp = WLAN_STATUS_SUCCESS;
- u16 reply_res;
+ u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
const u8 *pos;
int left, i;
struct sta_info *sta;
@@ -4465,7 +5692,7 @@ static void handle_assoc(struct hostapd_data *hapd,
os_free(tmp);
/*
- * Remove the station in case tranmission of a success response fails
+ * Remove the station in case transmission of a success response fails
* (the STA was added associated to the driver) or if the station was
* previously added unassociated.
*/
@@ -4801,6 +6028,31 @@ static int handle_action(struct hostapd_data *hapd,
/**
+ * notify_mgmt_frame - Notify of Management frames on the control interface
+ * @hapd: hostapd BSS data structure (the BSS to which the Management frame was
+ * sent to)
+ * @buf: Management frame data (starting from the IEEE 802.11 header)
+ * @len: Length of frame data in octets
+ *
+ * Notify the control interface of any received Management frame.
+ */
+static void notify_mgmt_frame(struct hostapd_data *hapd, const u8 *buf,
+ size_t len)
+{
+
+ int hex_len = len * 2 + 1;
+ char *hex = os_malloc(hex_len);
+
+ if (hex) {
+ wpa_snprintf_hex(hex, hex_len, buf, len);
+ wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO,
+ AP_MGMT_FRAME_RECEIVED "buf=%s", hex);
+ os_free(hex);
+ }
+}
+
+
+/**
* ieee802_11_mgmt - process incoming IEEE 802.11 management frames
* @hapd: hostapd BSS data structure (the BSS to which the management frame was
* sent to)
@@ -4890,6 +6142,9 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
if (hapd->iconf->track_sta_max_num)
sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
+ if (hapd->conf->notify_mgmt_frames)
+ notify_mgmt_frame(hapd, buf, len);
+
switch (stype) {
case WLAN_FC_STYPE_AUTH:
wpa_printf(MSG_DEBUG, "mgmt::auth");
@@ -4937,18 +6192,7 @@ static void handle_auth_cb(struct hostapd_data *hapd,
{
u16 auth_alg, auth_transaction, status_code;
struct sta_info *sta;
-
- if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
- wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
- (unsigned long) len);
-
- /*
- * Initialize status_code here because we are not able to read
- * it from the short payload.
- */
- status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
+ bool success_status;
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
@@ -4958,6 +6202,15 @@ static void handle_auth_cb(struct hostapd_data *hapd,
return;
}
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
+ wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
+ (unsigned long) len);
+ auth_alg = 0;
+ auth_transaction = 0;
+ status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
status_code = le_to_host16(mgmt->u.auth.status_code);
@@ -4981,7 +6234,12 @@ static void handle_auth_cb(struct hostapd_data *hapd,
}
fail:
- if (status_code != WLAN_STATUS_SUCCESS && sta->added_unassoc) {
+ success_status = status_code == WLAN_STATUS_SUCCESS;
+#ifdef CONFIG_SAE
+ if (auth_alg == WLAN_AUTH_SAE && auth_transaction == 1)
+ success_status = sae_status_success(hapd, status_code);
+#endif /* CONFIG_SAE */
+ if (!success_status && sta->added_unassoc) {
hostapd_drv_sta_remove(hapd, sta->addr);
sta->added_unassoc = 0;
}
@@ -5511,4 +6769,169 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
}
+u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ struct hostapd_config *iconf = iface->conf;
+ struct hostapd_hw_modes *mode = iface->current_mode;
+ struct hostapd_channel_data *chan;
+ int dfs, i;
+ u8 channel, tx_pwr_count, local_pwr_constraint;
+ int max_tx_power;
+ u8 tx_pwr;
+
+ if (!mode)
+ return eid;
+
+ if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
+ return eid;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].freq == iface->freq)
+ break;
+ }
+ if (i == mode->num_channels)
+ return eid;
+
+ switch (hostapd_get_oper_chwidth(iconf)) {
+ case CHANWIDTH_USE_HT:
+ if (iconf->secondary_channel == 0) {
+ /* Max Transmit Power count = 0 (20 MHz) */
+ tx_pwr_count = 0;
+ } else {
+ /* Max Transmit Power count = 1 (20, 40 MHz) */
+ tx_pwr_count = 1;
+ }
+ break;
+ case CHANWIDTH_80MHZ:
+ /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
+ tx_pwr_count = 2;
+ break;
+ case CHANWIDTH_80P80MHZ:
+ case CHANWIDTH_160MHZ:
+ /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
+ tx_pwr_count = 3;
+ break;
+ default:
+ return eid;
+ }
+
+ /*
+ * Below local_pwr_constraint logic is referred from
+ * hostapd_eid_pwr_constraint.
+ *
+ * Check if DFS is required by regulatory.
+ */
+ dfs = hostapd_is_dfs_required(hapd->iface);
+ if (dfs < 0)
+ dfs = 0;
+
+ /*
+ * In order to meet regulations when TPC is not implemented using
+ * a transmit power that is below the legal maximum (including any
+ * mitigation factor) should help. In this case, indicate 3 dB below
+ * maximum allowed transmit power.
+ */
+ if (hapd->iconf->local_pwr_constraint == -1)
+ local_pwr_constraint = (dfs == 0) ? 0 : 3;
+ else
+ local_pwr_constraint = hapd->iconf->local_pwr_constraint;
+
+ /*
+ * A STA that is not an AP shall use a transmit power less than or
+ * equal to the local maximum transmit power level for the channel.
+ * The local maximum transmit power can be calculated from the formula:
+ * local max TX pwr = max TX pwr - local pwr constraint
+ * Where max TX pwr is maximum transmit power level specified for
+ * channel in Country element and local pwr constraint is specified
+ * for channel in this Power Constraint element.
+ */
+ chan = &mode->channels[i];
+ max_tx_power = chan->max_tx_power - local_pwr_constraint;
+
+ /*
+ * Local Maximum Transmit power is encoded as two's complement
+ * with a 0.5 dB step.
+ */
+ max_tx_power *= 2; /* in 0.5 dB steps */
+ if (max_tx_power > 127) {
+ /* 63.5 has special meaning of 63.5 dBm or higher */
+ max_tx_power = 127;
+ }
+ if (max_tx_power < -128)
+ max_tx_power = -128;
+ if (max_tx_power < 0)
+ tx_pwr = 0x80 + max_tx_power + 128;
+ else
+ tx_pwr = max_tx_power;
+
+ *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE;
+ *eid++ = 2 + tx_pwr_count;
+
+ /*
+ * Max Transmit Power count and
+ * Max Transmit Power units = 0 (EIRP)
+ */
+ *eid++ = tx_pwr_count;
+
+ for (i = 0; i <= tx_pwr_count; i++)
+ *eid++ = tx_pwr;
+
+ return eid;
+}
+
+
+u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 bw, chan1, chan2 = 0;
+ int freq1;
+
+ if (!hapd->cs_freq_params.channel ||
+ (!hapd->cs_freq_params.vht_enabled &&
+ !hapd->cs_freq_params.he_enabled))
+ return eid;
+
+ /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
+ switch (hapd->cs_freq_params.bandwidth) {
+ case 40:
+ bw = 0;
+ break;
+ case 80:
+ /* check if it's 80+80 */
+ if (!hapd->cs_freq_params.center_freq2)
+ bw = 1;
+ else
+ bw = 3;
+ break;
+ case 160:
+ bw = 2;
+ break;
+ default:
+ /* not valid VHT bandwidth or not in CSA */
+ return eid;
+ }
+
+ freq1 = hapd->cs_freq_params.center_freq1 ?
+ hapd->cs_freq_params.center_freq1 :
+ hapd->cs_freq_params.freq;
+ if (ieee80211_freq_to_chan(freq1, &chan1) !=
+ HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ if (hapd->cs_freq_params.center_freq2 &&
+ ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
+ &chan2) != HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
+ *eid++ = 5; /* Length of Channel Switch Wrapper */
+ *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
+ *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
+ *eid++ = bw; /* New Channel Width */
+ *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
+ *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
+
+ return eid;
+}
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index f1f2442f..c27bb1fc 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -304,6 +304,11 @@ u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
if (spr->sr_ctrl & SPATIAL_REUSE_SRG_INFORMATION_PRESENT) {
*spr_param++ = hapd->iface->conf->spr.srg_obss_pd_min_offset;
*spr_param++ = hapd->iface->conf->spr.srg_obss_pd_max_offset;
+ os_memcpy(spr_param,
+ hapd->iface->conf->spr.srg_bss_color_bitmap, 8);
+ spr_param += 8;
+ os_memcpy(spr_param,
+ hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8);
pos += 18;
}
@@ -313,46 +318,38 @@ u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid)
{
+ struct hostapd_config *conf = hapd->iface->conf;
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+ struct he_capabilities *he_cap;
struct ieee80211_he_6ghz_band_cap *cap;
- u32 vht_cap;
- u8 ht_info;
- u8 params;
+ u16 capab;
u8 *pos;
- if (!mode || !is_6ghz_op_class(hapd->iconf->op_class))
+ if (!mode || !is_6ghz_op_class(hapd->iconf->op_class) ||
+ !is_6ghz_freq(hapd->iface->freq))
return eid;
- vht_cap = hapd->iface->conf->vht_capab;
- ht_info = mode->a_mpdu_params;
+ he_cap = &mode->he_capab[IEEE80211_MODE_AP];
+ capab = he_cap->he_6ghz_capa & HE_6GHZ_BAND_CAP_MIN_MPDU_START;
+ capab |= (conf->he_6ghz_max_ampdu_len_exp <<
+ HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT) &
+ HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK;
+ capab |= (conf->he_6ghz_max_mpdu <<
+ HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT) &
+ HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK;
+ capab |= HE_6GHZ_BAND_CAP_SMPS_DISABLED;
+ if (conf->he_6ghz_rx_ant_pat)
+ capab |= HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS;
+ if (conf->he_6ghz_tx_ant_pat)
+ capab |= HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS;
pos = eid;
*pos++ = WLAN_EID_EXTENSION;
*pos++ = 1 + sizeof(*cap);
*pos++ = WLAN_EID_EXT_HE_6GHZ_BAND_CAP;
- /* Minimum MPDU Start Spacing B0..B2 */
- params = (ht_info >> 2) & HE_6GHZ_BAND_CAP_MIN_MPDU_START_SPACE_MASK;
-
- /* Maximum A-MPDU Length Exponent B3..B5 */
- params |= ((((vht_cap & VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) >>
- VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX_SHIFT) &
- HE_6GHZ_BAND_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) <<
- HE_6GHZ_BAND_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
-
- /* Maximum MPDU Length B6..B7 */
- params |= ((((vht_cap & VHT_CAP_MAX_MPDU_LENGTH_MASK) >>
- VHT_CAP_MAX_MPDU_LENGTH_MASK_SHIFT) &
- HE_6GHZ_BAND_CAP_MAX_MPDU_LENGTH_MASK) <<
- HE_6GHZ_BAND_CAP_MAX_MPDU_LENGTH_SHIFT);
-
cap = (struct ieee80211_he_6ghz_band_cap *) pos;
- cap->a_mpdu_params = params;
- cap->info = HE_6GHZ_BAND_CAP_SMPS_DISABLED;
- if (vht_cap & VHT_CAP_RX_ANTENNA_PATTERN)
- cap->info |= HE_6GHZ_BAND_CAP_RX_ANTENNA_PATTERN;
- if (vht_cap & VHT_CAP_TX_ANTENNA_PATTERN)
- cap->info |= HE_6GHZ_BAND_CAP_TX_ANTENNA_PATTERN;
+ cap->capab = host_to_le16(capab);
pos += sizeof(*cap);
return pos;
@@ -438,6 +435,7 @@ u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
size_t he_capab_len)
{
if (!he_capab || !hapd->iconf->ieee80211ax ||
+ hapd->conf->disable_11ax ||
!check_valid_he_mcs(hapd, he_capab, opmode) ||
ieee80211_invalid_he_cap_size(he_capab, he_capab_len) ||
he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
@@ -467,6 +465,7 @@ u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *he_6ghz_capab)
{
if (!he_6ghz_capab || !hapd->iconf->ieee80211ax ||
+ hapd->conf->disable_11ax ||
!is_6ghz_op_class(hapd->iconf->op_class)) {
sta->flags &= ~WLAN_STA_6GHZ;
os_free(sta->he_6ghz_capab);
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 74a837f8..a429b5dd 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ocv.h"
+#include "common/wpa_ctrl.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_config.h"
@@ -72,6 +73,16 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
"Failed to get channel info for OCI element in SA Query Request");
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->oci_freq_override_saquery_req) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ hapd->conf->oci_freq_override_saquery_req);
+ ci.frequency =
+ hapd->conf->oci_freq_override_saquery_req;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@@ -151,6 +162,16 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
"Failed to get channel info for OCI element in SA Query Response");
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->oci_freq_override_saquery_resp) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ hapd->conf->oci_freq_override_saquery_resp);
+ ci.frequency =
+ hapd->conf->oci_freq_override_saquery_resp;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@@ -254,14 +275,21 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd,
return;
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ tx_chanwidth, tx_seg1_idx) !=
+ OCI_SUCCESS) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
+ MACSTR " frame=saquery%s error=%s",
+ MAC2STR(sa),
+ action_type == WLAN_SA_QUERY_REQUEST ?
+ "req" : "resp", ocv_errorstr);
return;
}
}
#endif /* CONFIG_OCV */
if (action_type == WLAN_SA_QUERY_REQUEST) {
+ if (sta)
+ sta->post_csa_sa_query = 0;
ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
return;
}
@@ -397,9 +425,19 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
* Identifiers Used Exclusively */
}
#endif /* CONFIG_SAE */
- if (hapd->conf->beacon_prot)
+ if (hapd->conf->beacon_prot &&
+ (hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_BEACON_PROTECTION))
*pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
break;
+ case 11: /* Bits 88-95 */
+#ifdef CONFIG_SAE_PK
+ if (hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ hostapd_sae_pk_exclusively(hapd->conf))
+ *pos |= 0x01; /* Bit 88 - SAE PK Exclusively */
+#endif /* CONFIG_SAE_PK */
+ break;
}
}
@@ -458,8 +496,15 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
hostapd_sae_pw_id_in_use(hapd->conf))
len = 11;
#endif /* CONFIG_SAE */
- if (len < 11 && hapd->conf->beacon_prot)
+ if (len < 11 && hapd->conf->beacon_prot &&
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION))
len = 11;
+#ifdef CONFIG_SAE_PK
+ if (len < 12 && hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ hostapd_sae_pk_exclusively(hapd->conf))
+ len = 12;
+#endif /* CONFIG_SAE_PK */
if (len < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len;
if (len == 0)
@@ -1054,20 +1099,46 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
{
u8 *pos = eid;
+ bool sae_pk = false;
+ u16 capab = 0;
+ size_t flen;
- if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
- !wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) ||
- (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2 &&
- !hostapd_sae_pw_id_in_use(hapd->conf)) ||
- hapd->conf->sae_pwe == 3 ||
- len < 3)
- return pos;
+ if (!(hapd->conf->wpa & WPA_PROTO_RSN))
+ return eid;
+
+#ifdef CONFIG_SAE_PK
+ sae_pk = hostapd_sae_pk_in_use(hapd->conf);
+#endif /* CONFIG_SAE_PK */
+
+ if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ (hapd->conf->sae_pwe == 1 || hapd->conf->sae_pwe == 2 ||
+ hostapd_sae_pw_id_in_use(hapd->conf) || sae_pk) &&
+ hapd->conf->sae_pwe != 3) {
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (sae_pk)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+ }
+
+ if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+ if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+ if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG)
+ capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
+
+ flen = (capab & 0xff00) ? 2 : 1;
+ if (len < 2 + flen || !capab)
+ return eid; /* no supported extended RSN capabilities */
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
*pos++ = WLAN_EID_RSNX;
- *pos++ = 1;
- /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
- * used for now */
- *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+ *pos++ = flen;
+ *pos++ = capab & 0x00ff;
+ capab >>= 8;
+ if (capab)
+ *pos++ = capab;
return pos;
}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index f50f142d..d0370229 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -167,171 +167,6 @@ static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
}
-u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
-{
- u8 bw, chan1, chan2 = 0;
- int freq1;
-
- if (!hapd->cs_freq_params.channel ||
- !hapd->cs_freq_params.vht_enabled)
- return eid;
-
- /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
- switch (hapd->cs_freq_params.bandwidth) {
- case 40:
- bw = 0;
- break;
- case 80:
- /* check if it's 80+80 */
- if (!hapd->cs_freq_params.center_freq2)
- bw = 1;
- else
- bw = 3;
- break;
- case 160:
- bw = 2;
- break;
- default:
- /* not valid VHT bandwidth or not in CSA */
- return eid;
- }
-
- freq1 = hapd->cs_freq_params.center_freq1 ?
- hapd->cs_freq_params.center_freq1 :
- hapd->cs_freq_params.freq;
- if (ieee80211_freq_to_chan(freq1, &chan1) !=
- HOSTAPD_MODE_IEEE80211A)
- return eid;
-
- if (hapd->cs_freq_params.center_freq2 &&
- ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
- &chan2) != HOSTAPD_MODE_IEEE80211A)
- return eid;
-
- *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
- *eid++ = 5; /* Length of Channel Switch Wrapper */
- *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
- *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
- *eid++ = bw; /* New Channel Width */
- *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
- *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
-
- return eid;
-}
-
-
-u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
-{
- struct hostapd_iface *iface = hapd->iface;
- struct hostapd_config *iconf = iface->conf;
- struct hostapd_hw_modes *mode = iface->current_mode;
- struct hostapd_channel_data *chan;
- int dfs, i;
- u8 channel, tx_pwr_count, local_pwr_constraint;
- int max_tx_power;
- u8 tx_pwr;
-
- if (!mode)
- return eid;
-
- if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
- return eid;
-
- for (i = 0; i < mode->num_channels; i++) {
- if (mode->channels[i].freq == iface->freq)
- break;
- }
- if (i == mode->num_channels)
- return eid;
-
- switch (iface->conf->vht_oper_chwidth) {
- case CHANWIDTH_USE_HT:
- if (iconf->secondary_channel == 0) {
- /* Max Transmit Power count = 0 (20 MHz) */
- tx_pwr_count = 0;
- } else {
- /* Max Transmit Power count = 1 (20, 40 MHz) */
- tx_pwr_count = 1;
- }
- break;
- case CHANWIDTH_80MHZ:
- /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
- tx_pwr_count = 2;
- break;
- case CHANWIDTH_80P80MHZ:
- case CHANWIDTH_160MHZ:
- /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
- tx_pwr_count = 3;
- break;
- default:
- return eid;
- }
-
- /*
- * Below local_pwr_constraint logic is referred from
- * hostapd_eid_pwr_constraint.
- *
- * Check if DFS is required by regulatory.
- */
- dfs = hostapd_is_dfs_required(hapd->iface);
- if (dfs < 0)
- dfs = 0;
-
- /*
- * In order to meet regulations when TPC is not implemented using
- * a transmit power that is below the legal maximum (including any
- * mitigation factor) should help. In this case, indicate 3 dB below
- * maximum allowed transmit power.
- */
- if (hapd->iconf->local_pwr_constraint == -1)
- local_pwr_constraint = (dfs == 0) ? 0 : 3;
- else
- local_pwr_constraint = hapd->iconf->local_pwr_constraint;
-
- /*
- * A STA that is not an AP shall use a transmit power less than or
- * equal to the local maximum transmit power level for the channel.
- * The local maximum transmit power can be calculated from the formula:
- * local max TX pwr = max TX pwr - local pwr constraint
- * Where max TX pwr is maximum transmit power level specified for
- * channel in Country element and local pwr constraint is specified
- * for channel in this Power Constraint element.
- */
- chan = &mode->channels[i];
- max_tx_power = chan->max_tx_power - local_pwr_constraint;
-
- /*
- * Local Maximum Transmit power is encoded as two's complement
- * with a 0.5 dB step.
- */
- max_tx_power *= 2; /* in 0.5 dB steps */
- if (max_tx_power > 127) {
- /* 63.5 has special meaning of 63.5 dBm or higher */
- max_tx_power = 127;
- }
- if (max_tx_power < -128)
- max_tx_power = -128;
- if (max_tx_power < 0)
- tx_pwr = 0x80 + max_tx_power + 128;
- else
- tx_pwr = max_tx_power;
-
- *eid++ = WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE;
- *eid++ = 2 + tx_pwr_count;
-
- /*
- * Max Transmit Power count and
- * Max Transmit Power units = 0 (EIRP)
- */
- *eid++ = tx_pwr_count;
-
- for (i = 0; i <= tx_pwr_count; i++)
- *eid++ = tx_pwr;
-
- return eid;
-}
-
-
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab)
{
@@ -425,7 +260,9 @@ u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
- if (!hapd->iface->current_mode)
+ /* Vendor VHT is applicable only to 2.4 GHz */
+ if (!hapd->iface->current_mode ||
+ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
return eid;
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index ee095f61..753c8833 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -2067,7 +2067,8 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
#ifdef CONFIG_FILS
#ifdef NEED_AP_MLME
- if (sta->flags & WLAN_STA_PENDING_FILS_ERP) {
+ if (sta->flags &
+ (WLAN_STA_PENDING_FILS_ERP | WLAN_STA_PENDING_PASN_FILS_ERP)) {
/* TODO: Add a PMKSA entry on success? */
ieee802_11_finish_fils_auth(
hapd, sta, hdr->code == RADIUS_CODE_ACCESS_ACCEPT,
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index 01bf8862..2bbe3185 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -220,7 +220,7 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
u16 capab = hostapd_own_capab_info(hapd);
int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
- int he = hapd->iconf->ieee80211ax;
+ int he = hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax;
struct wpa_ssid_value ssid;
u8 channel, op_class;
u8 center_freq1_idx = 0, center_freq2_idx = 0;
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 67b5e988..ccd1ed93 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -156,6 +156,37 @@ void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
}
+#ifdef CONFIG_PASN
+
+void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ if (sta->pasn) {
+ wpa_printf(MSG_DEBUG, "PASN: Free PASN context: " MACSTR,
+ MAC2STR(sta->addr));
+
+ if (sta->pasn->ecdh)
+ crypto_ecdh_deinit(sta->pasn->ecdh);
+
+ wpabuf_free(sta->pasn->secret);
+ sta->pasn->secret = NULL;
+
+#ifdef CONFIG_SAE
+ sae_clear_data(&sta->pasn->sae);
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_FILS
+ /* In practice this pointer should be NULL */
+ wpabuf_free(sta->pasn->fils.erp_resp);
+ sta->pasn->fils.erp_resp = NULL;
+#endif /* CONFIG_FILS */
+
+ bin_clear_free(sta->pasn, sizeof(*sta->pasn));
+ sta->pasn = NULL;
+ }
+}
+
+#endif /* CONFIG_PASN */
+
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_beacon = 0;
@@ -371,6 +402,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
#endif /* CONFIG_WNM_AP */
+#ifdef CONFIG_PASN
+ ap_free_sta_pasn(hapd, sta);
+#endif /* CONFIG_PASN */
+
os_free(sta->ifname_wds);
#ifdef CONFIG_TESTING_OPTIONS
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 940d3159..efa48e7e 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -14,6 +14,8 @@
#include "vlan.h"
#include "common/wpa_common.h"
#include "common/ieee802_11_defs.h"
+#include "common/sae.h"
+#include "crypto/sha384.h"
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
@@ -39,6 +41,7 @@
#define WLAN_STA_MULTI_AP BIT(23)
#define WLAN_STA_HE BIT(24)
#define WLAN_STA_6GHZ BIT(25)
+#define WLAN_STA_PENDING_PASN_FILS_ERP BIT(26)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -63,6 +66,42 @@ struct pending_eapol_rx {
struct os_reltime rx_time;
};
+enum pasn_fils_state {
+ PASN_FILS_STATE_NONE = 0,
+ PASN_FILS_STATE_PENDING_AS,
+ PASN_FILS_STATE_COMPLETE
+};
+
+struct pasn_fils_data {
+ u8 state;
+ u8 nonce[FILS_NONCE_LEN];
+ u8 anonce[FILS_NONCE_LEN];
+ u8 session[FILS_SESSION_LEN];
+ u8 erp_pmkid[PMKID_LEN];
+
+ struct wpabuf *erp_resp;
+};
+
+struct pasn_data {
+ int akmp;
+ int cipher;
+ u16 group;
+ u8 trans_seq;
+ u8 wrapped_data_format;
+
+ u8 hash[SHA384_MAC_LEN];
+ struct wpa_ptk ptk;
+ struct crypto_ecdh *ecdh;
+
+ struct wpabuf *secret;
+#ifdef CONFIG_SAE
+ struct sae_data sae;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ struct pasn_fils_data fils;
+#endif /* CONFIG_FILS */
+};
+
struct sta_info {
struct sta_info *next; /* next entry in sta list */
struct sta_info *hnext; /* next entry in hash table list */
@@ -122,6 +161,7 @@ struct sta_info {
unsigned int hs20_t_c_filtering:1;
unsigned int ft_over_ds:1;
unsigned int external_dh_updated:1;
+ unsigned int post_csa_sa_query:1;
u16 auth_alg;
@@ -285,6 +325,10 @@ struct sta_info {
unsigned int airtime_weight;
struct os_reltime backlogged_until;
#endif /* CONFIG_AIRTIME_POLICY */
+
+#ifdef CONFIG_PASN
+ struct pasn_data *pasn;
+#endif /* CONFIG_PASN */
};
@@ -362,4 +406,6 @@ int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta);
int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta);
+
#endif /* STA_INFO_H */
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 67281b38..d32967e6 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -103,6 +103,15 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
os_free(wnmtfs_ie);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->oci_freq_override_wnm_sleep) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ hapd->conf->oci_freq_override_wnm_sleep);
+ ci.frequency = hapd->conf->oci_freq_override_wnm_sleep;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@@ -160,7 +169,9 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
pos += igtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
(int) igtk_elem_len);
- if (hapd->conf->beacon_prot) {
+ if (hapd->conf->beacon_prot &&
+ (hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_BEACON_PROTECTION)) {
res = wpa_wnmsleep_bigtk_subelem(sta->wpa_sm, pos);
if (res < 0)
goto fail;
@@ -317,8 +328,9 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(hapd, MSG_WARNING, "WNM: %s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(hapd, MSG_WARNING, "WNM: OCV failed: %s",
+ ocv_errorstr);
return;
}
}
@@ -527,7 +539,8 @@ static void wnm_beacon_protection_failure(struct hostapd_data *hapd,
{
struct sta_info *sta;
- if (!hapd->conf->beacon_prot)
+ if (!hapd->conf->beacon_prot ||
+ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION))
return;
sta = ap_get_sta(hapd, addr);
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 019e5357..e2e6e1f3 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -15,6 +15,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ocv.h"
#include "common/dpp.h"
+#include "common/wpa_ctrl.h"
#include "crypto/aes.h"
#include "crypto/aes_wrap.h"
#include "crypto/aes_siv.h"
@@ -187,6 +188,10 @@ wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
{
if (!wpa_auth->cb->send_eapol)
return -1;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_auth->conf.skip_send_eapol)
+ return 0;
+#endif
return wpa_auth->cb->send_eapol(wpa_auth->cb_ctx, addr, data, data_len,
encrypt);
}
@@ -223,6 +228,23 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
}
+void wpa_auth_store_ptksa(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int cipher,
+ u32 life_time, const struct wpa_ptk *ptk)
+{
+ if (wpa_auth->cb->store_ptksa)
+ wpa_auth->cb->store_ptksa(wpa_auth->cb_ctx, addr, cipher,
+ life_time, ptk);
+}
+
+
+void wpa_auth_remove_ptksa(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int cipher)
+{
+ if (wpa_auth->cb->clear_ptksa)
+ wpa_auth->cb->clear_ptksa(wpa_auth->cb_ctx, addr, cipher);
+}
+
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt)
{
@@ -1662,7 +1684,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
wpa_auth_set_eapol(wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, 1);
wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len,
- sm->pairwise_set);
+ sm->pairwise_set);
os_free(hdr);
}
@@ -1697,6 +1719,11 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
#ifdef TEST_FUZZ
timeout_ms = 1;
#endif /* TEST_FUZZ */
+#ifdef CONFIG_TESTING_OPTIONS
+ if(wpa_auth->conf.enable_eapol_large_timeout) {
+ timeout_ms = 50 * 1000;
+ }
+#endif
wpa_printf(MSG_DEBUG,
"WPA: Use EAPOL-Key timeout of %u ms (retry counter %u)",
timeout_ms, ctr);
@@ -1738,6 +1765,9 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
{
sm->PTK_valid = false;
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+
+ wpa_auth_remove_ptksa(sm->wpa_auth, sm->addr, sm->pairwise);
+
if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
0, KEY_FLAG_PAIRWISE))
wpa_printf(MSG_DEBUG,
@@ -2257,9 +2287,17 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
struct wpa_ptk *ptk, int force_sha256)
{
const u8 *z = NULL;
- size_t z_len = 0;
+ size_t z_len = 0, kdk_len;
int akmp;
+ if (sm->wpa_auth->conf.force_kdk_derivation ||
+ (sm->wpa_auth->conf.secure_ltf &&
+ sm->rsnxe && sm->rsnxe_len >= 4 &&
+ sm->rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
if (sm->ft_completed) {
@@ -2271,7 +2309,8 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
sm->pmk_r1_name,
ptk, ptk_name,
sm->wpa_key_mgmt,
- sm->pairwise);
+ sm->pairwise,
+ kdk_len);
}
return wpa_auth_derive_ptk_ft(sm, ptk);
}
@@ -2289,7 +2328,7 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
akmp |= WPA_KEY_MGMT_PSK_SHA256;
return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
- ptk, akmp, sm->pairwise, z, z_len);
+ ptk, akmp, sm->pairwise, z, z_len, kdk_len);
}
@@ -2304,13 +2343,21 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
size_t ick_len;
int res;
u8 fils_ft[FILS_FT_MAX_LEN];
- size_t fils_ft_len = 0;
+ size_t fils_ft_len = 0, kdk_len;
+
+ if (sm->wpa_auth->conf.force_kdk_derivation ||
+ (sm->wpa_auth->conf.secure_ltf &&
+ sm->rsnxe && sm->rsnxe_len >= 4 &&
+ sm->rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
res = fils_pmk_to_ptk(pmk, pmk_len, sm->addr, sm->wpa_auth->addr,
snonce, anonce, dhss, dhss_len,
&sm->PTK, ick, &ick_len,
sm->wpa_key_mgmt, sm->pairwise,
- fils_ft, &fils_ft_len);
+ fils_ft, &fils_ft_len, kdk_len);
if (res < 0)
return res;
sm->PTK_valid = true;
@@ -2322,7 +2369,6 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
struct wpa_auth_config *conf = &wpa_auth->conf;
u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
- size_t pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
if (wpa_derive_pmk_r0(fils_ft, fils_ft_len,
conf->ssid, conf->ssid_len,
@@ -2333,10 +2379,6 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
use_sha384) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0",
- pmk_r0, pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
- pmk_r0_name, WPA_PMK_NAME_LEN);
wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
forced_memzero(fils_ft, sizeof(fils_ft));
@@ -2776,6 +2818,15 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
wpabuf_clear_free(plain);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conf->oci_freq_override_fils_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ conf->oci_freq_override_fils_assoc);
+ ci.frequency = conf->oci_freq_override_fils_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
if (ocv_insert_extended_oci(&ci, pos) < 0) {
@@ -2814,6 +2865,9 @@ int fils_set_tk(struct wpa_state_machine *sm)
}
sm->tk_already_set = true;
+ wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise,
+ dot11RSNAConfigPMKLifetime, &sm->PTK);
+
return 0;
}
@@ -3032,6 +3086,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
struct wpa_channel_info ci;
int tx_chanwidth;
int tx_seg1_idx;
+ enum oci_verify_result res;
if (wpa_channel_info(wpa_auth, &ci) != 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -3045,10 +3100,21 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
&tx_seg1_idx) < 0)
return;
- if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- ocv_errorstr);
+ res = ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx);
+ if (wpa_auth_uses_ocv(sm) == 2 && res == OCI_NOT_FOUND) {
+ /* Work around misbehaving STAs */
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "Disable OCV with a STA that does not send OCI");
+ wpa_auth_set_ocv(sm, 0);
+ } else if (res != OCI_SUCCESS) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "OCV failed: %s", ocv_errorstr);
+ if (wpa_auth->conf.msg_ctx)
+ wpa_msg(wpa_auth->conf.msg_ctx, MSG_INFO,
+ OCV_FAILURE "addr=" MACSTR
+ " frame=eapol-key-m2 error=%s",
+ MAC2STR(sm->addr), ocv_errorstr);
return;
}
}
@@ -3128,7 +3194,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
sm->pending_1_of_4_timeout = 0;
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
- if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && sm->PMK != pmk) {
/* PSK may have changed from the previous choice, so update
* state machine data based on whatever PSK was selected here.
*/
@@ -3211,6 +3277,14 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
else
os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn));
os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random BIGTK to each OSEN STA to prevent use
+ * of BIGTK in the BSS.
+ */
+ if (random_get_bytes(bigtk.bigtk, len) < 0)
+ return pos;
+ }
pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
(const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
NULL, 0);
@@ -3228,7 +3302,9 @@ static int ocv_oci_len(struct wpa_state_machine *sm)
return 0;
}
-static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
+
+static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos,
+ unsigned int freq)
{
#ifdef CONFIG_OCV
struct wpa_channel_info ci;
@@ -3241,6 +3317,14 @@ static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
"Failed to get channel info for OCI element");
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (freq) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %u MHz",
+ ci.frequency, freq);
+ ci.frequency = freq;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
return ocv_insert_oci_kde(&ci, argpos);
#else /* CONFIG_OCV */
@@ -3318,6 +3402,8 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
wpa_ie_len > wpa_ie[1] + 2U && wpa_ie[0] == WLAN_EID_RSN) {
/* WPA-only STA, remove RSN IE and possible MDIE */
wpa_ie = wpa_ie + wpa_ie[1] + 2;
+ if (wpa_ie[0] == WLAN_EID_RSNX)
+ wpa_ie = wpa_ie + wpa_ie[1] + 2;
if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
wpa_ie = wpa_ie + wpa_ie[1] + 2;
wpa_ie_len = wpa_ie[1] + 2;
@@ -3457,7 +3543,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
gtk, gtk_len);
}
pos = ieee80211w_kde_add(sm, pos);
- if (ocv_oci_add(sm, &pos) < 0)
+ if (ocv_oci_add(sm, &pos, conf->oci_freq_override_eapol_m3) < 0)
goto done;
#ifdef CONFIG_IEEE80211R_AP
@@ -3572,6 +3658,8 @@ SM_STATE(WPA_PTK, PTKINITDONE)
sm->pairwise_set = true;
wpa_auth_set_ptk_rekey_timer(sm);
+ wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise,
+ dot11RSNAConfigPMKLifetime, &sm->PTK);
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
@@ -3807,7 +3895,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gsm->GTK_len);
pos = ieee80211w_kde_add(sm, pos);
- if (ocv_oci_add(sm, &pos) < 0) {
+ if (ocv_oci_add(sm, &pos,
+ conf->oci_freq_override_eapol_g1) < 0) {
os_free(kde_buf);
return;
}
@@ -3873,7 +3962,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
if (wpa_channel_info(wpa_auth, &ci) != 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "Failed to get channel info to validate received OCI in EAPOL-Key group 1/2");
+ "Failed to get channel info to validate received OCI in EAPOL-Key group 2/2");
return;
}
@@ -3884,9 +3973,15 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
return;
if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- ocv_errorstr);
+ tx_chanwidth, tx_seg1_idx) !=
+ OCI_SUCCESS) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "OCV failed: %s", ocv_errorstr);
+ if (wpa_auth->conf.msg_ctx)
+ wpa_msg(wpa_auth->conf.msg_ctx, MSG_INFO,
+ OCV_FAILURE "addr=" MACSTR
+ " frame=eapol-key-g2 error=%s",
+ MAC2STR(sm->addr), ocv_errorstr);
return;
}
}
@@ -4072,6 +4167,7 @@ void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
u8 *start = pos;
@@ -4090,6 +4186,14 @@ int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
return 0;
pos += 8;
os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(pos, gsm->GTK_len) < 0)
+ return 0;
+ }
pos += gsm->GTK_len;
wpa_printf(MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit",
@@ -4103,6 +4207,7 @@ int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
u8 *start = pos;
size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
@@ -4120,6 +4225,14 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
pos += 6;
os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], len);
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random IGTK to each STA to prevent use
+ * of IGTK in the BSS.
+ */
+ if (random_get_bytes(pos, len) < 0)
+ return 0;
+ }
pos += len;
wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
@@ -4150,6 +4263,14 @@ int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos)
pos += 6;
os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random BIGTK to each STA to prevent use
+ * of BIGTK in the BSS.
+ */
+ if (random_get_bytes(pos, len) < 0)
+ return 0;
+ }
pos += len;
wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit",
@@ -5228,6 +5349,14 @@ void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
#endif /* CONFIG_DPP2 */
+void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
+ u8 val)
+{
+ if (wpa_auth)
+ wpa_auth->conf.transition_disable = val;
+}
+
+
#ifdef CONFIG_TESTING_OPTIONS
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
@@ -5259,6 +5388,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
u8 *opos;
size_t gtk_len, kde_len;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
int wpa_ie_len, secure, gtkidx, encr = 0;
@@ -5278,6 +5408,8 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
/* WPA-only STA, remove RSN IE and possible MDIE */
wpa_ie = wpa_ie + wpa_ie[1] + 2;
+ if (wpa_ie[0] == WLAN_EID_RSNX)
+ wpa_ie = wpa_ie + wpa_ie[1] + 2;
if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
wpa_ie = wpa_ie + wpa_ie[1] + 2;
wpa_ie_len = wpa_ie[1] + 2;
@@ -5369,7 +5501,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
opos += 2 + RSN_SELECTOR_LEN + 2;
os_memset(opos, 0, 6); /* clear PN */
}
- if (ocv_oci_add(sm, &pos) < 0) {
+ if (ocv_oci_add(sm, &pos, conf->oci_freq_override_eapol_m3) < 0) {
os_free(kde);
return -1;
}
@@ -5377,9 +5509,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
int res;
- struct wpa_auth_config *conf;
- conf = &sm->wpa_auth->conf;
if (sm->assoc_resp_ftie &&
kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
os_memcpy(pos, sm->assoc_resp_ftie,
@@ -5436,6 +5566,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
void *ctx1, void *ctx2)
{
u8 rsc[WPA_KEY_RSC_LEN];
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
const u8 *kde;
u8 *kde_buf = NULL, *pos, hdr[2];
@@ -5470,7 +5601,8 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
opos += 2 + RSN_SELECTOR_LEN + 2;
os_memset(opos, 0, 6); /* clear PN */
}
- if (ocv_oci_add(sm, &pos) < 0) {
+ if (ocv_oci_add(sm, &pos,
+ conf->oci_freq_override_eapol_g1) < 0) {
os_free(kde_buf);
return -1;
}
@@ -5512,4 +5644,42 @@ void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val)
wpa_auth->conf.ft_rsnxe_used = val;
}
+
+void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth,
+ enum wpa_auth_ocv_override_frame frame,
+ unsigned int freq)
+{
+ if (!wpa_auth)
+ return;
+ switch (frame) {
+ case WPA_AUTH_OCV_OVERRIDE_EAPOL_M3:
+ wpa_auth->conf.oci_freq_override_eapol_m3 = freq;
+ break;
+ case WPA_AUTH_OCV_OVERRIDE_EAPOL_G1:
+ wpa_auth->conf.oci_freq_override_eapol_g1 = freq;
+ break;
+ case WPA_AUTH_OCV_OVERRIDE_FT_ASSOC:
+ wpa_auth->conf.oci_freq_override_ft_assoc = freq;
+ break;
+ case WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC:
+ wpa_auth->conf.oci_freq_override_fils_assoc = freq;
+ break;
+ }
+}
+
+void wpa_auth_set_skip_send_eapol(struct wpa_authenticator *wpa_auth,
+ u8 val)
+{
+ if (wpa_auth)
+ wpa_auth->conf.skip_send_eapol = val;
+}
+
+void wpa_auth_set_enable_eapol_large_timeout(struct wpa_authenticator *wpa_auth,
+ u8 val)
+{
+ if (wpa_auth)
+ wpa_auth->conf.enable_eapol_large_timeout = val;
+}
+
+
#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 1ea067bc..70c13f6e 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -168,6 +168,7 @@ struct ft_remote_r1kh {
struct wpa_auth_config {
+ void *msg_ctx;
int wpa;
int extended_key_id;
int wpa_key_mgmt;
@@ -239,7 +240,13 @@ struct wpa_auth_config {
unsigned int gtk_rsc_override_set:1;
unsigned int igtk_rsc_override_set:1;
int ft_rsnxe_used;
+ unsigned int skip_send_eapol:1;
+ unsigned int enable_eapol_large_timeout:1;
#endif /* CONFIG_TESTING_OPTIONS */
+ unsigned int oci_freq_override_eapol_m3;
+ unsigned int oci_freq_override_eapol_g1;
+ unsigned int oci_freq_override_ft_assoc;
+ unsigned int oci_freq_override_fils_assoc;
#ifdef CONFIG_P2P
u8 ip_addr_go[4];
u8 ip_addr_mask[4];
@@ -251,11 +258,23 @@ struct wpa_auth_config {
u8 fils_cache_id[FILS_CACHE_ID_LEN];
#endif /* CONFIG_FILS */
int sae_pwe;
+ bool sae_pk;
+
+ unsigned int secure_ltf:1;
+ unsigned int secure_rtt:1;
+ unsigned int prot_range_neg:1;
+
int owe_ptk_workaround;
u8 transition_disable;
#ifdef CONFIG_DPP2
int dpp_pfs;
#endif /* CONFIG_DPP2 */
+
+ /*
+ * If set Key Derivation Key should be derived as part of PMK to
+ * PTK derivation regardless of advertised capabilities.
+ */
+ bool force_kdk_derivation;
};
typedef enum {
@@ -300,6 +319,9 @@ struct wpa_auth_callbacks {
int (*get_sta_tx_params)(void *ctx, const u8 *addr,
int ap_max_chanwidth, int ap_seg1_idx,
int *bandwidth, int *seg1_idx);
+ void (*store_ptksa)(void *ctx, const u8 *addr, int cipher,
+ u32 life_time, const struct wpa_ptk *ptk);
+ void (*clear_ptksa)(void *ctx, const u8 *addr, int cipher);
#ifdef CONFIG_IEEE80211R_AP
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
int (*add_sta_ft)(void *ctx, const u8 *sta_addr);
@@ -453,6 +475,14 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
void wpa_ft_deinit(struct wpa_authenticator *wpa_auth);
void wpa_ft_sta_deinit(struct wpa_state_machine *sm);
+int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
+ const u8 *spa, const u8 *pmk_r1_name,
+ u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
+ struct vlan_description *vlan,
+ const u8 **identity, size_t *identity_len,
+ const u8 **radius_cui, size_t *radius_cui_len,
+ int *session_timeout);
+
#endif /* CONFIG_IEEE80211R_AP */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
@@ -509,8 +539,12 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
u8 *pos, size_t max_len,
const u8 *req_ies, size_t req_ies_len);
+bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
+ u8 *fd_rsn_info);
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
+void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
+ u8 val);
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
void (*cb)(void *ctx1, void *ctx2),
@@ -525,4 +559,18 @@ int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth);
void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm);
void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val);
+enum wpa_auth_ocv_override_frame {
+ WPA_AUTH_OCV_OVERRIDE_EAPOL_M3,
+ WPA_AUTH_OCV_OVERRIDE_EAPOL_G1,
+ WPA_AUTH_OCV_OVERRIDE_FT_ASSOC,
+ WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC,
+};
+void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth,
+ enum wpa_auth_ocv_override_frame frame,
+ unsigned int freq);
+void wpa_auth_set_skip_send_eapol(struct wpa_authenticator *wpa_auth,
+ u8 val);
+void wpa_auth_set_enable_eapol_large_timeout(struct wpa_authenticator *wpa_auth,
+ u8 val);
+
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 5af65aad..32b74565 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -14,6 +14,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
+#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "crypto/aes.h"
#include "crypto/aes_siv.h"
@@ -1472,13 +1473,13 @@ static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
}
-static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
- const u8 *spa, const u8 *pmk_r1_name,
- u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
- struct vlan_description *vlan,
- const u8 **identity, size_t *identity_len,
- const u8 **radius_cui, size_t *radius_cui_len,
- int *session_timeout)
+int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
+ const u8 *spa, const u8 *pmk_r1_name,
+ u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
+ struct vlan_description *vlan,
+ const u8 **identity, size_t *identity_len,
+ const u8 **radius_cui, size_t *radius_cui_len,
+ int *session_timeout)
{
struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
struct wpa_ft_pmk_r1_sa *r1;
@@ -1897,7 +1898,7 @@ static void wpa_ft_block_r0kh(struct wpa_authenticator *wpa_auth,
return;
}
- wpa_hexdump(MSG_DEBUG, "FT: Blacklist R0KH-ID",
+ wpa_hexdump(MSG_DEBUG, "FT: Temporarily block R0KH-ID",
f_r0kh_id, f_r0kh_id_len);
if (r0kh) {
@@ -1985,7 +1986,7 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
return -1;
}
if (is_zero_ether_addr(r0kh->addr)) {
- wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID is blacklisted",
+ wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID is temporarily blocked",
sm->r0kh_id, sm->r0kh_id_len);
return -1;
}
@@ -2128,8 +2129,6 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
pmk_r0, pmk_r0_name,
wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
pmk_r0_name,
@@ -2140,9 +2139,6 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr,
pmk_r1, sm->pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
- WPA_PMK_NAME_LEN);
if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_len,
sm->pmk_r1_name, sm->pairwise, &vlan,
@@ -2151,7 +2147,8 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
return wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
sm->addr, sm->wpa_auth->addr, sm->pmk_r1_name,
- ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
+ ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise,
+ 0);
}
@@ -2167,11 +2164,12 @@ static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
{
u8 *subelem;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
size_t subelem_len, pad_len;
const u8 *key;
size_t key_len;
- u8 keybuf[32];
+ u8 keybuf[WPA_GTK_MAX_LEN];
const u8 *kek;
size_t kek_len;
@@ -2198,12 +2196,30 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
pad_len += 8;
if (pad_len && key_len < sizeof(keybuf)) {
os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
+ if (conf->disable_gtk ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(keybuf, key_len) < 0)
+ return NULL;
+ }
os_memset(keybuf + key_len, 0, pad_len);
keybuf[key_len] = 0xdd;
key_len += pad_len;
key = keybuf;
- } else
+ } else if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random GTK to each STA to prevent use of GTK
+ * in the BSS.
+ */
+ if (random_get_bytes(keybuf, key_len) < 0)
+ return NULL;
+ key = keybuf;
+ } else {
key = gsm->GTK[gsm->GN - 1];
+ }
/*
* Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
@@ -2237,11 +2253,13 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
{
u8 *subelem, *pos;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
size_t subelem_len;
- const u8 *kek;
+ const u8 *kek, *igtk;
size_t kek_len;
size_t igtk_len;
+ u8 dummy_igtk[WPA_IGTK_MAX_LEN];
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
kek = sm->PTK.kek2;
@@ -2268,8 +2286,19 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
pos += 6;
*pos++ = igtk_len;
- if (aes_wrap(kek, kek_len, igtk_len / 8,
- gsm->IGTK[gsm->GN_igtk - 4], pos)) {
+ igtk = gsm->IGTK[gsm->GN_igtk - 4];
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random IGTK to each STA to prevent use of
+ * IGTK in the BSS.
+ */
+ if (random_get_bytes(dummy_igtk, igtk_len / 8) < 0) {
+ os_free(subelem);
+ return NULL;
+ }
+ igtk = dummy_igtk;
+ }
+ if (aes_wrap(kek, kek_len, igtk_len / 8, igtk, pos)) {
wpa_printf(MSG_DEBUG,
"FT: IGTK subelem encryption failed: kek_len=%d",
(int) kek_len);
@@ -2287,9 +2316,10 @@ static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
u8 *subelem, *pos;
struct wpa_group *gsm = sm->group;
size_t subelem_len;
- const u8 *kek;
+ const u8 *kek, *bigtk;
size_t kek_len;
size_t bigtk_len;
+ u8 dummy_bigtk[WPA_IGTK_MAX_LEN];
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
kek = sm->PTK.kek2;
@@ -2316,8 +2346,19 @@ static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos);
pos += 6;
*pos++ = bigtk_len;
- if (aes_wrap(kek, kek_len, bigtk_len / 8,
- gsm->IGTK[gsm->GN_bigtk - 6], pos)) {
+ bigtk = gsm->IGTK[gsm->GN_bigtk - 6];
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random BIGTK to each OSEN STA to prevent use
+ * of BIGTK in the BSS.
+ */
+ if (random_get_bytes(dummy_bigtk, bigtk_len / 8) < 0) {
+ os_free(subelem);
+ return NULL;
+ }
+ bigtk = dummy_bigtk;
+ }
+ if (aes_wrap(kek, kek_len, bigtk_len / 8, bigtk, pos)) {
wpa_printf(MSG_DEBUG,
"FT: BIGTK subelem encryption failed: kek_len=%d",
(int) kek_len);
@@ -2621,6 +2662,15 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
os_free(subelem);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conf->oci_freq_override_ft_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ conf->oci_freq_override_ft_assoc);
+ ci.frequency = conf->oci_freq_override_ft_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
subelem_len += 2 + OCV_OCI_LEN;
nbuf = os_realloc(subelem, subelem_len);
@@ -2961,8 +3011,6 @@ static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth,
conf->r1_key_holder,
sm->addr, out_pmk_r1, pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", out_pmk_r1, r0->pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
os_get_reltime(&now);
if (r0->expiration)
@@ -3018,7 +3066,7 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
const u8 *identity, *radius_cui;
size_t identity_len = 0, radius_cui_len = 0;
int use_sha384;
- size_t pmk_r1_len;
+ size_t pmk_r1_len, kdk_len;
*resp_ies = NULL;
*resp_ies_len = 0;
@@ -3091,8 +3139,6 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
sm->wpa_auth->conf.r1_key_holder, sm->addr,
pmk_r1_name, use_sha384) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
- pmk_r1_name, WPA_PMK_NAME_LEN);
if (conf->ft_psk_generate_local &&
wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
@@ -3150,10 +3196,18 @@ pmk_r1_derived:
wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
sm->ANonce, WPA_NONCE_LEN);
+ if (sm->wpa_auth->conf.force_kdk_derivation ||
+ (sm->wpa_auth->conf.secure_ltf &&
+ sm->rsnxe && sm->rsnxe_len >= 4 &&
+ sm->rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
if (wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
sm->addr, sm->wpa_auth->addr, pmk_r1_name,
&sm->PTK, ptk_name, sm->wpa_key_mgmt,
- pairwise) < 0)
+ pairwise, kdk_len) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
sm->pairwise = pairwise;
@@ -3460,6 +3514,7 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
struct wpa_channel_info ci;
int tx_chanwidth;
int tx_seg1_idx;
+ enum oci_verify_result res;
if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
wpa_printf(MSG_WARNING,
@@ -3473,10 +3528,21 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
&tx_seg1_idx) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ res = ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx);
+ if (wpa_auth_uses_ocv(sm) == 2 && res == OCI_NOT_FOUND) {
+ /* Work around misbehaving STAs */
+ wpa_printf(MSG_INFO,
+ "Disable OCV with a STA that does not send OCI");
+ wpa_auth_set_ocv(sm, 0);
+ } else if (res != OCI_SUCCESS) {
+ wpa_printf(MSG_WARNING, "OCV failed: %s", ocv_errorstr);
+ if (sm->wpa_auth->conf.msg_ctx)
+ wpa_msg(sm->wpa_auth->conf.msg_ctx, MSG_INFO,
+ OCV_FAILURE "addr=" MACSTR
+ " frame=ft-reassoc-req error=%s",
+ MAC2STR(sm->addr), ocv_errorstr);
+ return WLAN_STATUS_INVALID_FTIE;
}
}
#endif /* CONFIG_OCV */
@@ -3699,14 +3765,11 @@ static int wpa_ft_rrb_build_r0(const u8 *key, const size_t key_len,
{ .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
};
+ wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 for peer AP");
if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_len,
pmk_r0->pmk_r0_name, r1kh_id,
s1kh_id, pmk_r1, pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 (for peer AP)",
- pmk_r1, pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name (for peer AP)",
- pmk_r1_name, WPA_PMK_NAME_LEN);
WPA_PUT_LE16(f_pairwise, pmk_r0->pairwise);
os_get_reltime(&now);
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 05d87ac5..e7550185 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -14,6 +14,7 @@
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "common/wpa_ctrl.h"
+#include "common/ptksa_cache.h"
#include "crypto/sha1.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
@@ -175,6 +176,13 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->igtk_rsc_override_set = 1;
}
wconf->ft_rsnxe_used = conf->ft_rsnxe_used;
+ wconf->oci_freq_override_eapol_m3 = conf->oci_freq_override_eapol_m3;
+ wconf->oci_freq_override_eapol_g1 = conf->oci_freq_override_eapol_g1;
+ wconf->oci_freq_override_ft_assoc = conf->oci_freq_override_ft_assoc;
+ wconf->oci_freq_override_fils_assoc =
+ conf->oci_freq_override_fils_assoc;
+ wconf->skip_send_eapol = iconf->skip_send_eapol;
+ wconf->enable_eapol_large_timeout = iconf->enable_eapol_large_timeout;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
@@ -193,6 +201,9 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->sae_pwe = 1;
else if (sae_pw_id == 1 && wconf->sae_pwe == 0)
wconf->sae_pwe = 2;
+#ifdef CONFIG_SAE_PK
+ wconf->sae_pk = hostapd_sae_pk_in_use(conf);
+#endif /* CONFIG_SAE_PK */
#ifdef CONFIG_OWE
wconf->owe_ptk_workaround = conf->owe_ptk_workaround;
#endif /* CONFIG_OWE */
@@ -200,6 +211,11 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
#ifdef CONFIG_DPP2
wconf->dpp_pfs = conf->dpp_pfs;
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ wconf->force_kdk_derivation = conf->force_kdk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN */
}
@@ -904,6 +920,27 @@ static int hostapd_channel_info(void *ctx, struct wpa_channel_info *ci)
}
+#ifdef CONFIG_PASN
+
+static void hostapd_store_ptksa(void *ctx, const u8 *addr,int cipher,
+ u32 life_time, const struct wpa_ptk *ptk)
+{
+ struct hostapd_data *hapd = ctx;
+
+ ptksa_cache_add(hapd->ptksa, addr, cipher, life_time, ptk);
+}
+
+
+static void hostapd_clear_ptksa(void *ctx, const u8 *addr, int cipher)
+{
+ struct hostapd_data *hapd = ctx;
+
+ ptksa_cache_flush(hapd->ptksa, addr, cipher);
+}
+
+#endif /* CONFIG_PASN */
+
+
static int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id)
{
#ifndef CONFIG_NO_VLAN
@@ -1429,6 +1466,11 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
.send_oui = hostapd_wpa_auth_send_oui,
.channel_info = hostapd_channel_info,
.update_vlan = hostapd_wpa_auth_update_vlan,
+#ifdef CONFIG_PASN
+ .store_ptksa = hostapd_store_ptksa,
+ .clear_ptksa = hostapd_clear_ptksa,
+#endif /* CONFIG_PASN */
+
#ifdef CONFIG_OCV
.get_sta_tx_params = hostapd_get_sta_tx_params,
#endif /* CONFIG_OCV */
@@ -1451,6 +1493,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
size_t wpa_ie_len;
hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf);
+ _conf.msg_ctx = hapd->msg_ctx;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
_conf.tx_status = 1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
@@ -1471,6 +1514,22 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
else
_conf.extended_key_id = 0;
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION))
+ _conf.beacon_prot = 0;
+
+#ifdef CONFIG_OCV
+ if (!(hapd->iface->drv_flags2 &
+ (WPA_DRIVER_FLAGS2_AP_SME | WPA_DRIVER_FLAGS2_OCV)))
+ _conf.ocv = 0;
+#endif /* CONFIG_OCV */
+
+ _conf.secure_ltf =
+ !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF);
+ _conf.secure_rtt =
+ !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT);
+ _conf.prot_range_neg =
+ !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG);
+
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
if (hapd->wpa_auth == NULL) {
wpa_printf(MSG_ERROR, "WPA initialization failed.");
@@ -1496,6 +1555,12 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
return -1;
}
+ hapd->ptksa = ptksa_cache_init();
+ if (!hapd->ptksa) {
+ wpa_printf(MSG_ERROR, "Failed to allocate PTKSA cache");
+ return -1;
+ }
+
#ifdef CONFIG_IEEE80211R_AP
if (!hostapd_drv_none(hapd) &&
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
@@ -1535,6 +1600,9 @@ void hostapd_reconfig_wpa(struct hostapd_data *hapd)
void hostapd_deinit_wpa(struct hostapd_data *hapd)
{
ieee80211_tkip_countermeasures_deinit(hapd);
+ ptksa_cache_deinit(hapd->ptksa);
+ hapd->ptksa = NULL;
+
rsn_preauth_iface_deinit(hapd);
if (hapd->wpa_auth) {
wpa_deinit(hapd->wpa_auth);
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index ba08ac25..a6dc1a59 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -95,8 +95,9 @@ struct wpa_state_machine {
#endif /* CONFIG_IEEE80211R_AP */
unsigned int is_wnmsleep:1;
unsigned int pmkid_set:1;
+
#ifdef CONFIG_OCV
- unsigned int ocv_enabled:1;
+ int ocv_enabled;
#endif /* CONFIG_OCV */
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 8dfd6570..d4710316 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -88,13 +88,42 @@ static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
}
+static u16 wpa_own_rsn_capab(struct wpa_auth_config *conf)
+{
+ u16 capab = 0;
+
+ if (conf->rsn_preauth)
+ capab |= WPA_CAPABILITY_PREAUTH;
+ if (conf->wmm_enabled) {
+ /* 4 PTKSA replay counters when using WMM */
+ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
+ }
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ capab |= WPA_CAPABILITY_MFPC;
+ if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
+ capab |= WPA_CAPABILITY_MFPR;
+ }
+#ifdef CONFIG_OCV
+ if (conf->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+#endif /* CONFIG_OCV */
+#ifdef CONFIG_RSN_TESTING
+ if (rsn_testing)
+ capab |= BIT(8) | BIT(15);
+#endif /* CONFIG_RSN_TESTING */
+ if (conf->extended_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
+
+ return capab;
+}
+
+
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid)
{
struct rsn_ie_hdr *hdr;
int num_suites, res;
u8 *pos, *count;
- u16 capab;
u32 suite;
hdr = (struct rsn_ie_hdr *) buf;
@@ -260,6 +289,13 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
num_suites++;
}
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_PASN
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PASN);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_PASN */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -277,29 +313,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
WPA_PUT_LE16(count, num_suites);
/* RSN Capabilities */
- capab = 0;
- if (conf->rsn_preauth)
- capab |= WPA_CAPABILITY_PREAUTH;
- if (conf->wmm_enabled) {
- /* 4 PTKSA replay counters when using WMM */
- capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
- }
- if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
- capab |= WPA_CAPABILITY_MFPC;
- if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
- capab |= WPA_CAPABILITY_MFPR;
- }
-#ifdef CONFIG_OCV
- if (conf->ocv)
- capab |= WPA_CAPABILITY_OCVC;
-#endif /* CONFIG_OCV */
-#ifdef CONFIG_RSN_TESTING
- if (rsn_testing)
- capab |= BIT(8) | BIT(15);
-#endif /* CONFIG_RSN_TESTING */
- if (conf->extended_key_id)
- capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
- WPA_PUT_LE16(pos, capab);
+ WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
pos += 2;
if (pmkid) {
@@ -377,18 +391,38 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
{
u8 *pos = buf;
-
- if (conf->sae_pwe != 1 && conf->sae_pwe != 2)
+ u16 capab = 0;
+ size_t flen;
+
+ if (wpa_key_mgmt_sae(conf->wpa_key_mgmt) &&
+ (conf->sae_pwe == 1 || conf->sae_pwe == 2 || conf->sae_pk)) {
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (conf->sae_pk)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+ }
+
+ if (conf->secure_ltf)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+ if (conf->secure_rtt)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+ if (conf->prot_range_neg)
+ capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
+
+ flen = (capab & 0xff00) ? 2 : 1;
+ if (!capab)
return 0; /* no supported extended RSN capabilities */
-
- if (len < 3)
+ if (len < 2 + flen)
return -1;
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
*pos++ = WLAN_EID_RSNX;
- *pos++ = 1;
- /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
- * used for now */
- *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+ *pos++ = flen;
+ *pos++ = capab & 0x00ff;
+ capab >>= 8;
+ if (capab)
+ *pos++ = capab;
return pos - buf;
}
@@ -803,14 +837,26 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_SAE */
#ifdef CONFIG_OCV
- if ((data.capabilities & WPA_CAPABILITY_OCVC) &&
+ if (wpa_auth->conf.ocv && (data.capabilities & WPA_CAPABILITY_OCVC) &&
!(data.capabilities & WPA_CAPABILITY_MFPC)) {
- wpa_printf(MSG_DEBUG,
- "Management frame protection required with OCV, but client did not enable it");
- return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ /* Some legacy MFP incapable STAs wrongly copy OCVC bit from
+ * AP RSN capabilities. To improve interoperability with such
+ * legacy STAs allow connection without enabling OCV when the
+ * workaround mode (ocv=2) is enabled.
+ */
+ if (wpa_auth->conf.ocv == 2) {
+ wpa_printf(MSG_DEBUG,
+ "Allow connecting MFP incapable and OCV capable STA without enabling OCV");
+ wpa_auth_set_ocv(sm, 0);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "Management frame protection required with OCV, but client did not enable it");
+ return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ }
+ } else {
+ wpa_auth_set_ocv(sm, (data.capabilities & WPA_CAPABILITY_OCVC) ?
+ wpa_auth->conf.ocv : 0);
}
- wpa_auth_set_ocv(sm, wpa_auth->conf.ocv &&
- (data.capabilities & WPA_CAPABILITY_OCVC));
#endif /* CONFIG_OCV */
if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
@@ -1079,6 +1125,7 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
#ifdef CONFIG_FILS
+
u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
u8 *pos, size_t max_len,
const u8 *req_ies, size_t req_ies_len)
@@ -1095,4 +1142,91 @@ u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
return pos;
return pos + res;
}
+
+
+bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
+ u8 *fd_rsn_info)
+{
+ struct wpa_auth_config *conf;
+ u32 selectors = 0;
+ u8 *pos = fd_rsn_info;
+ int i, res;
+ u32 cipher, suite, selector, mask;
+ u8 tmp[10 * RSN_SELECTOR_LEN];
+
+ if (!wpa_auth)
+ return false;
+ conf = &wpa_auth->conf;
+
+ if (!(conf->wpa & WPA_PROTO_RSN))
+ return false;
+
+ /* RSN Capability (B0..B15) */
+ WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
+ pos += 2;
+
+ /* Group Data Cipher Suite Selector (B16..B21) */
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
+ if (suite == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
+ cipher = 63; /* No cipher suite selected */
+ if ((suite >> 8) == 0x000fac && ((suite & 0xff) <= 13))
+ cipher = suite & 0xff;
+ else
+ cipher = 62; /* vendor specific */
+ selectors |= cipher;
+
+ /* Group Management Cipher Suite Selector (B22..B27) */
+ cipher = 63; /* Default to no cipher suite selected */
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ switch (conf->group_mgmt_cipher) {
+ case WPA_CIPHER_AES_128_CMAC:
+ cipher = RSN_CIPHER_SUITE_AES_128_CMAC & 0xff;
+ break;
+ case WPA_CIPHER_BIP_GMAC_128:
+ cipher = RSN_CIPHER_SUITE_BIP_GMAC_128 & 0xff;
+ break;
+ case WPA_CIPHER_BIP_GMAC_256:
+ cipher = RSN_CIPHER_SUITE_BIP_GMAC_256 & 0xff;
+ break;
+ case WPA_CIPHER_BIP_CMAC_256:
+ cipher = RSN_CIPHER_SUITE_BIP_CMAC_256 & 0xff;
+ break;
+ }
+ }
+ selectors |= cipher << 6;
+
+ /* Pairwise Cipher Suite Selector (B28..B33) */
+ cipher = 63; /* Default to no cipher suite selected */
+ res = rsn_cipher_put_suites(tmp, conf->rsn_pairwise);
+ if (res == 1 && tmp[0] == 0x00 && tmp[1] == 0x0f && tmp[2] == 0xac &&
+ tmp[3] <= 13)
+ cipher = tmp[3];
+ selectors |= cipher << 12;
+
+ /* AKM Suite Selector (B34..B39) */
+ selector = 0; /* default to AKM from RSNE in Beacon/Probe Response */
+ mask = WPA_KEY_MGMT_FILS_SHA256 | WPA_KEY_MGMT_FILS_SHA384 |
+ WPA_KEY_MGMT_FT_FILS_SHA384;
+ if ((conf->wpa_key_mgmt & mask) && (conf->wpa_key_mgmt & ~mask) == 0) {
+ suite = conf->wpa_key_mgmt & mask;
+ if (suite == WPA_KEY_MGMT_FILS_SHA256)
+ selector = 1; /* 00-0f-ac:14 */
+ else if (suite == WPA_KEY_MGMT_FILS_SHA384)
+ selector = 2; /* 00-0f-ac:15 */
+ else if (suite == (WPA_KEY_MGMT_FILS_SHA256 |
+ WPA_KEY_MGMT_FILS_SHA384))
+ selector = 3; /* 00-0f-ac:14 or 00-0f-ac:15 */
+ else if (suite == WPA_KEY_MGMT_FT_FILS_SHA384)
+ selector = 4; /* 00-0f-ac:17 */
+ }
+ selectors |= selector << 18;
+
+ for (i = 0; i < 3; i++) {
+ *pos++ = selectors & 0xff;
+ selectors >>= 8;
+ }
+
+ return true;
+}
+
#endif /* CONFIG_FILS */
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index dc8aa8f6..e97dbf99 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1376,6 +1376,48 @@ static void hostapd_wps_nfc_clear(struct wps_context *wps)
}
+static int hostapd_wps_update_multi_ap(struct hostapd_data *hapd,
+ struct wps_registrar *reg)
+{
+ struct hostapd_bss_config *conf = hapd->conf;
+ u8 *multi_ap_backhaul_network_key = NULL;
+ size_t multi_ap_backhaul_network_key_len = 0;
+ int ret;
+
+ if (!(conf->multi_ap & FRONTHAUL_BSS) ||
+ !conf->multi_ap_backhaul_ssid.ssid_len)
+ return 0;
+
+ if (conf->multi_ap_backhaul_ssid.wpa_passphrase) {
+ multi_ap_backhaul_network_key =
+ (u8 *) os_strdup(
+ conf->multi_ap_backhaul_ssid.wpa_passphrase);
+ if (!multi_ap_backhaul_network_key)
+ return -1;
+ multi_ap_backhaul_network_key_len =
+ os_strlen(conf->multi_ap_backhaul_ssid.wpa_passphrase);
+ } else if (conf->multi_ap_backhaul_ssid.wpa_psk) {
+ multi_ap_backhaul_network_key = os_malloc(2 * PMK_LEN + 1);
+ if (!multi_ap_backhaul_network_key)
+ return -1;
+ wpa_snprintf_hex((char *) multi_ap_backhaul_network_key,
+ 2 * PMK_LEN + 1,
+ conf->multi_ap_backhaul_ssid.wpa_psk->psk,
+ PMK_LEN);
+ multi_ap_backhaul_network_key_len = 2 * PMK_LEN;
+ }
+
+ ret = wps_registrar_update_multi_ap(
+ reg, conf->multi_ap_backhaul_ssid.ssid,
+ conf->multi_ap_backhaul_ssid.ssid_len,
+ multi_ap_backhaul_network_key,
+ multi_ap_backhaul_network_key_len);
+ os_free(multi_ap_backhaul_network_key);
+
+ return ret;
+}
+
+
void hostapd_deinit_wps(struct hostapd_data *hapd)
{
eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
@@ -1398,22 +1440,65 @@ void hostapd_deinit_wps(struct hostapd_data *hapd)
void hostapd_update_wps(struct hostapd_data *hapd)
{
- if (hapd->wps == NULL)
+ struct wps_context *wps = hapd->wps;
+ struct hostapd_bss_config *conf = hapd->conf;
+
+ if (!wps)
return;
#ifdef CONFIG_WPS_UPNP
- hapd->wps->friendly_name = hapd->conf->friendly_name;
- hapd->wps->manufacturer_url = hapd->conf->manufacturer_url;
- hapd->wps->model_description = hapd->conf->model_description;
- hapd->wps->model_url = hapd->conf->model_url;
- hapd->wps->upc = hapd->conf->upc;
+ wps->friendly_name = conf->friendly_name;
+ wps->manufacturer_url = conf->manufacturer_url;
+ wps->model_description = conf->model_description;
+ wps->model_url = conf->model_url;
+ wps->upc = conf->upc;
#endif /* CONFIG_WPS_UPNP */
- hostapd_wps_set_vendor_ext(hapd, hapd->wps);
- hostapd_wps_set_application_ext(hapd, hapd->wps);
+ os_memcpy(wps->ssid, conf->ssid.ssid, conf->ssid.ssid_len);
+ wps->ssid_len = conf->ssid.ssid_len;
- if (hapd->conf->wps_state)
- wps_registrar_update_ie(hapd->wps->registrar);
+ /* Clear WPS settings, then fill them again */
+ os_free(wps->network_key);
+ wps->network_key = NULL;
+ wps->network_key_len = 0;
+ wps->psk_set = 0;
+ if (conf->ssid.wpa_psk_file) {
+ /* Use per-device PSKs */
+ } else if (conf->ssid.wpa_passphrase) {
+ wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase);
+ if (!wps->network_key)
+ return;
+ wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
+ } else if (conf->ssid.wpa_psk) {
+ wps->network_key = os_malloc(2 * PMK_LEN + 1);
+ if (!wps->network_key)
+ return;
+ wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
+ conf->ssid.wpa_psk->psk, PMK_LEN);
+ wps->network_key_len = 2 * PMK_LEN;
+#ifdef CONFIG_WEP
+ } else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
+ wps->network_key = os_malloc(conf->ssid.wep.len[0]);
+ if (!wps->network_key)
+ return;
+ os_memcpy(wps->network_key, conf->ssid.wep.key[0],
+ conf->ssid.wep.len[0]);
+ wps->network_key_len = conf->ssid.wep.len[0];
+#endif /* CONFIG_WEP */
+ }
+
+ if (conf->ssid.wpa_psk) {
+ os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN);
+ wps->psk_set = 1;
+ }
+
+ hostapd_wps_update_multi_ap(hapd, wps->registrar);
+
+ hostapd_wps_set_vendor_ext(hapd, wps);
+ hostapd_wps_set_application_ext(hapd, wps);
+
+ if (conf->wps_state)
+ wps_registrar_update_ie(wps->registrar);
else
hostapd_deinit_wps(hapd);
}
diff --git a/src/build.rules b/src/build.rules
new file mode 100644
index 00000000..acda8847
--- /dev/null
+++ b/src/build.rules
@@ -0,0 +1,109 @@
+.PHONY: all
+all: _all
+
+# disable built-in rules
+.SUFFIXES:
+
+# setup some variables
+ROOTDIR := $(dir $(lastword $(MAKEFILE_LIST)))
+ROOTDIR := $(dir $(ROOTDIR:%../src/=%))../
+BUILDDIR ?= $(abspath $(ROOTDIR)build)
+BUILDDIR := $(BUILDDIR:%/=%)
+ABSROOT := $(abspath $(ROOTDIR))
+ifeq ($(origin OUT),command line)
+_PROJ := $(OUT:%/=%)
+_PROJ := $(_PROJ:$(BUILDDIR)/%=%)
+else
+_PROJ := $(abspath $(dir $(firstword $(MAKEFILE_LIST))))
+_PROJ := $(_PROJ:$(ABSROOT)/%=%)
+endif
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef RANLIB
+RANLIB=ranlib
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+ifneq ($(CONFIG_FILE),)
+-include $(CONFIG_FILE)
+
+# export for sub-makefiles
+export CONFIG_CODE_COVERAGE
+
+.PHONY: verify_config
+verify_config:
+ @if [ ! -r $(CONFIG_FILE) ]; then \
+ echo 'Building $(firstword $(ALL)) requires a configuration file'; \
+ echo '(.config). See README for more instructions. You can'; \
+ echo 'run "cp defconfig .config" to create an example'; \
+ echo 'configuration.'; \
+ exit 1; \
+ fi
+VERIFY := verify_config
+else
+VERIFY :=
+endif
+
+# default target
+.PHONY: _all
+_all: $(VERIFY) $(ALL) $(EXTRA_TARGETS)
+
+# continue setup
+COVSUFFIX := $(if $(CONFIG_CODE_COVERAGE),-cov,)
+PROJ := $(_PROJ)$(COVSUFFIX)
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+ifeq ($(QUIET), 1)
+Q=@
+E=true
+endif
+
+ifeq ($(Q),@)
+MAKEFLAGS += --no-print-directory
+endif
+
+_DIRS := $(BUILDDIR)/$(PROJ)
+.PHONY: _make_dirs
+_make_dirs:
+ @mkdir -p $(_DIRS)
+
+$(BUILDDIR)/$(PROJ)/src/%.o: $(ROOTDIR)src/%.c $(CONFIG_FILE) | _make_dirs
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+$(BUILDDIR)/$(PROJ)/%.o: %.c $(CONFIG_FILE) | _make_dirs
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+# for the fuzzing tests
+$(BUILDDIR)/$(PROJ)/wpa_supplicant/%.o: $(ROOTDIR)wpa_supplicant/%.c $(CONFIG_FILE) | _make_dirs
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+
+# libraries - they know how to build themselves
+# (lib_phony so we recurse all the time)
+.PHONY: lib_phony
+lib_phony:
+# nothing
+
+$(BUILDDIR)/$(PROJ)/%.a: $(CONFIG_FILE) lib_phony
+ $(Q)$(MAKE) -C $(ROOTDIR)$(dir $(@:$(BUILDDIR)/$(PROJ)/%=%)) OUT=$(abspath $(dir $@))/
+
+BUILDOBJ = $(patsubst %,$(BUILDDIR)/$(PROJ)/%,$(patsubst $(ROOTDIR)%,%,$(1)))
+
+.PHONY: common-clean
+common-clean:
+ $(Q)rm -rf $(ALL) $(BUILDDIR)/$(PROJ)
diff --git a/src/common/Makefile b/src/common/Makefile
index ccb280e9..e2c5f03c 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -1,27 +1,16 @@
-all: libcommon.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libcommon.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_IEEE80211R
CFLAGS += -DCONFIG_HS20
CFLAGS += -DCONFIG_SAE
CFLAGS += -DCONFIG_SUITE
CFLAGS += -DCONFIG_SUITEB
+CFLAGS += -DCONFIG_PTKSA_CACHE
LIB_OBJS= \
gas.o \
hw_features_common.o \
ieee802_11_common.o \
sae.o \
+ ptksa_cache.o \
wpa_common.o
-libcommon.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/common/brcm_vendor.h b/src/common/brcm_vendor.h
new file mode 100644
index 00000000..0a44a6c9
--- /dev/null
+++ b/src/common/brcm_vendor.h
@@ -0,0 +1,75 @@
+/*
+ * Broadcom Corporation OUI and vendor specific assignments
+ * Copyright (c) 2015, Broadcom Corporation.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BRCM_VENDOR_H
+#define BRCM_VENDOR_H
+
+/*
+ * This file is a registry of identifier assignments from the Broadcom
+ * OUI 00:10:18 for purposes other than MAC address assignment. New identifiers
+ * can be assigned through normal review process for changes to the upstream
+ * hostap.git repository.
+ */
+
+#define OUI_BRCM 0x001018
+
+/**
+ * enum brcm_nl80211_vendor_subcmds - BRCM nl80211 vendor command identifiers
+ *
+ * @BRCM_VENDOR_SUBCMD_UNSPEC: Reserved value 0
+ *
+ * @BRCM_VENDOR_SUBCMD_PRIV_STR: String command/event
+ */
+enum brcm_nl80211_vendor_subcmds {
+ BRCM_VENDOR_SUBCMD_UNSPEC = 0,
+ BRCM_VENDOR_SUBCMD_SET_PMK = 4,
+ BRCM_VENDOR_SUBCMD_SET_MAC = 6,
+ BRCM_VENDOR_SCMD_ACS = 9,
+ BRCM_VENDOR_SCMD_MAX = 10
+};
+
+/**
+ * enum brcm_nl80211_vendor_events - BRCM nl80211 asynchoronous event identifiers
+ *
+ * @BRCM_VENDOR_EVENT_UNSPEC: Reserved value 0
+ *
+ * @BRCM_VENDOR_EVENT_PRIV_STR: String command/event
+ */
+enum brcm_nl80211_vendor_events {
+ BRCM_VENDOR_EVENT_UNSPEC,
+ BRCM_VENDOR_EVENT_ACS = 42,
+ BRCM_VENDOR_EVENT_LAST = 44
+};
+
+enum wl_vendor_attr_acs_offload {
+ BRCM_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
+ BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ,
+ BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ,
+ BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
+ BRCM_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
+
+ BRCM_VENDOR_ATTR_ACS_HW_MODE,
+ BRCM_VENDOR_ATTR_ACS_HT_ENABLED,
+ BRCM_VENDOR_ATTR_ACS_HT40_ENABLED,
+ BRCM_VENDOR_ATTR_ACS_VHT_ENABLED,
+ BRCM_VENDOR_ATTR_ACS_CHWIDTH,
+ BRCM_VENDOR_ATTR_ACS_CH_LIST,
+ BRCM_VENDOR_ATTR_ACS_FREQ_LIST,
+
+ BRCM_VENDOR_ATTR_ACS_LAST
+};
+
+enum brcm_wlan_vendor_attr {
+ BRCM_ATTR_DRIVER_CMD = 0,
+ BRCM_ATTR_DRIVER_KEY_PMK = 1,
+ BRCM_ATTR_DRIVER_MAC_ADDR = 3,
+ BRCM_ATTR_DRIVER_AFTER_LAST = 5,
+ BRCM_ATTR_DRIVER_MAX = BRCM_ATTR_DRIVER_AFTER_LAST - 1,
+};
+#endif /* BRCM_VENDOR_H */
+
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index a58bf666..50ce1923 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -548,6 +548,267 @@ fail:
}
+static int sae_pk_tests(void)
+{
+#ifdef CONFIG_SAE_PK
+ const char *invalid[] = { "a2bc-de3f-ghim-", "a2bcde3fghim", "", NULL };
+ struct {
+ const char *pw;
+ const u8 *val;
+ } valid[] = {
+ { "a2bc-de3f-ghim", (u8 *) "\x06\x82\x21\x93\x65\x31\xd0\xc0" },
+ { "aaaa-aaaa-aaaj", (u8 *) "\x00\x00\x00\x00\x00\x00\x00\x90" },
+ { "7777-7777-777f", (u8 *) "\xff\xff\xff\xff\xff\xff\xfe\x50" },
+ { NULL, NULL }
+ };
+ int i;
+ bool failed;
+
+ for (i = 0; invalid[i]; i++) {
+ if (sae_pk_valid_password(invalid[i])) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Invalid password '%s' not recognized",
+ invalid[i]);
+ return -1;
+ }
+ }
+
+ failed = false;
+ for (i = 0; valid[i].pw; i++) {
+ u8 *res;
+ size_t res_len;
+ char *b32;
+ const char *pw = valid[i].pw;
+ const u8 *val = valid[i].val;
+ size_t pw_len = os_strlen(pw);
+ size_t bits = (pw_len - pw_len / 5) * 5;
+ size_t bytes = (bits + 7) / 8;
+
+ if (!sae_pk_valid_password(pw)) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Valid password '%s' not recognized",
+ pw);
+ failed = true;
+ continue;
+ }
+
+ res = sae_pk_base32_decode(pw, pw_len, &res_len);
+ if (!res) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Failed to decode password '%s'",
+ valid[i].pw);
+ failed = true;
+ continue;
+ }
+ if (res_len != bytes || os_memcmp(val, res, res_len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Mismatch for decoded password '%s'",
+ valid[i].pw);
+ wpa_hexdump(MSG_INFO, "SAE-PK: Decoded value",
+ res, res_len);
+ wpa_hexdump(MSG_INFO, "SAE-PK: Expected value",
+ val, bytes);
+ failed = true;
+ }
+ os_free(res);
+
+ b32 = sae_pk_base32_encode(val, bits - 5);
+ if (!b32) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Failed to encode password '%s'",
+ pw);
+ failed = true;
+ continue;
+ }
+ if (os_strcmp(b32, pw) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Mismatch for password '%s'", pw);
+ wpa_printf(MSG_INFO, "SAE-PK: Encoded value: '%s'",
+ b32);
+ failed = true;
+ }
+ os_free(b32);
+ }
+
+ return failed ? -1 : 0;
+#else /* CONFIG_SAE_PK */
+ return 0;
+#endif /* CONFIG_SAE_PK */
+}
+
+
+#ifdef CONFIG_PASN
+
+static int pasn_test_pasn_auth(void)
+{
+ /* Test vector taken from IEEE P802.11az/D2.6, J.12 */
+ const u8 pmk[] = {
+ 0xde, 0xf4, 0x3e, 0x55, 0x67, 0xe0, 0x1c, 0xa6,
+ 0x64, 0x92, 0x65, 0xf1, 0x9a, 0x29, 0x0e, 0xef,
+ 0xf8, 0xbd, 0x88, 0x8f, 0x6c, 0x1d, 0x9c, 0xc9,
+ 0xd1, 0x0f, 0x04, 0xbd, 0x37, 0x8f, 0x3c, 0xad
+ };
+
+ const u8 spa_addr[] = {
+ 0x00, 0x90, 0x4c, 0x01, 0xc1, 0x07
+ };
+ const u8 bssid[] = {
+ 0xc0, 0xff, 0xd4, 0xa8, 0xdb, 0xc1
+ };
+ const u8 dhss[] = {
+ 0xf8, 0x7b, 0x20, 0x8e, 0x7e, 0xd2, 0xb7, 0x37,
+ 0xaf, 0xdb, 0xc2, 0xe1, 0x3e, 0xae, 0x78, 0xda,
+ 0x30, 0x01, 0x23, 0xd4, 0xd8, 0x4b, 0xa8, 0xb0,
+ 0xea, 0xfe, 0x90, 0xc4, 0x8c, 0xdf, 0x1f, 0x93
+ };
+ const u8 kck[] = {
+ 0x7b, 0xb8, 0x21, 0xac, 0x0a, 0xa5, 0x90, 0x9d,
+ 0xd6, 0x54, 0xa5, 0x60, 0x65, 0xad, 0x7c, 0x77,
+ 0xeb, 0x88, 0x9c, 0xbe, 0x29, 0x05, 0xbb, 0xf0,
+ 0x5a, 0xbb, 0x1e, 0xea, 0xc8, 0x8b, 0xa3, 0x06
+ };
+ const u8 tk[] = {
+ 0x67, 0x3e, 0xab, 0x46, 0xb8, 0x32, 0xd5, 0xa8,
+ 0x0c, 0xbc, 0x02, 0x43, 0x01, 0x6e, 0x20, 0x7e
+ };
+ const u8 kdk[] = {
+ 0x2d, 0x0f, 0x0e, 0x82, 0xc7, 0x0d, 0xd2, 0x6b,
+ 0x79, 0x06, 0x1a, 0x46, 0x81, 0xe8, 0xdb, 0xb2,
+ 0xea, 0x83, 0xbe, 0xa3, 0x99, 0x84, 0x4b, 0xd5,
+ 0x89, 0x4e, 0xb3, 0x20, 0xf6, 0x9d, 0x7d, 0xd6
+ };
+ struct wpa_ptk ptk;
+ int ret;
+
+ ret = pasn_pmk_to_ptk(pmk, sizeof(pmk),
+ spa_addr, bssid,
+ dhss, sizeof(dhss),
+ &ptk, WPA_KEY_MGMT_PASN, WPA_CIPHER_CCMP,
+ WPA_KDK_MAX_LEN);
+
+ if (ret)
+ return ret;
+
+ if (ptk.kck_len != sizeof(kck) ||
+ os_memcmp(kck, ptk.kck, sizeof(kck)) != 0) {
+ wpa_printf(MSG_ERROR, "PASN: Mismatched KCK");
+ return -1;
+ }
+
+ if (ptk.tk_len != sizeof(tk) ||
+ os_memcmp(tk, ptk.tk, sizeof(tk)) != 0) {
+ wpa_printf(MSG_ERROR, "PASN: Mismatched TK");
+ return -1;
+ }
+
+ if (ptk.kdk_len != sizeof(kdk) ||
+ os_memcmp(kdk, ptk.kdk, sizeof(kdk)) != 0) {
+ wpa_printf(MSG_ERROR, "PASN: Mismatched KDK");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int pasn_test_no_pasn_auth(void)
+{
+ /* Test vector taken from IEEE P802.11az/D2.6, J.13 */
+ const u8 pmk[] = {
+ 0xde, 0xf4, 0x3e, 0x55, 0x67, 0xe0, 0x1c, 0xa6,
+ 0x64, 0x92, 0x65, 0xf1, 0x9a, 0x29, 0x0e, 0xef,
+ 0xf8, 0xbd, 0x88, 0x8f, 0x6c, 0x1d, 0x9c, 0xc9,
+ 0xd1, 0x0f, 0x04, 0xbd, 0x37, 0x8f, 0x3c, 0xad
+ };
+ const u8 aa[] = {
+ 0xc0, 0xff, 0xd4, 0xa8, 0xdb, 0xc1
+ };
+ const u8 spa[] = {
+ 0x00, 0x90, 0x4c, 0x01, 0xc1, 0x07
+ };
+ const u8 anonce[] = {
+ 0xbe, 0x7a, 0x1c, 0xa2, 0x84, 0x34, 0x7b, 0x5b,
+ 0xd6, 0x7d, 0xbd, 0x2d, 0xfd, 0xb4, 0xd9, 0x9f,
+ 0x1a, 0xfa, 0xe0, 0xb8, 0x8b, 0xa1, 0x8e, 0x00,
+ 0x87, 0x18, 0x41, 0x7e, 0x4b, 0x27, 0xef, 0x5f
+ };
+ const u8 snonce[] = {
+ 0x40, 0x4b, 0x01, 0x2f, 0xfb, 0x43, 0xed, 0x0f,
+ 0xb4, 0x3e, 0xa1, 0xf2, 0x87, 0xc9, 0x1f, 0x25,
+ 0x06, 0xd2, 0x1b, 0x4a, 0x92, 0xd7, 0x4b, 0x5e,
+ 0xa5, 0x0c, 0x94, 0x33, 0x50, 0xce, 0x86, 0x71
+ };
+ const u8 kck[] = {
+ 0xcd, 0x7b, 0x9e, 0x75, 0x55, 0x36, 0x2d, 0xf0,
+ 0xb6, 0x35, 0x68, 0x48, 0x4a, 0x81, 0x12, 0xf5
+ };
+ const u8 kek[] = {
+ 0x99, 0xca, 0xd3, 0x58, 0x8d, 0xa0, 0xf1, 0xe6,
+ 0x3f, 0xd1, 0x90, 0x19, 0x10, 0x39, 0xbb, 0x4b
+ };
+ const u8 tk[] = {
+ 0x9e, 0x2e, 0x93, 0x77, 0xe7, 0x53, 0x2e, 0x73,
+ 0x7a, 0x1b, 0xc2, 0x50, 0xfe, 0x19, 0x4a, 0x03
+ };
+ const u8 kdk[] = {
+ 0x6c, 0x7f, 0xb9, 0x7c, 0xeb, 0x55, 0xb0, 0x1a,
+ 0xcf, 0xf0, 0x0f, 0x07, 0x09, 0x42, 0xbd, 0xf5,
+ 0x29, 0x1f, 0xeb, 0x4b, 0xee, 0x38, 0xe0, 0x36,
+ 0x5b, 0x25, 0xa2, 0x50, 0xbb, 0x2a, 0xc9, 0xff
+ };
+ struct wpa_ptk ptk;
+ int ret;
+
+ ret = wpa_pmk_to_ptk(pmk, sizeof(pmk),
+ "Pairwise key expansion",
+ spa, aa, snonce, anonce,
+ &ptk, WPA_KEY_MGMT_SAE, WPA_CIPHER_CCMP,
+ NULL, 0, WPA_KDK_MAX_LEN);
+
+ if (ret)
+ return ret;
+
+ if (ptk.kck_len != sizeof(kck) ||
+ os_memcmp(kck, ptk.kck, sizeof(kck)) != 0) {
+ wpa_printf(MSG_ERROR, "KDK no PASN auth: Mismatched KCK");
+ return -1;
+ }
+
+ if (ptk.kek_len != sizeof(kek) ||
+ os_memcmp(kek, ptk.kek, sizeof(kek)) != 0) {
+ wpa_printf(MSG_ERROR, "KDK no PASN auth: Mismatched KEK");
+ return -1;
+ }
+
+ if (ptk.tk_len != sizeof(tk) ||
+ os_memcmp(tk, ptk.tk, sizeof(tk)) != 0) {
+ wpa_printf(MSG_ERROR, "KDK no PASN auth: Mismatched TK");
+ return -1;
+ }
+
+ if (ptk.kdk_len != sizeof(kdk) ||
+ os_memcmp(kdk, ptk.kdk, sizeof(kdk)) != 0) {
+ wpa_printf(MSG_ERROR, "KDK no PASN auth: Mismatched KDK");
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_PASN */
+
+
+static int pasn_tests(void)
+{
+#ifdef CONFIG_PASN
+ if (pasn_test_pasn_auth() ||
+ pasn_test_no_pasn_auth())
+ return -1;
+#endif /* CONFIG_PASN */
+ return 0;
+}
+
+
int common_module_tests(void)
{
int ret = 0;
@@ -557,6 +818,8 @@ int common_module_tests(void)
if (ieee802_11_parse_tests() < 0 ||
gas_tests() < 0 ||
sae_tests() < 0 ||
+ sae_pk_tests() < 0 ||
+ pasn_tests() < 0 ||
rsn_ie_parse_tests() < 0)
ret = -1;
diff --git a/src/common/defs.h b/src/common/defs.h
index bbe3120d..f43bdb5d 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -49,6 +49,8 @@
#define WPA_KEY_MGMT_OWE BIT(22)
#define WPA_KEY_MGMT_DPP BIT(23)
#define WPA_KEY_MGMT_FT_IEEE8021X_SHA384 BIT(24)
+#define WPA_KEY_MGMT_PASN BIT(25)
+
#define WPA_KEY_MGMT_FT (WPA_KEY_MGMT_FT_PSK | \
WPA_KEY_MGMT_FT_IEEE8021X | \
@@ -388,9 +390,10 @@ enum mesh_plink_state {
};
enum set_band {
- WPA_SETBAND_AUTO,
- WPA_SETBAND_5G,
- WPA_SETBAND_2G
+ WPA_SETBAND_AUTO = 0,
+ WPA_SETBAND_5G = BIT(0),
+ WPA_SETBAND_2G = BIT(1),
+ WPA_SETBAND_6G = BIT(2),
};
enum wpa_radio_work_band {
@@ -402,7 +405,8 @@ enum wpa_radio_work_band {
enum beacon_rate_type {
BEACON_RATE_LEGACY,
BEACON_RATE_HT,
- BEACON_RATE_VHT
+ BEACON_RATE_VHT,
+ BEACON_RATE_HE
};
enum eap_proxy_sim_state {
diff --git a/src/common/dpp.c b/src/common/dpp.c
index d09f0d1c..e8697c5e 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -17,6 +17,7 @@
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "common/gas.h"
+#include "eap_common/eap_defs.h"
#include "crypto/crypto.h"
#include "crypto/random.h"
#include "crypto/aes.h"
@@ -244,6 +245,7 @@ int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
wpa_printf(MSG_DEBUG,
"DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
opclass, channel, freq);
+ bi->channels_listed = true;
if (freq < 0) {
wpa_printf(MSG_DEBUG,
"DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
@@ -828,6 +830,7 @@ struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
const char *tech = "infra";
const char *dpp_name;
struct wpabuf *buf, *json;
+ char *csr = NULL;
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
@@ -844,6 +847,17 @@ struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
if (mud_url && mud_url[0])
len += 10 + os_strlen(mud_url);
+#ifdef CONFIG_DPP2
+ if (auth->csr) {
+ size_t csr_len;
+
+ csr = base64_encode_no_lf(wpabuf_head(auth->csr),
+ wpabuf_len(auth->csr), &csr_len);
+ if (!csr)
+ return NULL;
+ len += 30 + csr_len;
+ }
+#endif /* CONFIG_DPP2 */
json = wpabuf_alloc(len);
if (!json)
return NULL;
@@ -870,10 +884,15 @@ struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
json_end_array(json);
}
+ if (csr) {
+ json_value_sep(json);
+ json_add_string(json, "pkcs10", csr);
+ }
json_end_object(json);
buf = dpp_build_conf_req(auth, wpabuf_head(json));
wpabuf_free(json);
+ os_free(csr);
return buf;
}
@@ -916,6 +935,8 @@ struct dpp_configuration * dpp_configuration_alloc(const char *type)
conf->akm = DPP_AKM_PSK_SAE_DPP;
else if (bin_str_eq(type, len, "dpp"))
conf->akm = DPP_AKM_DPP;
+ else if (bin_str_eq(type, len, "dot1x"))
+ conf->akm = DPP_AKM_DOT1X;
else
goto fail;
@@ -978,6 +999,7 @@ void dpp_configuration_free(struct dpp_configuration *conf)
return;
str_clear_free(conf->passphrase);
os_free(conf->group_id);
+ os_free(conf->csrattrs);
bin_clear_free(conf, sizeof(*conf));
}
@@ -988,6 +1010,7 @@ static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
const char *pos, *end;
struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
struct dpp_configuration *conf = NULL;
+ size_t len;
pos = os_strstr(cmd, " conf=sta-");
if (pos) {
@@ -1092,6 +1115,17 @@ static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
conf->netaccesskey_expiry = val;
}
+ pos = os_strstr(cmd, " csrattrs=");
+ if (pos) {
+ pos += 10;
+ end = os_strchr(pos, ' ');
+ len = end ? (size_t) (end - pos) : os_strlen(pos);
+ conf->csrattrs = os_zalloc(len + 1);
+ if (!conf->csrattrs)
+ goto fail;
+ os_memcpy(conf->csrattrs, pos, len);
+ }
+
if (!dpp_configuration_valid(conf))
goto fail;
@@ -1247,12 +1281,28 @@ void dpp_auth_deinit(struct dpp_authentication *auth)
os_free(conf->connector);
wpabuf_free(conf->c_sign_key);
+ wpabuf_free(conf->certbag);
+ wpabuf_free(conf->certs);
+ wpabuf_free(conf->cacert);
+ os_free(conf->server_name);
+ wpabuf_free(conf->pp_key);
}
#ifdef CONFIG_DPP2
dpp_free_asymmetric_key(auth->conf_key_pkg);
+ os_free(auth->csrattrs);
+ wpabuf_free(auth->csr);
+ wpabuf_free(auth->priv_key);
+ wpabuf_free(auth->cacert);
+ wpabuf_free(auth->certbag);
+ os_free(auth->trusted_eap_server_name);
+ wpabuf_free(auth->conf_resp_tcp);
#endif /* CONFIG_DPP2 */
wpabuf_free(auth->net_access_key);
dpp_bootstrap_info_free(auth->tmp_own_bi);
+ if (auth->tmp_peer_bi) {
+ dl_list_del(&auth->tmp_peer_bi->list);
+ dpp_bootstrap_info_free(auth->tmp_peer_bi);
+ }
#ifdef CONFIG_TESTING_OPTIONS
os_free(auth->config_obj_override);
os_free(auth->discovery_override);
@@ -1480,6 +1530,15 @@ skip_groups:
tailroom += os_strlen(signed_conn);
if (incl_legacy)
tailroom += 1000;
+ if (akm == DPP_AKM_DOT1X) {
+ if (auth->certbag)
+ tailroom += 2 * wpabuf_len(auth->certbag);
+ if (auth->cacert)
+ tailroom += 2 * wpabuf_len(auth->cacert);
+ if (auth->trusted_eap_server_name)
+ tailroom += os_strlen(auth->trusted_eap_server_name);
+ tailroom += 1000;
+ }
buf = dpp_build_conf_start(auth, conf, tailroom);
if (!buf)
goto fail;
@@ -1495,6 +1554,30 @@ skip_groups:
dpp_build_legacy_cred_params(buf, conf);
json_value_sep(buf);
}
+ if (akm == DPP_AKM_DOT1X) {
+ json_start_object(buf, "entCreds");
+ if (!auth->certbag)
+ goto fail;
+ json_add_base64(buf, "certBag", wpabuf_head(auth->certbag),
+ wpabuf_len(auth->certbag));
+ if (auth->cacert) {
+ json_value_sep(buf);
+ json_add_base64(buf, "caCert",
+ wpabuf_head(auth->cacert),
+ wpabuf_len(auth->cacert));
+ }
+ if (auth->trusted_eap_server_name) {
+ json_value_sep(buf);
+ json_add_string(buf, "trustedEapServerName",
+ auth->trusted_eap_server_name);
+ }
+ json_value_sep(buf);
+ json_start_array(buf, "eapMethods");
+ wpabuf_printf(buf, "%d", EAP_TYPE_TLS);
+ json_end_array(buf);
+ json_end_object(buf);
+ json_value_sep(buf);
+ }
wpabuf_put_str(buf, "\"signedConnector\":\"");
wpabuf_put_str(buf, signed_conn);
wpabuf_put_str(buf, "\"");
@@ -1504,6 +1587,16 @@ skip_groups:
wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
goto fail;
}
+#ifdef CONFIG_DPP2
+ if (auth->peer_version >= 2 && auth->conf->pp_key) {
+ json_value_sep(buf);
+ if (dpp_build_jwk(buf, "ppKey", auth->conf->pp_key, NULL,
+ curve) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to build ppKey JWK");
+ goto fail;
+ }
+ }
+#endif /* CONFIG_DPP2 */
json_end_object(buf);
json_end_object(buf);
@@ -1554,7 +1647,7 @@ dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
static struct wpabuf *
dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
- int idx)
+ int idx, bool cert_req)
{
struct dpp_configuration *conf = NULL;
@@ -1587,15 +1680,28 @@ dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
return NULL;
}
+ if (conf->akm == DPP_AKM_DOT1X) {
+ if (!auth->conf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No Configurator data available");
+ return NULL;
+ }
+ if (!cert_req && !auth->certbag) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No certificate data available for dot1x configuration");
+ return NULL;
+ }
+ return dpp_build_conf_obj_dpp(auth, conf);
+ }
if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
return dpp_build_conf_obj_dpp(auth, conf);
return dpp_build_conf_obj_legacy(auth, conf);
}
-static struct wpabuf *
+struct wpabuf *
dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
- u16 e_nonce_len, enum dpp_netrole netrole)
+ u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req)
{
struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL;
size_t clear_len, attr_len;
@@ -1605,21 +1711,33 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
size_t len[1];
enum dpp_status_error status;
+ if (auth->force_conf_resp_status != DPP_STATUS_OK) {
+ status = auth->force_conf_resp_status;
+ goto forced_status;
+ }
+
if (netrole == DPP_NETROLE_CONFIGURATOR) {
#ifdef CONFIG_DPP2
env_data = dpp_build_enveloped_data(auth);
#endif /* CONFIG_DPP2 */
} else {
- conf = dpp_build_conf_obj(auth, netrole, 0);
+ conf = dpp_build_conf_obj(auth, netrole, 0, cert_req);
if (conf) {
wpa_hexdump_ascii(MSG_DEBUG,
"DPP: configurationObject JSON",
wpabuf_head(conf), wpabuf_len(conf));
- conf2 = dpp_build_conf_obj(auth, netrole, 1);
+ conf2 = dpp_build_conf_obj(auth, netrole, 1, cert_req);
}
}
- status = (conf || env_data) ? DPP_STATUS_OK :
- DPP_STATUS_CONFIGURE_FAILURE;
+
+ if (conf || env_data)
+ status = DPP_STATUS_OK;
+ else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta &&
+ auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr)
+ status = DPP_STATUS_CSR_NEEDED;
+ else
+ status = DPP_STATUS_CONFIGURE_FAILURE;
+forced_status:
auth->conf_resp_status = status;
/* { E-nonce, configurationObject[, sendConnStatus]}ke */
@@ -1633,6 +1751,9 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
if (auth->peer_version >= 2 && auth->send_conn_status &&
netrole == DPP_NETROLE_STA)
clear_len += 4;
+ if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
+ auth->conf_sta->csrattrs)
+ clear_len += 4 + os_strlen(auth->conf_sta->csrattrs);
clear = wpabuf_alloc(clear_len);
attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
#ifdef CONFIG_TESTING_OPTIONS
@@ -1695,12 +1816,21 @@ skip_e_nonce:
}
if (auth->peer_version >= 2 && auth->send_conn_status &&
- netrole == DPP_NETROLE_STA) {
+ netrole == DPP_NETROLE_STA && status == DPP_STATUS_OK) {
wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
wpabuf_put_le16(clear, 0);
}
+ if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
+ auth->conf_sta->csrattrs) {
+ auth->waiting_csr = true;
+ wpa_printf(MSG_DEBUG, "DPP: CSR Attributes Request");
+ wpabuf_put_le16(clear, DPP_ATTR_CSR_ATTR_REQ);
+ wpabuf_put_le16(clear, os_strlen(auth->conf_sta->csrattrs));
+ wpabuf_put_str(clear, auth->conf_sta->csrattrs);
+ }
+
#ifdef CONFIG_TESTING_OPTIONS
skip_config_obj:
if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
@@ -1771,6 +1901,7 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
struct wpabuf *resp = NULL;
struct json_token *root = NULL, *token;
enum dpp_netrole netrole;
+ struct wpabuf *cert_req = NULL;
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
@@ -1879,6 +2010,7 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
dpp_auth_fail(auth, "Unsupported netRole");
goto fail;
}
+ auth->e_netrole = netrole;
token = json_get_member(root, "mudurl");
if (token && token->type == JSON_STRING) {
@@ -1930,9 +2062,56 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
txt);
}
- resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole);
+#ifdef CONFIG_DPP2
+ cert_req = json_get_member_base64(root, "pkcs10");
+ if (cert_req) {
+ char *txt;
+ int id;
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: CertificateRequest", cert_req);
+ if (dpp_validate_csr(auth, cert_req) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: CSR is not valid");
+ auth->force_conf_resp_status = DPP_STATUS_CSR_BAD;
+ goto cont;
+ }
+
+ if (auth->peer_bi) {
+ id = auth->peer_bi->id;
+ } else if (auth->tmp_peer_bi) {
+ id = auth->tmp_peer_bi->id;
+ } else {
+ struct dpp_bootstrap_info *bi;
+
+ bi = os_zalloc(sizeof(*bi));
+ if (!bi)
+ goto fail;
+ bi->id = dpp_next_id(auth->global);
+ dl_list_add(&auth->global->bootstrap, &bi->list);
+ auth->tmp_peer_bi = bi;
+ id = bi->id;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA");
+ txt = base64_encode_no_lf(wpabuf_head(cert_req),
+ wpabuf_len(cert_req), NULL);
+ if (!txt)
+ goto fail;
+
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_CSR "peer=%d csr=%s",
+ id, txt);
+ os_free(txt);
+ auth->waiting_csr = false;
+ auth->waiting_cert = true;
+ goto fail;
+ }
+cont:
+#endif /* CONFIG_DPP2 */
+
+ resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole,
+ cert_req);
fail:
+ wpabuf_free(cert_req);
json_free(root);
os_free(unwrapped);
return resp;
@@ -2255,6 +2434,20 @@ static void dpp_copy_csign(struct dpp_config_obj *conf, EVP_PKEY *csign)
}
+static void dpp_copy_ppkey(struct dpp_config_obj *conf, EVP_PKEY *ppkey)
+{
+ unsigned char *der = NULL;
+ int der_len;
+
+ der_len = i2d_PUBKEY(ppkey, &der);
+ if (der_len <= 0)
+ return;
+ wpabuf_free(conf->pp_key);
+ conf->pp_key = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+}
+
+
static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
struct dpp_config_obj *conf)
{
@@ -2290,10 +2483,10 @@ static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
struct json_token *cred)
{
struct dpp_signed_connector_info info;
- struct json_token *token, *csign;
+ struct json_token *token, *csign, *ppkey;
int ret = -1;
- EVP_PKEY *csign_pub = NULL;
- const struct dpp_curve_params *key_curve = NULL;
+ EVP_PKEY *csign_pub = NULL, *pp_pub = NULL;
+ const struct dpp_curve_params *key_curve = NULL, *pp_curve = NULL;
const char *signed_connector;
os_memset(&info, 0, sizeof(info));
@@ -2320,6 +2513,21 @@ static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
}
dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
+ ppkey = json_get_member(cred, "ppKey");
+ if (ppkey && ppkey->type == JSON_OBJECT) {
+ pp_pub = dpp_parse_jwk(ppkey, &pp_curve);
+ if (!pp_pub) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to parse ppKey JWK");
+ goto fail;
+ }
+ dpp_debug_print_key("DPP: Received ppKey", pp_pub);
+ if (key_curve != pp_curve) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: C-sign-key and ppKey do not use the same curve");
+ goto fail;
+ }
+ }
+
token = json_get_member(cred, "signedConnector");
if (!token || token->type != JSON_STRING) {
wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
@@ -2350,17 +2558,72 @@ static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
conf->connector = os_strdup(signed_connector);
dpp_copy_csign(conf, csign_pub);
+ if (pp_pub)
+ dpp_copy_ppkey(conf, pp_pub);
if (dpp_akm_dpp(conf->akm) || auth->peer_version >= 2)
dpp_copy_netaccesskey(auth, conf);
ret = 0;
fail:
EVP_PKEY_free(csign_pub);
+ EVP_PKEY_free(pp_pub);
os_free(info.payload);
return ret;
}
+#ifdef CONFIG_DPP2
+static int dpp_parse_cred_dot1x(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf,
+ struct json_token *cred)
+{
+ struct json_token *ent, *name;
+
+ ent = json_get_member(cred, "entCreds");
+ if (!ent || ent->type != JSON_OBJECT) {
+ dpp_auth_fail(auth, "No entCreds in JSON");
+ return -1;
+ }
+
+ conf->certbag = json_get_member_base64(ent, "certBag");
+ if (!conf->certbag) {
+ dpp_auth_fail(auth, "No certBag in JSON");
+ return -1;
+ }
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received certBag", conf->certbag);
+ conf->certs = dpp_pkcs7_certs(conf->certbag);
+ if (!conf->certs) {
+ dpp_auth_fail(auth, "No certificates in certBag");
+ return -1;
+ }
+
+ conf->cacert = json_get_member_base64(ent, "caCert");
+ if (conf->cacert)
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received caCert",
+ conf->cacert);
+
+ name = json_get_member(ent, "trustedEapServerName");
+ if (name &&
+ (name->type != JSON_STRING ||
+ has_ctrl_char((const u8 *) name->string,
+ os_strlen(name->string)))) {
+ dpp_auth_fail(auth,
+ "Invalid trustedEapServerName type in JSON");
+ return -1;
+ }
+ if (name && name->string) {
+ wpa_printf(MSG_DEBUG, "DPP: Received trustedEapServerName: %s",
+ name->string);
+ conf->server_name = os_strdup(name->string);
+ if (!conf->server_name)
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_DPP2 */
+
+
const char * dpp_akm_str(enum dpp_akm akm)
{
switch (akm) {
@@ -2376,6 +2639,8 @@ const char * dpp_akm_str(enum dpp_akm akm)
return "dpp+sae";
case DPP_AKM_PSK_SAE_DPP:
return "dpp+psk+sae";
+ case DPP_AKM_DOT1X:
+ return "dot1x";
default:
return "??";
}
@@ -2397,6 +2662,8 @@ const char * dpp_akm_selector_str(enum dpp_akm akm)
return "506F9A02+000FAC08";
case DPP_AKM_PSK_SAE_DPP:
return "506F9A02+000FAC08+000FAC02+000FAC06";
+ case DPP_AKM_DOT1X:
+ return "000FAC01+000FAC05";
default:
return "??";
}
@@ -2406,7 +2673,7 @@ const char * dpp_akm_selector_str(enum dpp_akm akm)
static enum dpp_akm dpp_akm_from_str(const char *akm)
{
const char *pos;
- int dpp = 0, psk = 0, sae = 0;
+ int dpp = 0, psk = 0, sae = 0, dot1x = 0;
if (os_strcmp(akm, "psk") == 0)
return DPP_AKM_PSK;
@@ -2420,6 +2687,8 @@ static enum dpp_akm dpp_akm_from_str(const char *akm)
return DPP_AKM_SAE_DPP;
if (os_strcmp(akm, "dpp+psk+sae") == 0)
return DPP_AKM_PSK_SAE_DPP;
+ if (os_strcmp(akm, "dot1x") == 0)
+ return DPP_AKM_DOT1X;
pos = akm;
while (*pos) {
@@ -2433,6 +2702,10 @@ static enum dpp_akm dpp_akm_from_str(const char *akm)
psk = 1;
else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
sae = 1;
+ else if (os_strncasecmp(pos, "000FAC01", 8) == 0)
+ dot1x = 1;
+ else if (os_strncasecmp(pos, "000FAC05", 8) == 0)
+ dot1x = 1;
pos += 8;
if (*pos != '+')
break;
@@ -2451,6 +2724,8 @@ static enum dpp_akm dpp_akm_from_str(const char *akm)
return DPP_AKM_SAE;
if (psk)
return DPP_AKM_PSK;
+ if (dot1x)
+ return DPP_AKM_DOT1X;
return DPP_AKM_UNKNOWN;
}
@@ -2568,6 +2843,12 @@ static int dpp_parse_conf_obj(struct dpp_authentication *auth,
(auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
goto fail;
+#ifdef CONFIG_DPP2
+ } else if (conf->akm == DPP_AKM_DOT1X) {
+ if (dpp_parse_cred_dot1x(auth, conf, cred) < 0 ||
+ dpp_parse_cred_dpp(auth, conf, cred) < 0)
+ goto fail;
+#endif /* CONFIG_DPP2 */
} else {
wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
token->string);
@@ -2584,6 +2865,20 @@ fail:
}
+#ifdef CONFIG_DPP2
+static u8 * dpp_get_csr_attrs(const u8 *attrs, size_t attrs_len, size_t *len)
+{
+ const u8 *b64;
+ u16 b64_len;
+
+ b64 = dpp_get_attr(attrs, attrs_len, DPP_ATTR_CSR_ATTR_REQ, &b64_len);
+ if (!b64)
+ return NULL;
+ return base64_decode((const char *) b64, b64_len, len);
+}
+#endif /* CONFIG_DPP2 */
+
+
int dpp_conf_resp_rx(struct dpp_authentication *auth,
const struct wpabuf *resp)
{
@@ -2661,6 +2956,28 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth,
}
auth->conf_resp_status = status[0];
wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
+#ifdef CONFIG_DPP2
+ if (status[0] == DPP_STATUS_CSR_NEEDED) {
+ u8 *csrattrs;
+ size_t csrattrs_len;
+
+ wpa_printf(MSG_DEBUG, "DPP: Configurator requested CSR");
+
+ csrattrs = dpp_get_csr_attrs(unwrapped, unwrapped_len,
+ &csrattrs_len);
+ if (!csrattrs) {
+ dpp_auth_fail(auth,
+ "Missing or invalid CSR Attributes Request attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: CsrAttrs", csrattrs, csrattrs_len);
+ os_free(auth->csrattrs);
+ auth->csrattrs = csrattrs;
+ auth->csrattrs_len = csrattrs_len;
+ ret = -2;
+ goto fail;
+ }
+#endif /* CONFIG_DPP2 */
if (status[0] != DPP_STATUS_OK) {
dpp_auth_fail(auth, "Configurator rejected configuration");
goto fail;
@@ -3086,6 +3403,7 @@ void dpp_configurator_free(struct dpp_configurator *conf)
os_free(conf->kid);
os_free(conf->connector);
EVP_PKEY_free(conf->connector_key);
+ EVP_PKEY_free(conf->pp_key);
os_free(conf);
}
@@ -3144,9 +3462,9 @@ static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
}
-struct dpp_configurator *
+static struct dpp_configurator *
dpp_keygen_configurator(const char *curve, const u8 *privkey,
- size_t privkey_len)
+ size_t privkey_len, const u8 *pp_key, size_t pp_key_len)
{
struct dpp_configurator *conf;
@@ -3166,7 +3484,12 @@ dpp_keygen_configurator(const char *curve, const u8 *privkey,
privkey_len);
else
conf->csign = dpp_gen_keypair(conf->curve);
- if (!conf->csign)
+ if (pp_key)
+ conf->pp_key = dpp_set_keypair(&conf->curve, pp_key,
+ pp_key_len);
+ else
+ conf->pp_key = dpp_gen_keypair(conf->curve);
+ if (!conf->csign || !conf->pp_key)
goto fail;
conf->own = 1;
@@ -3207,7 +3530,7 @@ int dpp_configurator_own_config(struct dpp_authentication *auth,
auth->peer_protocol_key = auth->own_protocol_key;
dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
- conf_obj = dpp_build_conf_obj(auth, ap, 0);
+ conf_obj = dpp_build_conf_obj(auth, ap, 0, NULL);
if (!conf_obj) {
wpabuf_free(auth->conf_obj[0].c_sign_key);
auth->conf_obj[0].c_sign_key = NULL;
@@ -3762,11 +4085,11 @@ static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
u8 op_class, channel;
char chan[20];
- if (peer_bi->num_freq == 0)
+ if (peer_bi->num_freq == 0 && !peer_bi->channels_listed)
return 0; /* no channel preference/constraint */
for (i = 0; i < peer_bi->num_freq; i++) {
- if (own_bi->num_freq == 0 ||
+ if ((own_bi->num_freq == 0 && !own_bi->channels_listed) ||
freq_included(own_bi->freq, own_bi->num_freq,
peer_bi->freq[i])) {
freq = peer_bi->freq[i];
@@ -3853,14 +4176,15 @@ static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
{
char *curve = NULL;
- char *key = NULL;
- u8 *privkey = NULL;
- size_t privkey_len = 0;
+ char *key = NULL, *ppkey = NULL;
+ u8 *privkey = NULL, *pp_key = NULL;
+ size_t privkey_len = 0, pp_key_len = 0;
int ret = -1;
struct dpp_configurator *conf = NULL;
curve = get_param(cmd, " curve=");
key = get_param(cmd, " key=");
+ ppkey = get_param(cmd, " ppkey=");
if (key) {
privkey_len = os_strlen(key) / 2;
@@ -3870,7 +4194,16 @@ int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
goto fail;
}
- conf = dpp_keygen_configurator(curve, privkey, privkey_len);
+ if (ppkey) {
+ pp_key_len = os_strlen(ppkey) / 2;
+ pp_key = os_malloc(pp_key_len);
+ if (!pp_key ||
+ hexstr2bin(ppkey, pp_key, pp_key_len) < 0)
+ goto fail;
+ }
+
+ conf = dpp_keygen_configurator(curve, privkey, privkey_len,
+ pp_key, pp_key_len);
if (!conf)
goto fail;
@@ -3881,7 +4214,9 @@ int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
fail:
os_free(curve);
str_clear_free(key);
+ str_clear_free(ppkey);
bin_clear_free(privkey, privkey_len);
+ bin_clear_free(pp_key, pp_key_len);
dpp_configurator_free(conf);
return ret;
}
@@ -3945,12 +4280,12 @@ int dpp_configurator_from_backup(struct dpp_global *dpp,
struct dpp_asymmetric_key *key)
{
struct dpp_configurator *conf;
- const EC_KEY *eckey;
- const EC_GROUP *group;
+ const EC_KEY *eckey, *eckey_pp;
+ const EC_GROUP *group, *group_pp;
int nid;
const struct dpp_curve_params *curve;
- if (!key->csign)
+ if (!key->csign || !key->pp_key)
return -1;
eckey = EVP_PKEY_get0_EC_KEY(key->csign);
if (!eckey)
@@ -3964,6 +4299,18 @@ int dpp_configurator_from_backup(struct dpp_global *dpp,
wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
return -1;
}
+ eckey_pp = EVP_PKEY_get0_EC_KEY(key->pp_key);
+ if (!eckey_pp)
+ return -1;
+ group_pp = EC_KEY_get0_group(eckey_pp);
+ if (!group_pp)
+ return -1;
+ if (EC_GROUP_get_curve_name(group) !=
+ EC_GROUP_get_curve_name(group_pp)) {
+ wpa_printf(MSG_INFO,
+ "DPP: Mismatch in c-sign-key and ppKey groups");
+ return -1;
+ }
conf = os_zalloc(sizeof(*conf));
if (!conf)
@@ -3971,6 +4318,8 @@ int dpp_configurator_from_backup(struct dpp_global *dpp,
conf->curve = curve;
conf->csign = key->csign;
key->csign = NULL;
+ conf->pp_key = key->pp_key;
+ key->pp_key = NULL;
conf->own = 1;
if (dpp_configurator_gen_kid(conf) < 0) {
dpp_configurator_free(conf);
@@ -4009,10 +4358,8 @@ struct dpp_global * dpp_global_init(struct dpp_global_config *config)
dpp = os_zalloc(sizeof(*dpp));
if (!dpp)
return NULL;
- dpp->msg_ctx = config->msg_ctx;
#ifdef CONFIG_DPP2
dpp->cb_ctx = config->cb_ctx;
- dpp->process_conf_obj = config->process_conf_obj;
dpp->remove_bi = config->remove_bi;
#endif /* CONFIG_DPP2 */
@@ -4050,6 +4397,7 @@ void dpp_global_deinit(struct dpp_global *dpp)
#ifdef CONFIG_DPP2
+
struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
{
struct wpabuf *msg;
@@ -4066,4 +4414,17 @@ struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
"DPP: Presence Announcement frame attributes", msg);
return msg;
}
+
+
+void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
+ unsigned int freq, const u8 *hash)
+{
+ char hex[SHA256_MAC_LEN * 2 + 1];
+
+ wpa_snprintf_hex(hex, sizeof(hex), hash, SHA256_MAC_LEN);
+ wpa_msg(msg_ctx, MSG_INFO,
+ DPP_EVENT_CHIRP_RX "id=%d src=" MACSTR " freq=%u hash=%s",
+ id, MAC2STR(src), freq, hex);
+}
+
#endif /* CONFIG_DPP2 */
diff --git a/src/common/dpp.h b/src/common/dpp.h
index d77762e9..6e397c3d 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -21,6 +21,7 @@ struct crypto_ecdh;
struct hostapd_ip_addr;
struct dpp_global;
struct json_token;
+struct dpp_reconfig_id;
#ifdef CONFIG_TESTING_OPTIONS
#define DPP_VERSION (dpp_version_override)
@@ -34,7 +35,7 @@ extern int dpp_version_override;
#endif /* CONFIG_TESTING_OPTIONS */
#define DPP_HDR_LEN (4 + 2) /* OUI, OUI Type, Crypto Suite, DPP frame type */
-#define DPP_TCP_PORT 7871
+#define DPP_TCP_PORT 8908
enum dpp_public_action_frame_type {
DPP_PA_AUTHENTICATION_REQ = 0,
@@ -87,6 +88,9 @@ enum dpp_attribute_id {
DPP_ATTR_RECONFIG_FLAGS = 0x101D,
DPP_ATTR_C_SIGN_KEY_HASH = 0x101E,
DPP_ATTR_CSR_ATTR_REQ = 0x101F,
+ DPP_ATTR_A_NONCE = 0x1020,
+ DPP_ATTR_E_PRIME_ID = 0x1021,
+ DPP_ATTR_CONFIGURATOR_NONCE = 0x1022,
};
enum dpp_status_error {
@@ -120,6 +124,7 @@ enum dpp_connector_key {
#define DPP_MAX_NONCE_LEN 32
#define DPP_MAX_HASH_LEN 64
#define DPP_MAX_SHARED_SECRET_LEN 66
+#define DPP_CP_LEN 64
struct dpp_curve_params {
const char *name;
@@ -149,6 +154,7 @@ struct dpp_bootstrap_info {
char *pk;
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
unsigned int num_freq;
+ bool channels_listed;
u8 version;
int own;
EVP_PKEY *pubkey;
@@ -196,6 +202,7 @@ enum dpp_akm {
DPP_AKM_PSK_SAE,
DPP_AKM_SAE_DPP,
DPP_AKM_PSK_SAE_DPP,
+ DPP_AKM_DOT1X,
};
enum dpp_netrole {
@@ -221,11 +228,14 @@ struct dpp_configuration {
char *passphrase;
u8 psk[32];
int psk_set;
+
+ char *csrattrs;
};
struct dpp_asymmetric_key {
struct dpp_asymmetric_key *next;
EVP_PKEY *csign;
+ EVP_PKEY *pp_key;
char *config_template;
char *connector_template;
};
@@ -241,18 +251,22 @@ struct dpp_authentication {
struct dpp_bootstrap_info *peer_bi;
struct dpp_bootstrap_info *own_bi;
struct dpp_bootstrap_info *tmp_own_bi;
+ struct dpp_bootstrap_info *tmp_peer_bi;
u8 waiting_pubkey_hash[SHA256_MAC_LEN];
int response_pending;
int reconfig;
enum dpp_connector_key reconfig_connector_key;
enum dpp_status_error auth_resp_status;
enum dpp_status_error conf_resp_status;
+ enum dpp_status_error force_conf_resp_status;
u8 peer_mac_addr[ETH_ALEN];
u8 i_nonce[DPP_MAX_NONCE_LEN];
u8 r_nonce[DPP_MAX_NONCE_LEN];
u8 e_nonce[DPP_MAX_NONCE_LEN];
+ u8 c_nonce[DPP_MAX_NONCE_LEN];
u8 i_capab;
u8 r_capab;
+ enum dpp_netrole e_netrole;
EVP_PKEY *own_protocol_key;
EVP_PKEY *peer_protocol_key;
EVP_PKEY *reconfig_old_protocol_key;
@@ -293,6 +307,7 @@ struct dpp_authentication {
bool reconfig_success;
struct wpabuf *conf_req;
const struct wpabuf *conf_resp; /* owned by GAS server */
+ struct wpabuf *conf_resp_tcp;
struct dpp_configuration *conf_ap;
struct dpp_configuration *conf2_ap;
struct dpp_configuration *conf_sta;
@@ -309,6 +324,11 @@ struct dpp_authentication {
int psk_set;
enum dpp_akm akm;
struct wpabuf *c_sign_key;
+ struct wpabuf *certbag;
+ struct wpabuf *certs;
+ struct wpabuf *cacert;
+ char *server_name;
+ struct wpabuf *pp_key;
} conf_obj[DPP_MAX_CONF_OBJ];
unsigned int num_conf_obj;
struct dpp_asymmetric_key *conf_key_pkg;
@@ -319,6 +339,17 @@ struct dpp_authentication {
int akm_use_selector;
int configurator_set;
u8 transaction_id;
+ u8 *csrattrs;
+ size_t csrattrs_len;
+ bool waiting_csr;
+ struct wpabuf *csr;
+ struct wpabuf *priv_key; /* DER-encoded private key used for csr */
+ bool waiting_cert;
+ char *trusted_eap_server_name;
+ struct wpabuf *cacert;
+ struct wpabuf *certbag;
+ void *cert_resp_ctx;
+ void *gas_server_ctx;
#ifdef CONFIG_TESTING_OPTIONS
char *config_obj_override;
char *discovery_override;
@@ -339,6 +370,7 @@ struct dpp_configurator {
const struct dpp_curve_params *curve;
char *connector; /* own Connector for reconfiguration */
EVP_PKEY *connector_key;
+ EVP_PKEY *pp_key;
};
struct dpp_introduction {
@@ -351,6 +383,7 @@ struct dpp_relay_config {
const struct hostapd_ip_addr *ipaddr;
const u8 *pkhash;
+ void *msg_ctx;
void *cb_ctx;
void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
size_t len);
@@ -362,6 +395,11 @@ struct dpp_controller_config {
const char *configurator_params;
int tcp_port;
u8 allowed_roles;
+ int qr_mutual;
+ enum dpp_netrole netrole;
+ void *msg_ctx;
+ void *cb_ctx;
+ int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
};
#ifdef CONFIG_TESTING_OPTIONS
@@ -519,6 +557,10 @@ void dpp_configuration_free(struct dpp_configuration *conf);
int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd);
void dpp_auth_deinit(struct dpp_authentication *auth);
struct wpabuf *
+dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
+ u16 e_nonce_len, enum dpp_netrole netrole,
+ bool cert_req);
+struct wpabuf *
dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
size_t attr_len);
int dpp_conf_resp_rx(struct dpp_authentication *auth,
@@ -548,9 +590,6 @@ const char * dpp_akm_selector_str(enum dpp_akm akm);
int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
size_t buflen);
void dpp_configurator_free(struct dpp_configurator *conf);
-struct dpp_configurator *
-dpp_keygen_configurator(const char *curve, const u8 *privkey,
- size_t privkey_len);
int dpp_configurator_own_config(struct dpp_authentication *auth,
const char *curve, int ap);
enum dpp_status_error
@@ -595,6 +634,11 @@ struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len);
void dpp_pfs_free(struct dpp_pfs *pfs);
+struct wpabuf * dpp_build_csr(struct dpp_authentication *auth,
+ const char *name);
+struct wpabuf * dpp_pkcs7_certs(const struct wpabuf *pkcs7);
+int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr);
+
struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
const char *uri);
struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
@@ -634,14 +678,23 @@ int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
int dpp_controller_start(struct dpp_global *dpp,
struct dpp_controller_config *config);
void dpp_controller_stop(struct dpp_global *dpp);
+struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp,
+ unsigned int id);
+void dpp_controller_new_qr_code(struct dpp_global *dpp,
+ struct dpp_bootstrap_info *bi);
int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
- const struct hostapd_ip_addr *addr, int port);
+ const struct hostapd_ip_addr *addr, int port,
+ const char *name, enum dpp_netrole netrole, void *msg_ctx,
+ void *cb_ctx,
+ int (*process_conf_obj)(void *ctx,
+ struct dpp_authentication *auth));
+
struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi);
+void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
+ unsigned int freq, const u8 *hash);
struct dpp_global_config {
- void *msg_ctx;
void *cb_ctx;
- int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
};
@@ -652,10 +705,15 @@ void dpp_global_deinit(struct dpp_global *dpp);
/* dpp_reconfig.c */
struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
- size_t csign_key_len);
+ size_t csign_key_len,
+ const u8 *net_access_key,
+ size_t net_access_key_len,
+ struct dpp_reconfig_id *id);
struct dpp_authentication *
dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
- struct dpp_configurator *conf, unsigned int freq);
+ struct dpp_configurator *conf, unsigned int freq, u16 group,
+ const u8 *a_nonce_attr, size_t a_nonce_len,
+ const u8 *e_id_attr, size_t e_id_len);
struct dpp_authentication *
dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx,
const char *own_connector,
@@ -669,5 +727,12 @@ dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len);
+struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
+ size_t csign_key_len,
+ const u8 *pp_key,
+ size_t pp_key_len);
+int dpp_update_reconfig_id(struct dpp_reconfig_id *id);
+void dpp_free_reconfig_id(struct dpp_reconfig_id *id);
+
#endif /* CONFIG_DPP */
#endif /* DPP_H */
diff --git a/src/common/dpp_auth.c b/src/common/dpp_auth.c
index f79cfef4..0cabd647 100644
--- a/src/common/dpp_auth.c
+++ b/src/common/dpp_auth.c
@@ -251,6 +251,7 @@ static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
u8 *attr_start, *attr_end, *pos;
auth->waiting_auth_conf = 1;
+ auth->auth_resp_status = status;
auth->auth_resp_tries = 0;
/* Build DPP Authentication Response frame attributes */
diff --git a/src/common/dpp_backup.c b/src/common/dpp_backup.c
index c675c427..3b81f096 100644
--- a/src/common/dpp_backup.c
+++ b/src/common/dpp_backup.c
@@ -40,6 +40,7 @@ void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key)
struct dpp_asymmetric_key *next = key->next;
EVP_PKEY_free(key->csign);
+ EVP_PKEY_free(key->pp_key);
str_clear_free(key->config_template);
str_clear_free(key->connector_template);
os_free(key);
@@ -48,35 +49,62 @@ void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key)
}
-static struct wpabuf * dpp_build_conf_params(void)
+static struct wpabuf * dpp_build_conf_params(struct dpp_configurator *conf)
{
- struct wpabuf *buf;
+ struct wpabuf *buf, *priv_key = NULL;
size_t len;
/* TODO: proper template values */
const char *conf_template = "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
const char *connector_template = NULL;
+ EC_KEY *eckey;
+ unsigned char *der = NULL;
+ int der_len;
+
+ if (!conf->pp_key)
+ return NULL;
+ eckey = EVP_PKEY_get0_EC_KEY(conf->pp_key);
+ if (!eckey)
+ return NULL;
+
+ EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
+ der_len = i2d_ECPrivateKey(eckey, &der);
+ if (der_len > 0)
+ priv_key = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+ if (!priv_key)
+ goto fail;
len = 100 + os_strlen(conf_template);
if (connector_template)
len += os_strlen(connector_template);
+ if (priv_key)
+ len += wpabuf_len(priv_key);
buf = wpabuf_alloc(len);
if (!buf)
- return NULL;
+ goto fail;
/*
* DPPConfigurationParameters ::= SEQUENCE {
+ * privacyProtectionKey PrivateKey,
* configurationTemplate UTF8String,
* connectorTemplate UTF8String OPTIONAL}
*/
+ /* PrivateKey ::= OCTET STRING */
+ asn1_put_octet_string(buf, priv_key);
+
asn1_put_utf8string(buf, conf_template);
if (connector_template)
asn1_put_utf8string(buf, connector_template);
+ wpabuf_clear_free(priv_key);
return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+fail:
+ wpabuf_clear_free(priv_key);
+ return NULL;
}
-static struct wpabuf * dpp_build_attribute(void)
+static struct wpabuf * dpp_build_attribute(struct dpp_configurator *conf)
{
struct wpabuf *conf_params, *attr;
@@ -88,7 +116,7 @@ static struct wpabuf * dpp_build_attribute(void)
* type OBJECT IDENTIFIER,
* values SET SIZE(1..MAX) OF Type
*/
- conf_params = dpp_build_conf_params();
+ conf_params = dpp_build_conf_params(conf);
conf_params = asn1_encaps(conf_params, ASN1_CLASS_UNIVERSAL,
ASN1_TAG_SET);
if (!conf_params)
@@ -167,7 +195,7 @@ static struct wpabuf * dpp_build_key_pkg(struct dpp_authentication *auth)
alg = dpp_build_key_alg(auth->conf->curve);
/* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
- attr = dpp_build_attribute();
+ attr = dpp_build_attribute(auth->conf);
attr = asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SET);
if (!priv_key || !attr || !alg)
goto fail;
@@ -189,7 +217,7 @@ static struct wpabuf * dpp_build_key_pkg(struct dpp_authentication *auth)
if (!key)
goto fail;
- asn1_put_integer(key, 1); /* version = v2(1) */
+ asn1_put_integer(key, 0); /* version = v1(0) */
/* PrivateKeyAlgorithmIdentifier */
wpabuf_put_buf(key, alg);
@@ -275,18 +303,21 @@ dpp_build_pw_recipient_info(struct dpp_authentication *auth, size_t hash_len,
struct wpabuf *pwri = NULL, *enc_key = NULL, *key_der_alg = NULL,
*key_enc_alg = NULL, *salt;
u8 kek[DPP_MAX_HASH_LEN];
- const u8 *key;
+ u8 key[DPP_MAX_HASH_LEN];
size_t key_len;
+ int res;
salt = wpabuf_alloc(64);
if (!salt || os_get_random(wpabuf_put(salt, 64), 64) < 0)
goto fail;
wpa_hexdump_buf(MSG_DEBUG, "DPP: PBKDF2 salt", salt);
- /* TODO: For initial testing, use ke as the key. Replace this with a
- * new key once that has been defined. */
- key = auth->ke;
key_len = auth->curve->hash_len;
+ /* password = HKDF-Expand(bk, "Enveloped Data Password", length) */
+ res = dpp_hkdf_expand(key_len, auth->bk, key_len,
+ "Enveloped Data Password", key, key_len);
+ if (res < 0)
+ goto fail;
wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
if (dpp_pbkdf2(hash_len, key, key_len, wpabuf_head(salt), 64, 1000,
@@ -905,7 +936,7 @@ dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
/* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
goto fail;
- if (val != 1) {
+ if (val != 0 && val != 1) {
wpa_printf(MSG_DEBUG,
"DPP: Unsupported DPPAsymmetricKeyPackage version %d",
val);
@@ -1056,6 +1087,7 @@ dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
/*
* DPPConfigurationParameters ::= SEQUENCE {
+ * privacyProtectionKey PrivateKey,
* configurationTemplate UTF8String,
* connectorTemplate UTF8String OPTIONAL}
*/
@@ -1072,6 +1104,37 @@ dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
end = pos;
pos = hdr.payload;
+ /*
+ * PrivateKey ::= OCTET STRING
+ * (Contains DER encoding of ECPrivateKey)
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: privacyProtectionKey",
+ hdr.payload, hdr.length);
+ pos = hdr.payload + hdr.length;
+ eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length);
+ if (!eckey) {
+ wpa_printf(MSG_INFO,
+ "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ key->pp_key = EVP_PKEY_new();
+ if (!key->pp_key || EVP_PKEY_assign_EC_KEY(key->pp_key, eckey) != 1) {
+ EC_KEY_free(eckey);
+ goto fail;
+ }
+ if (wpa_debug_show_keys)
+ dpp_debug_print_key("DPP: Received privacyProtectionKey",
+ key->pp_key);
+
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_UTF8STRING) {
@@ -1151,7 +1214,7 @@ dpp_parse_dpp_asymmetric_key_package(const u8 *key_pkg, size_t key_pkg_len)
int dpp_conf_resp_env_data(struct dpp_authentication *auth,
const u8 *env_data, size_t env_data_len)
{
- const u8 *key;
+ u8 key[DPP_MAX_HASH_LEN];
size_t key_len;
u8 kek[DPP_MAX_HASH_LEN];
u8 cont_encr_key[DPP_MAX_HASH_LEN];
@@ -1167,10 +1230,12 @@ int dpp_conf_resp_env_data(struct dpp_authentication *auth,
if (dpp_parse_enveloped_data(env_data, env_data_len, &data) < 0)
return -1;
- /* TODO: For initial testing, use ke as the key. Replace this with a
- * new key once that has been defined. */
- key = auth->ke;
key_len = auth->curve->hash_len;
+ /* password = HKDF-Expand(bk, "Enveloped Data Password", length) */
+ res = dpp_hkdf_expand(key_len, auth->bk, key_len,
+ "Enveloped Data Password", key, key_len);
+ if (res < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
if (dpp_pbkdf2(data.prf_hash_len, key, key_len, data.salt, 64, 1000,
diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c
index 8bf2a74a..c75fc787 100644
--- a/src/common/dpp_crypto.c
+++ b/src/common/dpp_crypto.c
@@ -12,12 +12,14 @@
#include <openssl/err.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
+#include <openssl/pem.h>
#include "utils/common.h"
#include "utils/base64.h"
#include "utils/json.h"
#include "common/ieee802_11_defs.h"
#include "crypto/crypto.h"
+#include "crypto/random.h"
#include "crypto/sha384.h"
#include "crypto/sha512.h"
#include "dpp.h"
@@ -129,6 +131,18 @@ const struct dpp_curve_params * dpp_get_curve_nid(int nid)
}
+const struct dpp_curve_params * dpp_get_curve_ike_group(u16 group)
+{
+ int i;
+
+ for (i = 0; dpp_curves[i].name; i++) {
+ if (dpp_curves[i].ike_group == group)
+ return &dpp_curves[i];
+ }
+ return NULL;
+}
+
+
void dpp_debug_print_point(const char *title, const EC_GROUP *group,
const EC_POINT *point)
{
@@ -855,7 +869,7 @@ int dpp_derive_bk_ke(struct dpp_authentication *auth)
"DPP: bk = HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x])",
auth->bk, hash_len);
- /* ke = HKDF-Expand(bkK, "DPP Key", length) */
+ /* ke = HKDF-Expand(bk, "DPP Key", length) */
res = dpp_hkdf_expand(hash_len, auth->bk, hash_len, info_ke, auth->ke,
hash_len);
if (res < 0)
@@ -2256,6 +2270,7 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
u8 prk[DPP_MAX_HASH_LEN];
const struct dpp_curve_params *curve;
int res = -1;
+ u8 nonces[2 * DPP_MAX_NONCE_LEN];
own_key = dpp_set_keypair(&auth->curve, net_access_key,
net_access_key_len);
@@ -2271,7 +2286,7 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
if (auth->curve != curve) {
wpa_printf(MSG_DEBUG,
- "DPP: Mismatching netAccessKey curves (%s != %s)",
+ "DPP: Mismatching netAccessKey curves (own=%s != peer=%s)",
auth->curve->name, curve->name);
goto fail;
}
@@ -2280,16 +2295,25 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
if (!auth->own_protocol_key)
goto fail;
+ if (random_get_bytes(auth->e_nonce, auth->curve->nonce_len)) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: E-nonce",
+ auth->e_nonce, auth->curve->nonce_len);
+
/* M = { cR + pR } * CI */
cR = EVP_PKEY_get0_EC_KEY(own_key);
pR = EVP_PKEY_get0_EC_KEY(auth->own_protocol_key);
+ if (!pR)
+ goto fail;
group = EC_KEY_get0_group(pR);
bnctx = BN_CTX_new();
sum = BN_new();
mx = BN_new();
q = BN_new();
m = EC_POINT_new(group);
- if (!cR || !pR || !bnctx || !sum || !mx || !q || !m)
+ if (!cR || !bnctx || !sum || !mx || !q || !m)
goto fail;
cR_bn = EC_KEY_get0_private_key(cR);
pR_bn = EC_KEY_get0_private_key(pR);
@@ -2312,10 +2336,12 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
goto fail;
wpa_hexdump_key(MSG_DEBUG, "DPP: M.x", Mx, curve->prime_len);
- /* ke = HKDF(I-nonce, "dpp reconfig key", M.x) */
+ /* ke = HKDF(C-nonce | E-nonce, "dpp reconfig key", M.x) */
- /* HKDF-Extract(I-nonce, M.x) */
- if (dpp_hmac(curve->hash_len, auth->i_nonce, curve->nonce_len,
+ /* HKDF-Extract(C-nonce | E-nonce, M.x) */
+ os_memcpy(nonces, auth->c_nonce, curve->nonce_len);
+ os_memcpy(&nonces[curve->nonce_len], auth->e_nonce, curve->nonce_len);
+ if (dpp_hmac(curve->hash_len, nonces, 2 * curve->nonce_len,
Mx, curve->prime_len, prk) < 0)
goto fail;
wpa_hexdump_key(MSG_DEBUG, "DPP: PRK", prk, curve->hash_len);
@@ -2325,7 +2351,7 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
"dpp reconfig key", auth->ke, curve->hash_len) < 0)
goto fail;
wpa_hexdump_key(MSG_DEBUG,
- "DPP: ke = HKDF(I-nonce, \"dpp reconfig key\", M.x)",
+ "DPP: ke = HKDF(C-nonce | E-nonce, \"dpp reconfig key\", M.x)",
auth->ke, curve->hash_len);
res = 0;
@@ -2362,6 +2388,7 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
u8 prk[DPP_MAX_HASH_LEN];
int res = -1;
const struct dpp_curve_params *curve;
+ u8 nonces[2 * DPP_MAX_NONCE_LEN];
pr = dpp_set_pubkey_point(auth->conf->connector_key,
r_proto, r_proto_len);
@@ -2380,7 +2407,7 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
if (auth->curve != curve) {
wpa_printf(MSG_DEBUG,
- "DPP: Mismatching netAccessKey curves (%s != %s)",
+ "DPP: Mismatching netAccessKey curves (own=%s != peer=%s)",
auth->curve->name, curve->name);
goto fail;
}
@@ -2407,10 +2434,12 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
wpa_hexdump_key(MSG_DEBUG, "DPP: M.x", Mx, curve->prime_len);
- /* ke = HKDF(I-nonce, "dpp reconfig key", M.x) */
+ /* ke = HKDF(C-nonce | E-nonce, "dpp reconfig key", M.x) */
- /* HKDF-Extract(I-nonce, M.x) */
- if (dpp_hmac(curve->hash_len, auth->i_nonce, curve->nonce_len,
+ /* HKDF-Extract(C-nonce | E-nonce, M.x) */
+ os_memcpy(nonces, auth->c_nonce, curve->nonce_len);
+ os_memcpy(&nonces[curve->nonce_len], auth->e_nonce, curve->nonce_len);
+ if (dpp_hmac(curve->hash_len, nonces, 2 * curve->nonce_len,
Mx, curve->prime_len, prk) < 0)
goto fail;
wpa_hexdump_key(MSG_DEBUG, "DPP: PRK", prk, curve->hash_len);
@@ -2420,7 +2449,7 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
"dpp reconfig key", auth->ke, curve->hash_len) < 0)
goto fail;
wpa_hexdump_key(MSG_DEBUG,
- "DPP: ke = HKDF(I-nonce, \"dpp reconfig key\", M.x)",
+ "DPP: ke = HKDF(C-nonce | E-nonce, \"dpp reconfig key\", M.x)",
auth->ke, curve->hash_len);
res = 0;
@@ -2664,6 +2693,521 @@ void dpp_pfs_free(struct dpp_pfs *pfs)
os_free(pfs);
}
+
+struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name)
+{
+ X509_REQ *req = NULL;
+ struct wpabuf *buf = NULL;
+ unsigned char *der;
+ int der_len;
+ EVP_PKEY *key;
+ const EVP_MD *sign_md;
+ unsigned int hash_len = auth->curve->hash_len;
+ EC_KEY *eckey;
+ BIO *out = NULL;
+ u8 cp[DPP_CP_LEN];
+ char *password;
+ size_t password_len;
+ int res;
+
+ /* TODO: use auth->csrattrs */
+
+ /* TODO: support generation of a new private key if csrAttrs requests
+ * a specific group to be used */
+ key = auth->own_protocol_key;
+
+ eckey = EVP_PKEY_get1_EC_KEY(key);
+ if (!eckey)
+ goto fail;
+ der = NULL;
+ der_len = i2d_ECPrivateKey(eckey, &der);
+ if (der_len <= 0)
+ goto fail;
+ wpabuf_free(auth->priv_key);
+ auth->priv_key = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+ if (!auth->priv_key)
+ goto fail;
+
+ req = X509_REQ_new();
+ if (!req || !X509_REQ_set_pubkey(req, key))
+ goto fail;
+
+ if (name) {
+ X509_NAME *n;
+
+ n = X509_REQ_get_subject_name(req);
+ if (!n)
+ goto fail;
+
+ if (X509_NAME_add_entry_by_txt(
+ n, "CN", MBSTRING_UTF8,
+ (const unsigned char *) name, -1, -1, 0) != 1)
+ goto fail;
+ }
+
+ /* cp = HKDF-Expand(bk, "CSR challengePassword", 64) */
+ if (dpp_hkdf_expand(hash_len, auth->bk, hash_len,
+ "CSR challengePassword", cp, DPP_CP_LEN) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: cp = HKDF-Expand(bk, \"CSR challengePassword\", 64)",
+ cp, DPP_CP_LEN);
+ password = base64_encode_no_lf(cp, DPP_CP_LEN, &password_len);
+ forced_memzero(cp, DPP_CP_LEN);
+ if (!password)
+ goto fail;
+
+ res = X509_REQ_add1_attr_by_NID(req, NID_pkcs9_challengePassword,
+ V_ASN1_UTF8STRING,
+ (const unsigned char *) password,
+ password_len);
+ bin_clear_free(password, password_len);
+ if (!res)
+ goto fail;
+
+ /* TODO */
+
+ /* TODO: hash func selection based on csrAttrs */
+ if (hash_len == SHA256_MAC_LEN) {
+ sign_md = EVP_sha256();
+ } else if (hash_len == SHA384_MAC_LEN) {
+ sign_md = EVP_sha384();
+ } else if (hash_len == SHA512_MAC_LEN) {
+ sign_md = EVP_sha512();
+ } else {
+ wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
+ goto fail;
+ }
+
+ if (!X509_REQ_sign(req, key, sign_md))
+ goto fail;
+
+ der = NULL;
+ der_len = i2d_X509_REQ(req, &der);
+ if (der_len < 0)
+ goto fail;
+ buf = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: CSR", buf);
+
+fail:
+ BIO_free_all(out);
+ X509_REQ_free(req);
+ return buf;
+}
+
+
+struct wpabuf * dpp_pkcs7_certs(const struct wpabuf *pkcs7)
+{
+#ifdef OPENSSL_IS_BORINGSSL
+ CBS pkcs7_cbs;
+#else /* OPENSSL_IS_BORINGSSL */
+ PKCS7 *p7 = NULL;
+ const unsigned char *p = wpabuf_head(pkcs7);
+#endif /* OPENSSL_IS_BORINGSSL */
+ STACK_OF(X509) *certs;
+ int i, num;
+ BIO *out = NULL;
+ size_t rlen;
+ struct wpabuf *pem = NULL;
+ int res;
+
+#ifdef OPENSSL_IS_BORINGSSL
+ certs = sk_X509_new_null();
+ if (!certs)
+ goto fail;
+ CBS_init(&pkcs7_cbs, wpabuf_head(pkcs7), wpabuf_len(pkcs7));
+ if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) {
+ wpa_printf(MSG_INFO, "DPP: Could not parse PKCS#7 object: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+#else /* OPENSSL_IS_BORINGSSL */
+ p7 = d2i_PKCS7(NULL, &p, wpabuf_len(pkcs7));
+ if (!p7) {
+ wpa_printf(MSG_INFO, "DPP: Could not parse PKCS#7 object: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ switch (OBJ_obj2nid(p7->type)) {
+ case NID_pkcs7_signed:
+ certs = p7->d.sign->cert;
+ break;
+ case NID_pkcs7_signedAndEnveloped:
+ certs = p7->d.signed_and_enveloped->cert;
+ break;
+ default:
+ certs = NULL;
+ break;
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+
+ if (!certs || ((num = sk_X509_num(certs)) == 0)) {
+ wpa_printf(MSG_INFO,
+ "DPP: No certificates found in PKCS#7 object");
+ goto fail;
+ }
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ goto fail;
+
+ for (i = 0; i < num; i++) {
+ X509 *cert = sk_X509_value(certs, i);
+
+ PEM_write_bio_X509(out, cert);
+ }
+
+ rlen = BIO_ctrl_pending(out);
+ pem = wpabuf_alloc(rlen);
+ if (!pem)
+ goto fail;
+ res = BIO_read(out, wpabuf_put(pem, 0), rlen);
+ if (res <= 0) {
+ wpabuf_free(pem);
+ pem = NULL;
+ goto fail;
+ }
+ wpabuf_put(pem, res);
+
+fail:
+#ifdef OPENSSL_IS_BORINGSSL
+ if (certs)
+ sk_X509_pop_free(certs, X509_free);
+#else /* OPENSSL_IS_BORINGSSL */
+ PKCS7_free(p7);
+#endif /* OPENSSL_IS_BORINGSSL */
+ if (out)
+ BIO_free_all(out);
+
+ return pem;
+}
+
+
+int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr)
+{
+ X509_REQ *req;
+ const unsigned char *pos;
+ EVP_PKEY *pkey;
+ int res, loc, ret = -1;
+ X509_ATTRIBUTE *attr;
+ ASN1_TYPE *type;
+ ASN1_STRING *str;
+ unsigned char *utf8 = NULL;
+ unsigned char *cp = NULL;
+ size_t cp_len;
+ u8 exp_cp[DPP_CP_LEN];
+ unsigned int hash_len = auth->curve->hash_len;
+
+ pos = wpabuf_head(csr);
+ req = d2i_X509_REQ(NULL, &pos, wpabuf_len(csr));
+ if (!req) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to parse CSR");
+ return -1;
+ }
+
+ pkey = X509_REQ_get_pubkey(req);
+ if (!pkey) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to get public key from CSR");
+ goto fail;
+ }
+
+ res = X509_REQ_verify(req, pkey);
+ EVP_PKEY_free(pkey);
+ if (res != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: CSR does not have a valid signature");
+ goto fail;
+ }
+
+ loc = X509_REQ_get_attr_by_NID(req, NID_pkcs9_challengePassword, -1);
+ if (loc < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: CSR does not include challengePassword");
+ goto fail;
+ }
+
+ attr = X509_REQ_get_attr(req, loc);
+ if (!attr) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not get challengePassword attribute");
+ goto fail;
+ }
+
+ type = X509_ATTRIBUTE_get0_type(attr, 0);
+ if (!type) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not get challengePassword attribute type");
+ goto fail;
+ }
+
+ res = ASN1_TYPE_get(type);
+ /* This is supposed to be UTF8String, but allow other strings as well
+ * since challengePassword is using ASCII (base64 encoded). */
+ if (res != V_ASN1_UTF8STRING && res != V_ASN1_PRINTABLESTRING &&
+ res != V_ASN1_IA5STRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected challengePassword attribute type %d",
+ res);
+ goto fail;
+ }
+
+ str = X509_ATTRIBUTE_get0_data(attr, 0, res, NULL);
+ if (!str) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not get ASN.1 string for challengePassword");
+ goto fail;
+ }
+
+ res = ASN1_STRING_to_UTF8(&utf8, str);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not get UTF8 version of challengePassword");
+ goto fail;
+ }
+
+ cp = base64_decode((const char *) utf8, res, &cp_len);
+ OPENSSL_free(utf8);
+ if (!cp) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not base64 decode challengePassword");
+ goto fail;
+ }
+ if (cp_len != DPP_CP_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected cp length (%zu) in CSR challengePassword",
+ cp_len);
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: cp from CSR challengePassword",
+ cp, cp_len);
+
+ /* cp = HKDF-Expand(bk, "CSR challengePassword", 64) */
+ if (dpp_hkdf_expand(hash_len, auth->bk, hash_len,
+ "CSR challengePassword", exp_cp, DPP_CP_LEN) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: cp = HKDF-Expand(bk, \"CSR challengePassword\", 64)",
+ exp_cp, DPP_CP_LEN);
+ if (os_memcmp_const(cp, exp_cp, DPP_CP_LEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: CSR challengePassword does not match calculated cp");
+ goto fail;
+ }
+
+ ret = 0;
+fail:
+ os_free(cp);
+ X509_REQ_free(req);
+ return ret;
+}
+
+
+struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
+ size_t csign_key_len,
+ const u8 *pp_key,
+ size_t pp_key_len)
+{
+ const unsigned char *p;
+ EVP_PKEY *csign = NULL, *ppkey = NULL;
+ struct dpp_reconfig_id *id = NULL;
+ BN_CTX *ctx = NULL;
+ BIGNUM *bn = NULL, *q = NULL;
+ const EC_KEY *eckey;
+ const EC_GROUP *group;
+ EC_POINT *e_id = NULL;
+
+ p = csign_key;
+ csign = d2i_PUBKEY(NULL, &p, csign_key_len);
+ if (!csign)
+ goto fail;
+
+ if (!pp_key)
+ goto fail;
+ p = pp_key;
+ ppkey = d2i_PUBKEY(NULL, &p, pp_key_len);
+ if (!ppkey)
+ goto fail;
+
+ eckey = EVP_PKEY_get0_EC_KEY(csign);
+ if (!eckey)
+ goto fail;
+ group = EC_KEY_get0_group(eckey);
+ if (!group)
+ goto fail;
+
+ e_id = EC_POINT_new(group);
+ ctx = BN_CTX_new();
+ bn = BN_new();
+ q = BN_new();
+ if (!e_id || !ctx || !bn || !q ||
+ !EC_GROUP_get_order(group, q, ctx) ||
+ !BN_rand_range(bn, q) ||
+ !EC_POINT_mul(group, e_id, bn, NULL, NULL, ctx))
+ goto fail;
+
+ dpp_debug_print_point("DPP: Generated random point E-id", group, e_id);
+
+ id = os_zalloc(sizeof(*id));
+ if (!id)
+ goto fail;
+ id->group = group;
+ id->e_id = e_id;
+ e_id = NULL;
+ id->csign = csign;
+ csign = NULL;
+ id->pp_key = ppkey;
+ ppkey = NULL;
+fail:
+ EC_POINT_free(e_id);
+ EVP_PKEY_free(csign);
+ EVP_PKEY_free(ppkey);
+ BN_clear_free(bn);
+ BN_CTX_free(ctx);
+ return id;
+}
+
+
+static EVP_PKEY * dpp_pkey_from_point(const EC_GROUP *group,
+ const EC_POINT *point)
+{
+ EC_KEY *eckey;
+ EVP_PKEY *pkey = NULL;
+
+ eckey = EC_KEY_new();
+ if (!eckey ||
+ EC_KEY_set_group(eckey, group) != 1 ||
+ EC_KEY_set_public_key(eckey, point) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to set EC_KEY: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
+
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ goto fail;
+ }
+
+fail:
+ EC_KEY_free(eckey);
+ return pkey;
+}
+
+
+int dpp_update_reconfig_id(struct dpp_reconfig_id *id)
+{
+ BN_CTX *ctx = NULL;
+ BIGNUM *bn = NULL, *q = NULL;
+ EC_POINT *e_prime_id = NULL, *a_nonce = NULL;
+ int ret = -1;
+ const EC_KEY *pp;
+ const EC_POINT *pp_point;
+
+ pp = EVP_PKEY_get0_EC_KEY(id->pp_key);
+ if (!pp)
+ goto fail;
+ pp_point = EC_KEY_get0_public_key(pp);
+ e_prime_id = EC_POINT_new(id->group);
+ a_nonce = EC_POINT_new(id->group);
+ ctx = BN_CTX_new();
+ bn = BN_new();
+ q = BN_new();
+ /* Generate random 0 <= a-nonce < q
+ * A-NONCE = a-nonce * G
+ * E'-id = E-id + a-nonce * P_pk */
+ if (!pp_point || !e_prime_id || !a_nonce || !ctx || !bn || !q ||
+ !EC_GROUP_get_order(id->group, q, ctx) ||
+ !BN_rand_range(bn, q) || /* bn = a-nonce */
+ !EC_POINT_mul(id->group, a_nonce, bn, NULL, NULL, ctx) ||
+ !EC_POINT_mul(id->group, e_prime_id, NULL, pp_point, bn, ctx) ||
+ !EC_POINT_add(id->group, e_prime_id, id->e_id, e_prime_id, ctx))
+ goto fail;
+
+ dpp_debug_print_point("DPP: Generated A-NONCE", id->group, a_nonce);
+ dpp_debug_print_point("DPP: Encrypted E-id to E'-id",
+ id->group, e_prime_id);
+
+ EVP_PKEY_free(id->a_nonce);
+ EVP_PKEY_free(id->e_prime_id);
+ id->a_nonce = dpp_pkey_from_point(id->group, a_nonce);
+ id->e_prime_id = dpp_pkey_from_point(id->group, e_prime_id);
+ if (!id->a_nonce || !id->e_prime_id)
+ goto fail;
+
+ ret = 0;
+
+fail:
+ EC_POINT_free(e_prime_id);
+ EC_POINT_free(a_nonce);
+ BN_clear_free(bn);
+ BN_CTX_free(ctx);
+ return ret;
+}
+
+
+void dpp_free_reconfig_id(struct dpp_reconfig_id *id)
+{
+ if (id) {
+ EC_POINT_clear_free(id->e_id);
+ EVP_PKEY_free(id->csign);
+ EVP_PKEY_free(id->a_nonce);
+ EVP_PKEY_free(id->e_prime_id);
+ EVP_PKEY_free(id->pp_key);
+ os_free(id);
+ }
+}
+
+
+EC_POINT * dpp_decrypt_e_id(EVP_PKEY *ppkey, EVP_PKEY *a_nonce,
+ EVP_PKEY *e_prime_id)
+{
+ const EC_KEY *pp_ec, *a_nonce_ec, *e_prime_id_ec;
+ const BIGNUM *pp_bn;
+ const EC_GROUP *group;
+ EC_POINT *e_id = NULL;
+ const EC_POINT *a_nonce_point, *e_prime_id_point;
+ BN_CTX *ctx = NULL;
+
+ if (!ppkey)
+ return NULL;
+
+ /* E-id = E'-id - s_C * A-NONCE */
+ pp_ec = EVP_PKEY_get0_EC_KEY(ppkey);
+ a_nonce_ec = EVP_PKEY_get0_EC_KEY(a_nonce);
+ e_prime_id_ec = EVP_PKEY_get0_EC_KEY(e_prime_id);
+ if (!pp_ec || !a_nonce_ec || !e_prime_id_ec)
+ return NULL;
+ pp_bn = EC_KEY_get0_private_key(pp_ec);
+ group = EC_KEY_get0_group(pp_ec);
+ a_nonce_point = EC_KEY_get0_public_key(a_nonce_ec);
+ e_prime_id_point = EC_KEY_get0_public_key(e_prime_id_ec);
+ ctx = BN_CTX_new();
+ if (!pp_bn || !group || !a_nonce_point || !e_prime_id_point || !ctx)
+ goto fail;
+ e_id = EC_POINT_new(group);
+ if (!e_id ||
+ !EC_POINT_mul(group, e_id, NULL, a_nonce_point, pp_bn, ctx) ||
+ !EC_POINT_invert(group, e_id, ctx) ||
+ !EC_POINT_add(group, e_id, e_prime_id_point, e_id, ctx)) {
+ EC_POINT_clear_free(e_id);
+ goto fail;
+ }
+
+ dpp_debug_print_point("DPP: Decrypted E-id", group, e_id);
+
+fail:
+ BN_CTX_free(ctx);
+ return e_id;
+}
+
#endif /* CONFIG_DPP2 */
diff --git a/src/common/dpp_i.h b/src/common/dpp_i.h
index e66eb6cf..af12467a 100644
--- a/src/common/dpp_i.h
+++ b/src/common/dpp_i.h
@@ -73,6 +73,7 @@ dpp_check_signed_connector(struct dpp_signed_connector_info *info,
const struct dpp_curve_params * dpp_get_curve_name(const char *name);
const struct dpp_curve_params * dpp_get_curve_jwk_crv(const char *name);
const struct dpp_curve_params * dpp_get_curve_nid(int nid);
+const struct dpp_curve_params * dpp_get_curve_ike_group(u16 group);
int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
const u8 *data, size_t data_len);
struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix);
@@ -132,11 +133,22 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
const u8 *r_proto, u16 r_proto_len,
struct json_token *net_access_key);
+EC_POINT * dpp_decrypt_e_id(EVP_PKEY *ppkey, EVP_PKEY *a_nonce,
+ EVP_PKEY *e_prime_id);
char * dpp_sign_connector(struct dpp_configurator *conf,
const struct wpabuf *dppcon);
int dpp_test_gen_invalid_key(struct wpabuf *msg,
const struct dpp_curve_params *curve);
+struct dpp_reconfig_id {
+ const EC_GROUP *group;
+ EC_POINT *e_id; /* E-id */
+ EVP_PKEY *csign;
+ EVP_PKEY *a_nonce; /* A-NONCE */
+ EVP_PKEY *e_prime_id; /* E'-id */
+ EVP_PKEY *pp_key;
+};
+
/* dpp_tcp.c */
void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
diff --git a/src/common/dpp_reconfig.c b/src/common/dpp_reconfig.c
index 0bb00cc1..c4a02736 100644
--- a/src/common/dpp_reconfig.c
+++ b/src/common/dpp_reconfig.c
@@ -34,9 +34,12 @@ static void dpp_build_attr_csign_key_hash(struct wpabuf *msg, const u8 *hash)
struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
- size_t csign_key_len)
+ size_t csign_key_len,
+ const u8 *net_access_key,
+ size_t net_access_key_len,
+ struct dpp_reconfig_id *id)
{
- struct wpabuf *msg;
+ struct wpabuf *msg = NULL;
EVP_PKEY *csign = NULL;
const unsigned char *p;
struct wpabuf *uncomp;
@@ -44,39 +47,86 @@ struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
const u8 *addr[1];
size_t len[1];
int res;
+ size_t attr_len;
+ const struct dpp_curve_params *own_curve;
+ EVP_PKEY *own_key;
+ struct wpabuf *a_nonce = NULL, *e_id = NULL;
wpa_printf(MSG_DEBUG, "DPP: Build Reconfig Announcement frame");
+ own_key = dpp_set_keypair(&own_curve, net_access_key,
+ net_access_key_len);
+ if (!own_key) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
+ goto fail;
+ }
+
p = csign_key;
csign = d2i_PUBKEY(NULL, &p, csign_key_len);
if (!csign) {
wpa_printf(MSG_ERROR,
"DPP: Failed to parse local C-sign-key information");
- return NULL;
+ goto fail;
}
uncomp = dpp_get_pubkey_point(csign, 1);
EVP_PKEY_free(csign);
if (!uncomp)
- return NULL;
+ goto fail;
addr[0] = wpabuf_head(uncomp);
len[0] = wpabuf_len(uncomp);
wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed C-sign key", addr[0], len[0]);
res = sha256_vector(1, addr, len, hash);
wpabuf_free(uncomp);
if (res < 0)
- return NULL;
+ goto fail;
wpa_hexdump(MSG_DEBUG, "DPP: kid = SHA256(uncompressed C-sign key)",
hash, SHA256_MAC_LEN);
- msg = dpp_alloc_msg(DPP_PA_RECONFIG_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
+ if (dpp_update_reconfig_id(id) < 0) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate E'-id");
+ goto fail;
+ }
+
+ a_nonce = dpp_get_pubkey_point(id->a_nonce, 0);
+ e_id = dpp_get_pubkey_point(id->e_prime_id, 0);
+ if (!a_nonce || !e_id)
+ goto fail;
+
+ attr_len = 4 + SHA256_MAC_LEN;
+ attr_len += 4 + 2;
+ attr_len += 4 + wpabuf_len(a_nonce);
+ attr_len += 4 + wpabuf_len(e_id);
+ msg = dpp_alloc_msg(DPP_PA_RECONFIG_ANNOUNCEMENT, attr_len);
if (!msg)
- return NULL;
+ goto fail;
/* Configurator C-sign key Hash */
dpp_build_attr_csign_key_hash(msg, hash);
+
+ /* Finite Cyclic Group attribute */
+ wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
+ own_curve->ike_group);
+ wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
+ wpabuf_put_le16(msg, 2);
+ wpabuf_put_le16(msg, own_curve->ike_group);
+
+ /* A-NONCE */
+ wpabuf_put_le16(msg, DPP_ATTR_A_NONCE);
+ wpabuf_put_le16(msg, wpabuf_len(a_nonce));
+ wpabuf_put_buf(msg, a_nonce);
+
+ /* E'-id */
+ wpabuf_put_le16(msg, DPP_ATTR_E_PRIME_ID);
+ wpabuf_put_le16(msg, wpabuf_len(e_id));
+ wpabuf_put_buf(msg, e_id);
+
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Reconfig Announcement frame attributes", msg);
+fail:
+ wpabuf_free(a_nonce);
+ wpabuf_free(e_id);
+ EVP_PKEY_free(own_key);
return msg;
}
@@ -108,10 +158,10 @@ static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth)
wpabuf_put_le16(msg, os_strlen(auth->conf->connector));
wpabuf_put_str(msg, auth->conf->connector);
- /* I-nonce */
- wpabuf_put_le16(msg, DPP_ATTR_I_NONCE);
+ /* C-nonce */
+ wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE);
wpabuf_put_le16(msg, auth->curve->nonce_len);
- wpabuf_put_data(msg, auth->i_nonce, auth->curve->nonce_len);
+ wpabuf_put_data(msg, auth->c_nonce, auth->curve->nonce_len);
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Reconfig Authentication Request frame attributes",
@@ -121,7 +171,9 @@ static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth)
}
-static int dpp_configurator_build_own_connector(struct dpp_configurator *conf)
+static int
+dpp_configurator_build_own_connector(struct dpp_configurator *conf,
+ const struct dpp_curve_params *curve)
{
struct wpabuf *dppcon = NULL;
int ret = -1;
@@ -132,12 +184,12 @@ static int dpp_configurator_build_own_connector(struct dpp_configurator *conf)
wpa_printf(MSG_DEBUG,
"DPP: Sign own Configurator Connector for reconfiguration with curve %s",
conf->curve->name);
- conf->connector_key = dpp_gen_keypair(conf->curve);
+ conf->connector_key = dpp_gen_keypair(curve);
if (!conf->connector_key)
goto fail;
/* Connector (JSON dppCon object) */
- dppcon = wpabuf_alloc(1000 + 2 * conf->curve->prime_len * 4 / 3);
+ dppcon = wpabuf_alloc(1000 + 2 * curve->prime_len * 4 / 3);
if (!dppcon)
goto fail;
json_start_object(dppcon, NULL);
@@ -150,7 +202,7 @@ static int dpp_configurator_build_own_connector(struct dpp_configurator *conf)
json_end_array(dppcon);
json_value_sep(dppcon);
if (dpp_build_jwk(dppcon, "netAccessKey", conf->connector_key, NULL,
- conf->curve) < 0) {
+ curve) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
goto fail;
}
@@ -172,9 +224,58 @@ fail:
struct dpp_authentication *
dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
- struct dpp_configurator *conf, unsigned int freq)
+ struct dpp_configurator *conf, unsigned int freq, u16 group,
+ const u8 *a_nonce_attr, size_t a_nonce_len,
+ const u8 *e_id_attr, size_t e_id_len)
{
struct dpp_authentication *auth;
+ const struct dpp_curve_params *curve;
+ EVP_PKEY *a_nonce, *e_prime_id;
+ EC_POINT *e_id;
+
+ curve = dpp_get_curve_ike_group(group);
+ if (!curve) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported group %u - cannot reconfigure",
+ group);
+ return NULL;
+ }
+
+ if (!a_nonce_attr) {
+ wpa_printf(MSG_INFO, "DPP: Missing required A-NONCE attribute");
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: A-NONCE", a_nonce_attr, a_nonce_len);
+ a_nonce = dpp_set_pubkey_point(conf->csign, a_nonce_attr, a_nonce_len);
+ if (!a_nonce) {
+ wpa_printf(MSG_INFO, "DPP: Invalid A-NONCE");
+ return NULL;
+ }
+ dpp_debug_print_key("A-NONCE", a_nonce);
+
+ if (!e_id_attr) {
+ wpa_printf(MSG_INFO, "DPP: Missing required E'-id attribute");
+ return NULL;
+ }
+ e_prime_id = dpp_set_pubkey_point(conf->csign, e_id_attr, e_id_len);
+ if (!e_prime_id) {
+ wpa_printf(MSG_INFO, "DPP: Invalid E'-id");
+ EVP_PKEY_free(a_nonce);
+ return NULL;
+ }
+ dpp_debug_print_key("E'-id", e_prime_id);
+ e_id = dpp_decrypt_e_id(conf->pp_key, a_nonce, e_prime_id);
+ EVP_PKEY_free(a_nonce);
+ EVP_PKEY_free(e_prime_id);
+ if (!e_id) {
+ wpa_printf(MSG_INFO, "DPP: Could not decrypt E'-id");
+ return NULL;
+ }
+ /* TODO: could use E-id to determine whether reconfiguration with this
+ * Enrollee has already been started and is waiting for updated
+ * configuration instead of replying again before such configuration
+ * becomes available */
+ EC_POINT_clear_free(e_id);
auth = dpp_alloc_auth(dpp, msg_ctx);
if (!auth)
@@ -186,16 +287,16 @@ dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
auth->waiting_auth_resp = 1;
auth->allowed_roles = DPP_CAPAB_CONFIGURATOR;
auth->configurator = 1;
- auth->curve = conf->curve;
+ auth->curve = curve;
auth->transaction_id = 1;
if (freq && dpp_prepare_channel_list(auth, freq, NULL, 0) < 0)
goto fail;
- if (dpp_configurator_build_own_connector(conf) < 0)
+ if (dpp_configurator_build_own_connector(conf, curve) < 0)
goto fail;
- if (random_get_bytes(auth->i_nonce, auth->curve->nonce_len)) {
- wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
+ if (random_get_bytes(auth->c_nonce, auth->curve->nonce_len)) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate C-nonce");
goto fail;
}
@@ -224,21 +325,16 @@ static int dpp_reconfig_build_resp(struct dpp_authentication *auth,
int res = -1;
/* Build DPP Reconfig Authentication Response frame attributes */
- clear_len = 2 * (4 + auth->curve->nonce_len) +
+ clear_len = 4 + auth->curve->nonce_len +
4 + wpabuf_len(conn_status);
clear = wpabuf_alloc(clear_len);
if (!clear)
goto fail;
- /* I-nonce (wrapped) */
- wpabuf_put_le16(clear, DPP_ATTR_I_NONCE);
- wpabuf_put_le16(clear, auth->curve->nonce_len);
- wpabuf_put_data(clear, auth->i_nonce, auth->curve->nonce_len);
-
- /* R-nonce (wrapped) */
- wpabuf_put_le16(clear, DPP_ATTR_R_NONCE);
+ /* C-nonce (wrapped) */
+ wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE);
wpabuf_put_le16(clear, auth->curve->nonce_len);
- wpabuf_put_data(clear, auth->r_nonce, auth->curve->nonce_len);
+ wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len);
/* Connection Status (wrapped) */
wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
@@ -251,6 +347,7 @@ static int dpp_reconfig_build_resp(struct dpp_authentication *auth,
attr_len = 4 + 1 + 4 + 1 +
4 + os_strlen(own_connector) +
+ 4 + auth->curve->nonce_len +
4 + wpabuf_len(pr) +
4 + wpabuf_len(clear) + AES_BLOCK_SIZE;
msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_RESP, attr_len);
@@ -274,6 +371,11 @@ static int dpp_reconfig_build_resp(struct dpp_authentication *auth,
wpabuf_put_le16(msg, os_strlen(own_connector));
wpabuf_put_str(msg, own_connector);
+ /* E-nonce */
+ wpabuf_put_le16(msg, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(msg, auth->curve->nonce_len);
+ wpabuf_put_data(msg, auth->e_nonce, auth->curve->nonce_len);
+
/* Responder Protocol Key (Pr) */
wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
wpabuf_put_le16(msg, wpabuf_len(pr));
@@ -291,7 +393,7 @@ static int dpp_reconfig_build_resp(struct dpp_authentication *auth,
len[1] = attr_end - attr_start;
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
- /* Wrapped Data: {I-nonce, R-nonce, Connection Status}ke */
+ /* Wrapped Data: {C-nonce, E-nonce, Connection Status}ke */
wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
@@ -329,8 +431,8 @@ dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx,
const u8 *attr_start, size_t attr_len)
{
struct dpp_authentication *auth = NULL;
- const u8 *trans_id, *version, *i_connector, *i_nonce;
- u16 trans_id_len, version_len, i_connector_len, i_nonce_len;
+ const u8 *trans_id, *version, *i_connector, *c_nonce;
+ u16 trans_id_len, version_len, i_connector_len, c_nonce_len;
struct dpp_signed_connector_info info;
enum dpp_status_error res;
struct json_token *root = NULL, *own_root = NULL, *token;
@@ -364,14 +466,14 @@ dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx,
wpa_hexdump_ascii(MSG_DEBUG, "DPP: I-Connector",
i_connector, i_connector_len);
- i_nonce = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_NONCE,
- &i_nonce_len);
- if (!i_nonce || i_nonce_len > DPP_MAX_NONCE_LEN) {
+ c_nonce = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
+ if (!c_nonce || c_nonce_len > DPP_MAX_NONCE_LEN) {
wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid I-Nonce attribute");
+ "DPP: Missing or invalid C-nonce attribute");
goto fail;
}
- wpa_hexdump(MSG_DEBUG, "DPP: I-Nonce", i_nonce, i_nonce_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
i_connector, i_connector_len);
@@ -418,25 +520,18 @@ dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx,
wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
auth->peer_version);
- os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
+ os_memcpy(auth->c_nonce, c_nonce, c_nonce_len);
if (dpp_reconfig_derive_ke_responder(auth, net_access_key,
net_access_key_len, token) < 0)
goto fail;
- if (i_nonce_len != auth->curve->nonce_len) {
+ if (c_nonce_len != auth->curve->nonce_len) {
wpa_printf(MSG_DEBUG,
- "DPP: Unexpected I-nonce length %u (curve nonce len %zu)",
- i_nonce_len, auth->curve->nonce_len);
- goto fail;
- }
-
- if (random_get_bytes(auth->r_nonce, auth->curve->nonce_len)) {
- wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
+ "DPP: Unexpected C-nonce length %u (curve nonce len %zu)",
+ c_nonce_len, auth->curve->nonce_len);
goto fail;
}
- wpa_hexdump_key(MSG_DEBUG, "DPP: R-nonce",
- auth->r_nonce, auth->curve->nonce_len);
/* Build Connection Status object */
/* TODO: Get appropriate result value */
@@ -462,40 +557,19 @@ fail:
}
-static struct wpabuf *
-dpp_build_reconfig_flags(enum dpp_connector_key connector_key)
-{
- struct wpabuf *json;
-
- json = wpabuf_alloc(100);
- if (!json)
- return NULL;
- json_start_object(json, NULL);
- json_add_int(json, "connectorKey", connector_key);
- json_end_object(json);
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: Reconfig-Flags JSON",
- wpabuf_head(json), wpabuf_len(json));
-
- return json;
-}
-
-
struct wpabuf *
dpp_reconfig_build_conf(struct dpp_authentication *auth)
{
- struct wpabuf *msg = NULL, *clear = NULL, *reconfig_flags;
+ struct wpabuf *msg = NULL, *clear;
u8 *attr_start, *attr_end;
size_t clear_len, attr_len, len[2];
const u8 *addr[2];
u8 *wrapped;
-
- reconfig_flags = dpp_build_reconfig_flags(DPP_CONFIG_REPLACEKEY);
- if (!reconfig_flags)
- goto fail;
+ u8 flags;
/* Build DPP Reconfig Authentication Confirm frame attributes */
clear_len = 4 + 1 + 4 + 1 + 2 * (4 + auth->curve->nonce_len) +
- 4 + wpabuf_len(reconfig_flags);
+ 4 + 1;
clear = wpabuf_alloc(clear_len);
if (!clear)
goto fail;
@@ -510,27 +584,33 @@ dpp_reconfig_build_conf(struct dpp_authentication *auth)
wpabuf_put_le16(clear, 1);
wpabuf_put_u8(clear, auth->peer_version);
- /* I-nonce (wrapped) */
- wpabuf_put_le16(clear, DPP_ATTR_I_NONCE);
+ /* C-nonce (wrapped) */
+ wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE);
wpabuf_put_le16(clear, auth->curve->nonce_len);
- wpabuf_put_data(clear, auth->i_nonce, auth->curve->nonce_len);
+ wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len);
- /* R-nonce (wrapped) */
- wpabuf_put_le16(clear, DPP_ATTR_R_NONCE);
+ /* E-nonce (wrapped) */
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
wpabuf_put_le16(clear, auth->curve->nonce_len);
- wpabuf_put_data(clear, auth->r_nonce, auth->curve->nonce_len);
+ wpabuf_put_data(clear, auth->e_nonce, auth->curve->nonce_len);
/* Reconfig-Flags (wrapped) */
+ flags = DPP_CONFIG_REPLACEKEY;
wpabuf_put_le16(clear, DPP_ATTR_RECONFIG_FLAGS);
- wpabuf_put_le16(clear, wpabuf_len(reconfig_flags));
- wpabuf_put_buf(clear, reconfig_flags);
+ wpabuf_put_le16(clear, 1);
+ wpabuf_put_u8(clear, flags);
attr_len = 4 + wpabuf_len(clear) + AES_BLOCK_SIZE;
+ attr_len += 4 + 1;
msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_CONF, attr_len);
if (!msg)
goto fail;
attr_start = wpabuf_put(msg, 0);
+
+ /* DPP Status */
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+
attr_end = wpabuf_put(msg, 0);
/* OUI, OUI type, Crypto Suite, DPP frame type */
@@ -559,7 +639,6 @@ dpp_reconfig_build_conf(struct dpp_authentication *auth)
msg);
out:
- wpabuf_free(reconfig_flags);
wpabuf_free(clear);
return msg;
fail:
@@ -574,9 +653,9 @@ dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len)
{
const u8 *trans_id, *version, *r_connector, *r_proto, *wrapped_data,
- *i_nonce, *r_nonce, *conn_status;
+ *c_nonce, *e_nonce, *conn_status;
u16 trans_id_len, version_len, r_connector_len, r_proto_len,
- wrapped_data_len, i_nonce_len, r_nonce_len, conn_status_len;
+ wrapped_data_len, c_nonce_len, e_nonce_len, conn_status_len;
struct wpabuf *conf = NULL;
char *signed_connector = NULL;
struct dpp_signed_connector_info info;
@@ -634,6 +713,15 @@ dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
wpa_hexdump_ascii(MSG_DEBUG, "DPP: R-Connector",
r_connector, r_connector_len);
+ e_nonce = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len);
+ if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth, "Missing or invalid E-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len);
+ os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
+
r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
&r_proto_len);
if (!r_proto) {
@@ -702,23 +790,14 @@ dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
goto fail;
}
- i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
- &i_nonce_len);
- if (!i_nonce || i_nonce_len != auth->curve->nonce_len ||
- os_memcmp(i_nonce, auth->i_nonce, i_nonce_len) != 0) {
- dpp_auth_fail(auth, "Missing or invalid I-nonce");
+ c_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
+ if (!c_nonce || c_nonce_len != auth->curve->nonce_len ||
+ os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Missing or invalid C-nonce");
goto fail;
}
- wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
-
- r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
- &r_nonce_len);
- if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
- dpp_auth_fail(auth, "Missing or invalid R-nonce");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
- os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
conn_status = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_CONN_STATUS, &conn_status_len);
@@ -758,16 +837,16 @@ fail:
int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len)
{
- const u8 *trans_id, *version, *wrapped_data, *i_nonce, *r_nonce,
- *reconfig_flags;
- u16 trans_id_len, version_len, wrapped_data_len, i_nonce_len,
- r_nonce_len, reconfig_flags_len;
+ const u8 *trans_id, *version, *wrapped_data, *c_nonce, *e_nonce,
+ *reconfig_flags, *status;
+ u16 trans_id_len, version_len, wrapped_data_len, c_nonce_len,
+ e_nonce_len, reconfig_flags_len, status_len;
const u8 *addr[2];
size_t len[2];
u8 *unwrapped = NULL;
size_t unwrapped_len = 0;
- struct json_token *root = NULL, *token;
int res = -1;
+ u8 flags;
if (!auth->reconfig || auth->configurator)
goto fail;
@@ -781,11 +860,26 @@ int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
}
wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
wrapped_data, wrapped_data_len);
+ attr_len = wrapped_data - 4 - attr_start;
+
+ status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
+ &status_len);
+ if (!status || status_len < 1) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required DPP Status attribute");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
+ if (status[0] != DPP_STATUS_OK) {
+ dpp_auth_fail(auth,
+ "Reconfiguration did not complete successfully");
+ goto fail;
+ }
addr[0] = hdr;
len[0] = DPP_HDR_LEN;
addr[1] = attr_start;
- len[1] = 0;
+ len[1] = attr_len;
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
@@ -825,55 +919,38 @@ int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
goto fail;
}
- i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
- &i_nonce_len);
- if (!i_nonce || i_nonce_len != auth->curve->nonce_len ||
- os_memcmp(i_nonce, auth->i_nonce, i_nonce_len) != 0) {
- dpp_auth_fail(auth, "Missing or invalid I-nonce");
+ c_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
+ if (!c_nonce || c_nonce_len != auth->curve->nonce_len ||
+ os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Missing or invalid C-nonce");
goto fail;
}
- wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
- r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
- &r_nonce_len);
- if (!r_nonce || r_nonce_len != auth->curve->nonce_len ||
- os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
- dpp_auth_fail(auth, "Missing or invalid R-nonce");
+ e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len);
+ if (!e_nonce || e_nonce_len != auth->curve->nonce_len ||
+ os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Missing or invalid E-nonce");
goto fail;
}
- wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len);
reconfig_flags = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_RECONFIG_FLAGS,
&reconfig_flags_len);
- if (!reconfig_flags) {
+ if (!reconfig_flags || reconfig_flags_len < 1) {
dpp_auth_fail(auth, "Missing or invalid Reconfig-Flags");
goto fail;
}
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: Reconfig-Flags",
- reconfig_flags, reconfig_flags_len);
- root = json_parse((const char *) reconfig_flags, reconfig_flags_len);
- if (!root) {
- dpp_auth_fail(auth, "Could not parse Reconfig-Flags");
- goto fail;
- }
- token = json_get_member(root, "connectorKey");
- if (!token || token->type != JSON_NUMBER) {
- dpp_auth_fail(auth, "No connectorKey in Reconfig-Flags");
- goto fail;
- }
- if (token->number != DPP_CONFIG_REUSEKEY &&
- token->number != DPP_CONFIG_REPLACEKEY) {
- dpp_auth_fail(auth,
- "Unsupported connectorKey value in Reconfig-Flags");
- goto fail;
- }
- auth->reconfig_connector_key = token->number;
+ flags = reconfig_flags[0] & BIT(0);
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Flags connectorKey=%u", flags);
+ auth->reconfig_connector_key = flags;
auth->reconfig_success = true;
res = 0;
fail:
- json_free(root);
bin_clear_free(unwrapped, unwrapped_len);
return res;
}
diff --git a/src/common/dpp_tcp.c b/src/common/dpp_tcp.c
index fc53b8a0..609c243a 100644
--- a/src/common/dpp_tcp.c
+++ b/src/common/dpp_tcp.c
@@ -25,6 +25,9 @@ struct dpp_connection {
struct dpp_relay_controller *relay;
struct dpp_global *global;
struct dpp_authentication *auth;
+ void *msg_ctx;
+ void *cb_ctx;
+ int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
int sock;
u8 mac_addr[ETH_ALEN];
unsigned int freq;
@@ -38,6 +41,10 @@ struct dpp_connection {
unsigned int on_tcp_tx_complete_gas_done:1;
unsigned int on_tcp_tx_complete_remove:1;
unsigned int on_tcp_tx_complete_auth_ok:1;
+ unsigned int gas_comeback_in_progress:1;
+ u8 gas_dialog_token;
+ char *name;
+ enum dpp_netrole netrole;
};
/* Remote Controller */
@@ -46,6 +53,7 @@ struct dpp_relay_controller {
struct dpp_global *global;
u8 pkhash[SHA256_MAC_LEN];
struct hostapd_ip_addr ipaddr;
+ void *msg_ctx;
void *cb_ctx;
void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
size_t len);
@@ -62,12 +70,18 @@ struct dpp_controller {
int sock;
struct dl_list conn; /* struct dpp_connection */
char *configurator_params;
+ enum dpp_netrole netrole;
+ void *msg_ctx;
+ void *cb_ctx;
+ int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
};
static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx);
static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx);
static void dpp_controller_auth_success(struct dpp_connection *conn,
int initiator);
+static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx);
+static void dpp_tcp_gas_query_comeback(void *eloop_ctx, void *timeout_ctx);
static void dpp_connection_free(struct dpp_connection *conn)
@@ -81,9 +95,12 @@ static void dpp_connection_free(struct dpp_connection *conn)
}
eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout,
conn, NULL);
+ eloop_cancel_timeout(dpp_tcp_build_csr, conn, NULL);
+ eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL);
wpabuf_free(conn->msg);
wpabuf_free(conn->msg_out);
dpp_auth_deinit(conn->auth);
+ os_free(conn->name);
os_free(conn);
}
@@ -110,6 +127,7 @@ int dpp_relay_add_controller(struct dpp_global *dpp,
ctrl->global = dpp;
os_memcpy(&ctrl->ipaddr, config->ipaddr, sizeof(*config->ipaddr));
os_memcpy(ctrl->pkhash, config->pkhash, SHA256_MAC_LEN);
+ ctrl->msg_ctx = config->msg_ctx;
ctrl->cb_ctx = config->cb_ctx;
ctrl->tx = config->tx;
ctrl->gas_resp_tx = config->gas_resp_tx;
@@ -139,7 +157,12 @@ dpp_relay_controller_get(struct dpp_global *dpp, const u8 *pkhash)
static void dpp_controller_gas_done(struct dpp_connection *conn)
{
struct dpp_authentication *auth = conn->auth;
- void *msg_ctx;
+
+ if (auth->waiting_csr) {
+ wpa_printf(MSG_DEBUG, "DPP: Waiting for CSR");
+ conn->on_tcp_tx_complete_gas_done = 0;
+ return;
+ }
if (auth->peer_version >= 2 &&
auth->conf_resp_status == DPP_STATUS_OK) {
@@ -148,11 +171,7 @@ static void dpp_controller_gas_done(struct dpp_connection *conn)
return;
}
- if (conn->ctrl)
- msg_ctx = conn->ctrl->global->msg_ctx;
- else
- msg_ctx = auth->msg_ctx;
- wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
dpp_connection_remove(conn);
}
@@ -243,9 +262,11 @@ static void dpp_controller_start_gas_client(struct dpp_connection *conn)
{
struct dpp_authentication *auth = conn->auth;
struct wpabuf *buf;
- int netrole_ap = 0; /* TODO: make this configurable */
+ const char *dpp_name;
- buf = dpp_build_conf_req_helper(auth, "Test", netrole_ap, NULL, NULL);
+ dpp_name = conn->name ? conn->name : "Test";
+ buf = dpp_build_conf_req_helper(auth, dpp_name, conn->netrole, NULL,
+ NULL);
if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
@@ -266,7 +287,7 @@ static void dpp_controller_auth_success(struct dpp_connection *conn,
return;
wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
- wpa_msg(conn->global->msg_ctx, MSG_INFO,
+ wpa_msg(conn->msg_ctx, MSG_INFO,
DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
@@ -356,6 +377,8 @@ dpp_relay_new_conn(struct dpp_relay_controller *ctrl, const u8 *src,
conn->global = ctrl->global;
conn->relay = ctrl;
+ conn->msg_ctx = ctrl->msg_ctx;
+ conn->cb_ctx = ctrl->global->cb_ctx;
os_memcpy(conn->mac_addr, src, ETH_ALEN);
conn->freq = freq;
@@ -608,8 +631,7 @@ static int dpp_controller_rx_auth_req(struct dpp_connection *conn,
return 0;
}
- conn->auth = dpp_auth_req_rx(conn->ctrl->global,
- conn->ctrl->global->msg_ctx,
+ conn->auth = dpp_auth_req_rx(conn->ctrl->global, conn->msg_ctx,
conn->ctrl->allowed_roles,
conn->ctrl->qr_mutual,
peer_bi, own_bi, -1, hdr, buf, len);
@@ -645,7 +667,7 @@ static int dpp_controller_rx_auth_resp(struct dpp_connection *conn,
if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
wpa_printf(MSG_DEBUG,
"DPP: Start wait for full response");
- return -1;
+ return 0;
}
wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
dpp_connection_remove(conn);
@@ -692,7 +714,7 @@ void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
wpa_printf(MSG_DEBUG,
"DPP: Timeout while waiting for Connection Status Result");
- wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+ wpa_msg(conn->msg_ctx, MSG_INFO,
DPP_EVENT_CONN_STATUS_RESULT "timeout");
dpp_connection_remove(conn);
}
@@ -704,7 +726,7 @@ static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
{
struct dpp_authentication *auth = conn->auth;
enum dpp_status_error status;
- void *msg_ctx;
+ void *msg_ctx = conn->msg_ctx;
if (!conn->ctrl && (!auth || !auth->configurator))
return 0;
@@ -716,10 +738,6 @@ static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
"DPP: No DPP Configuration waiting for result - drop");
return -1;
}
- if (conn->ctrl)
- msg_ctx = conn->ctrl->global->msg_ctx;
- else
- msg_ctx = auth->msg_ctx;
status = dpp_conf_result_rx(auth, hdr, buf, len);
if (status == DPP_STATUS_OK && auth->send_conn_status) {
@@ -765,8 +783,7 @@ static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn,
status = dpp_conn_status_result_rx(auth, hdr, buf, len,
ssid, &ssid_len, &channel_list);
- wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
- DPP_EVENT_CONN_STATUS_RESULT
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT
"result=%d ssid=%s channel_list=%s",
status, wpa_ssid_txt(ssid, ssid_len),
channel_list ? channel_list : "N/A");
@@ -796,7 +813,7 @@ static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn,
r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
&r_bootstrap_len);
if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
- wpa_msg(dpp->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
"Missing or invalid required Responder Bootstrapping Key Hash attribute");
return -1;
}
@@ -809,7 +826,7 @@ static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn,
return -1;
}
- auth = dpp_auth_init(dpp, dpp->msg_ctx, peer_bi, NULL,
+ auth = dpp_auth_init(dpp, conn->msg_ctx, peer_bi, NULL,
DPP_CAPAB_CONFIGURATOR, -1, NULL, 0);
if (!auth)
return -1;
@@ -828,11 +845,12 @@ static int dpp_controller_rx_reconfig_announcement(struct dpp_connection *conn,
const u8 *hdr, const u8 *buf,
size_t len)
{
- const u8 *csign_hash;
- u16 csign_hash_len;
+ 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_global *dpp = conn->ctrl->global;
struct dpp_authentication *auth;
+ u16 group;
if (conn->auth) {
wpa_printf(MSG_DEBUG,
@@ -845,7 +863,7 @@ static int dpp_controller_rx_reconfig_announcement(struct dpp_connection *conn,
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(dpp->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
"Missing or invalid required Configurator C-sign key Hash attribute");
return -1;
}
@@ -858,7 +876,21 @@ static int dpp_controller_rx_reconfig_announcement(struct dpp_connection *conn,
return -1;
}
- auth = dpp_reconfig_init(dpp, dpp->msg_ctx, conf, 0);
+ fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &fcgroup_len);
+ if (!fcgroup || fcgroup_len != 2) {
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Finite Cyclic Group attribute");
+ return -1;
+ }
+ 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(dpp, conn->msg_ctx, conf, 0, group,
+ a_nonce, a_nonce_len, e_id, e_id_len);
if (!auth)
return -1;
if (dpp_set_configurator(auth, conn->ctrl->configurator_params) < 0) {
@@ -965,14 +997,91 @@ static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
}
+static int dpp_tcp_send_comeback_delay(struct dpp_connection *conn, u8 action)
+{
+ struct wpabuf *buf;
+ size_t len = 18;
+
+ if (action == WLAN_PA_GAS_COMEBACK_RESP)
+ len++;
+
+ buf = wpabuf_alloc(4 + len);
+ if (!buf)
+ return -1;
+
+ wpabuf_put_be32(buf, len);
+
+ wpabuf_put_u8(buf, action);
+ wpabuf_put_u8(buf, conn->gas_dialog_token);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ if (action == WLAN_PA_GAS_COMEBACK_RESP)
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_le16(buf, 500); /* GAS Comeback Delay */
+
+ dpp_write_adv_proto(buf);
+ wpabuf_put_le16(buf, 0); /* Query Response Length */
+
+ /* Send Config Response over TCP */
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = buf;
+ dpp_tcp_send(conn);
+ return 0;
+}
+
+
+static int dpp_tcp_send_gas_resp(struct dpp_connection *conn, u8 action,
+ struct wpabuf *resp)
+{
+ struct wpabuf *buf;
+ size_t len;
+
+ if (!resp)
+ return -1;
+
+ len = 18 + wpabuf_len(resp);
+ if (action == WLAN_PA_GAS_COMEBACK_RESP)
+ len++;
+
+ buf = wpabuf_alloc(4 + len);
+ if (!buf) {
+ wpabuf_free(resp);
+ return -1;
+ }
+
+ wpabuf_put_be32(buf, len);
+
+ wpabuf_put_u8(buf, action);
+ wpabuf_put_u8(buf, conn->gas_dialog_token);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ if (action == WLAN_PA_GAS_COMEBACK_RESP)
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */
+
+ dpp_write_adv_proto(buf);
+ dpp_write_gas_query(buf, resp);
+ wpabuf_free(resp);
+
+ /* Send Config Response over TCP; GAS fragmentation is taken care of by
+ * the Relay */
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = buf;
+ conn->on_tcp_tx_complete_gas_done = 1;
+ dpp_tcp_send(conn);
+ return 0;
+}
+
+
static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
size_t len)
{
const u8 *pos, *end, *next;
- u8 dialog_token;
const u8 *adv_proto;
u16 slen;
- struct wpabuf *resp, *buf;
+ struct wpabuf *resp;
struct dpp_authentication *auth = conn->auth;
if (len < 1 + 2)
@@ -990,7 +1099,7 @@ static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
pos = msg;
end = msg + len;
- dialog_token = *pos++;
+ conn->gas_dialog_token = *pos++;
adv_proto = pos++;
slen = *pos++;
if (*adv_proto != WLAN_EID_ADV_PROTO ||
@@ -1015,35 +1124,76 @@ static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
return -1;
resp = dpp_conf_req_rx(auth, pos, slen);
- if (!resp)
+ if (!resp && auth->waiting_cert) {
+ wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready");
+ conn->gas_comeback_in_progress = 1;
+ return dpp_tcp_send_comeback_delay(conn,
+ WLAN_PA_GAS_INITIAL_RESP);
+ }
+
+ return dpp_tcp_send_gas_resp(conn, WLAN_PA_GAS_INITIAL_RESP, resp);
+}
+
+
+static int dpp_controller_rx_gas_comeback_req(struct dpp_connection *conn,
+ const u8 *msg, size_t len)
+{
+ u8 dialog_token;
+ struct dpp_authentication *auth = conn->auth;
+ struct wpabuf *resp;
+
+ if (len < 1)
return -1;
- buf = wpabuf_alloc(4 + 18 + wpabuf_len(resp));
- if (!buf) {
- wpabuf_free(resp);
+ wpa_printf(MSG_DEBUG,
+ "DPP: Received DPP Configuration Request over TCP (comeback)");
+
+ if (!auth || (!conn->ctrl && !auth->configurator) ||
+ (!auth->auth_success && !auth->reconfig_success) ||
+ !conn->gas_comeback_in_progress) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return -1;
}
- wpabuf_put_be32(buf, 18 + wpabuf_len(resp));
+ dialog_token = msg[0];
+ if (dialog_token != conn->gas_dialog_token) {
+ wpa_printf(MSG_DEBUG, "DPP: Dialog token mismatch (%u != %u)",
+ dialog_token, conn->gas_dialog_token);
+ return -1;
+ }
- wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
- wpabuf_put_u8(buf, dialog_token);
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
- wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */
+ if (!auth->conf_resp_tcp) {
+ wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready");
+ return dpp_tcp_send_comeback_delay(conn,
+ WLAN_PA_GAS_COMEBACK_RESP);
+ }
- dpp_write_adv_proto(buf);
- dpp_write_gas_query(buf, resp);
- wpabuf_free(resp);
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configuration response is ready to be sent out");
+ resp = auth->conf_resp_tcp;
+ auth->conf_resp_tcp = NULL;
+ return dpp_tcp_send_gas_resp(conn, WLAN_PA_GAS_COMEBACK_RESP, resp);
+}
- /* Send Config Response over TCP; GAS fragmentation is taken care of by
- * the Relay */
- wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
- wpabuf_free(conn->msg_out);
- conn->msg_out_pos = 0;
- conn->msg_out = buf;
- conn->on_tcp_tx_complete_gas_done = 1;
- dpp_tcp_send(conn);
- return 0;
+
+static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+ struct dpp_authentication *auth = conn->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, conn->name ? conn->name : "Test");
+ if (!auth->csr) {
+ dpp_connection_remove(conn);
+ return;
+ }
+
+ dpp_controller_start_gas_client(conn);
}
@@ -1062,14 +1212,18 @@ static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
else
res = -1;
wpabuf_free(resp);
+ if (res == -2) {
+ wpa_printf(MSG_DEBUG, "DPP: CSR needed");
+ eloop_register_timeout(0, 0, dpp_tcp_build_csr, conn, NULL);
+ return 0;
+ }
if (res < 0) {
wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
return -1;
}
- if (conn->global->process_conf_obj)
- res = conn->global->process_conf_obj(conn->global->cb_ctx,
- auth);
+ if (conn->process_conf_obj)
+ res = conn->process_conf_obj(conn->cb_ctx, auth);
else
res = 0;
@@ -1092,15 +1246,40 @@ static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
}
+static void dpp_tcp_gas_query_comeback(void *eloop_ctx, void *timeout_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+ struct dpp_authentication *auth = conn->auth;
+ struct wpabuf *msg;
+
+ if (!auth)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Send GAS Comeback Request");
+ msg = wpabuf_alloc(4 + 2);
+ if (!msg)
+ return;
+ wpabuf_put_be32(msg, 2);
+ wpabuf_put_u8(msg, WLAN_PA_GAS_COMEBACK_REQ);
+ wpabuf_put_u8(msg, conn->gas_dialog_token);
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
+
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = msg;
+ dpp_tcp_send(conn);
+}
+
+
static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
- size_t len)
+ size_t len, bool comeback)
{
struct wpabuf *buf;
u8 dialog_token;
const u8 *pos, *end, *next, *adv_proto;
- u16 status, slen;
+ u16 status, slen, comeback_delay;
- if (len < 5 + 2)
+ if (len < (size_t) (5 + 2 + (comeback ? 1 : 0)))
return -1;
wpa_printf(MSG_DEBUG,
@@ -1116,7 +1295,10 @@ static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
return -1;
}
pos += 2;
- pos += 2; /* ignore GAS Comeback Delay */
+ if (comeback)
+ pos++; /* ignore Fragment ID */
+ comeback_delay = WPA_GET_LE16(pos);
+ pos += 2;
adv_proto = pos++;
slen = *pos++;
@@ -1141,6 +1323,20 @@ static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
if (slen > end - pos)
return -1;
+ if (comeback_delay) {
+ unsigned int secs, usecs;
+
+ conn->gas_dialog_token = dialog_token;
+ secs = (comeback_delay * 1024) / 1000000;
+ usecs = comeback_delay * 1024 - secs * 1000000;
+ wpa_printf(MSG_DEBUG, "DPP: Comeback delay: %u",
+ comeback_delay);
+ eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL);
+ eloop_register_timeout(secs, usecs, dpp_tcp_gas_query_comeback,
+ conn, NULL);
+ return 0;
+ }
+
buf = wpabuf_alloc(slen);
if (!buf)
return -1;
@@ -1264,8 +1460,15 @@ static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx)
dpp_connection_remove(conn);
break;
case WLAN_PA_GAS_INITIAL_RESP:
+ case WLAN_PA_GAS_COMEBACK_RESP:
if (dpp_rx_gas_resp(conn, pos + 1,
- wpabuf_len(conn->msg) - 1) < 0)
+ wpabuf_len(conn->msg) - 1,
+ *pos == WLAN_PA_GAS_COMEBACK_RESP) < 0)
+ dpp_connection_remove(conn);
+ break;
+ case WLAN_PA_GAS_COMEBACK_REQ:
+ if (dpp_controller_rx_gas_comeback_req(
+ conn, pos + 1, wpabuf_len(conn->msg) - 1) < 0)
dpp_connection_remove(conn);
break;
default:
@@ -1302,7 +1505,11 @@ static void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx)
conn->global = ctrl->global;
conn->ctrl = ctrl;
+ conn->msg_ctx = ctrl->msg_ctx;
+ conn->cb_ctx = ctrl->cb_ctx;
+ conn->process_conf_obj = ctrl->process_conf_obj;
conn->sock = fd;
+ conn->netrole = ctrl->netrole;
if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
@@ -1327,7 +1534,10 @@ fail:
int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
- const struct hostapd_ip_addr *addr, int port)
+ const struct hostapd_ip_addr *addr, int port, const char *name,
+ enum dpp_netrole netrole, void *msg_ctx, void *cb_ctx,
+ int (*process_conf_obj)(void *ctx,
+ struct dpp_authentication *auth))
{
struct dpp_connection *conn;
struct sockaddr_storage saddr;
@@ -1349,6 +1559,11 @@ int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
return -1;
}
+ conn->msg_ctx = msg_ctx;
+ conn->cb_ctx = cb_ctx;
+ conn->process_conf_obj = process_conf_obj;
+ conn->name = os_strdup(name ? name : "Test");
+ conn->netrole = netrole;
conn->global = dpp;
conn->auth = auth;
conn->sock = socket(AF_INET, SOCK_STREAM, 0);
@@ -1418,7 +1633,11 @@ int dpp_controller_start(struct dpp_global *dpp,
os_strdup(config->configurator_params);
dl_list_init(&ctrl->conn);
ctrl->allowed_roles = config->allowed_roles;
- ctrl->qr_mutual = 0;
+ ctrl->qr_mutual = config->qr_mutual;
+ ctrl->netrole = config->netrole;
+ ctrl->msg_ctx = config->msg_ctx;
+ ctrl->cb_ctx = config->cb_ctx;
+ ctrl->process_conf_obj = config->process_conf_obj;
ctrl->sock = socket(AF_INET, SOCK_STREAM, 0);
if (ctrl->sock < 0)
@@ -1474,6 +1693,69 @@ void dpp_controller_stop(struct dpp_global *dpp)
}
+static bool dpp_tcp_peer_id_match(struct dpp_authentication *auth,
+ unsigned int id)
+{
+ return auth &&
+ ((auth->peer_bi && auth->peer_bi->id == id) ||
+ (auth->tmp_peer_bi && auth->tmp_peer_bi->id == id));
+}
+
+
+static struct dpp_authentication * dpp_tcp_get_auth(struct dpp_global *dpp,
+ unsigned int id)
+{
+ struct dpp_connection *conn;
+
+ dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) {
+ if (dpp_tcp_peer_id_match(conn->auth, id))
+ return conn->auth;
+ }
+
+ return NULL;
+}
+
+
+struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp,
+ unsigned int id)
+{
+ struct dpp_controller *ctrl = dpp->controller;
+ struct dpp_connection *conn;
+
+ if (!ctrl)
+ return dpp_tcp_get_auth(dpp, id);
+
+ dl_list_for_each(conn, &ctrl->conn, struct dpp_connection, list) {
+ if (dpp_tcp_peer_id_match(conn->auth, id))
+ return conn->auth;
+ }
+
+ return dpp_tcp_get_auth(dpp, id);
+}
+
+
+void dpp_controller_new_qr_code(struct dpp_global *dpp,
+ struct dpp_bootstrap_info *bi)
+{
+ struct dpp_controller *ctrl = dpp->controller;
+ struct dpp_connection *conn;
+
+ if (!ctrl)
+ return;
+
+ dl_list_for_each(conn, &ctrl->conn, struct dpp_connection, list) {
+ struct dpp_authentication *auth = conn->auth;
+
+ if (!auth->response_pending ||
+ dpp_notify_new_qr_code(auth, bi) != 1)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Sending out pending authentication response");
+ dpp_tcp_send_msg(conn, conn->auth->resp_msg);
+ }
+}
+
+
void dpp_tcp_init_flush(struct dpp_global *dpp)
{
struct dpp_connection *conn, *tmp;
diff --git a/src/common/gas_server.c b/src/common/gas_server.c
index ca46758c..5f44ffeb 100644
--- a/src/common/gas_server.c
+++ b/src/common/gas_server.c
@@ -1,6 +1,7 @@
/*
* Generic advertisement service (GAS) server
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -23,8 +24,9 @@ struct gas_server_handler {
struct dl_list list;
u8 adv_proto_id[MAX_ADV_PROTO_ID_LEN];
u8 adv_proto_id_len;
- struct wpabuf * (*req_cb)(void *ctx, const u8 *sa,
- const u8 *query, size_t query_len);
+ struct wpabuf * (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
+ const u8 *query, size_t query_len,
+ u16 *comeback_delay);
void (*status_cb)(void *ctx, struct wpabuf *resp, int ok);
void *ctx;
struct gas_server *gas;
@@ -39,6 +41,7 @@ struct gas_server_response {
u8 dst[ETH_ALEN];
u8 dialog_token;
struct gas_server_handler *handler;
+ u16 comeback_delay;
};
struct gas_server {
@@ -61,7 +64,8 @@ static void gas_server_response_timeout(void *eloop_ctx, void *user_ctx)
response, MAC2STR(response->dst), response->dialog_token,
response->freq, response->frag_id,
(unsigned long) response->offset,
- (unsigned long) wpabuf_len(response->resp));
+ (unsigned long) (response->resp ?
+ wpabuf_len(response->resp) : 0));
response->handler->status_cb(response->handler->ctx,
response->resp, 0);
response->resp = NULL;
@@ -83,30 +87,29 @@ static void gas_server_free_response(struct gas_server_response *response)
static void
gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
+ struct gas_server_response *response,
const u8 *da, int freq, u8 dialog_token,
- struct wpabuf *query_resp)
+ struct wpabuf *query_resp, u16 comeback_delay)
{
size_t max_len = (freq > 56160) ? 928 : 1400;
size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2;
size_t resp_frag_len;
struct wpabuf *resp;
- u16 comeback_delay;
- struct gas_server_response *response;
- if (!query_resp)
- return;
-
- response = os_zalloc(sizeof(*response));
- if (!response) {
- wpabuf_free(query_resp);
+ if (comeback_delay == 0 && !query_resp) {
+ gas_server_free_response(response);
return;
}
- wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
+
response->freq = freq;
response->handler = handler;
os_memcpy(response->dst, da, ETH_ALEN);
response->dialog_token = dialog_token;
- if (hdr_len + wpabuf_len(query_resp) > max_len) {
+ if (comeback_delay) {
+ /* Need more time to prepare the response */
+ resp_frag_len = 0;
+ response->comeback_delay = comeback_delay;
+ } else if (hdr_len + wpabuf_len(query_resp) > max_len) {
/* Need to use comeback to initiate fragmentation */
comeback_delay = 1;
resp_frag_len = 0;
@@ -135,10 +138,12 @@ gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
/* Query Response Length */
wpabuf_put_le16(resp, resp_frag_len);
- if (!comeback_delay)
+ if (!comeback_delay && query_resp)
wpabuf_put_buf(resp, query_resp);
- if (comeback_delay) {
+ if (comeback_delay && !query_resp) {
+ wpa_printf(MSG_DEBUG, "GAS: No response available yet");
+ } else if (comeback_delay) {
wpa_printf(MSG_DEBUG,
"GAS: Need to fragment query response");
} else {
@@ -165,6 +170,7 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
u16 query_req_len;
struct gas_server_handler *handler;
struct wpabuf *resp;
+ struct gas_server_response *response;
wpa_hexdump(MSG_MSGDUMP, "GAS: Received GAS Initial Request frame",
data, len);
@@ -210,8 +216,15 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
pos, end - pos);
}
+ response = os_zalloc(sizeof(*response));
+ if (!response)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
dl_list_for_each(handler, &gas->handlers, struct gas_server_handler,
list) {
+ u16 comeback_delay = 0;
+
if (adv_proto_len < 1 + handler->adv_proto_id_len ||
os_memcmp(adv_proto + 1, handler->adv_proto_id,
handler->adv_proto_id_len) != 0)
@@ -219,17 +232,22 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
wpa_printf(MSG_DEBUG,
"GAS: Calling handler for the requested Advertisement Protocol ID");
- resp = handler->req_cb(handler->ctx, sa, query_req,
- query_req_len);
+ resp = handler->req_cb(handler->ctx, response, sa, query_req,
+ query_req_len, &comeback_delay);
wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler",
resp);
- gas_server_send_resp(gas, handler, sa, freq, dialog_token,
- resp);
+ if (comeback_delay)
+ wpa_printf(MSG_DEBUG,
+ "GAS: Handler requested comeback delay: %u TU",
+ comeback_delay);
+ gas_server_send_resp(gas, handler, response, sa, freq,
+ dialog_token, resp, comeback_delay);
return 0;
}
wpa_printf(MSG_DEBUG,
"GAS: No registered handler for the requested Advertisement Protocol ID");
+ gas_server_free_response(response);
return -1;
}
@@ -243,6 +261,31 @@ gas_server_handle_rx_comeback_req(struct gas_server_response *response)
size_t hdr_len = 24 + 2 + 6 + 3 + handler->adv_proto_id_len + 2;
size_t remaining, resp_frag_len;
struct wpabuf *resp;
+ unsigned int wait_time = 0;
+
+ if (!response->resp) {
+ resp = gas_build_comeback_resp(response->dialog_token,
+ WLAN_STATUS_SUCCESS, 0, 0,
+ response->comeback_delay,
+ handler->adv_proto_id_len);
+ if (!resp) {
+ dl_list_del(&response->list);
+ gas_server_free_response(response);
+ return;
+ }
+
+ /* Advertisement Protocol element */
+ wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
+ wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
+ wpabuf_put_u8(resp, 0x7f);
+ /* Advertisement Protocol ID */
+ wpabuf_put_data(resp, handler->adv_proto_id,
+ handler->adv_proto_id_len);
+
+ /* Query Response Length */
+ wpabuf_put_le16(resp, 0);
+ goto send_resp;
+ }
remaining = wpabuf_len(response->resp) - response->offset;
if (hdr_len + remaining > max_len)
@@ -279,8 +322,11 @@ gas_server_handle_rx_comeback_req(struct gas_server_response *response)
response->offset += resp_frag_len;
- gas->tx(gas->ctx, response->freq, response->dst, resp,
- remaining > resp_frag_len ? 2000 : 0);
+ if (remaining > resp_frag_len)
+ wait_time = 2000;
+
+send_resp:
+ gas->tx(gas->ctx, response->freq, response->dst, resp, wait_time);
wpabuf_free(resp);
}
@@ -359,12 +405,19 @@ int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
static void gas_server_handle_tx_status(struct gas_server_response *response,
int ack)
{
- if (ack && response->offset < wpabuf_len(response->resp)) {
+ if (ack && response->resp &&
+ response->offset < wpabuf_len(response->resp)) {
wpa_printf(MSG_DEBUG,
"GAS: More fragments remaining - keep pending entry");
return;
}
+ if (ack && !response->resp && response->comeback_delay) {
+ wpa_printf(MSG_DEBUG,
+ "GAS: Waiting for response - keep pending entry");
+ return;
+ }
+
if (!ack)
wpa_printf(MSG_DEBUG,
"GAS: No ACK received - drop pending entry");
@@ -415,6 +468,42 @@ void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
}
+int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
+ struct wpabuf *resp)
+{
+ struct gas_server_response *tmp, *response = NULL;
+
+ dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
+ list) {
+ if (tmp == resp_ctx) {
+ response = tmp;
+ break;
+ }
+ }
+
+ if (!response || response->resp)
+ return -1;
+
+ response->resp = resp;
+ return 0;
+}
+
+
+bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx)
+{
+ struct gas_server_response *tmp;
+
+ dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
+ list) {
+ if (tmp == resp_ctx)
+ return tmp->resp &&
+ tmp->offset == wpabuf_len(tmp->resp);
+ }
+
+ return false;
+}
+
+
struct gas_server * gas_server_init(void *ctx,
void (*tx)(void *ctx, int freq,
const u8 *da,
@@ -461,8 +550,9 @@ void gas_server_deinit(struct gas_server *gas)
int gas_server_register(struct gas_server *gas,
const u8 *adv_proto_id, u8 adv_proto_id_len,
struct wpabuf *
- (*req_cb)(void *ctx, const u8 *sa,
- const u8 *query, size_t query_len),
+ (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
+ const u8 *query, size_t query_len,
+ u16 *comeback_delay),
void (*status_cb)(void *ctx, struct wpabuf *resp,
int ok),
void *ctx)
diff --git a/src/common/gas_server.h b/src/common/gas_server.h
index 299f529f..db00f87e 100644
--- a/src/common/gas_server.h
+++ b/src/common/gas_server.h
@@ -1,6 +1,7 @@
/*
* Generic advertisement service (GAS) server
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,8 +23,9 @@ void gas_server_deinit(struct gas_server *gas);
int gas_server_register(struct gas_server *gas,
const u8 *adv_proto_id, u8 adv_proto_id_len,
struct wpabuf *
- (*req_cb)(void *ctx, const u8 *sa,
- const u8 *query, size_t query_len),
+ (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
+ const u8 *query, size_t query_len,
+ u16 *comeback_delay),
void (*status_cb)(void *ctx, struct wpabuf *resp,
int ok),
void *ctx);
@@ -32,6 +34,9 @@ int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
int freq);
void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
size_t data_len, int ack);
+int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
+ struct wpabuf *resp);
+bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx);
#else /* CONFIG_GAS_SERVER */
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index f6c67a37..b8b886fa 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -41,10 +41,30 @@ struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
struct hostapd_channel_data *
+hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan)
+{
+ int i;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *ch = &mode->channels[i];
+
+ if (ch->freq == freq) {
+ if (chan)
+ *chan = ch->chan;
+ return ch;
+ }
+ }
+
+ return NULL;
+}
+
+
+struct hostapd_channel_data *
hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
struct hostapd_hw_modes *hw_features, int num_hw_features)
{
- int i, j;
+ struct hostapd_channel_data *chan_data;
+ int i;
if (chan)
*chan = 0;
@@ -52,21 +72,15 @@ hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
if (!hw_features)
return NULL;
- for (j = 0; j < num_hw_features; j++) {
- struct hostapd_hw_modes *curr_mode = &hw_features[j];
+ for (i = 0; i < num_hw_features; i++) {
+ struct hostapd_hw_modes *curr_mode = &hw_features[i];
if (curr_mode->mode != mode)
continue;
- for (i = 0; i < curr_mode->num_channels; i++) {
- struct hostapd_channel_data *ch =
- &curr_mode->channels[i];
-
- if (ch->freq == freq) {
- if (chan)
- *chan = ch->chan;
- return ch;
- }
- }
+
+ chan_data = hw_mode_get_channel(curr_mode, freq, chan);
+ if (chan_data)
+ return chan_data;
}
return NULL;
@@ -415,7 +429,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
return -1;
}
- if (center_idx_to_bw_6ghz(channel) != 0) {
+ if (center_idx_to_bw_6ghz(channel) < 0) {
wpa_printf(MSG_ERROR,
"Invalid control channel for 6 GHz band");
return -1;
@@ -540,13 +554,20 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
if (center_segment1 ||
(center_segment0 != 0 &&
5000 + center_segment0 * 5 != data->center_freq1 &&
- 2407 + center_segment0 * 5 != data->center_freq1))
+ 2407 + center_segment0 * 5 != data->center_freq1)) {
+ wpa_printf(MSG_ERROR,
+ "20/40 MHz: center segment 0 (=%d) and center freq 1 (=%d) not in sync",
+ center_segment0, data->center_freq1);
return -1;
+ }
break;
case CHANWIDTH_80P80MHZ:
if (center_segment1 == center_segment0 + 4 ||
- center_segment1 == center_segment0 - 4)
+ center_segment1 == center_segment0 - 4) {
+ wpa_printf(MSG_ERROR,
+ "80+80 MHz: center segment 1 only 20 MHz apart");
return -1;
+ }
data->center_freq2 = 5000 + center_segment1 * 5;
/* fall through */
case CHANWIDTH_80MHZ:
@@ -555,8 +576,11 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
center_segment1) ||
(oper_chwidth == CHANWIDTH_80P80MHZ &&
!center_segment1) ||
- !sec_channel_offset)
+ !sec_channel_offset) {
+ wpa_printf(MSG_ERROR,
+ "80/80+80 MHz: center segment 1 wrong or no second channel offset");
return -1;
+ }
if (!center_segment0) {
if (channel <= 48)
center_segment0 = 42;
@@ -570,6 +594,8 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
center_segment0 = 138;
else if (channel <= 161)
center_segment0 = 155;
+ else if (channel <= 177)
+ center_segment0 = 171;
data->center_freq1 = 5000 + center_segment0 * 5;
} else {
/*
@@ -582,16 +608,25 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
center_segment0 == channel - 2 ||
center_segment0 == channel - 6)
data->center_freq1 = 5000 + center_segment0 * 5;
- else
+ else {
+ wpa_printf(MSG_ERROR,
+ "Wrong coupling between HT and VHT/HE channel setting");
return -1;
+ }
}
break;
case CHANWIDTH_160MHZ:
data->bandwidth = 160;
- if (center_segment1)
+ if (center_segment1) {
+ wpa_printf(MSG_ERROR,
+ "160 MHz: center segment 1 should not be set");
return -1;
- if (!sec_channel_offset)
+ }
+ if (!sec_channel_offset) {
+ wpa_printf(MSG_ERROR,
+ "160 MHz: second channel offset not set");
return -1;
+ }
/*
* Note: HT/VHT config and params are coupled. Check if
* HT40 channel band is in VHT160 channel band configuration.
@@ -605,8 +640,11 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
center_segment0 == channel - 10 ||
center_segment0 == channel - 14)
data->center_freq1 = 5000 + center_segment0 * 5;
- else
+ else {
+ wpa_printf(MSG_ERROR,
+ "160 MHz: HT40 channel band is not in 160 MHz band");
return -1;
+ }
break;
}
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index e57a8d65..ddde36b9 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -15,6 +15,9 @@
struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
int chan, int *freq);
struct hostapd_channel_data *
+hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan);
+
+struct hostapd_channel_data *
hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
struct hostapd_hw_modes *hw_features, int num_hw_features);
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 92960e28..fa39761e 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -136,6 +136,10 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
case DPP_CC_OUI_TYPE:
/* DPP Configurator Connectivity element */
break;
+ case SAE_PK_OUI_TYPE:
+ elems->sae_pk = pos + 4;
+ elems->sae_pk_len = elen - 4;
+ break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
@@ -303,6 +307,10 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
break;
elems->he_6ghz_band_cap = pos;
break;
+ case WLAN_EID_EXT_PASN_PARAMS:
+ elems->pasn_params = pos;
+ elems->pasn_params_len = elen;
+ break;
default:
if (show_errors) {
wpa_printf(MSG_MSGDUMP,
@@ -566,6 +574,11 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->dils = pos;
elems->dils_len = elen;
break;
+ case WLAN_EID_S1G_CAPABILITIES:
+ if (elen < 15)
+ break;
+ elems->s1g_capab = pos;
+ break;
case WLAN_EID_FRAGMENT:
ieee802_11_parse_fragment(&elems->frag_ies, pos, elen);
break;
@@ -769,6 +782,98 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
}
+/* convert floats with one decimal place to value*10 int, i.e.,
+ * "1.5" will return 15
+ */
+static int hostapd_config_read_int10(const char *value)
+{
+ int i, d;
+ char *pos;
+
+ i = atoi(value);
+ pos = os_strchr(value, '.');
+ d = 0;
+ if (pos) {
+ pos++;
+ if (*pos >= '0' && *pos <= '9')
+ d = *pos - '0';
+ }
+
+ return i * 10 + d;
+}
+
+
+static int valid_cw(int cw)
+{
+ return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
+ cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
+ cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
+ cw == 32767);
+}
+
+
+int hostapd_config_tx_queue(struct hostapd_tx_queue_params tx_queue[],
+ const char *name, const char *val)
+{
+ int num;
+ const char *pos;
+ struct hostapd_tx_queue_params *queue;
+
+ /* skip 'tx_queue_' prefix */
+ pos = name + 9;
+ if (os_strncmp(pos, "data", 4) == 0 &&
+ pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
+ num = pos[4] - '0';
+ pos += 6;
+ } else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
+ os_strncmp(pos, "beacon_", 7) == 0) {
+ wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
+ return 0;
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
+ return -1;
+ }
+
+ if (num >= NUM_TX_QUEUES) {
+ /* for backwards compatibility, do not trigger failure */
+ wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
+ return 0;
+ }
+
+ queue = &tx_queue[num];
+
+ if (os_strcmp(pos, "aifs") == 0) {
+ queue->aifs = atoi(val);
+ if (queue->aifs < 0 || queue->aifs > 255) {
+ wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
+ queue->aifs);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "cwmin") == 0) {
+ queue->cwmin = atoi(val);
+ if (!valid_cw(queue->cwmin)) {
+ wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
+ queue->cwmin);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "cwmax") == 0) {
+ queue->cwmax = atoi(val);
+ if (!valid_cw(queue->cwmax)) {
+ wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
+ queue->cwmax);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "burst") == 0) {
+ queue->burst = hostapd_config_read_int10(val);
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown queue field '%s'", pos);
+ return -1;
+ }
+
+ return 0;
+}
+
+
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
{
u8 op_class;
@@ -780,7 +885,7 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
/**
* ieee80211_freq_to_channel_ext - Convert frequency into channel info
- * for HT40 and VHT. DFS channels are not covered.
+ * for HT40, VHT, and HE. DFS channels are not covered.
* @freq: Frequency (MHz) to convert
* @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
* @chanwidth: VHT/EDMG channel width (CHANWIDTH_*)
@@ -891,8 +996,8 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
return HOSTAPD_MODE_IEEE80211A;
}
- /* 5 GHz, channels 149..169 */
- if (freq >= 5745 && freq <= 5845) {
+ /* 5 GHz, channels 149..177 */
+ if (freq >= 5745 && freq <= 5885) {
if ((freq - 5000) % 5)
return NUM_HOSTAPD_MODES;
@@ -940,15 +1045,28 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
}
if (freq > 5950 && freq <= 7115) {
- int bw;
- u8 idx = (freq - 5950) / 5;
-
- bw = center_idx_to_bw_6ghz(idx);
- if (bw < 0)
+ if ((freq - 5950) % 5)
return NUM_HOSTAPD_MODES;
- *channel = idx;
- *op_class = 131 + bw;
+ switch (chanwidth) {
+ case CHANWIDTH_80MHZ:
+ *op_class = 133;
+ break;
+ case CHANWIDTH_160MHZ:
+ *op_class = 134;
+ break;
+ case CHANWIDTH_80P80MHZ:
+ *op_class = 135;
+ break;
+ default:
+ if (sec_channel)
+ *op_class = 132;
+ else
+ *op_class = 131;
+ break;
+ }
+
+ *channel = (freq - 5950) / 5;
return HOSTAPD_MODE_IEEE80211A;
}
@@ -1309,22 +1427,22 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
return -1;
return 5000 + 5 * chan;
case 124: /* channels 149,153,157,161 */
- case 126: /* channels 149,157; 40 MHz */
- case 127: /* channels 153,161; 40 MHz */
if (chan < 149 || chan > 161)
return -1;
return 5000 + 5 * chan;
- case 125: /* channels 149,153,157,161,165,169 */
- if (chan < 149 || chan > 169)
+ case 125: /* channels 149,153,157,161,165,169,173,177 */
+ case 126: /* channels 149,157,165,173; 40 MHz */
+ case 127: /* channels 153,161,169,177; 40 MHz */
+ if (chan < 149 || chan > 177)
return -1;
return 5000 + 5 * chan;
- case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
- case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
- if (chan < 36 || chan > 161)
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
+ case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
+ if (chan < 36 || chan > 177)
return -1;
return 5000 + 5 * chan;
- case 129: /* center freqs 50, 114; 160 MHz */
- if (chan < 36 || chan > 128)
+ case 129: /* center freqs 50, 114, 163; 160 MHz */
+ if (chan < 36 || chan > 177)
return -1;
return 5000 + 5 * chan;
case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
@@ -1421,7 +1539,8 @@ int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
static int is_11b(u8 rate)
{
- return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
+ return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16
+ || rate == 0x82 || rate == 0x84 || rate == 0x8b || rate == 0x96;
}
@@ -1682,7 +1801,9 @@ const char * status2str(u16 status)
S2S(FILS_AUTHENTICATION_FAILURE)
S2S(UNKNOWN_AUTHENTICATION_SERVER)
S2S(UNKNOWN_PASSWORD_IDENTIFIER)
+ S2S(DENIED_HE_NOT_SUPPORTED)
S2S(SAE_HASH_TO_ELEMENT)
+ S2S(SAE_PK)
}
return "UNKNOWN";
#undef S2S
@@ -1766,22 +1887,26 @@ const struct oper_class_map global_op_class[] = {
{ HOSTAPD_MODE_IEEE80211A, 122, 100, 132, 8, BW40PLUS, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 123, 104, 136, 8, BW40MINUS, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 125, 149, 177, 4, BW20, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 126, 149, 173, 8, BW40PLUS, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 127, 153, 177, 8, BW40MINUS, P2P_SUPP },
/*
- * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center
- * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of
- * 80 MHz, but currently use the following definition for simplicity
+ * IEEE P802.11ax/D8.0 Table E-4 actually talks about channel center
+ * frequency index 42, 58, 106, 122, 138, 155, 171 with channel spacing
+ * of 80 MHz, but currently use the following definition for simplicity
* (these center frequencies are not actual channels, which makes
- * wpas_p2p_allow_channel() fail). wpas_p2p_verify_80mhz() should take
+ * wpas_p2p_verify_channel() fail). wpas_p2p_verify_80mhz() should take
* care of removing invalid channels.
*/
- { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 128, 36, 177, 4, BW80, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 129, 36, 177, 4, BW160, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 135, 1, 233, 16, BW80P80, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 136, 2, 2, 4, BW20, NO_P2P_SUPP },
/*
* IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes.
@@ -1792,6 +1917,12 @@ const struct oper_class_map global_op_class[] = {
{ HOSTAPD_MODE_IEEE80211AD, 181, 9, 13, 1, BW4320, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211AD, 182, 17, 20, 1, BW6480, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211AD, 183, 25, 27, 1, BW8640, P2P_SUPP },
+
+ /* Keep the operating class 130 as the last entry as a workaround for
+ * the OneHundredAndThirty Delimiter value used in the Supported
+ * Operating Classes element to indicate the end of the Operating
+ * Classes field. */
+ { HOSTAPD_MODE_IEEE80211A, 130, 36, 177, 4, BW80P80, P2P_SUPP },
{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
};
@@ -2089,6 +2220,7 @@ int oper_class_bw_to_int(const struct oper_class_map *map)
switch (map->bw) {
case BW20:
return 20;
+ case BW40:
case BW40PLUS:
case BW40MINUS:
return 40;
@@ -2124,44 +2256,44 @@ int center_idx_to_bw_6ghz(u8 idx)
}
-int is_6ghz_freq(int freq)
+bool is_6ghz_freq(int freq)
{
if (freq < 5935 || freq > 7115)
- return 0;
+ return false;
if (freq == 5935)
- return 1;
+ return true;
if (center_idx_to_bw_6ghz((freq - 5950) / 5) < 0)
- return 0;
+ return false;
- return 1;
+ return true;
}
-int is_6ghz_op_class(u8 op_class)
+bool is_6ghz_op_class(u8 op_class)
{
return op_class >= 131 && op_class <= 136;
}
-int is_6ghz_psc_frequency(int freq)
+bool is_6ghz_psc_frequency(int freq)
{
int i;
if (!is_6ghz_freq(freq) || freq == 5935)
- return 0;
+ return false;
if ((((freq - 5950) / 5) & 0x3) != 0x1)
- return 0;
+ return false;
i = (freq - 5950 + 55) % 80;
if (i == 0)
i = (freq - 5950 + 55) / 80;
if (i >= 1 && i <= 15)
- return 1;
+ return true;
- return 0;
+ return false;
}
@@ -2372,16 +2504,16 @@ int op_class_to_bandwidth(u8 op_class)
case 123: /* channels 104-136; 40 MHz */
return 40;
case 124: /* channels 149,153,157,161 */
- case 125: /* channels 149,153,157,161,165,169 */
+ case 125: /* channels 149,153,157,161,165,169,173,177 */
return 20;
- case 126: /* channels 149,157; 40 MHz */
- case 127: /* channels 153,161; 40 MHz */
+ case 126: /* channels 149,157,161,165,169,173; 40 MHz */
+ case 127: /* channels 153..177; 40 MHz */
return 40;
- case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
return 80;
- case 129: /* center freqs 50, 114; 160 MHz */
+ case 129: /* center freqs 50, 114, 163; 160 MHz */
return 160;
- case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80+80 MHz */
+ case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */
return 80;
case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
return 20;
@@ -2433,16 +2565,16 @@ int op_class_to_ch_width(u8 op_class)
case 123: /* channels 104-136; 40 MHz */
return CHANWIDTH_USE_HT;
case 124: /* channels 149,153,157,161 */
- case 125: /* channels 149,153,157,161,165,169 */
+ case 125: /* channels 149,153,157,161,165,169,171 */
return CHANWIDTH_USE_HT;
- case 126: /* channels 149,157; 40 MHz */
- case 127: /* channels 153,161; 40 MHz */
+ case 126: /* channels 149,157,165, 173; 40 MHz */
+ case 127: /* channels 153,161,169,177; 40 MHz */
return CHANWIDTH_USE_HT;
- case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
return CHANWIDTH_80MHZ;
- case 129: /* center freqs 50, 114; 160 MHz */
+ case 129: /* center freqs 50, 114, 163; 160 MHz */
return CHANWIDTH_160MHZ;
- case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80+80 MHz */
+ case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */
return CHANWIDTH_80P80MHZ;
case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
return CHANWIDTH_USE_HT;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 55f7aa62..e4992b3d 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -114,6 +114,9 @@ struct ieee802_11_elems {
const u8 *he_operation;
const u8 *short_ssid_list;
const u8 *he_6ghz_band_cap;
+ const u8 *sae_pk;
+ const u8 *s1g_capab;
+ const u8 *pasn_params;
u8 ssid_len;
u8 supp_rates_len;
@@ -166,6 +169,8 @@ struct ieee802_11_elems {
u8 he_capabilities_len;
u8 he_operation_len;
u8 short_ssid_list_len;
+ u8 sae_pk_len;
+ u8 pasn_params_len;
struct mb_ies_info mb_ies;
struct frag_ies_info frag_ies;
@@ -192,6 +197,18 @@ struct hostapd_wmm_ac_params {
int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
const char *name, const char *val);
+
+struct hostapd_tx_queue_params {
+ int aifs;
+ int cwmin;
+ int cwmax;
+ int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
+};
+
+#define NUM_TX_QUEUES 4
+
+int hostapd_config_tx_queue(struct hostapd_tx_queue_params queue[],
+ const char *name, const char *val);
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
@@ -218,8 +235,8 @@ struct oper_class_map {
u8 min_chan;
u8 max_chan;
u8 inc;
- enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160, BW160, BW80P80, BW4320,
- BW6480, BW8640} bw;
+ enum { BW20, BW40PLUS, BW40MINUS, BW40, BW80, BW2160, BW160, BW80P80,
+ BW4320, BW6480, BW8640} bw;
enum { P2P_SUPP, NO_P2P_SUPP } p2p;
};
@@ -244,9 +261,9 @@ u8 country_to_global_op_class(const char *country, u8 op_class);
const struct oper_class_map * get_oper_class(const char *country, u8 op_class);
int oper_class_bw_to_int(const struct oper_class_map *map);
int center_idx_to_bw_6ghz(u8 idx);
-int is_6ghz_freq(int freq);
-int is_6ghz_op_class(u8 op_class);
-int is_6ghz_psc_frequency(int freq);
+bool is_6ghz_freq(int freq);
+bool is_6ghz_op_class(u8 op_class);
+bool is_6ghz_psc_frequency(int freq);
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 65cc4df6..c3859237 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -50,6 +50,7 @@
#define WLAN_FC_STYPE_AUTH 11
#define WLAN_FC_STYPE_DEAUTH 12
#define WLAN_FC_STYPE_ACTION 13
+#define WLAN_FC_STYPE_ACTION_NO_ACK 14
/* control */
#define WLAN_FC_STYPE_PSPOLL 10
@@ -84,6 +85,7 @@
#define WLAN_AUTH_FILS_SK 4
#define WLAN_AUTH_FILS_SK_PFS 5
#define WLAN_AUTH_FILS_PK 6
+#define WLAN_AUTH_PASN 7
#define WLAN_AUTH_LEAP 128
#define WLAN_AUTH_CHALLENGE_LEN 128
@@ -204,7 +206,9 @@
#define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
#define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
+#define WLAN_STATUS_DENIED_HE_NOT_SUPPORTED 124
#define WLAN_STATUS_SAE_HASH_TO_ELEMENT 126
+#define WLAN_STATUS_SAE_PK 127
/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
#define WLAN_REASON_UNSPECIFIED 1
@@ -430,7 +434,7 @@
#define WLAN_EID_VHT_OPERATION 192
#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
#define WLAN_EID_VHT_WIDE_BW_CHSWITCH 194
-#define WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE 195
+#define WLAN_EID_TRANSMIT_POWER_ENVELOPE 195
#define WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER 196
#define WLAN_EID_VHT_AID 197
#define WLAN_EID_VHT_QUIET_CHANNEL 198
@@ -441,7 +445,10 @@
#define WLAN_EID_DEVICE_LOCATION 204
#define WLAN_EID_WHITE_SPACE_MAP 205
#define WLAN_EID_FTM_PARAMETERS 206
+#define WLAN_EID_S1G_BCN_COMPAT 213
+#define WLAN_EID_S1G_CAPABILITIES 217
#define WLAN_EID_VENDOR_SPECIFIC 221
+#define WLAN_EID_S1G_OPERATION 232
#define WLAN_EID_CAG_NUMBER 237
#define WLAN_EID_AP_CSN 239
#define WLAN_EID_FILS_INDICATION 240
@@ -476,8 +483,11 @@
#define WLAN_EID_EXT_HE_6GHZ_BAND_CAP 59
#define WLAN_EID_EXT_EDMG_CAPABILITIES 61
#define WLAN_EID_EXT_EDMG_OPERATION 62
+#define WLAN_EID_EXT_MSCS_DESCRIPTOR 88
+#define WLAN_EID_EXT_TCLAS_MASK 89
#define WLAN_EID_EXT_REJECTED_GROUPS 92
#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93
+#define WLAN_EID_EXT_PASN_PARAMS 100
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -521,7 +531,6 @@
#define WLAN_EXT_CAPAB_TDLS_PROHIBITED 38
#define WLAN_EXT_CAPAB_TDLS_CHANNEL_SWITCH_PROHIBITED 39
#define WLAN_EXT_CAPAB_REJECT_UNADMITTED_FRAME 40
-#define WLAN_EXT_CAPAB_
/* 41-43 - Service Interval Granularity */
#define WLAN_EXT_CAPAB_IDENTIFIER_LOCATION 44
#define WLAN_EXT_CAPAB_U_APSD_COEX 45
@@ -542,7 +551,6 @@
#define WLAN_EXT_CAPAB_PROT_QLOAD_REPORT 60
#define WLAN_EXT_CAPAB_TDLS_WIDER_BW 61
#define WLAN_EXT_CAPAB_OPMODE_NOTIF 62
-#define WLAN_EXT_CAPAB_
/* 63-64 - Max Number of MSDUs In A-MSDU */
#define WLAN_EXT_CAPAB_CHANNEL_SCHEDULE_MGMT 65
#define WLAN_EXT_CAPAB_GEODB_INBAND_ENABLING_SIGNAL 66
@@ -560,11 +568,17 @@
#define WLAN_EXT_CAPAB_SAE_PW_ID 81
#define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82
#define WLAN_EXT_CAPAB_BEACON_PROTECTION 84
+#define WLAN_EXT_CAPAB_MSCS 85
+#define WLAN_EXT_CAPAB_SAE_PK_EXCLUSIVELY 88
/* Extended RSN Capabilities */
/* bits 0-3: Field length (n-1) */
#define WLAN_RSNX_CAPAB_PROTECTED_TWT 4
#define WLAN_RSNX_CAPAB_SAE_H2E 5
+#define WLAN_RSNX_CAPAB_SAE_PK 6
+#define WLAN_RSNX_CAPAB_SECURE_LTF 8
+#define WLAN_RSNX_CAPAB_SECURE_RTT 9
+#define WLAN_RSNX_CAPAB_PROT_RANGE_NEG 10
/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
@@ -590,6 +604,7 @@
#define WLAN_ACTION_UNPROTECTED_DMG 20
#define WLAN_ACTION_VHT 21
#define WLAN_ACTION_FILS 26
+#define WLAN_ACTION_PROTECTED_FTM 34
#define WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED 126
#define WLAN_ACTION_VENDOR_SPECIFIC 127
/* Note: 128-255 used to report errors by setting category | 0x80 */
@@ -630,6 +645,7 @@
#define WLAN_PA_FTM_REQUEST 32
#define WLAN_PA_FTM 33
#define WLAN_PA_FILS_DISCOVERY 34
+#define WLAN_PA_LOCATION_MEASUREMENT_REPORT 47
/* Protected Dual of Public Action frames (IEEE Std 802.11-2016, 9.6.11,
* Table 9-332) */
@@ -687,6 +703,11 @@
#define WLAN_RRM_NEIGHBOR_REPORT_REQUEST 4
#define WLAN_RRM_NEIGHBOR_REPORT_RESPONSE 5
+/* Protected Fine Timing Frame Action Field value */
+#define WLAN_PROT_FTM_REQUEST 1
+#define WLAN_PROT_FTM 2
+#define WLAN_PROT_FTM_REPORT 3
+
/* Radio Measurement capabilities (from RM Enabled Capabilities element)
* IEEE Std 802.11-2016, 9.4.2.45, Table 9-157 */
/* byte 1 (out of 5) */
@@ -1325,6 +1346,8 @@ struct ieee80211_ampe_ie {
#define MULTI_AP_OUI_TYPE 0x1B
#define DPP_CC_IE_VENDOR_TYPE 0x506f9a1e
#define DPP_CC_OUI_TYPE 0x1e
+#define SAE_PK_IE_VENDOR_TYPE 0x506f9a1f
+#define SAE_PK_OUI_TYPE 0x1f
#define MULTI_AP_SUB_ELEM_TYPE 0x06
#define MULTI_AP_TEAR_DOWN BIT(4)
@@ -2178,23 +2201,30 @@ struct ieee80211_he_6ghz_band_cap {
/* Minimum MPDU Start Spacing B0..B2
* Maximum A-MPDU Length Exponent B3..B5
* Maximum MPDU Length B6..B7 */
- u8 a_mpdu_params; /* B0..B7 */
- u8 info; /* B8..B15 */
+ le16 capab;
} STRUCT_PACKED;
-#define HE_6GHZ_BAND_CAP_MIN_MPDU_START_SPACE_MASK 0x7
-#define HE_6GHZ_BAND_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK 0x7
-#define HE_6GHZ_BAND_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT 3
-#define HE_6GHZ_BAND_CAP_MAX_MPDU_LENGTH_MASK 0x3
-#define HE_6GHZ_BAND_CAP_MAX_MPDU_LENGTH_SHIFT 6
-
-#define HE_6GHZ_BAND_CAP_SMPS_MASK (BIT(1) | BIT(2))
-#define HE_6GHZ_BAND_CAP_SMPS_STATIC 0
-#define HE_6GHZ_BAND_CAP_SMPS_DYNAMIC BIT(1)
-#define HE_6GHZ_BAND_CAP_SMPS_DISABLED (BIT(1) | BIT(2))
-#define HE_6GHZ_BAND_CAP_RD_RESPONDER BIT(3)
-#define HE_6GHZ_BAND_CAP_RX_ANTENNA_PATTERN BIT(4)
-#define HE_6GHZ_BAND_CAP_TX_ANTENNA_PATTERN BIT(5)
+#define HE_6GHZ_BAND_CAP_MIN_MPDU_START (BIT(0) | BIT(1) | BIT(2))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_16K BIT(3)
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_32K BIT(4)
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_64K (BIT(3) | BIT(4))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_128K BIT(5)
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_256K (BIT(3) | BIT(5))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_512K (BIT(4) | BIT(5))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_1024K (BIT(3) | BIT(4) | BIT(5))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK (BIT(3) | BIT(4) | BIT(5))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT 3
+#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_7991 BIT(6)
+#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_11454 BIT(7)
+#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK (BIT(6) | BIT(7))
+#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT 6
+#define HE_6GHZ_BAND_CAP_SMPS_MASK (BIT(9) | BIT(10))
+#define HE_6GHZ_BAND_CAP_SMPS_STATIC 0
+#define HE_6GHZ_BAND_CAP_SMPS_DYNAMIC BIT(9)
+#define HE_6GHZ_BAND_CAP_SMPS_DISABLED (BIT(9) | BIT(10))
+#define HE_6GHZ_BAND_CAP_RD_RESPONDER BIT(11)
+#define HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS BIT(12)
+#define HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS BIT(13)
/*
* IEEE P802.11ax/D4.0, 9.4.2.246 Spatial Reuse Parameter Set element
@@ -2355,4 +2385,72 @@ enum edmg_bw_config {
/* DPP Public Action frame identifiers - OUI_WFA */
#define DPP_OUI_TYPE 0x1A
+/* Robust AV streaming Action field values */
+enum robust_av_streaming_action {
+ ROBUST_AV_SCS_REQ = 0,
+ ROBUST_AV_SCS_RESP = 1,
+ ROBUST_AV_GROUP_MEMBERSHIP_REQ = 2,
+ ROBUST_AV_GROUP_MEMBERSHIP_RESP = 3,
+ ROBUST_AV_MSCS_REQ = 4,
+ ROBUST_AV_MSCS_RESP = 5,
+};
+
+enum scs_request_type {
+ SCS_REQ_ADD = 0,
+ SCS_REQ_REMOVE = 1,
+ SCS_REQ_CHANGE = 2,
+};
+
+/* Optional subelement IDs for MSCS Descriptor element */
+enum mscs_description_subelem {
+ MCSC_SUBELEM_STATUS = 1,
+};
+
+/*
+ * IEEE Std 802.11ai-2016, 9.6.8.36 FILS Discovery frame format,
+ * Figure 9-687b - FILS Discovery Frame Control subfield format
+ */
+#define FD_FRAME_CTL_CAP_PRESENT ((u16) BIT(5))
+#define FD_FRAME_CTL_SHORT_SSID_PRESENT ((u16) BIT(6))
+#define FD_FRAME_CTL_AP_CSN_PRESENT ((u16) BIT(7))
+#define FD_FRAME_CTL_ANO_PRESENT ((u16) BIT(8))
+#define FD_FRAME_CTL_FREQ_SEG1_PRESENT ((u16) BIT(9))
+#define FD_FRAME_CTL_PRI_CHAN_PRESENT ((u16) BIT(10))
+#define FD_FRAME_CTL_RSN_INFO_PRESENT ((u16) BIT(11))
+#define FD_FRAME_CTL_LENGTH_PRESENT ((u16) BIT(12))
+#define FD_FRAME_CTL_MD_PRESENT ((u16) BIT(13))
+
+/*
+ * IEEE Std 802.11ai-2016, 9.6.8.36 FILS Discovery frame format,
+ * Figure 9-687c - FD Capability subfield format
+ */
+#define FD_CAP_ESS BIT(0)
+#define FD_CAP_PRIVACY BIT(1)
+#define FD_CAP_MULTI_BSSID_PRESENT BIT(9)
+
+#define FD_CAP_BSS_CHWIDTH_20 0
+#define FD_CAP_BSS_CHWIDTH_40 1
+#define FD_CAP_BSS_CHWIDTH_80 2
+#define FD_CAP_BSS_CHWIDTH_160_80_80 3
+#define FD_CAP_BSS_CHWIDTH_SHIFT 2
+
+#define FD_CAP_NSS_1 0
+#define FD_CAP_NSS_2 1
+#define FD_CAP_NSS_3 2
+#define FD_CAP_NSS_4 3
+#define FD_CAP_NSS_5_8 4
+#define FD_CAP_NSS_SHIFT 5
+
+#define FD_CAP_PHY_INDEX_HR_DSSS 0
+#define FD_CAP_PHY_INDEX_ERP_OFDM 1
+#define FD_CAP_PHY_INDEX_HT 2
+#define FD_CAP_PHY_INDEX_VHT 3
+#define FD_CAP_PHY_INDEX_HE 4 /* P802.11ax */
+#define FD_CAP_PHY_INDEX_SHIFT 10
+
+/*
+ * IEEE P802.11ax/D8.0 26.17.2.3.2, AP behavior for fast passive scanning
+ */
+#define FD_MAX_INTERVAL_6GHZ 20 /* TUs */
+
#endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/ocv.c b/src/common/ocv.c
index 06badfbf..c9dc14fa 100644
--- a/src/common/ocv.c
+++ b/src/common/ocv.c
@@ -45,6 +45,8 @@ int ocv_derive_all_parameters(struct oci_info *oci)
oci->sec_channel = 1;
else if (op_class_map->bw == BW40MINUS)
oci->sec_channel = -1;
+ else if (op_class_map->bw == BW40)
+ oci->sec_channel = (((oci->channel - 1) / 4) % 2) ? -1 : 1;
return 0;
}
@@ -95,23 +97,24 @@ int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos)
}
-int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
- struct wpa_channel_info *ci, int tx_chanwidth,
- int tx_seg1_idx)
+enum oci_verify_result
+ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
+ struct wpa_channel_info *ci, int tx_chanwidth,
+ int tx_seg1_idx)
{
struct oci_info oci;
if (!oci_ie) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: did not receive mandatory OCI");
- return -1;
+ "did not receive mandatory OCI");
+ return OCI_NOT_FOUND;
}
if (oci_ie_len != 3) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: received OCI of unexpected length (%d)",
+ "received OCI of unexpected length (%d)",
(int) oci_ie_len);
- return -1;
+ return OCI_INVALID_LENGTH;
}
os_memset(&oci, 0, sizeof(oci));
@@ -120,25 +123,25 @@ int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
oci.seg1_idx = oci_ie[2];
if (ocv_derive_all_parameters(&oci) != 0) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: unable to interpret received OCI");
- return -1;
+ "unable to interpret received OCI");
+ return OCI_PARSE_ERROR;
}
/* Primary frequency used to send frames to STA must match the STA's */
if ((int) ci->frequency != oci.freq) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: primary channel mismatch in received OCI (we use %d but receiver is using %d)",
+ "primary channel mismatch in received OCI (we use %d but receiver is using %d)",
ci->frequency, oci.freq);
- return -1;
+ return OCI_PRIMARY_FREQ_MISMATCH;
}
/* We shouldn't transmit with a higher bandwidth than the STA supports
*/
if (tx_chanwidth > oci.chanwidth) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: channel bandwidth mismatch in received OCI (we use %d but receiver only supports %d)",
+ "channel bandwidth mismatch in received OCI (we use %d but receiver only supports %d)",
tx_chanwidth, oci.chanwidth);
- return -1;
+ return OCI_CHANNEL_WIDTH_MISMATCH;
}
/*
@@ -150,9 +153,9 @@ int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
if (tx_chanwidth == 40 && ci->frequency < 2500 &&
ci->sec_channel != oci.sec_channel) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: secondary channel mismatch in received OCI (we use %d but receiver is using %d)",
+ "secondary channel mismatch in received OCI (we use %d but receiver is using %d)",
ci->sec_channel, oci.sec_channel);
- return -1;
+ return OCI_SECONDARY_FREQ_MISMATCH;
}
/*
@@ -163,10 +166,10 @@ int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
ci->chanwidth == CHAN_WIDTH_80P80) &&
tx_seg1_idx != oci.seg1_idx) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
+ "frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
tx_seg1_idx, oci.seg1_idx);
- return -1;
+ return OCI_SEG_1_INDEX_MISMATCH;
}
- return 0;
+ return OCI_SUCCESS;
}
diff --git a/src/common/ocv.h b/src/common/ocv.h
index 6379d9d0..7fa4522c 100644
--- a/src/common/ocv.h
+++ b/src/common/ocv.h
@@ -27,14 +27,21 @@ struct oci_info {
#define OCV_OCI_EXTENDED_LEN (3 + OCV_OCI_LEN)
#define OCV_OCI_KDE_LEN (2 + RSN_SELECTOR_LEN + OCV_OCI_LEN)
+enum oci_verify_result {
+ OCI_SUCCESS, OCI_NOT_FOUND, OCI_INVALID_LENGTH, OCI_PARSE_ERROR,
+ OCI_PRIMARY_FREQ_MISMATCH, OCI_CHANNEL_WIDTH_MISMATCH,
+ OCI_SECONDARY_FREQ_MISMATCH, OCI_SEG_1_INDEX_MISMATCH
+};
+
extern char ocv_errorstr[256];
int ocv_derive_all_parameters(struct oci_info *oci);
int ocv_insert_oci(struct wpa_channel_info *ci, u8 **argpos);
int ocv_insert_oci_kde(struct wpa_channel_info *ci, u8 **argpos);
int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos);
-int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
- struct wpa_channel_info *ci, int tx_chanwidth,
- int tx_seg1_idx);
+enum oci_verify_result
+ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
+ struct wpa_channel_info *ci, int tx_chanwidth,
+ int tx_seg1_idx);
#endif /* OCV_H */
diff --git a/src/common/ptksa_cache.c b/src/common/ptksa_cache.c
new file mode 100644
index 00000000..6a053d65
--- /dev/null
+++ b/src/common/ptksa_cache.c
@@ -0,0 +1,321 @@
+/*
+ * RSN PTKSA cache implementation
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include "utils/common.h"
+#include "eloop.h"
+#include "common/ptksa_cache.h"
+
+#define PTKSA_CACHE_MAX_ENTRIES 16
+
+struct ptksa_cache {
+ struct dl_list ptksa;
+ unsigned int n_ptksa;
+};
+
+static void ptksa_cache_set_expiration(struct ptksa_cache *ptksa);
+
+
+static void ptksa_cache_free_entry(struct ptksa_cache *ptksa,
+ struct ptksa_cache_entry *entry)
+{
+ ptksa->n_ptksa--;
+
+ dl_list_del(&entry->list);
+ bin_clear_free(entry, sizeof(*entry));
+}
+
+
+static void ptksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
+{
+ struct ptksa_cache *ptksa = eloop_ctx;
+ struct ptksa_cache_entry *e, *next;
+ struct os_reltime now;
+
+ if (!ptksa)
+ return;
+
+ os_get_reltime(&now);
+
+ dl_list_for_each_safe(e, next, &ptksa->ptksa,
+ struct ptksa_cache_entry, list) {
+ if (e->expiration > now.sec)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "Expired PTKSA cache entry for " MACSTR,
+ MAC2STR(e->addr));
+
+ ptksa_cache_free_entry(ptksa, e);
+ }
+
+ ptksa_cache_set_expiration(ptksa);
+}
+
+
+static void ptksa_cache_set_expiration(struct ptksa_cache *ptksa)
+{
+ struct ptksa_cache_entry *e;
+ int sec;
+ struct os_reltime now;
+
+ eloop_cancel_timeout(ptksa_cache_expire, ptksa, NULL);
+
+ if (!ptksa || !ptksa->n_ptksa)
+ return;
+
+ e = dl_list_first(&ptksa->ptksa, struct ptksa_cache_entry, list);
+ if (!e)
+ return;
+
+ os_get_reltime(&now);
+ sec = e->expiration - now.sec;
+ if (sec < 0)
+ sec = 0;
+
+ eloop_register_timeout(sec + 1, 0, ptksa_cache_expire, ptksa, NULL);
+}
+
+
+/*
+ * ptksa_cache_init - Initialize PTKSA cache
+ *
+ * Returns: Pointer to PTKSA cache data or %NULL on failure
+ */
+struct ptksa_cache * ptksa_cache_init(void)
+{
+ struct ptksa_cache *ptksa = os_zalloc(sizeof(struct ptksa_cache));
+
+ wpa_printf(MSG_DEBUG, "PTKSA: Initializing");
+
+ if (ptksa)
+ dl_list_init(&ptksa->ptksa);
+
+ return ptksa;
+}
+
+
+/*
+ * ptksa_cache_deinit - Free all entries in PTKSA cache
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ */
+void ptksa_cache_deinit(struct ptksa_cache *ptksa)
+{
+ struct ptksa_cache_entry *e, *next;
+
+ if (!ptksa)
+ return;
+
+ wpa_printf(MSG_DEBUG, "PTKSA: Deinit. n_ptksa=%u", ptksa->n_ptksa);
+
+ dl_list_for_each_safe(e, next, &ptksa->ptksa,
+ struct ptksa_cache_entry, list)
+ ptksa_cache_free_entry(ptksa, e);
+
+ eloop_cancel_timeout(ptksa_cache_expire, ptksa, NULL);
+ os_free(ptksa);
+}
+
+
+/*
+ * ptksa_cache_get - Fetch a PTKSA cache entry
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ * @addr: Peer address or %NULL to match any
+ * @cipher: Specific cipher suite to search for or WPA_CIPHER_NONE for any
+ * Returns: Pointer to PTKSA cache entry or %NULL if no match was found
+ */
+struct ptksa_cache_entry * ptksa_cache_get(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher)
+{
+ struct ptksa_cache_entry *e;
+
+ if (!ptksa)
+ return NULL;
+
+ dl_list_for_each(e, &ptksa->ptksa, struct ptksa_cache_entry, list) {
+ if ((!addr || os_memcmp(e->addr, addr, ETH_ALEN) == 0) &&
+ (cipher == WPA_CIPHER_NONE || cipher == e->cipher))
+ return e;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * ptksa_cache_list - Dump text list of entries in PTKSA cache
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ * @buf: Buffer for the list
+ * @len: Length of the buffer
+ * Returns: Number of bytes written to buffer
+ *
+ * This function is used to generate a text format representation of the
+ * current PTKSA cache contents for the ctrl_iface PTKSA command.
+ */
+int ptksa_cache_list(struct ptksa_cache *ptksa, char *buf, size_t len)
+{
+ struct ptksa_cache_entry *e;
+ int i = 0, ret;
+ char *pos = buf;
+ struct os_reltime now;
+
+ if (!ptksa)
+ return 0;
+
+ os_get_reltime(&now);
+
+ ret = os_snprintf(pos, buf + len - pos,
+ "Index / ADDR / Cipher / expiration (secs) / TK / KDK\n");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ dl_list_for_each(e, &ptksa->ptksa, struct ptksa_cache_entry, list) {
+ ret = os_snprintf(pos, buf + len - pos, "%u " MACSTR,
+ i, MAC2STR(e->addr));
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, buf + len - pos, " %s %lu ",
+ wpa_cipher_txt(e->cipher),
+ e->expiration - now.sec);
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = wpa_snprintf_hex(pos, buf + len - pos, e->ptk.tk,
+ e->ptk.tk_len);
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, buf + len - pos, " ");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = wpa_snprintf_hex(pos, buf + len - pos, e->ptk.kdk,
+ e->ptk.kdk_len);
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, buf + len - pos, "\n");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ i++;
+ }
+
+ return pos - buf;
+}
+
+
+/*
+ * ptksa_cache_flush - Flush PTKSA cache entries
+ *
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ * @addr: Peer address or %NULL to match any
+ * @cipher: Specific cipher suite to search for or WPA_CIPHER_NONE for any
+ */
+void ptksa_cache_flush(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher)
+{
+ struct ptksa_cache_entry *e, *next;
+ bool removed = false;
+
+ if (!ptksa)
+ return;
+
+ dl_list_for_each_safe(e, next, &ptksa->ptksa, struct ptksa_cache_entry,
+ list) {
+ if ((!addr || os_memcmp(e->addr, addr, ETH_ALEN) == 0) &&
+ (cipher == WPA_CIPHER_NONE || cipher == e->cipher)) {
+ wpa_printf(MSG_DEBUG,
+ "Flush PTKSA cache entry for " MACSTR,
+ MAC2STR(e->addr));
+
+ ptksa_cache_free_entry(ptksa, e);
+ removed = true;
+ }
+ }
+
+ if (removed)
+ ptksa_cache_set_expiration(ptksa);
+}
+
+
+/*
+ * ptksa_cache_add - Add a PTKSA cache entry
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ * @addr: Peer address
+ * @cipher: The cipher used
+ * @life_time: The PTK life time in seconds
+ * @ptk: The PTK
+ * Returns: Pointer to the added PTKSA cache entry or %NULL on error
+ *
+ * This function creates a PTKSA entry and adds it to the PTKSA cache.
+ * If an old entry is already in the cache for the same peer and cipher
+ * this entry will be replaced with the new entry.
+ */
+struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher,
+ u32 life_time,
+ const struct wpa_ptk *ptk)
+{
+ struct ptksa_cache_entry *entry, *tmp;
+ struct os_reltime now;
+
+ if (!ptksa || !ptk || !addr || !life_time || cipher == WPA_CIPHER_NONE)
+ return NULL;
+
+ /* remove a previous entry if present */
+ ptksa_cache_flush(ptksa, addr, cipher);
+
+ /* no place to add another entry */
+ if (ptksa->n_ptksa >= PTKSA_CACHE_MAX_ENTRIES)
+ return NULL;
+
+ entry = os_zalloc(sizeof(*entry));
+ if (!entry)
+ return NULL;
+
+ dl_list_init(&entry->list);
+ os_memcpy(entry->addr, addr, ETH_ALEN);
+ entry->cipher = cipher;
+
+ os_memcpy(&entry->ptk, ptk, sizeof(entry->ptk));
+
+ os_get_reltime(&now);
+ entry->expiration = now.sec + life_time;
+
+ dl_list_for_each(tmp, &ptksa->ptksa, struct ptksa_cache_entry, list) {
+ if (tmp->expiration > entry->expiration)
+ break;
+ }
+
+ /*
+ * If the list was empty add to the head; otherwise if the expiration is
+ * later then all other entries, add it to the end of the list;
+ * otherwise add it before the relevant entry.
+ */
+ if (!tmp)
+ dl_list_add(&ptksa->ptksa, &entry->list);
+ else if (tmp->expiration < entry->expiration)
+ dl_list_add(&tmp->list, &entry->list);
+ else
+ dl_list_add_tail(&tmp->list, &entry->list);
+
+ ptksa->n_ptksa++;
+ wpa_printf(MSG_DEBUG,
+ "Added PTKSA cache entry addr=" MACSTR " cipher=%u",
+ MAC2STR(addr), cipher);
+
+ return entry;
+}
diff --git a/src/common/ptksa_cache.h b/src/common/ptksa_cache.h
new file mode 100644
index 00000000..28ef2914
--- /dev/null
+++ b/src/common/ptksa_cache.h
@@ -0,0 +1,79 @@
+/*
+ * RSN PTKSA cache interface
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PTKSA_CACHE_H
+#define PTKSA_CACHE_H
+
+#include "wpa_common.h"
+#include "defs.h"
+#include "list.h"
+
+/**
+ * struct ptksa_cache_entry - PTKSA cache entry
+ */
+struct ptksa_cache_entry {
+ struct dl_list list;
+ struct wpa_ptk ptk;
+ os_time_t expiration;
+ u32 cipher;
+ u8 addr[ETH_ALEN];
+};
+
+#ifdef CONFIG_PTKSA_CACHE
+
+struct ptksa_cache;
+
+struct ptksa_cache * ptksa_cache_init(void);
+void ptksa_cache_deinit(struct ptksa_cache *ptksa);
+struct ptksa_cache_entry * ptksa_cache_get(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher);
+int ptksa_cache_list(struct ptksa_cache *ptksa, char *buf, size_t len);
+struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher,
+ u32 life_time,
+ const struct wpa_ptk *ptk);
+void ptksa_cache_flush(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher);
+
+#else /* CONFIG_PTKSA_CACHE */
+
+static inline struct ptksa_cache * ptksa_cache_init(void)
+{
+ return (struct ptksa_cache *) 1;
+}
+
+static inline void ptksa_cache_deinit(struct ptksa_cache *ptksa)
+{
+}
+
+static inline struct ptksa_cache_entry *
+ptksa_cache_get(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher)
+{
+ return NULL;
+}
+
+static inline int ptksa_cache_list(struct ptksa_cache *ptksa,
+ char *buf, size_t len)
+{
+ return -1;
+}
+
+static inline struct ptksa_cache_entry *
+ptksa_cache_add(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher,
+ u32 life_time, const struct wpa_ptk *ptk)
+{
+ return NULL;
+}
+
+static inline void ptksa_cache_flush(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher)
+{
+}
+
+#endif /* CONFIG_PTKSA_CACHE */
+#endif /* PTKSA_CACHE_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index e599b8d7..f7e5571d 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1,7 +1,7 @@
/*
* Qualcomm Atheros OUI and vendor specific assignments
* Copyright (c) 2014-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.
@@ -174,6 +174,22 @@ enum qca_radiotap_vendor_ids {
* to notify the connected station's status. The attributes for this
* command are defined in enum qca_wlan_vendor_attr_link_properties.
*
+ * @QCA_NL80211_VENDOR_SUBCMD_SETBAND: Command to configure the enabled band(s)
+ * to the driver. This command sets the band(s) through either the
+ * attribute QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE or
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK (or both).
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE refers enum qca_set_band as unsigned
+ * integer values and QCA_WLAN_VENDOR_ATTR_SETBAND_MASK refers it as 32
+ * bit unsigned bitmask values. The allowed values for
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE are limited to QCA_SETBAND_AUTO,
+ * QCA_SETBAND_5G, and QCA_SETBAND_2G. Other values/bitmasks are valid for
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK. The attribute
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE is deprecated and the recommendation
+ * is to use the QCA_WLAN_VENDOR_ATTR_SETBAND_MASK. If the both attributes
+ * are included for backwards compatibility, the configurations through
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK will take the precedence with drivers
+ * that support both attributes.
+ *
* @QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY: This command is used to configure
* DFS policy and channel hint for ACS operation. This command uses the
* attributes defined in enum qca_wlan_vendor_attr_acs_config and
@@ -646,6 +662,44 @@ enum qca_radiotap_vendor_ids {
* code immediately prior to triggering cfg80211_disconnected(). The
* attributes used with this event are defined in enum
* qca_wlan_vendor_attr_driver_disconnect_reason.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_CONFIG_TSPEC: This vendor subcommand is used to
+ * add/delete TSPEC for each AC. One command is for one specific AC only.
+ * This command can only be used in STA mode and the STA must be
+ * associated with an AP when the command is issued. Uses attributes
+ * defined in enum qca_wlan_vendor_attr_config_tspec.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT: Vendor subcommand to configure TWT.
+ * Uses attributes defined in enum qca_wlan_vendor_attr_config_twt.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GETBAND: Command to get the enabled band(s) from
+ * the driver. The band configurations obtained are referred through
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS: Vendor subcommand/event for medium
+ * assessment.
+ * Uses attributes defined in enum qca_wlan_vendor_attr_medium_assess.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_UPDATE_SSID: This acts as a vendor event and is
+ * used to update SSID information in hostapd when it is updated in the
+ * driver. Uses the attribute NL80211_ATTR_SSID.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_WIFI_FW_STATS: This vendor subcommand is used by
+ * the driver to send opaque data from the firmware to userspace. The
+ * driver sends an event to userspace whenever such data is received from
+ * the firmware.
+ *
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA is used as the attribute to
+ * send this opaque data for this event.
+ *
+ * The format of the opaque data is specific to the particular firmware
+ * version and there is no guarantee of the format remaining same.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_MBSSID_TX_VDEV_STATUS: This acts as an event.
+ * The host driver selects Tx VDEV, and notifies user. The attributes
+ * used with this event are defined in enum
+ * qca_wlan_vendor_attr_mbssid_tx_vdev_status.
+ *
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -825,6 +879,13 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS_EVENT = 187,
QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO = 188,
QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON = 189,
+ QCA_NL80211_VENDOR_SUBCMD_CONFIG_TSPEC = 190,
+ QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT = 191,
+ QCA_NL80211_VENDOR_SUBCMD_GETBAND = 192,
+ QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS = 193,
+ QCA_NL80211_VENDOR_SUBCMD_UPDATE_SSID = 194,
+ QCA_NL80211_VENDOR_SUBCMD_WIFI_FW_STATS = 195,
+ QCA_NL80211_VENDOR_SUBCMD_MBSSID_TX_VDEV_STATUS = 196,
};
enum qca_wlan_vendor_attr {
@@ -855,7 +916,11 @@ enum qca_wlan_vendor_attr {
QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND = 10,
/* Unsigned 32-bit value */
QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND = 11,
- /* Unsigned 32-bit value from enum qca_set_band. */
+ /* Unsigned 32-bit value from enum qca_set_band. The allowed values for
+ * this attribute are limited to QCA_SETBAND_AUTO, QCA_SETBAND_5G, and
+ * QCA_SETBAND_2G. This attribute is deprecated. Recommendation is to
+ * use QCA_WLAN_VENDOR_ATTR_SETBAND_MASK instead.
+ */
QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12,
/* Dummy (NOP) attribute for 64 bit padding */
QCA_WLAN_VENDOR_ATTR_PAD = 13,
@@ -1018,6 +1083,15 @@ enum qca_wlan_vendor_attr {
*/
QCA_WLAN_VENDOR_ATTR_FW_STATE = 42,
+ /* Unsigned 32-bitmask value from enum qca_set_band. Substitutes the
+ * attribute QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE for which only a subset
+ * of single values from enum qca_set_band are valid. This attribute
+ * uses bitmask combinations to define the respective allowed band
+ * combinations and this attributes takes precedence over
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE if both attributes are included.
+ */
+ QCA_WLAN_VENDOR_ATTR_SETBAND_MASK = 43,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
@@ -1371,6 +1445,25 @@ enum qca_wlan_vendor_acs_hw_mode {
* %QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL and
* %QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW attributes from
* userspace.
+ * @QCA_WLAN_VENDOR_FEATURE_ADAPTIVE_11R: Device supports Adaptive 11r.
+ * With Adaptive 11r feature, access points advertise the vendor
+ * specific IEs and MDE but do not include FT AKM in the RSNE.
+ * The Adaptive 11r supported stations are expected to identify
+ * such vendor specific IEs and connect to the AP in FT mode though
+ * the profile is configured in non-FT mode.
+ * The driver-based SME cases also need to have this support for
+ * Adaptive 11r to handle the connection and roaming scenarios.
+ * This flag indicates the support for the same to the user space.
+ * @QCA_WLAN_VENDOR_FEATURE_CONCURRENT_BAND_SESSIONS: Device supports
+ * concurrent network sessions on different Wi-Fi bands. This feature
+ * capability is attributed to the hardware's capability to support
+ * the same (e.g., DBS).
+ * @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT: Flag indicating whether the
+ * responses for the respective TWT operations are asynchronous (separate
+ * event message) from the driver. If not specified, the responses are
+ * synchronous (in vendor command reply) to the request. Each TWT
+ * operation is specifically mentioned (against its respective
+ * documentation) to support either of these or both modes.
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
@@ -1386,6 +1479,9 @@ enum qca_wlan_vendor_features {
QCA_WLAN_VENDOR_FEATURE_11AX = 9,
QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT = 10,
QCA_WLAN_VENDOR_FEATURE_THERMAL_CONFIG = 11,
+ QCA_WLAN_VENDOR_FEATURE_ADAPTIVE_11R = 12,
+ QCA_WLAN_VENDOR_FEATURE_CONCURRENT_BAND_SESSIONS = 13,
+ QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT = 14,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -1565,9 +1661,10 @@ enum qca_iface_type {
};
enum qca_set_band {
- QCA_SETBAND_AUTO,
- QCA_SETBAND_5G,
- QCA_SETBAND_2G,
+ QCA_SETBAND_AUTO = 0,
+ QCA_SETBAND_5G = BIT(0),
+ QCA_SETBAND_2G = BIT(1),
+ QCA_SETBAND_6G = BIT(2),
};
/**
@@ -1695,6 +1792,8 @@ enum qca_vendor_attr_wisa_cmd {
* (not including the Element ID Extension field). Please note that the
* draft is still work in progress and this element payload is subject to
* change.
+ *
+ * @QCA_VENDOR_ELEM_ALLPLAY: Allplay element
*/
enum qca_vendor_element_id {
QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST = 0,
@@ -1703,6 +1802,7 @@ enum qca_vendor_element_id {
QCA_VENDOR_ELEM_RAPS = 3,
QCA_VENDOR_ELEM_MU_EDCA_PARAMS = 4,
QCA_VENDOR_ELEM_BSS_COLOR_CHANGE = 5,
+ QCA_VENDOR_ELEM_ALLPLAY = 6,
};
/**
@@ -2120,6 +2220,185 @@ enum qca_wlan_vendor_attr_config {
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_ROAM_REASON = 61,
+ /* 32-bit unsigned value to configure different PHY modes to the
+ * driver/firmware. The possible values are defined in
+ * enum qca_wlan_vendor_phy_mode. The configuration will be reset to
+ * default value, i.e., QCA_WLAN_VENDOR_PHY_MODE_AUTO upon restarting
+ * the driver.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_PHY_MODE = 62,
+
+ /* 8-bit unsigned value to configure the maximum supported channel width
+ * for STA mode. If this value is configured when STA is in connected
+ * state, it should not exceed the negotiated channel width. If it is
+ * configured when STA is in disconnected state, the configured value
+ * will take effect for the next immediate connection.
+ * Possible values are:
+ * NL80211_CHAN_WIDTH_20
+ * NL80211_CHAN_WIDTH_40
+ * NL80211_CHAN_WIDTH_80
+ * NL80211_CHAN_WIDTH_80P80
+ * NL80211_CHAN_WIDTH_160
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH = 63,
+
+ /* 8-bit unsigned value to enable/disable dynamic bandwidth adjustment.
+ * This attribute is only applicable for STA mode. When dynamic
+ * bandwidth adjustment is disabled, STA will use static channel width
+ * the value of which is negotiated during connection.
+ * 1-enable (default), 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_BW = 64,
+
+ /* 8-bit unsigned value to configure the maximum number of subframes of
+ * TX MSDU for aggregation. Possible values are 0-31. When set to 0,
+ * it is decided by the hardware.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MSDU_AGGREGATION = 65,
+
+ /* 8-bit unsigned value to configure the maximum number of subframes of
+ * RX MSDU for aggregation. Possible values are 0-31. When set to 0,
+ * it is decided by the hardware.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MSDU_AGGREGATION = 66,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically
+ * enable/disable the LDPC capability of the device. When configured in
+ * the disconnected state, the updated configuration will be considered
+ * for the immediately following connection attempt. If this
+ * configuration is modified while the device is in the connected state,
+ * the LDPC TX will be updated with this configuration immediately,
+ * while the LDPC RX configuration update will take place starting from
+ * the subsequent association attempt.
+ * 1-Enable, 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LDPC = 67,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically
+ * enable/disable the TX STBC capability of the device. When configured
+ * in the disconnected state, the updated configuration will be
+ * considered for the immediately following connection attempt. If the
+ * connection is formed with TX STBC enabled and if this configuration
+ * is disabled during that association, the TX will be impacted
+ * immediately. Further connection attempts will disable TX STBC.
+ * However, enabling the TX STBC for a connected session with disabled
+ * capability is not allowed and will fail.
+ * 1-Enable, 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TX_STBC = 68,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically
+ * enable/disable the RX STBC capability of the device. When configured
+ * in the disconnected state, the updated configuration will be
+ * considered for the immediately following connection attempt. If the
+ * configuration is modified in the connected state, there will be no
+ * impact for the current association, but further connection attempts
+ * will use the updated configuration.
+ * 1-Enable, 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_STBC = 69,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of spatial streams. When configured in the disconnected
+ * state, the updated configuration will be considered for the
+ * immediately following connection attempt. If the NSS is updated after
+ * the connection, the updated NSS value is notified to the peer using
+ * the Operating Mode Notification/Spatial Multiplexing Power Save
+ * frame. The updated NSS value after the connection shall not be
+ * greater than the one negotiated during the connection. Any such
+ * higher value configuration shall be returned with a failure.
+ * Only symmetric NSS configuration (such as 2X2 or 1X1) can be done
+ * using this attribute. QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS and
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS attributes shall be used to
+ * configure the asymmetric NSS configuration (such as 1X2).
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_NSS = 70,
+ /* 8-bit unsigned value to trigger Optimized Power Management:
+ * 1-Enable, 0-Disable
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT = 71,
+
+ /* 8-bit unsigned value. This attribute takes the QoS/access category
+ * value represented by the enum qca_wlan_ac_type and expects the driver
+ * to upgrade the UDP frames to this access category. The value of
+ * QCA_WLAN_AC_ALL is invalid for this attribute. This will override the
+ * DSCP value configured in the frame with the intention to only upgrade
+ * the access category. That said, it is not intended to downgrade the
+ * access category for the frames.
+ * Set the value to QCA_WLAN_AC_BK if the QoS upgrade needs to be
+ * disabled, as BK is of the lowest priority and an upgrade to it does
+ * not result in any changes for the frames.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE = 72,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of chains to be used for transmitting data. This
+ * configuration is allowed only when in connected state and will be
+ * effective until disconnected. The driver rejects this configuration
+ * if the number of spatial streams being used in the current connection
+ * cannot be supported by this configuration.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS = 73,
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of chains to be used for receiving data. This
+ * configuration is allowed only when in connected state and will be
+ * effective until disconnected. The driver rejects this configuration
+ * if the number of spatial streams being used in the current connection
+ * cannot be supported by this configuration.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS = 74,
+
+ /* 8-bit unsigned value to configure ANI setting type.
+ * See &enum qca_wlan_ani_setting for possible values.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANI_SETTING = 75,
+ /* 32-bit signed value to configure ANI level. This is used when
+ * ANI settings type is &QCA_WLAN_ANI_SETTING_FIXED.
+ * The set and get of ANI level with &QCA_WLAN_ANI_SETTING_AUTO
+ * is invalid, the driver will return a failure.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANI_LEVEL = 76,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of spatial streams used for transmitting the data. When
+ * configured in the disconnected state, the configured value will
+ * be considered for the following connection attempt.
+ * If the NSS is updated after the connection, the updated NSS value
+ * is notified to the peer using the Operating Mode Notification/Spatial
+ * Multiplexing Power Save frame.
+ * The TX NSS value configured after the connection shall not be greater
+ * than the value negotiated during the connection. Any such higher
+ * value configuration shall be treated as invalid configuration by
+ * the driver. This attribute shall be configured along with
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS attribute to define the symmetric
+ * configuration (such as 2X2 or 1X1) or the asymmetric
+ * configuration (such as 1X2).
+ * If QCA_WLAN_VENDOR_ATTR_CONFIG_NSS attribute is also provided along
+ * with this QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS attribute the driver
+ * will update the TX NSS based on QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS = 77,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of spatial streams used for receiving the data. When
+ * configured in the disconnected state, the configured value will
+ * be considered for the following connection attempt.
+ * If the NSS is updated after the connection, the updated NSS value
+ * is notified to the peer using the Operating Mode Notification/Spatial
+ * Multiplexing Power Save frame.
+ * The RX NSS value configured after the connection shall not be greater
+ * than the value negotiated during the connection. Any such higher
+ * value configuration shall be treated as invalid configuration by
+ * the driver. This attribute shall be configured along with
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS attribute to define the symmetric
+ * configuration (such as 2X2 or 1X1) or the asymmetric
+ * configuration (such as 1X2).
+ * If QCA_WLAN_VENDOR_ATTR_CONFIG_NSS attribute is also provided along
+ * with this QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS attribute the driver
+ * will update the RX NSS based on QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS = 78,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -2135,6 +2414,16 @@ enum qca_wlan_vendor_attr_config {
QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL
/**
+ * enum qca_wlan_ani_setting - ANI setting type
+ * @QCA_WLAN_ANI_SETTING_AUTO: Automatically determine ANI level
+ * @QCA_WLAN_ANI_SETTING_FIXED: Fix ANI level to the dBm parameter
+ */
+enum qca_wlan_ani_setting {
+ QCA_WLAN_ANI_SETTING_AUTO = 0,
+ QCA_WLAN_ANI_SETTING_FIXED = 1,
+};
+
+/**
* enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration
*
* @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL: Optional (u8)
@@ -2189,19 +2478,87 @@ enum qca_wlan_vendor_attr_sap_conditional_chan_switch {
/**
* enum qca_wlan_gpio_attr - Parameters for GPIO configuration
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND: Required (u32)
+ * value to specify the GPIO command. Please refer to enum qca_gpio_cmd_type
+ * for the available values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM: Required (u32)
+ * value to specify the GPIO number.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG or %QCA_WLAN_VENDOR_GPIO_OUTPUT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE: Required (u32)
+ * value to specify the GPIO output level. Please refer to enum qca_gpio_value
+ * for the available values.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_OUTPUT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE: Optional (u32)
+ * value to specify the GPIO pull type. Please refer to enum qca_gpio_pull_type
+ * for the available values.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG and
+ * %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG attribute is not present.
+ * Optional when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG
+ * attribute is present.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE: Optional (u32)
+ * value to specify the GPIO interrupt mode. Please refer to enum
+ * qca_gpio_interrupt_mode for the available values.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG and
+ * %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG attribute is not present.
+ * Optional when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG
+ * attribute is present.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DIR: Optional (u32)
+ * value to specify the GPIO direction. Please refer to enum qca_gpio_direction
+ * for the available values.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG and
+ * %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG attribute is not present.
+ * Optional when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG
+ * attribute is present.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MUX_CONFIG: Optional (u32)
+ * Value to specify the mux config. Meaning of a given value is dependent
+ * on the target chipset and GPIO pin. Must be of the range 0-15.
+ * Optional when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG. Defaults to 0.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DRIVE: Optional (u32)
+ * Value to specify the drive, refer to enum qca_gpio_drive.
+ * Optional when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG. Defaults to QCA_WLAN_GPIO_DRIVE_2MA(0).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG: Optional (flag)
+ * Optional when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG. When present this attribute signals that all
+ * other parameters for the given GPIO will be obtained from internal
+ * configuration. Only %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM must be
+ * specified to indicate the GPIO pin being configured.
*/
enum qca_wlan_gpio_attr {
QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INVALID = 0,
/* Unsigned 32-bit attribute for GPIO command */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND = 1,
/* Unsigned 32-bit attribute for GPIO PIN number to configure */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM = 2,
/* Unsigned 32-bit attribute for GPIO value to configure */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE = 3,
/* Unsigned 32-bit attribute for GPIO pull type */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE = 4,
/* Unsigned 32-bit attribute for GPIO interrupt mode */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE = 5,
+ /* Unsigned 32-bit attribute for GPIO direction to configure */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DIR = 6,
+ /* Unsigned 32-bit attribute for GPIO mux config */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MUX_CONFIG = 7,
+ /* Unsigned 32-bit attribute for GPIO drive */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DRIVE = 8,
+ /* Flag attribute for using internal GPIO configuration */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG = 9,
/* keep last */
QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_LAST,
@@ -2210,6 +2567,97 @@ enum qca_wlan_gpio_attr {
};
/**
+ * enum gpio_cmd_type - GPIO configuration command type
+ * @QCA_WLAN_VENDOR_GPIO_CONFIG: Set GPIO configuration info
+ * @QCA_WLAN_VENDOR_GPIO_OUTPUT: Set GPIO output level
+ */
+enum qca_gpio_cmd_type {
+ QCA_WLAN_VENDOR_GPIO_CONFIG = 0,
+ QCA_WLAN_VENDOR_GPIO_OUTPUT = 1,
+};
+
+/**
+ * enum qca_gpio_pull_type - GPIO pull type
+ * @QCA_WLAN_GPIO_PULL_NONE: Set GPIO pull type to none
+ * @QCA_WLAN_GPIO_PULL_UP: Set GPIO pull up
+ * @QCA_WLAN_GPIO_PULL_DOWN: Set GPIO pull down
+ */
+enum qca_gpio_pull_type {
+ QCA_WLAN_GPIO_PULL_NONE = 0,
+ QCA_WLAN_GPIO_PULL_UP = 1,
+ QCA_WLAN_GPIO_PULL_DOWN = 2,
+ QCA_WLAN_GPIO_PULL_MAX,
+};
+
+/**
+ * enum qca_gpio_direction - GPIO direction
+ * @QCA_WLAN_GPIO_INPUT: Set GPIO as input mode
+ * @QCA_WLAN_GPIO_OUTPUT: Set GPIO as output mode
+ * @QCA_WLAN_GPIO_VALUE_MAX: Invalid value
+ */
+enum qca_gpio_direction {
+ QCA_WLAN_GPIO_INPUT = 0,
+ QCA_WLAN_GPIO_OUTPUT = 1,
+ QCA_WLAN_GPIO_DIR_MAX,
+};
+
+/**
+ * enum qca_gpio_value - GPIO Value
+ * @QCA_WLAN_GPIO_LEVEL_LOW: set gpio output level to low
+ * @QCA_WLAN_GPIO_LEVEL_HIGH: set gpio output level to high
+ * @QCA_WLAN_GPIO_LEVEL_MAX: Invalid value
+ */
+enum qca_gpio_value {
+ QCA_WLAN_GPIO_LEVEL_LOW = 0,
+ QCA_WLAN_GPIO_LEVEL_HIGH = 1,
+ QCA_WLAN_GPIO_LEVEL_MAX,
+};
+
+/**
+ * enum gpio_interrupt_mode - GPIO interrupt mode
+ * @QCA_WLAN_GPIO_INTMODE_DISABLE: Disable interrupt trigger
+ * @QCA_WLAN_GPIO_INTMODE_RISING_EDGE: Interrupt with GPIO rising edge trigger
+ * @QCA_WLAN_GPIO_INTMODE_FALLING_EDGE: Interrupt with GPIO falling edge trigger
+ * @QCA_WLAN_GPIO_INTMODE_BOTH_EDGE: Interrupt with GPIO both edge trigger
+ * @QCA_WLAN_GPIO_INTMODE_LEVEL_LOW: Interrupt with GPIO level low trigger
+ * @QCA_WLAN_GPIO_INTMODE_LEVEL_HIGH: Interrupt with GPIO level high trigger
+ * @QCA_WLAN_GPIO_INTMODE_MAX: Invalid value
+ */
+enum qca_gpio_interrupt_mode {
+ QCA_WLAN_GPIO_INTMODE_DISABLE = 0,
+ QCA_WLAN_GPIO_INTMODE_RISING_EDGE = 1,
+ QCA_WLAN_GPIO_INTMODE_FALLING_EDGE = 2,
+ QCA_WLAN_GPIO_INTMODE_BOTH_EDGE = 3,
+ QCA_WLAN_GPIO_INTMODE_LEVEL_LOW = 4,
+ QCA_WLAN_GPIO_INTMODE_LEVEL_HIGH = 5,
+ QCA_WLAN_GPIO_INTMODE_MAX,
+};
+
+/**
+ * enum qca_gpio_drive - GPIO drive
+ * @QCA_WLAN_GPIO_DRIVE_2MA: drive 2MA
+ * @QCA_WLAN_GPIO_DRIVE_4MA: drive 4MA
+ * @QCA_WLAN_GPIO_DRIVE_6MA: drive 6MA
+ * @QCA_WLAN_GPIO_DRIVE_8MA: drive 8MA
+ * @QCA_WLAN_GPIO_DRIVE_10MA: drive 10MA
+ * @QCA_WLAN_GPIO_DRIVE_12MA: drive 12MA
+ * @QCA_WLAN_GPIO_DRIVE_14MA: drive 14MA
+ * @QCA_WLAN_GPIO_DRIVE_16MA: drive 16MA
+ * @QCA_WLAN_GPIO_DRIVE_MAX: invalid GPIO drive
+ */
+enum qca_gpio_drive {
+ QCA_WLAN_GPIO_DRIVE_2MA = 0,
+ QCA_WLAN_GPIO_DRIVE_4MA = 1,
+ QCA_WLAN_GPIO_DRIVE_6MA = 2,
+ QCA_WLAN_GPIO_DRIVE_8MA = 3,
+ QCA_WLAN_GPIO_DRIVE_10MA = 4,
+ QCA_WLAN_GPIO_DRIVE_12MA = 5,
+ QCA_WLAN_GPIO_DRIVE_14MA = 6,
+ QCA_WLAN_GPIO_DRIVE_16MA = 7,
+ QCA_WLAN_GPIO_DRIVE_MAX,
+};
+
+/**
* qca_wlan_set_qdepth_thresh_attr - Parameters for setting
* MSDUQ depth threshold per peer per tid in the target
*
@@ -3297,7 +3745,7 @@ enum qca_wlan_vendor_attr_ll_stats_results {
QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS = 66,
/* Signifies the nested list of channel attributes
- * QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_*
+ * QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_*
*/
QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO = 67,
@@ -3359,6 +3807,17 @@ enum qca_wlan_vendor_attr_ll_stats_results {
*/
QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_PENDING_MSDU = 83,
+ /* u32 value representing total time in milliseconds for which the radio
+ * is transmitting on this channel. This attribute will be nested
+ * within QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_TX_TIME = 84,
+ /* u32 value representing total time in milliseconds for which the radio
+ * is receiving all 802.11 frames intended for this device on this
+ * channel. This attribute will be nested within
+ * QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_RX_TIME = 85,
/* keep last */
QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX =
@@ -3706,6 +4165,30 @@ enum qca_vendor_attr_scan_freq_list_scheme {
QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_AFTER_LAST - 1,
};
+/**
+ * enum qca_roam_scan_scheme: Scan scheme
+ *
+ * @QCA_ROAM_SCAN_SCHEME_NO_SCAN: No frequencies specified to scan.
+ * Indicates the driver to not scan on a Roam Trigger scenario, but
+ * disconnect. E.g., on a BTM request from the AP the driver/firmware shall
+ * disconnect from the current connected AP by notifying a failure
+ * code in the BTM response.
+ *
+ * @QCA_ROAM_SCAN_SCHEME_PARTIAL_SCAN: Indicates the driver/firmware to
+ * trigger partial frequency scans. These frequencies are the ones learned
+ * or maintained by the driver based on the probability of finding the
+ * BSSIDs in the ESS for which the roaming is triggered.
+ *
+ * @QCA_ROAM_SCAN_SCHEME_FULL_SCAN: Indicates the driver/firmware to
+ * trigger the scan on all the valid frequencies to find better
+ * candidates to roam.
+ */
+enum qca_roam_scan_scheme {
+ QCA_ROAM_SCAN_SCHEME_NO_SCAN = 0,
+ QCA_ROAM_SCAN_SCHEME_PARTIAL_SCAN = 1,
+ QCA_ROAM_SCAN_SCHEME_FULL_SCAN = 2,
+};
+
/*
* enum qca_vendor_roam_triggers: Bitmap of roaming triggers
*
@@ -3726,6 +4209,18 @@ enum qca_vendor_attr_scan_freq_list_scheme {
* when BTM Request frame is received from the connected AP.
* @QCA_ROAM_TRIGGER_REASON_BSS_LOAD: Set if the roam has to be triggered
* when the channel utilization is goes above the configured threshold.
+ * @QCA_ROAM_TRIGGER_REASON_USER_TRIGGER: Set if the roam has to be triggered
+ * based on the request from the user (space).
+ * @QCA_ROAM_TRIGGER_REASON_DEAUTH: Set if the roam has to be triggered when
+ * device receives Deauthentication/Disassociation frame from connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_IDLE: Set if the roam has to be triggered when the
+ * device is in idle state (no TX/RX) and suspend mode, if the current RSSI
+ * is determined to be a poor one.
+ * @QCA_ROAM_TRIGGER_REASON_TX_FAILURES: Set if the roam has to be triggered
+ * based on continuous TX Data frame failures to the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_EXTERNAL_SCAN: Set if the roam has to be triggered
+ * based on the scan results obtained from an external scan (not triggered
+ * to aim roaming).
*
* Set the corresponding roam trigger reason bit to consider it for roam
* trigger.
@@ -3741,6 +4236,144 @@ enum qca_vendor_roam_triggers {
QCA_ROAM_TRIGGER_REASON_DENSE = 1 << 5,
QCA_ROAM_TRIGGER_REASON_BTM = 1 << 6,
QCA_ROAM_TRIGGER_REASON_BSS_LOAD = 1 << 7,
+ QCA_ROAM_TRIGGER_REASON_USER_TRIGGER = 1 << 8,
+ QCA_ROAM_TRIGGER_REASON_DEAUTH = 1 << 9,
+ QCA_ROAM_TRIGGER_REASON_IDLE = 1 << 10,
+ QCA_ROAM_TRIGGER_REASON_TX_FAILURES = 1 << 11,
+ QCA_ROAM_TRIGGER_REASON_EXTERNAL_SCAN = 1 << 12,
+};
+
+/*
+ * enum qca_vendor_roam_fail_reasons: Defines the various roam
+ * fail reasons. This enum value is used in
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_FAIL_REASON attribute.
+ *
+ * @QCA_ROAM_FAIL_REASON_SCAN_NOT_ALLOWED: Roam module in the firmware is not
+ * able to trigger the scan.
+ * @QCA_ROAM_FAIL_REASON_NO_AP_FOUND: No roamable APs found during roam scan.
+ * @QCA_ROAM_FAIL_REASON_NO_CAND_AP_FOUND: No candidate APs found during roam
+ * scan.
+ * @QCA_ROAM_FAIL_REASON_HOST: Roam fail due to disconnect issued from host.
+ * @QCA_ROAM_FAIL_REASON_AUTH_SEND: Unable to send Authentication frame.
+ * @QCA_ROAM_FAIL_REASON_AUTH_RECV: Received Authentication frame with error
+ * status code.
+ * @QCA_ROAM_FAIL_REASON_NO_AUTH_RESP: Authentication frame not received.
+ * @QCA_ROAM_FAIL_REASON_REASSOC_SEND: Unable to send Reassociation Request
+ * frame.
+ * @QCA_ROAM_FAIL_REASON_REASSOC_RECV: Received Reassociation Response frame
+ * with error status code.
+ * @QCA_ROAM_FAIL_REASON_NO_REASSOC_RESP: Reassociation Response frame not
+ * received.
+ * @QCA_ROAM_FAIL_REASON_SCAN_FAIL: Scan module not able to start scan.
+ * @QCA_ROAM_FAIL_REASON_AUTH_NO_ACK: No ACK is received for Authentication
+ * frame.
+ * @QCA_ROAM_FAIL_REASON_AUTH_INTERNAL_DROP: Authentication frame is dropped
+ * internally before transmission.
+ * @QCA_ROAM_FAIL_REASON_REASSOC_NO_ACK: No ACK is received for Reassociation
+ * Request frame.
+ * @QCA_ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP: Reassociation Request frame is
+ * dropped internally.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M1_TIMEOUT: EAPOL-Key M1 is not received and
+ * times out.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M2_SEND: Unable to send EAPOL-Key M2 frame.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP: EAPOL-Key M2 frame dropped
+ * internally.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M2_NO_ACK: No ACK is received for EAPOL-Key
+ * M2 frame.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT: EAPOL-Key M3 frame is not received.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M4_SEND: Unable to send EAPOL-Key M4 frame.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP: EAPOL-Key M4 frame dropped
+ * internally.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M4_NO_ACK: No ACK is received for EAPOL-Key M4
+ * frame.
+ * @QCA_ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BEACON_MISS: Roam scan is not
+ * started for final beacon miss case.
+ * @QCA_ROAM_FAIL_REASON_DISCONNECT: Deauthentication or Disassociation frame
+ * received from the AP during roaming handoff.
+ * @QCA_ROAM_FAIL_REASON_RESUME_ABORT: Firmware roams to the AP when the Apps
+ * or host is suspended and gives the indication of the last roamed AP only
+ * when the Apps is resumed. If the Apps is resumed while the roaming is in
+ * progress, this ongoing roaming is aborted and the last roamed AP is
+ * indicated to host.
+ * @QCA_ROAM_FAIL_REASON_SAE_INVALID_PMKID: WPA3-SAE invalid PMKID.
+ * @QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT: WPA3-SAE pre-authentication times
+ * out.
+ * @QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL: WPA3-SAE pre-authentication fails.
+ */
+enum qca_vendor_roam_fail_reasons {
+ QCA_ROAM_FAIL_REASON_NONE = 0,
+ QCA_ROAM_FAIL_REASON_SCAN_NOT_ALLOWED = 1,
+ QCA_ROAM_FAIL_REASON_NO_AP_FOUND = 2,
+ QCA_ROAM_FAIL_REASON_NO_CAND_AP_FOUND = 3,
+ QCA_ROAM_FAIL_REASON_HOST = 4,
+ QCA_ROAM_FAIL_REASON_AUTH_SEND = 5,
+ QCA_ROAM_FAIL_REASON_AUTH_RECV = 6,
+ QCA_ROAM_FAIL_REASON_NO_AUTH_RESP = 7,
+ QCA_ROAM_FAIL_REASON_REASSOC_SEND = 8,
+ QCA_ROAM_FAIL_REASON_REASSOC_RECV = 9,
+ QCA_ROAM_FAIL_REASON_NO_REASSOC_RESP = 10,
+ QCA_ROAM_FAIL_REASON_SCAN_FAIL = 11,
+ QCA_ROAM_FAIL_REASON_AUTH_NO_ACK = 12,
+ QCA_ROAM_FAIL_REASON_AUTH_INTERNAL_DROP = 13,
+ QCA_ROAM_FAIL_REASON_REASSOC_NO_ACK = 14,
+ QCA_ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP = 15,
+ QCA_ROAM_FAIL_REASON_EAPOL_M1_TIMEOUT = 16,
+ QCA_ROAM_FAIL_REASON_EAPOL_M2_SEND = 17,
+ QCA_ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP = 18,
+ QCA_ROAM_FAIL_REASON_EAPOL_M2_NO_ACK = 19,
+ QCA_ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT = 20,
+ QCA_ROAM_FAIL_REASON_EAPOL_M4_SEND = 21,
+ QCA_ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP = 22,
+ QCA_ROAM_FAIL_REASON_EAPOL_M4_NO_ACK = 23,
+ QCA_ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BEACON_MISS = 24,
+ QCA_ROAM_FAIL_REASON_DISCONNECT = 25,
+ QCA_ROAM_FAIL_REASON_RESUME_ABORT = 26,
+ QCA_ROAM_FAIL_REASON_SAE_INVALID_PMKID = 27,
+ QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT = 28,
+ QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL = 29,
+};
+
+/*
+ * enum qca_vendor_roam_invoke_fail_reasons: Defines the various roam
+ * invoke fail reasons. This enum value is used in
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_INVOKE_FAIL_REASON attribute.
+ *
+ * @QCA_ROAM_INVOKE_STATUS_IFACE_INVALID: Invalid interface ID is passed
+ * in roam invoke command.
+ * @QCA_ROAM_INVOKE_STATUS_OFFLOAD_DISABLE: Roam offload in firmware is not
+ * enabled.
+ * @QCA_ROAM_INVOKE_STATUS_AP_SSID_LENGTH_INVALID: Connected AP profile SSID
+ * length is invalid.
+ * @QCA_ROAM_INVOKE_STATUS_ROAM_DISALLOW: Firmware internal roaming is already
+ * in progress.
+ * @QCA_ROAM_INVOKE_STATUS_NON_ROAMABLE_AP: Host sends the Beacon/Probe Response
+ * of the AP in the roam invoke command to firmware. This reason is sent by the
+ * firmware when the given AP is configured to be ignored or SSID/security
+ * does not match.
+ * @QCA_ROAM_INVOKE_STATUS_ROAM_INTERNAL_FAIL: Roam handoff failed because of
+ * firmware internal reasons.
+ * @QCA_ROAM_INVOKE_STATUS_DISALLOW: Roam invoke trigger is not enabled.
+ * @QCA_ROAM_INVOKE_STATUS_SCAN_FAIL: Scan start fail for roam invoke.
+ * @QCA_ROAM_INVOKE_STATUS_START_ROAM_FAIL: Roam handoff start fail.
+ * @QCA_ROAM_INVOKE_STATUS_INVALID_PARAMS: Roam invoke parameters are invalid.
+ * @QCA_ROAM_INVOKE_STATUS_NO_CAND_AP: No candidate AP found to roam to.
+ * @QCA_ROAM_INVOKE_STATUS_ROAM_FAIL: Roam handoff failed.
+ */
+enum qca_vendor_roam_invoke_fail_reasons {
+ QCA_ROAM_INVOKE_STATUS_NONE = 0,
+ QCA_ROAM_INVOKE_STATUS_IFACE_INVALID = 1,
+ QCA_ROAM_INVOKE_STATUS_OFFLOAD_DISABLE = 2,
+ QCA_ROAM_INVOKE_STATUS_AP_SSID_LENGTH_INVALID = 3,
+ QCA_ROAM_INVOKE_STATUS_ROAM_DISALLOW = 4,
+ QCA_ROAM_INVOKE_STATUS_NON_ROAMABLE_AP = 5,
+ QCA_ROAM_INVOKE_STATUS_ROAM_INTERNAL_FAIL = 6,
+ QCA_ROAM_INVOKE_STATUS_DISALLOW = 7,
+ QCA_ROAM_INVOKE_STATUS_SCAN_FAIL = 8,
+ QCA_ROAM_INVOKE_STATUS_START_ROAM_FAIL = 9,
+ QCA_ROAM_INVOKE_STATUS_INVALID_PARAMS = 10,
+ QCA_ROAM_INVOKE_STATUS_NO_CAND_AP = 11,
+ QCA_ROAM_INVOKE_STATUS_ROAM_FAIL = 12,
+
};
/**
@@ -3897,6 +4530,40 @@ enum qca_vendor_attr_roam_candidate_selection_criteria {
*
* Clears the selection criteria configured in the driver when specified
* with clear command.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME: Unsigned 32-bit value.
+ * Represents value of the scan frequency scheme from enum
+ * qca_roam_scan_scheme.
+ * It's an optional attribute. If this attribute is not configured, the
+ * driver shall proceed with default behavior.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_CONNECTED_RSSI_THRESHOLD: Signed 32-bit value in dBm,
+ * signifying the RSSI threshold of the current connected AP, indicating
+ * the driver to trigger roam only when the current connected AP's RSSI
+ * is less than this threshold.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD: Signed 32-bit value in dBm,
+ * signifying the RSSI threshold of the candidate AP, indicating
+ * the driver to trigger roam only to the candidate AP with RSSI
+ * better than this threshold.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_USER_REASON: Unsigned 32-bit value. Represents the
+ * user defined reason code to be sent to the AP in response to AP's
+ * request to trigger the roam if the roaming cannot be triggered.
+ * Applies to all the scenarios of AP assisted roaming (e.g., BTM).
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME_TRIGGERS: Unsigned 32-bit value.
+ * Carries a bitmap of the roam triggers specified in
+ * enum qca_vendor_roam_triggers.
+ * Represents the roam triggers for which the specific scan scheme from
+ * enum qca_roam_scan_scheme has to be applied.
+ * It's an optional attribute. If this attribute is not configured, but
+ * QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME is specified, the scan scheme
+ * specified through QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME is applicable for
+ * all the roams.
+ * If both QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME and
+ * QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME_TRIGGERS are not specified, the
+ * driver shall proceed with the default behavior.
*/
enum qca_vendor_attr_roam_control {
QCA_ATTR_ROAM_CONTROL_ENABLE = 1,
@@ -3907,6 +4574,11 @@ enum qca_vendor_attr_roam_control {
QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD = 6,
QCA_ATTR_ROAM_CONTROL_TRIGGERS = 7,
QCA_ATTR_ROAM_CONTROL_SELECTION_CRITERIA = 8,
+ QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME = 9,
+ QCA_ATTR_ROAM_CONTROL_CONNECTED_RSSI_THRESHOLD = 10,
+ QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD = 11,
+ QCA_ATTR_ROAM_CONTROL_USER_REASON = 12,
+ QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME_TRIGGERS = 13,
/* keep last */
QCA_ATTR_ROAM_CONTROL_AFTER_LAST,
@@ -3926,7 +4598,7 @@ enum qca_vendor_attr_roam_control {
* Represents the Request ID for the specific set of commands.
* This also helps to map specific set of commands to the respective
* ID / client. e.g., helps to identify the user entity configuring the
- * Blacklist BSSID and accordingly clear the respective ones with the
+ * ignored BSSIDs and accordingly clear the respective ones with the
* matching ID.
*
* @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS: Unsigned
@@ -3993,17 +4665,18 @@ enum qca_vendor_attr_roam_control {
* the BSSID for the purpose of comparing it with other roam candidate.
*
* @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS: Nested attribute,
- * represents the BSSIDs to get blacklisted for roaming.
+ * represents the BSSIDs to get ignored for roaming.
*
* @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID: Unsigned
- * 32-bit value, represents the number of blacklisted BSSIDs.
+ * 32-bit value, represents the number of ignored BSSIDs.
*
* @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID: 6-byte MAC
- * address representing the Blacklisted BSSID.
+ * address representing the ignored BSSID.
*
* @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT: Flag attribute,
- * indicates this BSSID blacklist as a hint to the driver. The driver can
- * select this BSSID in the worst case (when no other BSSIDs are better).
+ * indicates this request to ignore the BSSID as a hint to the driver. The
+ * driver can select this BSSID in the worst case (when no other BSSIDs are
+ * better).
*
* @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL: Nested attribute to
* set/get/clear the roam control config as
@@ -4038,11 +4711,11 @@ enum qca_wlan_vendor_attr_roaming_config_params {
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID = 16,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER = 17,
- /* Attribute for set_blacklist bssid params */
+ /* Attribute for setting ignored BSSID parameters */
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS = 18,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID = 19,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID = 20,
- /* Flag attribute indicates this BSSID blacklist as a hint */
+ /* Flag attribute indicates this entry as a hint */
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT = 21,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL = 22,
@@ -4078,9 +4751,9 @@ enum qca_wlan_vendor_attr_roaming_config_params {
* QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS to set the BSSID
* preference.
*
- * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID: Sets the Blacklist
- * BSSIDs. Refers QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS to
- * set the same.
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID: Sets the list of BSSIDs
+ * to ignore in roaming decision. Uses
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS to set the list.
*
* @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET: Command to set the
* roam control config to the driver with the attribute
@@ -4742,9 +5415,9 @@ enum qca_wlan_vendor_channel_prop_flags_ext {
QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DISALLOW_ADHOC = 1 << 6,
/* Station only channel */
QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DISALLOW_HOSTAP = 1 << 7,
- /* DFS radar history for slave device (STA mode) */
+ /* DFS radar history for client device (STA mode) */
QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_HISTORY_RADAR = 1 << 8,
- /* DFS CAC valid for slave device (STA mode) */
+ /* DFS CAC valid for client device (STA mode) */
QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_CAC_VALID = 1 << 9,
};
@@ -5805,6 +6478,14 @@ enum qca_wlan_vendor_hang_reason {
* the FW on a specific VDEV.
*/
QCA_WLAN_HANG_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT = 22,
+ /* WMI sequence mismatch between WMI command and Tx completion */
+ QCA_WLAN_HANG_WMI_BUF_SEQUENCE_MISMATCH = 23,
+ /* Write to Device HAL register failed */
+ QCA_WLAN_HANG_REG_WRITE_FAILURE = 24,
+ /* No credit left to send the wow_wakeup_from_sleep to firmware */
+ QCA_WLAN_HANG_SUSPEND_NO_CREDIT = 25,
+ /* Bus failure */
+ QCA_WLAN_HANG_BUS_FAILURE = 26,
};
/**
@@ -6471,8 +7152,9 @@ enum qca_wlan_vendor_attr_wake_stats {
/**
* enum qca_wlan_vendor_thermal_level - Defines various thermal levels
- * configured by userspace to the driver/firmware. The values will be
- * encapsulated in QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL attribute.
+ * configured by userspace to the driver/firmware.
+ * The values can be encapsulated in QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL or
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_LEVEL attribute.
* The driver/firmware takes actions requested by userspace such as throttling
* wifi TX etc. in order to mitigate high temperature.
*
@@ -6506,8 +7188,9 @@ enum qca_wlan_vendor_attr_thermal_cmd {
*/
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE = 1,
/* Userspace uses this attribute to configure thermal level to the
- * driver/firmware. Used in request, u32 attribute, possible values
- * are defined in enum qca_wlan_vendor_thermal_level.
+ * driver/firmware, or get thermal level from the driver/firmware.
+ * Used in request or response, u32 attribute,
+ * possible values are defined in enum qca_wlan_vendor_thermal_level.
*/
QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL = 2,
/* Userspace uses this attribute to configure the time in which the
@@ -6545,6 +7228,9 @@ enum qca_wlan_vendor_attr_thermal_cmd {
* resume action.
* @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL: Configure thermal level to
* the driver/firmware.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_LEVEL: Request to get the current
+ * thermal level from the driver/firmware. The driver should respond with a
+ * thermal level defined in enum qca_wlan_vendor_thermal_level.
*/
enum qca_wlan_vendor_attr_thermal_cmd_type {
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS,
@@ -6552,6 +7238,7 @@ enum qca_wlan_vendor_attr_thermal_cmd_type {
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SUSPEND,
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME,
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_LEVEL,
};
/**
@@ -6634,6 +7321,11 @@ enum qca_wlan_vendor_attr_thermal_event {
* NLA_FLAG attribute.
*/
QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_RESUME_COMPLETE,
+ /* Thermal level from the driver.
+ * u32 attribute. Possible values are defined in
+ * enum qca_wlan_vendor_thermal_level.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_LEVEL = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_AFTER_LAST,
@@ -6847,6 +7539,72 @@ enum qca_wlan_vendor_attr_he_omi_tx {
QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST - 1,
};
+ /**
+ * enum qca_wlan_vendor_phy_mode - Different PHY modes
+ * These values are used with %QCA_WLAN_VENDOR_ATTR_CONFIG_PHY_MODE.
+ *
+ * @QCA_WLAN_VENDOR_PHY_MODE_AUTO: autoselect
+ * @QCA_WLAN_VENDOR_PHY_MODE_2G_AUTO: 2.4 GHz 802.11b/g/n/ax autoselect
+ * @QCA_WLAN_VENDOR_PHY_MODE_5G_AUTO: 5 GHz 802.11a/n/ac/ax autoselect
+ * @QCA_WLAN_VENDOR_PHY_MODE_11A: 5 GHz, OFDM
+ * @QCA_WLAN_VENDOR_PHY_MODE_11B: 2.4 GHz, CCK
+ * @QCA_WLAN_VENDOR_PHY_MODE_11G: 2.4 GHz, OFDM
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AGN: Support 802.11n in both 2.4 GHz and 5 GHz
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NG_HT20: 2.4 GHz, HT20
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40PLUS: 2.4 GHz, HT40 (ext ch +1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40MINUS: 2.4 GHz, HT40 (ext ch -1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40: 2.4 GHz, Auto HT40
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NA_HT20: 5 GHz, HT20
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40PLUS: 5 GHz, HT40 (ext ch +1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40MINUS: 5 GHz, HT40 (ext ch -1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40: 5 GHz, Auto HT40
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT20: 5 GHz, VHT20
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40PLUS: 5 GHz, VHT40 (Ext ch +1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40MINUS: 5 GHz VHT40 (Ext ch -1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40: 5 GHz, VHT40
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80: 5 GHz, VHT80
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80P80: 5 GHz, VHT80+80
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160: 5 GHz, VHT160
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE20: HE20
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40: HE40
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40PLUS: HE40 (ext ch +1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40MINUS: HE40 (ext ch -1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80: HE80
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80P80: HE 80P80
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160: HE160
+ */
+enum qca_wlan_vendor_phy_mode {
+ QCA_WLAN_VENDOR_PHY_MODE_AUTO = 0,
+ QCA_WLAN_VENDOR_PHY_MODE_2G_AUTO = 1,
+ QCA_WLAN_VENDOR_PHY_MODE_5G_AUTO = 2,
+ QCA_WLAN_VENDOR_PHY_MODE_11A = 3,
+ QCA_WLAN_VENDOR_PHY_MODE_11B = 4,
+ QCA_WLAN_VENDOR_PHY_MODE_11G = 5,
+ QCA_WLAN_VENDOR_PHY_MODE_11AGN = 6,
+ QCA_WLAN_VENDOR_PHY_MODE_11NG_HT20 = 7,
+ QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40PLUS = 8,
+ QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40MINUS = 9,
+ QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40 = 10,
+ QCA_WLAN_VENDOR_PHY_MODE_11NA_HT20 = 11,
+ QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40PLUS = 12,
+ QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40MINUS = 13,
+ QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40 = 14,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT20 = 15,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40PLUS = 16,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40MINUS = 17,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40 = 18,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80 = 19,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80P80 = 20,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160 = 21,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE20 = 22,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40 = 23,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40PLUS = 24,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40MINUS = 25,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80 = 26,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80P80 = 27,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160 = 28,
+};
+
/* Attributes for data used by
* QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION
*/
@@ -7130,6 +7888,107 @@ enum qca_wlan_vendor_attr_wifi_test_config {
*/
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TWT_REQ_SUPPORT = 37,
+ /* 8-bit unsigned value to configure protection for Management
+ * frames when PMF is enabled for the association.
+ * This attribute is used to configure the testbed device.
+ * 0-use the correct key, 1-use an incorrect key, 2-disable protection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_PMF_PROTECTION = 38,
+
+ /* Flag attribute to inject Disassociation frame to the connected AP.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_DISASSOC_TX = 39,
+
+ /* 8-bit unsigned value to configure an override for the RSNXE Used
+ * subfield in the MIC control field of the FTE in FT Reassociation
+ * Request frame.
+ * 0 - Default behavior, 1 - override with 1, 2 - override with 0.
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only when STA is in associated state
+ * and the configuration is valid until the disconnection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FT_REASSOCREQ_RSNXE_USED = 40,
+
+ /* 8-bit unsigned value to configure the driver to ignore CSA (Channel
+ * Switch Announcement) when STA is in connected state.
+ * 0 - Default behavior, 1 - Ignore CSA.
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only when STA is in associated state
+ * and the configuration is valid until the disconnection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_IGNORE_CSA = 41,
+
+ /* Nested attribute values required to configure OCI (Operating Channel
+ * Information). Attributes defined in enum
+ * qca_wlan_vendor_attr_oci_override are nested within this attribute.
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only when STA is in associated state
+ * and the configuration is valid until the disconnection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OCI_OVERRIDE = 42,
+
+ /* 8-bit unsigned value to configure the driver/firmware to ignore SA
+ * Query timeout. If this configuration is enabled STA shall not send
+ * Deauthentication frmae when SA Query times out (mainly, after a
+ * channel switch when OCV is enabled).
+ * 0 - Default behavior, 1 - Ignore SA Query timeout.
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only when STA is in associated state
+ * and the configuration is valid until the disconnection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_IGNORE_SA_QUERY_TIMEOUT = 43,
+
+ /* 8-bit unsigned value to configure the driver/firmware to start or
+ * stop transmitting FILS discovery frames.
+ * 0 - Stop transmitting FILS discovery frames
+ * 1 - Start transmitting FILS discovery frames
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only in AP mode and the
+ * configuration is valid until AP restart.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FILS_DISCOVERY_FRAMES_TX = 44,
+
+ /* 8-bit unsigned value to configure the driver/firmware to enable or
+ * disable full bandwidth UL MU-MIMO subfield in the HE PHY capabilities
+ * information field.
+ * 0 - Disable full bandwidth UL MU-MIMO subfield
+ * 1 - Enable full bandwidth UL MU-MIMO subfield
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FULL_BW_UL_MU_MIMO = 45,
+
+ /* 16-bit unsigned value to configure the driver with a specific BSS
+ * max idle period to advertise in the BSS Max Idle Period element
+ * (IEEE Std 802.11-2016, 9.4.2.79) in (Re)Association Request frames.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BSS_MAX_IDLE_PERIOD = 46,
+
+ /* 8-bit unsigned value to configure the driver to use only RU 242 tone
+ * for data transmission.
+ * 0 - Default behavior, 1 - Configure RU 242 tone for data Tx.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_RU_242_TONE_TX = 47,
+
+ /* 8-bit unsigned value to configure the driver to disable data and
+ * management response frame transmission to test the BSS max idle
+ * feature.
+ * 0 - Default behavior, 1 - Disable data and management response Tx.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_DISABLE_DATA_MGMT_RSP_TX = 48,
+
+ /* 8-bit unsigned value to configure the driver/firmware to enable or
+ * disable Punctured Preamble Rx subfield in the HE PHY capabilities
+ * information field.
+ * 0 - Disable Punctured Preamble Rx subfield
+ * 1 - Enable Punctured Preamble Rx subfield
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_PUNCTURED_PREAMBLE_RX = 49,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
@@ -7137,6 +7996,111 @@ enum qca_wlan_vendor_attr_wifi_test_config {
};
/**
+ * enum qca_wlan_twt_operation - Operation of the config TWT request
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION.
+ * The response for the respective operations can be either synchronous or
+ * asynchronous (wherever specified). If synchronous, the response to this
+ * operation is obtained in the corresponding vendor command reply to the user
+ * space. For the asynchronous case the response is obtained as an event with
+ * the same operation type.
+ *
+ * Drivers shall support either of these modes but not both simultaneously.
+ * This support for asynchronous mode is advertised through the flag
+ * QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT. If this flag is not advertised,
+ * the driver shall support synchronous mode.
+ *
+ * @QCA_WLAN_TWT_SET: Setup a TWT session. Required parameters are configured
+ * through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_setup. Depending upon the
+ * @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT capability, this is either a
+ * synchronous or asynchronous operation.
+ *
+ * @QCA_WLAN_TWT_GET: Get the configured TWT parameters. Required parameters are
+ * obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_setup. This is a synchronous operation.
+ *
+ * @QCA_WLAN_TWT_TERMINATE: Terminate the TWT session. Required parameters are
+ * obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_setup. Valid only after the TWT session is setup.
+ * This terminate can either get triggered by the user space or can as well be
+ * a notification from the firmware if it initiates a terminate.
+ * Depending upon the @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT capability,
+ * the request from user space can either be a synchronous or asynchronous
+ * operation.
+ *
+ * @QCA_WLAN_TWT_SUSPEND: Suspend the TWT session. Required parameters are
+ * obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_setup. Valid only after the TWT session is setup.
+ * Depending upon the @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT capability,
+ * this is either a synchronous or asynchronous operation.
+ *
+ * @QCA_WLAN_TWT_RESUME: Resume the TWT session. Required parameters are
+ * configured through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_resume. Valid only after the TWT session is setup.
+ * This can as well be a notification from the firmware on a QCA_WLAN_TWT_NUDGE
+ * request. Depending upon the @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT
+ * capability, this is either a synchronous or asynchronous operation.
+ *
+ * @QCA_WLAN_TWT_NUDGE: Suspend and resume the TWT session. TWT nudge is a
+ * combination of suspend and resume in a single request. Required parameters
+ * are configured through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the
+ * enum qca_wlan_vendor_attr_twt_nudge. Valid only after the TWT session is
+ * setup. Depending upon the @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT
+ * capability, this is either a synchronous or asynchronous operation.
+ *
+ * @QCA_WLAN_TWT_GET_STATS: Get the TWT session traffic statistics information.
+ * Refers the enum qca_wlan_vendor_attr_twt_stats. Valid only after the TWT
+ * session is setup. It's a synchronous operation.
+ *
+ * @QCA_WLAN_TWT_CLEAR_STATS: Clear TWT session traffic statistics information.
+ * Valid only after the TWT session is setup. It's a synchronous operation.
+ *
+ * @QCA_WLAN_TWT_GET_CAPABILITIES: Get TWT capabilities of this device and its
+ * peer. Refers the enum qca_wlan_vendor_attr_twt_capability. It's a synchronous
+ * operation.
+ *
+ * @QCA_WLAN_TWT_SETUP_READY_NOTIFY: Notify userspace that the firmare is
+ * ready for a new TWT session setup after it issued a TWT teardown.
+ */
+enum qca_wlan_twt_operation {
+ QCA_WLAN_TWT_SET = 0,
+ QCA_WLAN_TWT_GET = 1,
+ QCA_WLAN_TWT_TERMINATE = 2,
+ QCA_WLAN_TWT_SUSPEND = 3,
+ QCA_WLAN_TWT_RESUME = 4,
+ QCA_WLAN_TWT_NUDGE = 5,
+ QCA_WLAN_TWT_GET_STATS = 6,
+ QCA_WLAN_TWT_CLEAR_STATS = 7,
+ QCA_WLAN_TWT_GET_CAPABILITIES = 8,
+ QCA_WLAN_TWT_SETUP_READY_NOTIFY = 9,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_config_twt: Defines attributes used by
+ * %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION: u8 attribute. Specify the TWT
+ * operation of this request. Possible values are defined in enum
+ * qca_wlan_twt_operation. The parameters for the respective operation is
+ * specified through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS: Nested attribute representing the
+ * parameters configured for TWT. These parameters are represented by
+ * enum qca_wlan_vendor_attr_twt_setup, enum qca_wlan_vendor_attr_twt_resume,
+ * or enum qca_wlan_vendor_attr_twt_stats based on the operation.
+ */
+enum qca_wlan_vendor_attr_config_twt {
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION = 1,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX =
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_AFTER_LAST - 1,
+};
+
+/**
* enum qca_wlan_vendor_attr_bss_filter - Used by the vendor command
* QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
* The user can add/delete the filter by specifying the BSSID/STA MAC address in
@@ -7284,10 +8248,24 @@ enum qca_wlan_vendor_attr_nan_params {
};
/**
+ * qca_wlan_twt_setup_state: Represents the TWT session states.
+ *
+ * QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED: TWT session not established.
+ * QCA_WLAN_TWT_SETUP_STATE_ACTIVE: TWT session is active.
+ * QCA_WLAN_TWT_SETUP_STATE_SUSPEND: TWT session is in suspended state.
+ */
+enum qca_wlan_twt_setup_state {
+ QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED = 0,
+ QCA_WLAN_TWT_SETUP_STATE_ACTIVE = 1,
+ QCA_WLAN_TWT_SETUP_STATE_SUSPEND = 2,
+};
+
+/**
* enum qca_wlan_vendor_attr_twt_setup: Represents attributes for
* TWT (Target Wake Time) setup request. These attributes are sent as part of
* %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP and
- * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION. Also used by
+ * attributes through %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST: Flag attribute.
* Disable (flag attribute not present) - Individual TWT
@@ -7297,10 +8275,13 @@ enum qca_wlan_vendor_attr_nan_params {
* STA and AP.
* Broadcast means the session is across multiple STAs and an AP. The
* configuration parameters are announced in Beacon frames by the AP.
+ * This is used in
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE: Required (u8).
* Unsigned 8-bit qca_wlan_vendor_twt_setup_req_type to
- * specify the TWT request type
+ * specify the TWT request type. This is used in TWT SET operation.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER: Flag attribute
* Enable (flag attribute present) - TWT with trigger support.
@@ -7308,40 +8289,139 @@ enum qca_wlan_vendor_attr_nan_params {
* Trigger means the AP will send the trigger frame to allow STA to send data.
* Without trigger, the STA will wait for the MU EDCA timer before
* transmitting the data.
+ * This is used in
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE: Required (u8)
* 0 - Announced TWT - In this mode, STA may skip few service periods to
* save more power. If STA wants to wake up, it will send a PS-POLL/QoS
* NULL frame to AP.
* 1 - Unannounced TWT - The STA will wakeup during every SP.
+ * This is a required parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID: Optional (u8)
* Flow ID is the unique identifier for each TWT session.
- * Currently this is not required and dialog ID will be set to zero.
+ * If not provided then dialog ID will be set to zero.
+ * This is an optional parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Request and Response
+ * 3. TWT TERMINATE Request and Response
+ * 4. TWT SUSPEND Request and Response
+ * Flow ID values from 0 to 254 represent a single TWT session
+ * Flow ID value of 255 represents all TWT sessions for the following
+ * 1. TWT TERMINATE Request and Response
+ * 2. TWT SUSPEND Request and Response
+ * 4. TWT CLEAR STATISTICS request
+ * 5. TWT GET STATISTICS request and response
+ * If an invalid dialog ID is provided, status
+ * QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST will be returned.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP: Required (u8)
* This attribute (exp) is used along with the mantissa to derive the
* wake interval using the following formula:
* pow(2,exp) = wake_intvl_us/wake_intvl_mantis
* Wake interval is the interval between 2 successive SP.
+ * This is a required parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION: Flag attribute
* Enable (flag attribute present) - Protection required.
* Disable (flag attribute not present) - Protection not required.
* If protection is enabled, then the AP will use protection
* mechanism using RTS/CTS to self to reserve the airtime.
+ * This is used in
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME: Optional (u32)
* This attribute is used as the SP offset which is the offset from
* TSF after which the wake happens. The units are in microseconds. If
* this attribute is not provided, then the value will be set to zero.
+ * This is an optional parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION: Required (u32)
- * This is the duration of the service period. The units are in TU.
+ * This is the duration of the service period. This is specified as
+ * multiples of 256 microseconds. Valid values are 0x1 to 0xFF.
+ * This is a required parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA: Required (u32)
* This attribute is used to configure wake interval mantissa.
* The units are in TU.
+ * This is a required parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS: Required (u8)
+ * This field is applicable for TWT response only.
+ * This contains status values in enum qca_wlan_vendor_twt_status
+ * and is passed to the userspace. This is used in TWT SET operation.
+ * This is a required parameter for
+ * 1. TWT SET Response
+ * 2. TWT TERMINATE Response
+ * 3. TWT SUSPEND Response
+ * 4. TWT RESUME Response
+ * 5. TWT NUDGE Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE: Required (u8)
+ * This field is applicable for TWT response only.
+ * This field contains response type from the TWT responder and is
+ * passed to the userspace. The values for this field are defined in
+ * enum qca_wlan_vendor_twt_setup_resp_type. This is used in TWT SET
+ * response.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF: Required (u64)
+ * This field is applicable for TWT response only.
+ * This field contains absolute TSF value of the wake time received
+ * from the TWT responder and is passed to the userspace.
+ * This is a required parameter for
+ * 1. TWT SET Response
+ * 2. TWT GET Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED: Flag attribute.
+ * Enable (flag attribute present) - Indicates that the TWT responder
+ * supports reception of TWT information frame from the TWT requestor.
+ * Disable (flag attribute not present) - Indicates that the responder
+ * doesn't support reception of TWT information frame from requestor.
+ * This is used in
+ * 1. TWT SET Response
+ * 2. TWT GET Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR: 6-byte MAC address
+ * Represents the MAC address of the peer for which the TWT session
+ * is being configured. This is used in AP mode to represent the respective
+ * client. In AP mode, this is an optional parameter for response and is
+ * a required parameter for
+ * 1. TWT SET Request
+ * 2. TWT GET Request
+ * 3. TWT TERMINATE Request
+ * 4. TWT SUSPEND Request
+ * In STA mode, this is an optional parameter in request and response for
+ * the above four TWT operations.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL: Optional (u32)
+ * Minimum tolerance limit of wake interval parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL: Optional (u32)
+ * Maximum tolerance limit of wake interval parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION: Optional (u32)
+ * Minimum tolerance limit of wake duration parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION: Optional (u32)
+ * Maximum tolerance limit of wake duration parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE: Optional (u32)
+ * TWT state for the given dialog id. The values for this are represented
+ * by enum qca_wlan_twt_setup_state.
+ * This is obtained through TWT GET operation.
*/
enum qca_wlan_vendor_attr_twt_setup {
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_INVALID = 0,
@@ -7356,6 +8436,19 @@ enum qca_wlan_vendor_attr_twt_setup {
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION = 9,
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA = 10,
+ /* TWT Response only attributes */
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS = 11,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE = 12,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF = 13,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED = 14,
+
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR = 15,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL = 16,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL = 17,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION = 18,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION = 19,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE = 20,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX =
@@ -7363,24 +8456,101 @@ enum qca_wlan_vendor_attr_twt_setup {
};
/**
- * enum qca_wlan_vendor_attr_twt_resume: Represents attributes for
+ * enum qca_wlan_vendor_twt_status - Represents the status of the requested
+ * TWT operation
+ *
+ * @QCA_WLAN_VENDOR_TWT_STATUS_OK: TWT request successfully completed
+ * @QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_ENABLED: TWT not enabled
+ * @QCA_WLAN_VENDOR_TWT_STATUS_USED_DIALOG_ID: TWT dialog ID is already used
+ * @QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY: TWT session is busy
+ * @QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST: TWT session does not exist
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NOT_SUSPENDED: TWT session not in suspend state
+ * @QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM: Invalid parameters
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NOT_READY: FW not ready
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE: FW resource exhausted
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK: Peer AP/STA did not ACK the
+ * request/response frame
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NO_RESPONSE: Peer AP did not send the response
+ * frame
+ * @QCA_WLAN_VENDOR_TWT_STATUS_DENIED: AP did not accept the request
+ * @QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR: Adding TWT dialog failed due to an
+ * unknown reason
+ * @QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED: TWT session already in
+ * suspend state
+ * @QCA_WLAN_VENDOR_TWT_STATUS_IE_INVALID: FW has dropped the frame due to
+ * invalid IE in the received TWT frame
+ * @QCA_WLAN_VENDOR_TWT_STATUS_PARAMS_NOT_IN_RANGE: Parameters received from
+ * the responder are not in the specified range
+ * @QCA_WLAN_VENDOR_TWT_STATUS_PEER_INITIATED_TERMINATE: FW terminated the TWT
+ * session due to request from the responder. Used on the TWT_TERMINATE
+ * notification from the firmware.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_ROAM_INITIATED_TERMINATE: FW terminated the TWT
+ * session due to roaming. Used on the TWT_TERMINATE notification from the
+ * firmware.
+ */
+enum qca_wlan_vendor_twt_status {
+ QCA_WLAN_VENDOR_TWT_STATUS_OK = 0,
+ QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_ENABLED = 1,
+ QCA_WLAN_VENDOR_TWT_STATUS_USED_DIALOG_ID = 2,
+ QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY = 3,
+ QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST = 4,
+ QCA_WLAN_VENDOR_TWT_STATUS_NOT_SUSPENDED = 5,
+ QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM = 6,
+ QCA_WLAN_VENDOR_TWT_STATUS_NOT_READY = 7,
+ QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE = 8,
+ QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK = 9,
+ QCA_WLAN_VENDOR_TWT_STATUS_NO_RESPONSE = 10,
+ QCA_WLAN_VENDOR_TWT_STATUS_DENIED = 11,
+ QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR = 12,
+ QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED = 13,
+ QCA_WLAN_VENDOR_TWT_STATUS_IE_INVALID = 14,
+ QCA_WLAN_VENDOR_TWT_STATUS_PARAMS_NOT_IN_RANGE = 15,
+ QCA_WLAN_VENDOR_TWT_STATUS_PEER_INITIATED_TERMINATE = 16,
+ QCA_WLAN_VENDOR_TWT_STATUS_ROAM_INITIATED_TERMINATE = 17,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_twt_resume - Represents attributes for
* TWT (Target Wake Time) resume request. These attributes are sent as part of
* %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_RESUME and
- * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION. Also used by
+ * attributes through %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT: Optional (u8)
- * This attribute is used as the SP offset which is the offset from
- * TSF after which the wake happens. The units are in microseconds.
- * If this attribute is not provided, then the value will be set to
- * zero.
+ * @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT: Optional (u32)
+ * These attributes are used as the SP offset which is the offset from TSF after
+ * which the wake happens. The units are in microseconds. Please note that
+ * _NEXT_TWT is limited to u8 whereas _NEXT2_TWT takes the u32 data.
+ * _NEXT2_TWT takes the precedence over _NEXT_TWT and thus the recommendation
+ * is to use _NEXT2_TWT. If neither of these attributes is provided, the value
+ * will be set to zero.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE: Required (u32)
* This attribute represents the next TWT subfield size.
+ * Value 0 represents 0 bits, 1 represents 32 bits, 2 for 48 bits,
+ * and 4 for 64 bits.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID: Required (u8).
+ * Flow ID is the unique identifier for each TWT session. This attribute
+ * represents the respective TWT session to resume.
+ * Flow ID values from 0 to 254 represent a single TWT session
+ * Flow ID value of 255 represents all TWT sessions.
+ * If an invalid dialog id is provided, status
+ * QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST will be returned.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAC_ADDR: 6-byte MAC address
+ * Represents the MAC address of the peer to which TWT Resume is
+ * being sent. This is used in AP mode to represent the respective
+ * client and is a required parameter. In STA mode, this is an optional
+ * parameter
*/
enum qca_wlan_vendor_attr_twt_resume {
QCA_WLAN_VENDOR_ATTR_TWT_RESUME_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT = 1,
QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE = 2,
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID = 3,
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT = 4,
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAC_ADDR = 5,
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_RESUME_AFTER_LAST,
@@ -7389,6 +8559,232 @@ enum qca_wlan_vendor_attr_twt_resume {
};
/**
+ * enum qca_wlan_vendor_attr_twt_nudge - Represents attributes for
+ * TWT (Target Wake Time) nudge request. TWT nudge is a combination of suspend
+ * and resume in a single request. These attributes are sent as part of
+ * %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID: Required (u8)
+ * Flow ID is the unique identifier for each TWT session. This attribute
+ * represents the respective TWT session to suspend and resume.
+ * Flow ID values from 0 to 254 represent a single TWT session
+ * Flow ID value of 255 represents all TWT sessions in TWT NUDGE request
+ * and response.
+ * If an invalid dialog id is provided, status
+ * QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST will be returned.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME: Required (u32)
+ * This attribute is used as the SP offset which is the offset from
+ * TSF after which the wake happens. The units are in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE: Required (u32)
+ * This attribute represents the next TWT subfield size.
+ * Value 0 represents 0 bits, 1 represents 32 bits, 2 for 48 bits,
+ * and 4 for 64 bits.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR: 6-byte MAC address
+ * Represents the MAC address of the peer to which TWT Suspend and Resume is
+ * being sent. This is used in AP mode to represent the respective
+ * client and is a required parameter. In STA mode, this is an optional
+ * parameter.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME_TSF: Optional (u64)
+ * This field contains absolute TSF value of the time at which the TWT
+ * session will be resumed.
+ */
+enum qca_wlan_vendor_attr_twt_nudge {
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID = 1,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME = 2,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE = 3,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR = 4,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME_TSF = 5,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX =
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_twt_stats: Represents attributes for
+ * TWT (Target Wake Time) get statistics and clear statistics request.
+ * These attributes are sent as part of
+ * %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID: Required (u8)
+ * Flow ID is the unique identifier for each TWT session. This attribute
+ * represents the respective TWT session for get and clear TWT statistics.
+ * Flow ID values from 0 to 254 represent a single TWT session
+ * Flow ID value of 255 represents all TWT sessions in
+ * 1) TWT GET STATISTICS request and response
+ * 2) TWT CLEAR STATISTICS request
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAC_ADDR: 6-byte MAC address
+ * Represents the MAC address of the peer for which TWT Statistics
+ * is required.
+ * In AP mode this is used to represent the respective
+ * client and is a required parameter for
+ * 1) TWT GET STATISTICS request and response
+ * 2) TWT CLEAR STATISTICS request and response
+ * In STA mode, this is an optional parameter.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_SESSION_WAKE_DURATION: Required (u32)
+ * This is the duration of the service period in microseconds.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVG_WAKE_DURATION: Required (u32)
+ * Average of the actual wake duration observed so far. Unit is microseconds.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS: Required (u32)
+ * The number of TWT service periods elapsed so far.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_MIN_WAKE_DURATION: Required (u32)
+ * This is the minimum value of the wake duration observed across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS. Unit is
+ * microseconds.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX_WAKE_DURATION: Required (u32)
+ * This is the maximum value of wake duration observed across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS. Unit is
+ * microseconds.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_MPDU: Required (u32)
+ * Average number of MPDUs transmitted successfully across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_MPDU: Required (u32)
+ * Average number of MPDUs received successfully across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_PACKET_SIZE: Required (u32)
+ * Average number of bytes transmitted successfully across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_PACKET_SIZE: Required (u32)
+ * Average number of bytes received successfully across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_STATUS: Required (u32)
+ * Status of the TWT GET STATISTICS request.
+ * This contains status values in enum qca_wlan_vendor_twt_status
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ */
+enum qca_wlan_vendor_attr_twt_stats {
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID = 1,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAC_ADDR = 2,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_SESSION_WAKE_DURATION = 3,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVG_WAKE_DURATION = 4,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS = 5,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_MIN_WAKE_DURATION = 6,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX_WAKE_DURATION = 7,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_MPDU = 8,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_MPDU = 9,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_PACKET_SIZE = 10,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_PACKET_SIZE = 11,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_STATUS = 12,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX =
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AFTER_LAST - 1,
+};
+
+/**
+ * qca_wlan_twt_get_capa - Represents the bitmap of TWT capabilities
+ * supported by the device and the peer.
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_GET_CAPABILITIES
+ *
+ * @QCA_WLAN_TWT_CAPA_REQUESTOR: TWT requestor support is advertised by
+ * TWT non-scheduling STA. This capability is advertised in the HE
+ * Capability/Extended Capabilities information element in the
+ * Association Request frame by the device.
+ *
+ * @QCA_WLAN_TWT_CAPA_RESPONDER: TWT responder support is advertised by
+ * the TWT scheduling AP. This capability is advertised in the Extended
+ * Capabilities/HE Capabilities information element.
+ *
+ * @QCA_WLAN_TWT_CAPA_BROADCAST: On the requestor side, this indicates support
+ * for the broadcast TWT functionality. On the responder side, this indicates
+ * support for the role of broadcast TWT scheduling functionality. This
+ * capability is advertised in the HE Capabilities information element.
+ *
+ * @QCA_WLAN_TWT_CAPA_TWT_FLEXIBLE: The device supports flexible TWT schedule.
+ * This capability is advertised in the HE Capabilities information element.
+ *
+ * @QCA_WLAN_TWT_CAPA_REQUIRED: The TWT Required is advertised by AP to indicate
+ * that it mandates the associated HE STAs to support TWT. This capability is
+ * advertised by AP in the HE Operation Parameters field of the HE Operation
+ * information element.
+ */
+enum qca_wlan_twt_capa {
+ QCA_WLAN_TWT_CAPA_REQUESTOR = BIT(0),
+ QCA_WLAN_TWT_CAPA_RESPONDER = BIT(1),
+ QCA_WLAN_TWT_CAPA_BROADCAST = BIT(2),
+ QCA_WLAN_TWT_CAPA_FLEXIBLE = BIT(3),
+ QCA_WLAN_TWT_CAPA_REQUIRED = BIT(4),
+};
+
+/**
+ * enum qca_wlan_vendor_attr_twt_capability - Represents attributes for TWT
+ * get capabilities request type. Used by QCA_WLAN_TWT_GET_CAPABILITIES TWT
+ * operation.
+ * @QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MAC_ADDR: 6-byte MAC address
+ * Represents the MAC address of the peer for which the TWT capabilities
+ * are being queried. This is used in AP mode to represent the respective
+ * client. In STA mode, this is an optional parameter.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF: (u16).
+ * Self TWT capabilities. Carries a bitmap of TWT capabilities specified in
+ * enum qca_wlan_twt_capa.
+ * @QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER: (u16).
+ * Peer TWT capabilities. Carries a bitmap of TWT capabilities specified in
+ * enum qca_wlan_twt_capa.
+ */
+enum qca_wlan_vendor_attr_twt_capability {
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MAC_ADDR = 1,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF = 2,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER = 3,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MAX =
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_twt_setup_resp_type - Represents the response type by
+ * the TWT responder
+ *
+ * @QCA_WLAN_VENDOR_TWT_RESP_ALTERNATE: TWT responder suggests TWT
+ * parameters that are different from TWT requesting STA suggested
+ * or demanded TWT parameters
+ * @QCA_WLAN_VENDOR_TWT_RESP_DICTATE: TWT responder demands TWT
+ * parameters that are different from TWT requesting STA TWT suggested
+ * or demanded parameters
+ * @QCA_WLAN_VENDOR_TWT_RESP_REJECT: TWT responder rejects TWT
+ * setup
+ * @QCA_WLAN_VENDOR_TWT_RESP_ACCEPT: TWT responder accepts the TWT
+ * setup.
+ */
+enum qca_wlan_vendor_twt_setup_resp_type {
+ QCA_WLAN_VENDOR_TWT_RESP_ALTERNATE = 1,
+ QCA_WLAN_VENDOR_TWT_RESP_DICTATE = 2,
+ QCA_WLAN_VENDOR_TWT_RESP_REJECT = 3,
+ QCA_WLAN_VENDOR_TWT_RESP_ACCEPT = 4,
+};
+
+/**
* enum qca_wlan_vendor_twt_setup_req_type - Required (u8)
* Represents the setup type being requested for TWT.
* @QCA_WLAN_VENDOR_TWT_SETUP_REQUEST: STA is not specifying all the TWT
@@ -8321,10 +9717,14 @@ enum qca_vendor_oem_device_type {
* enum qca_wlan_vendor_attr_oem_data_params - Used by the vendor command/event
* QCA_NL80211_VENDOR_SUBCMD_OEM_DATA.
*
- * @QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA: The binary blob for the vendor
- * command/event QCA_NL80211_VENDOR_SUBCMD_OEM_DATA are carried through this
- * attribute.
- * NLA_BINARY attribute, the max size is 1024 bytes.
+ * @QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA: This NLA_BINARY attribute is
+ * used to set/query the data to/from the firmware. On query, the same
+ * attribute is used to carry the respective data in the reply sent by the
+ * driver to userspace. The request to set/query the data and the format of the
+ * respective data from the firmware are embedded in the attribute. The
+ * maximum size of the attribute payload is 1024 bytes.
+ * Userspace has to set the QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED
+ * attribute when the data is queried from the firmware.
*
* @QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO: The binary blob will be routed
* based on this field. This optional attribute is included to specify whether
@@ -8333,11 +9733,16 @@ enum qca_vendor_oem_device_type {
* command/event.
* This u8 attribute is used to carry information for the device type using
* values defined by enum qca_vendor_oem_device_type.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED: This NLA_FLAG attribute
+ * is set when the userspace queries data from the firmware. This attribute
+ * should not be set when userspace sets the OEM data to the firmware.
*/
enum qca_wlan_vendor_attr_oem_data_params {
QCA_WLAN_VENDOR_ATTR_OEM_DATA_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA = 1,
QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO = 2,
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST,
@@ -8671,6 +10076,70 @@ enum qca_vendor_wlan_sta_guard_interval {
* disconnect reason for the last disconnection if the disconnection is
* triggered from the host driver. The values are referred from
* enum qca_disconnect_reason_codes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_MIC_ERROR_COUNT: u32, used in STA mode
+ * only. This represents the number of group addressed robust management frames
+ * received from this station with an invalid MIC or a missing MME when PMF is
+ * enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_REPLAY_COUNT: u32, used in STA mode
+ * only. This represents the number of group addressed robust management frames
+ * received from this station with the packet number less than or equal to the
+ * last received packet number when PMF is enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_MIC_ERROR_COUNT: u32, used in STA
+ * mode only. This represents the number of Beacon frames received from this
+ * station with an invalid MIC or a missing MME when beacon protection is
+ * enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_REPLAY_COUNT: u32, used in STA mode
+ * only. This represents number of Beacon frames received from this station with
+ * the packet number less than or equal to the last received packet number when
+ * beacon protection is enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE: u32, used in
+ * STA mode only. The driver uses this attribute to populate the connection
+ * failure reason codes and the values are defined in
+ * enum qca_sta_connect_fail_reason_codes. Userspace applications can send
+ * QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO vendor command after receiving
+ * a connection failure indication from the driver. The driver shall not
+ * include this attribute in response to the
+ * QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO command if there is no connection
+ * failure observed in the last attempted connection.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_RATE: u32, latest TX rate (Kbps)
+ * used by the station in its last TX frame while communicating to the AP in the
+ * connected state. When queried in the disconnected state, this represents the
+ * rate used by the STA in the last TX frame to the AP when it was connected.
+ * This attribute is used for STA mode only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_RIX: u32, used in STA mode only.
+ * This represents the rate index used by the STA for the last TX frame to the
+ * AP. When queried in the disconnected state, this gives the last RIX used by
+ * the STA in the last TX frame to the AP when it was connected.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TSF_OUT_OF_SYNC_COUNT: u32, used in STA
+ * mode only. This represents the number of times the STA TSF goes out of sync
+ * from the AP after the connection. If queried in the disconnected state, this
+ * gives the count of TSF out of sync for the last connection.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_TRIGGER_REASON: u32, used in STA
+ * mode only. This represents the roam trigger reason for the last roaming
+ * attempted by the firmware. This can be queried either in connected state or
+ * disconnected state. Each bit of this attribute represents the different
+ * roam trigger reason code which are defined in enum qca_vendor_roam_triggers.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_FAIL_REASON: u32, used in STA mode
+ * only. This represents the roam fail reason for the last failed roaming
+ * attempt by the firmware. Different roam failure reason codes are specified
+ * in enum qca_vendor_roam_fail_reasons. This can be queried either in
+ * connected state or disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_INVOKE_FAIL_REASON: u32, used in
+ * STA mode only. This represents the roam invoke fail reason for the last
+ * failed roam invoke. Different roam invoke failure reason codes
+ * are specified in enum qca_vendor_roam_invoke_fail_reasons. This can be
+ * queried either in connected state or disconnected state.
*/
enum qca_wlan_vendor_attr_get_sta_info {
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID = 0,
@@ -8712,6 +10181,17 @@ enum qca_wlan_vendor_attr_get_sta_info {
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_IES = 36,
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PROBE_RESP_IES = 37,
QCA_WLAN_VENDOR_ATTR_GET_STA_DRIVER_DISCONNECT_REASON = 38,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_MIC_ERROR_COUNT = 39,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_REPLAY_COUNT = 40,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_MIC_ERROR_COUNT = 41,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_REPLAY_COUNT = 42,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE = 43,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_RATE = 44,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_RIX = 45,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TSF_OUT_OF_SYNC_COUNT = 46,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_TRIGGER_REASON = 47,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_FAIL_REASON = 48,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_INVOKE_FAIL_REASON = 49,
/* keep last */
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST,
@@ -8841,4 +10321,352 @@ enum qca_wlan_vendor_attr_driver_disconnect_reason {
QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_tspec_operation - Operation of the config TSPEC request
+ *
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_OPERATION.
+ */
+enum qca_wlan_tspec_operation {
+ QCA_WLAN_TSPEC_ADD = 0,
+ QCA_WLAN_TSPEC_DEL = 1,
+ QCA_WLAN_TSPEC_GET = 2,
+};
+
+/**
+ * enum qca_wlan_tspec_direction - Direction in TSPEC
+ * As what is defined in IEEE Std 802.11-2016, Table 9-139.
+ *
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_DIRECTION.
+ */
+enum qca_wlan_tspec_direction {
+ QCA_WLAN_TSPEC_DIRECTION_UPLINK = 0,
+ QCA_WLAN_TSPEC_DIRECTION_DOWNLINK = 1,
+ QCA_WLAN_TSPEC_DIRECTION_DIRECT = 2,
+ QCA_WLAN_TSPEC_DIRECTION_BOTH = 3,
+};
+
+/**
+ * enum qca_wlan_tspec_ack_policy - MAC acknowledgement policy in TSPEC
+ * As what is defined in IEEE Std 802.11-2016, Table 9-141.
+ *
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_ACK_POLICY.
+ */
+enum qca_wlan_tspec_ack_policy {
+ QCA_WLAN_TSPEC_NORMAL_ACK = 0,
+ QCA_WLAN_TSPEC_NO_ACK = 1,
+ /* Reserved */
+ QCA_WLAN_TSPEC_BLOCK_ACK = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_config_tspec - Defines attributes
+ * used by %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TSPEC vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_OPERATION:
+ * u8 attribute. Specify the TSPEC operation of this request. Possible values
+ * are defined in enum qca_wlan_tspec_operation.
+ * Mandatory attribute for all kinds of config TSPEC requests.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_TSID:
+ * u8 attribute. TS ID. Possible values are 0-7.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD, QCA_WLAN_TSPEC_DEL,
+ * QCA_WLAN_TSPEC_GET. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_DIRECTION:
+ * u8 attribute. Direction of data carried by the TS. Possible values are
+ * defined in enum qca_wlan_tspec_direction.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_APSD:
+ * Flag attribute. Indicate whether APSD is enabled for the traffic associated
+ * with the TS. set - enabled, not set - disabled.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_USER_PRIORITY:
+ * u8 attribute. User priority to be used for the transport of MSDUs/A-MSDUs
+ * belonging to this TS. Possible values are 0-7.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_ACK_POLICY:
+ * u8 attribute. Indicate whether MAC acknowledgements are required for
+ * MPDUs/A-MSDUs belonging to this TS and the form of those acknowledgements.
+ * Possible values are defined in enum qca_wlan_tspec_ack_policy.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_NOMINAL_MSDU_SIZE:
+ * u16 attribute. Specify the nominal size in bytes of MSDUs/A-MSDUs
+ * belonging to this TS.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAXIMUM_MSDU_SIZE:
+ * u16 attribute. Specify the maximum size in bytes of MSDUs/A-MSDUs
+ * belonging to this TS.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MIN_SERVICE_INTERVAL:
+ * u32 attribute. Specify the minimum interval in microseconds between the
+ * start of two successive SPs.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX_SERVICE_INTERVAL:
+ * u32 attribute. Specify the maximum interval in microseconds between the
+ * start of two successive SPs.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_INACTIVITY_INTERVAL:
+ * u32 attribute. Specify the minimum interval in microseconds that can elapse
+ * without arrival or transfer of an MPDU belonging to the TS before this TS
+ * is deleted by the MAC entity at the HC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SUSPENSION_INTERVAL:
+ * u32 attribute. Specify the minimum interval in microseconds that can elapse
+ * without arrival or transfer of an MSDU belonging to the TS before the
+ * generation of successive QoS(+)CF-Poll is stopped for this TS. A value of
+ * 0xFFFFFFFF disables the suspension interval. The value of the suspension
+ * interval is always less than or equal to the inactivity interval.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_DATA_RATE:
+ * u32 attribute. Indicate the lowest data rate in bps specified at the MAC
+ * SAP for transport of MSDUs or A-MSDUs belonging to this TS within the
+ * bounds of this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MEAN_DATA_RATE:
+ * u32 attribute. Indicate the average data rate in bps specified at the MAC
+ * SAP for transport of MSDUs or A-MSDUs belonging to this TS within the
+ * bounds of this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_PEAK_DATA_RATE:
+ * u32 attribute. Indicate the maximum allowable data rate in bps specified at
+ * the MAC SAP for transport of MSDUs or A-MSDUs belonging to this TS within
+ * the bounds of this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_BURST_SIZE:
+ * u32 attribute. Specify the maximum burst size in bytes of the MSDUs/A-MSDUs
+ * belonging to this TS that arrive at the MAC SAP at the peak data rate. A
+ * value of 0 indicates that there are no bursts.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_PHY_RATE:
+ * u32 attribute. Indicate the minimum PHY rate in bps for transport of
+ * MSDUs/A-MSDUs belonging to this TS within the bounds of this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE:
+ * u16 attribute. Specify the excess allocation of time (and bandwidth) over
+ * and above the stated application rates required to transport an MSDU/A-MSDU
+ * belonging to the TS in this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ */
+enum qca_wlan_vendor_attr_config_tspec {
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_OPERATION = 1,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_TSID = 2,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_DIRECTION = 3,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_APSD = 4,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_USER_PRIORITY = 5,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_ACK_POLICY = 6,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_NOMINAL_MSDU_SIZE = 7,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAXIMUM_MSDU_SIZE = 8,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MIN_SERVICE_INTERVAL = 9,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX_SERVICE_INTERVAL = 10,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_INACTIVITY_INTERVAL = 11,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SUSPENSION_INTERVAL = 12,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_DATA_RATE = 13,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MEAN_DATA_RATE = 14,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_PEAK_DATA_RATE = 15,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_BURST_SIZE = 16,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_PHY_RATE = 17,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE = 18,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX =
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_oci_override_frame_type - OCI override frame type
+ * @QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_SA_QUERY_REQ: SA Query Request frame
+ * @QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_SA_QUERY_RESP: SA Query Response frame
+ * @QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_FT_REASSOC_REQ: FT Reassociation Request
+ * frame
+ * @QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_FILS_REASSOC_REQ: FILS Reassociation
+ * Request frame.
+ */
+enum qca_wlan_vendor_oci_override_frame_type {
+ QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_SA_QUERY_REQ = 1,
+ QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_SA_QUERY_RESP = 2,
+ QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_FT_REASSOC_REQ = 3,
+ QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_FILS_REASSOC_REQ = 4,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_oci_override: Represents attributes for
+ * OCI override request. These attributes are used inside nested attribute
+ * %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OCI_OVERRIDE in QCA vendor command
+ * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FRAME_TYPE: Required attribute, u8.
+ * Values from enum qca_wlan_vendor_oci_override_frame_type used in this
+ * attribute to specify the frame type in which the OCI is to be overridden.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FREQUENCY: Required (u32)
+ * OCI frequency (in MHz) to override in the specified frame type.
+ */
+enum qca_wlan_vendor_attr_oci_override {
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FRAME_TYPE = 1,
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FREQUENCY = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_MAX =
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_medium_assess_type - Type of medium assess request
+ *
+ * Values for %QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE.
+ */
+enum qca_wlan_medium_assess_type {
+ QCA_WLAN_MEDIUM_ASSESS_CCA = 0,
+ QCA_WLAN_MEDIUM_ASSESS_CONGESTION_REPORT = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_medium_assess - Attributes used by
+ * %QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE:
+ * u8 attribute. Mandatory in all kinds of medium assess requests/responses.
+ * Specify the type of medium assess request and indicate its type in response.
+ * Possible values are defined in enum qca_wlan_medium_assess_type.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_PERIOD:
+ * u32 attribute. Mandatory in CCA request.
+ * Specify the assessment period in terms of seconds. Assessment result will be
+ * sent as the response to the CCA request after the assessment period.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TOTAL_CYCLE_COUNT:
+ * u32 attribute. Mandatory in response to CCA request.
+ * Total timer tick count of the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IDLE_COUNT:
+ * u32 attribute. Mandatory in response to CCA request.
+ * Timer tick count of idle time in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IBSS_RX_COUNT:
+ * u32 attribute. Mandatory in response to CCA request.
+ * Timer tick count of Intra BSS traffic RX time in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_OBSS_RX_COUNT:
+ * u32 attribute. Mandatory in response to CCA request.
+ * Timer tick count of Overlapping BSS traffic RX time in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX_IBSS_RSSI:
+ * s32 attribute. Mandatory in response to CCA request.
+ * Maximum RSSI of Intra BSS traffic in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MIN_IBSS_RSSI:
+ * s32 attribute. Mandatory in response to CCA request.
+ * Minimum RSSI of Intra BSS traffic in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_ENABLE:
+ * u8 attribute. Mandatory in congestion report request.
+ * 1-enable 0-disable.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_THRESHOLD:
+ * u8 attribute. Mandatory in congestion report enable request and will be
+ * ignored if present in congestion report disable request. Possible values are
+ * 0-100. A vendor event QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS with the type
+ * QCA_WLAN_MEDIUM_ASSESS_CONGESTION_REPORT will be sent to userspace if
+ * congestion percentage reaches the configured threshold.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_INTERVAL:
+ * u8 attribute. Optional in congestion report enable request and will be
+ * ignored if present in congestion report disable request.
+ * Specify the interval of congestion report event in terms of seconds. Possible
+ * values are 1-255. Default value 1 will be used if this attribute is omitted
+ * or using invalid values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_PERCENTAGE:
+ * u8 attribute. Mandatory in congestion report event.
+ * Indicate the actual congestion percentage. Possible values are 0-100.
+ */
+enum qca_wlan_vendor_attr_medium_assess {
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE = 1,
+
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_PERIOD = 2,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TOTAL_CYCLE_COUNT = 3,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IDLE_COUNT = 4,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IBSS_RX_COUNT = 5,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_OBSS_RX_COUNT = 6,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX_IBSS_RSSI = 7,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MIN_IBSS_RSSI = 8,
+
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_ENABLE = 9,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_THRESHOLD = 10,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_INTERVAL = 11,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_PERCENTAGE = 12,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX =
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_mbssid_tx_vdev_status - Defines attributes
+ * used by QCA_NL80211_VENDOR_SUBCMD_MBSSID_TX_VDEV_STATUS vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_VAL:
+ * u8 attribute. Notify the TX VDEV status. Possible values 0, 1
+ * belonging to MBSSID/EMA_AP configuration. 0 means Non-Tx VDEV,
+ * 1 means Tx VDEV. Mandatory attribute for all MBSSID VDEV status events.
+ */
+enum qca_wlan_vendor_attr_mbssid_tx_vdev_status {
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_VAL = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_MAX =
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_sta_connect_fail_reason_codes - Defines values carried
+ * by QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE vendor
+ * attribute.
+ * @QCA_STA_CONNECT_FAIL_REASON_NO_BSS_FOUND: No Probe Response frame received
+ * for unicast Probe Request frame.
+ * @QCA_STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL: STA failed to send auth request.
+ * @QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED: AP didn't send ACK for
+ * auth request.
+ * @QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED: Auth response is not
+ * received from AP.
+ * @QCA_STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL: STA failed to send
+ * Association Request frame.
+ * @QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED: AP didn't send ACK for
+ * Association Request frame.
+ * @QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED: Association Response
+ * frame is not received from AP.
+ */
+enum qca_sta_connect_fail_reason_codes {
+ QCA_STA_CONNECT_FAIL_REASON_NO_BSS_FOUND = 1,
+ QCA_STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL = 2,
+ QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED = 3,
+ QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED = 4,
+ QCA_STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL = 5,
+ QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED = 6,
+ QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED = 7,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index 1b4ec6d8..372905db 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -713,6 +713,8 @@ static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group,
goto fail;
const_time_select_bin(m_is_zero, bin1, bin2, prime_len, bin);
x1 = crypto_bignum_init_set(bin, prime_len);
+ if (!x1)
+ goto fail;
debug_print_bignum("SSWU: x1 = CSEL(l, x1a, x1b)", x1, prime_len);
/* gx1 = x1^3 + a * x1 + b */
@@ -753,6 +755,8 @@ static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group,
goto fail;
const_time_select_bin(is_qr, bin1, bin2, prime_len, bin);
v = crypto_bignum_init_set(bin, prime_len);
+ if (!v)
+ goto fail;
debug_print_bignum("SSWU: v = CSEL(l, gx1, gx2)", v, prime_len);
/* x = CSEL(l, x1, x2) */
@@ -1052,10 +1056,17 @@ sae_derive_pt_group(int group, const u8 *ssid, size_t ssid_len,
wpa_printf(MSG_DEBUG, "SAE: Derive PT - group %d", group);
+ if (ssid_len > 32)
+ return NULL;
+
pt = os_zalloc(sizeof(*pt));
if (!pt)
return NULL;
+#ifdef CONFIG_SAE_PK
+ os_memcpy(pt->ssid, ssid, ssid_len);
+ pt->ssid_len = ssid_len;
+#endif /* CONFIG_SAE_PK */
pt->group = group;
pt->ec = crypto_ec_init(group);
if (pt->ec) {
@@ -1354,14 +1365,15 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
identifier) < 0))
return -1;
- sae->tmp->h2e = 0;
+ sae->h2e = 0;
+ sae->pk = 0;
return sae_derive_commit(sae);
}
int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
const u8 *addr1, const u8 *addr2,
- int *rejected_groups)
+ int *rejected_groups, const struct sae_pk *pk)
{
if (!sae->tmp)
return -1;
@@ -1377,6 +1389,11 @@ int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
return -1;
}
+#ifdef CONFIG_SAE_PK
+ os_memcpy(sae->tmp->ssid, pt->ssid, pt->ssid_len);
+ sae->tmp->ssid_len = pt->ssid_len;
+ sae->tmp->ap_pk = pk;
+#endif /* CONFIG_SAE_PK */
sae->tmp->own_addr_higher = os_memcmp(addr1, addr2, ETH_ALEN) > 0;
wpabuf_free(sae->tmp->own_rejected_groups);
sae->tmp->own_rejected_groups = NULL;
@@ -1409,7 +1426,7 @@ int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
return -1;
}
- sae->tmp->h2e = 1;
+ sae->h2e = 1;
return sae_derive_commit(sae);
}
@@ -1515,7 +1532,7 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
const u8 *salt;
struct wpabuf *rejected_groups = NULL;
u8 keyseed[SAE_MAX_HASH_LEN];
- u8 keys[SAE_MAX_HASH_LEN + SAE_PMK_LEN];
+ u8 keys[2 * SAE_MAX_HASH_LEN + SAE_PMK_LEN];
struct crypto_bignum *tmp;
int ret = -1;
size_t hash_len, salt_len, prime_len = sae->tmp->prime_len;
@@ -1530,15 +1547,18 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
* KCK || PMK = KDF-Hash-Length(keyseed, "SAE KCK and PMK",
* (commit-scalar + peer-commit-scalar) modulo r)
* PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
+ *
+ * When SAE-PK is used,
+ * KCK || PMK || KEK = KDF-Hash-Length(keyseed, "SAE-PK keys", context)
*/
- if (!sae->tmp->h2e)
+ if (!sae->h2e)
hash_len = SHA256_MAC_LEN;
else if (sae->tmp->dh)
hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
else
hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
- if (sae->tmp->h2e && (sae->tmp->own_rejected_groups ||
- sae->tmp->peer_rejected_groups)) {
+ if (sae->h2e && (sae->tmp->own_rejected_groups ||
+ sae->tmp->peer_rejected_groups)) {
struct wpabuf *own, *peer;
own = sae->tmp->own_rejected_groups;
@@ -1589,15 +1609,40 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
* octets). */
crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len);
wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
+
+#ifdef CONFIG_SAE_PK
+ if (sae->pk) {
+ if (sae_kdf_hash(hash_len, keyseed, "SAE-PK keys",
+ val, sae->tmp->order_len,
+ keys, 2 * hash_len + SAE_PMK_LEN) < 0)
+ goto fail;
+ } else {
+ if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
+ val, sae->tmp->order_len,
+ keys, hash_len + SAE_PMK_LEN) < 0)
+ goto fail;
+ }
+#else /* CONFIG_SAE_PK */
if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
val, sae->tmp->order_len,
keys, hash_len + SAE_PMK_LEN) < 0)
goto fail;
+#endif /* !CONFIG_SAE_PK */
+
forced_memzero(keyseed, sizeof(keyseed));
os_memcpy(sae->tmp->kck, keys, hash_len);
sae->tmp->kck_len = hash_len;
os_memcpy(sae->pmk, keys + hash_len, SAE_PMK_LEN);
os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
+#ifdef CONFIG_SAE_PK
+ if (sae->pk) {
+ os_memcpy(sae->tmp->kek, keys + hash_len + SAE_PMK_LEN,
+ hash_len);
+ sae->tmp->kek_len = hash_len;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: KEK for SAE-PK",
+ sae->tmp->kek, sae->tmp->kek_len);
+ }
+#endif /* CONFIG_SAE_PK */
forced_memzero(keys, sizeof(keys));
wpa_hexdump_key(MSG_DEBUG, "SAE: KCK",
sae->tmp->kck, sae->tmp->kck_len);
@@ -1632,7 +1677,7 @@ int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
return -1;
wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
- if (!sae->tmp->h2e && token) {
+ if (!sae->h2e && token) {
wpabuf_put_buf(buf, token);
wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
wpabuf_head(token), wpabuf_len(token));
@@ -1673,7 +1718,7 @@ int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
identifier);
}
- if (sae->tmp->h2e && sae->tmp->own_rejected_groups) {
+ if (sae->h2e && sae->tmp->own_rejected_groups) {
wpa_hexdump_buf(MSG_DEBUG, "SAE: own Rejected Groups",
sae->tmp->own_rejected_groups);
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
@@ -1683,7 +1728,7 @@ int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
wpabuf_put_buf(buf, sae->tmp->own_rejected_groups);
}
- if (sae->tmp->h2e && token) {
+ if (sae->h2e && token) {
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
wpabuf_put_u8(buf, 1 + wpabuf_len(token));
wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
@@ -2189,13 +2234,14 @@ static int sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
}
-void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
+int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
{
const u8 *sc;
size_t hash_len;
+ int res;
if (sae->tmp == NULL)
- return;
+ return -1;
hash_len = sae->tmp->kck_len;
@@ -2206,17 +2252,26 @@ void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
sae->send_confirm++;
if (sae->tmp->ec)
- sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
- sae->tmp->own_commit_element_ecc,
- sae->peer_commit_scalar,
- sae->tmp->peer_commit_element_ecc,
- wpabuf_put(buf, hash_len));
+ res = sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ecc,
+ sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ecc,
+ wpabuf_put(buf, hash_len));
else
- sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
- sae->tmp->own_commit_element_ffc,
- sae->peer_commit_scalar,
- sae->tmp->peer_commit_element_ffc,
- wpabuf_put(buf, hash_len));
+ res = sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ffc,
+ sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ffc,
+ wpabuf_put(buf, hash_len));
+ if (res)
+ return res;
+
+#ifdef CONFIG_SAE_PK
+ if (sae_write_confirm_pk(sae, buf) < 0)
+ return -1;
+#endif /* CONFIG_SAE_PK */
+
+ return 0;
}
@@ -2270,6 +2325,12 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
return -1;
}
+#ifdef CONFIG_SAE_PK
+ if (sae_check_confirm_pk(sae, data + 2 + hash_len,
+ len - 2 - hash_len) < 0)
+ return -1;
+#endif /* CONFIG_SAE_PK */
+
return 0;
}
diff --git a/src/common/sae.h b/src/common/sae.h
index 7966d70e..2243c0f3 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -16,11 +16,27 @@
#define SAE_MAX_ECC_PRIME_LEN 66
#define SAE_MAX_HASH_LEN 64
#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN + 255)
+#ifdef CONFIG_SAE_PK
+#define SAE_CONFIRM_MAX_LEN ((2 + SAE_MAX_HASH_LEN) + 1500)
+#else /* CONFIG_SAE_PK */
#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_HASH_LEN)
+#endif /* CONFIG_SAE_PK */
+#define SAE_PK_M_LEN 16
/* Special value returned by sae_parse_commit() */
#define SAE_SILENTLY_DISCARD 65535
+struct sae_pk {
+ struct wpabuf *m;
+ struct crypto_ec_key *key;
+ int group;
+ struct wpabuf *pubkey; /* DER encoded subjectPublicKey */
+#ifdef CONFIG_TESTING_OPTIONS
+ struct crypto_ec_key *sign_key_override;
+#endif /* CONFIG_TESTING_OPTIONS */
+};
+
+
struct sae_temporary_data {
u8 kck[SAE_MAX_HASH_LEN];
size_t kck_len;
@@ -46,8 +62,25 @@ struct sae_temporary_data {
u8 bssid[ETH_ALEN];
struct wpabuf *own_rejected_groups;
struct wpabuf *peer_rejected_groups;
- unsigned int h2e:1;
unsigned int own_addr_higher:1;
+
+#ifdef CONFIG_SAE_PK
+ u8 kek[SAE_MAX_HASH_LEN];
+ size_t kek_len;
+ const struct sae_pk *ap_pk;
+ u8 own_addr[ETH_ALEN];
+ u8 peer_addr[ETH_ALEN];
+ u8 fingerprint[SAE_MAX_HASH_LEN];
+ size_t fingerprint_bytes;
+ size_t fingerprint_bits;
+ size_t lambda;
+ unsigned int sec;
+ u8 ssid[32];
+ size_t ssid_len;
+#ifdef CONFIG_TESTING_OPTIONS
+ bool omit_pk_elem;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_SAE_PK */
};
struct sae_pt {
@@ -58,6 +91,10 @@ struct sae_pt {
const struct dh_group *dh;
struct crypto_bignum *ffc_pt;
+#ifdef CONFIG_SAE_PK
+ u8 ssid[32];
+ size_t ssid_len;
+#endif /* CONFIG_SAE_PK */
};
enum sae_state {
@@ -74,6 +111,8 @@ struct sae_data {
int group;
unsigned int sync; /* protocol instance variable: Sync */
u16 rc; /* protocol instance variable: Rc (received send-confirm) */
+ unsigned int h2e:1;
+ unsigned int pk:1;
struct sae_temporary_data *tmp;
};
@@ -86,17 +125,19 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
const char *identifier, struct sae_data *sae);
int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
const u8 *addr1, const u8 *addr2,
- int *rejected_groups);
+ int *rejected_groups, const struct sae_pk *pk);
int sae_process_commit(struct sae_data *sae);
int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
const struct wpabuf *token, const char *identifier);
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
const u8 **token, size_t *token_len, int *allowed_groups,
int h2e);
-void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
+int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);
u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group);
const char * sae_state_txt(enum sae_state state);
+size_t sae_ecc_prime_len_2_hash_len(size_t prime_len);
+size_t sae_ffc_prime_len_2_hash_len(size_t prime_len);
struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
const u8 *password, size_t password_len,
const char *identifier);
@@ -108,4 +149,24 @@ sae_derive_pwe_from_pt_ffc(const struct sae_pt *pt,
const u8 *addr1, const u8 *addr2);
void sae_deinit_pt(struct sae_pt *pt);
+/* sae_pk.c */
+#ifdef CONFIG_SAE_PK
+bool sae_pk_valid_password(const char *pw);
+#else /* CONFIG_SAE_PK */
+static inline bool sae_pk_valid_password(const char *pw)
+{
+ return false;
+}
+#endif /* CONFIG_SAE_PK */
+char * sae_pk_base32_encode(const u8 *src, size_t len_bits);
+u8 * sae_pk_base32_decode(const char *src, size_t len, size_t *out_len);
+int sae_pk_set_password(struct sae_data *sae, const char *password);
+void sae_deinit_pk(struct sae_pk *pk);
+struct sae_pk * sae_parse_pk(const char *val);
+int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf);
+int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len);
+int sae_hash(size_t hash_len, const u8 *data, size_t len, u8 *hash);
+u32 sae_pk_get_be19(const u8 *buf);
+void sae_pk_buf_shift_left_19(u8 *buf, size_t len);
+
#endif /* SAE_H */
diff --git a/src/common/sae_pk.c b/src/common/sae_pk.c
new file mode 100644
index 00000000..df79e5f2
--- /dev/null
+++ b/src/common/sae_pk.c
@@ -0,0 +1,884 @@
+/*
+ * SAE-PK
+ * 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 <stdint.h>
+
+#include "utils/common.h"
+#include "utils/base64.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "crypto/crypto.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
+#include "sae.h"
+
+
+/* RFC 4648 base 32 alphabet with lowercase characters */
+static const char *sae_pk_base32_table = "abcdefghijklmnopqrstuvwxyz234567";
+
+
+static const u8 d_mult_table[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16,
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22,
+ 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7,
+ 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23,
+ 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
+ 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
+ 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18,
+ 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2,
+ 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
+ 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3,
+ 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20,
+ 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4,
+ 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21,
+ 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5,
+ 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22,
+ 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6,
+ 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23,
+ 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7,
+ 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24,
+ 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8,
+ 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25,
+ 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9,
+ 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26,
+ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10,
+ 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27,
+ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11,
+ 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28,
+ 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12,
+ 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29,
+ 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13,
+ 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30,
+ 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
+ 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31,
+ 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15,
+ 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
+ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+};
+
+static const u8 d_perm_table[] = {
+ 7, 2, 1, 30, 16, 20, 27, 11, 31, 6, 8, 13, 29, 5, 10, 21,
+ 22, 3, 24, 0, 23, 25, 12, 9, 28, 14, 4, 15, 17, 18, 19, 26
+};
+
+
+static u8 d_permute(u8 val, unsigned int iter)
+{
+ if (iter == 0)
+ return val;
+ return d_permute(d_perm_table[val], iter - 1);
+}
+
+
+static u8 d_invert(u8 val)
+{
+ if (val > 0 && val < 16)
+ return 16 - val;
+ return val;
+}
+
+
+static char d_check_char(const char *str, size_t len)
+{
+ size_t i;
+ u8 val = 0;
+ u8 dtable[256];
+ unsigned int iter = 1;
+ int j;
+
+ os_memset(dtable, 0x80, 256);
+ for (i = 0; sae_pk_base32_table[i]; i++)
+ dtable[(u8) sae_pk_base32_table[i]] = i;
+
+ for (j = len - 1; j >= 0; j--) {
+ u8 c, p;
+
+ c = dtable[(u8) str[j]];
+ if (c == 0x80)
+ continue;
+ p = d_permute(c, iter);
+ iter++;
+ val = d_mult_table[val * 32 + p];
+ }
+
+ return sae_pk_base32_table[d_invert(val)];
+}
+
+
+bool sae_pk_valid_password(const char *pw)
+{
+ int pos;
+ size_t i, pw_len = os_strlen(pw);
+ u8 sec_1b;
+ u8 dtable[256];
+
+ os_memset(dtable, 0x80, 256);
+ for (i = 0; sae_pk_base32_table[i]; i++)
+ dtable[(u8) sae_pk_base32_table[i]] = i;
+
+ /* SAE-PK password has at least three four character components
+ * separated by hyphens. */
+ if (pw_len < 14 || pw_len % 5 != 4) {
+ wpa_printf(MSG_DEBUG, "SAE-PK: Not a valid password (length)");
+ return false;
+ }
+
+ for (pos = 0; pw[pos]; pos++) {
+ if (pos && pos % 5 == 4) {
+ if (pw[pos] != '-') {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: Not a valid password (separator)");
+ return false;
+ }
+ continue;
+ }
+ if (dtable[(u8) pw[pos]] == 0x80) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: Not a valid password (character)");
+ return false;
+ }
+ }
+
+ /* Verify that the checksum character is valid */
+ if (pw[pw_len - 1] != d_check_char(pw, pw_len - 1)) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: Not a valid password (checksum)");
+ return false;
+ }
+
+ /* Verify that Sec_1b bits match */
+ sec_1b = dtable[(u8) pw[0]] & BIT(4);
+ for (i = 5; i < pw_len; i += 5) {
+ if (sec_1b != (dtable[(u8) pw[i]] & BIT(4))) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: Not a valid password (Sec_1b)");
+ return false;
+ }
+ }
+ return true;
+}
+
+
+static char * add_char(const char *start, char *pos, u8 idx, size_t *bits)
+{
+ if (*bits == 0)
+ return pos;
+ if (*bits > 5)
+ *bits -= 5;
+ else
+ *bits = 0;
+
+ if ((pos - start) % 5 == 4)
+ *pos++ = '-';
+ *pos++ = sae_pk_base32_table[idx];
+ return pos;
+}
+
+
+/* Base32 encode a password and add hyper separators and checksum */
+char * sae_pk_base32_encode(const u8 *src, size_t len_bits)
+{
+ char *out, *pos;
+ size_t olen, extra_pad, i;
+ u64 block = 0;
+ u8 val;
+ size_t len = (len_bits + 7) / 8;
+ size_t left = len_bits;
+ int j;
+
+ if (len == 0 || len >= SIZE_MAX / 8)
+ return NULL;
+ olen = len * 8 / 5 + 1;
+ olen += olen / 4; /* hyphen separators */
+ pos = out = os_zalloc(olen + 2); /* include room for ChkSum and nul */
+ if (!out)
+ return NULL;
+
+ extra_pad = (5 - len % 5) % 5;
+ for (i = 0; i < len + extra_pad; i++) {
+ val = i < len ? src[i] : 0;
+ block <<= 8;
+ block |= val;
+ if (i % 5 == 4) {
+ for (j = 7; j >= 0; j--)
+ pos = add_char(out, pos,
+ (block >> j * 5) & 0x1f, &left);
+ block = 0;
+ }
+ }
+
+ *pos = d_check_char(out, os_strlen(out));
+
+ return out;
+}
+
+
+u8 * sae_pk_base32_decode(const char *src, size_t len, size_t *out_len)
+{
+ u8 dtable[256], *out, *pos, tmp;
+ u64 block = 0;
+ size_t i, count, olen;
+ int pad = 0;
+ size_t extra_pad;
+
+ os_memset(dtable, 0x80, 256);
+ for (i = 0; sae_pk_base32_table[i]; i++)
+ dtable[(u8) sae_pk_base32_table[i]] = i;
+ dtable['='] = 0;
+
+ count = 0;
+ for (i = 0; i < len; i++) {
+ if (dtable[(u8) src[i]] != 0x80)
+ count++;
+ }
+
+ if (count == 0)
+ return NULL;
+ extra_pad = (8 - count % 8) % 8;
+
+ olen = (count + extra_pad) / 8 * 5;
+ pos = out = os_malloc(olen);
+ if (!out)
+ return NULL;
+
+ count = 0;
+ for (i = 0; i < len + extra_pad; i++) {
+ u8 val;
+
+ if (i >= len)
+ val = '=';
+ else
+ val = src[i];
+ tmp = dtable[val];
+ if (tmp == 0x80)
+ continue;
+
+ if (val == '=')
+ pad++;
+ block <<= 5;
+ block |= tmp;
+ count++;
+ if (count == 8) {
+ *pos++ = (block >> 32) & 0xff;
+ *pos++ = (block >> 24) & 0xff;
+ *pos++ = (block >> 16) & 0xff;
+ *pos++ = (block >> 8) & 0xff;
+ *pos++ = block & 0xff;
+ count = 0;
+ block = 0;
+ if (pad) {
+ /* Leave in all the available bits with zero
+ * padding to full octets from right. */
+ pos -= pad * 5 / 8;
+ break;
+ }
+ }
+ }
+
+ *out_len = pos - out;
+ return out;
+}
+
+
+u32 sae_pk_get_be19(const u8 *buf)
+{
+ return (buf[0] << 11) | (buf[1] << 3) | (buf[2] >> 5);
+}
+
+
+/* shift left by two octets and three bits; fill in zeros from right;
+ * len must be at least three */
+void sae_pk_buf_shift_left_19(u8 *buf, size_t len)
+{
+ u8 *dst, *src, *end;
+
+ dst = buf;
+ src = buf + 2;
+ end = buf + len;
+
+ while (src + 1 < end) {
+ *dst++ = (src[0] << 3) | (src[1] >> 5);
+ src++;
+ }
+ *dst++ = *src << 3;
+ *dst++ = 0;
+ *dst++ = 0;
+}
+
+
+static void sae_pk_buf_shift_left_1(u8 *buf, size_t len)
+{
+ u8 *dst, *src, *end;
+
+ dst = buf;
+ src = buf;
+ end = buf + len;
+
+ while (src + 1 < end) {
+ *dst++ = (src[0] << 1) | (src[1] >> 7);
+ src++;
+ }
+ *dst++ = *src << 1;
+}
+
+
+int sae_pk_set_password(struct sae_data *sae, const char *password)
+{
+ struct sae_temporary_data *tmp = sae->tmp;
+ size_t len, pw_len;
+ u8 *pw, *pos;
+ int bits;
+ u32 val = 0, val19;
+ unsigned int val_bits = 0;
+
+ if (!tmp)
+ return -1;
+
+ os_memset(tmp->fingerprint, 0, sizeof(tmp->fingerprint));
+ tmp->fingerprint_bytes = tmp->fingerprint_bits = 0;
+
+ len = os_strlen(password);
+ if (len < 1 || !sae_pk_valid_password(password))
+ return -1;
+
+ pw = sae_pk_base32_decode(password, len, &pw_len);
+ if (!pw)
+ return -1;
+
+ tmp->sec = (pw[0] & BIT(7)) ? 3 : 5;
+ tmp->lambda = len - len / 5;
+ tmp->fingerprint_bits = 8 * tmp->sec + 19 * tmp->lambda / 4 - 5;
+ wpa_printf(MSG_DEBUG, "SAE-PK: Sec=%u Lambda=%zu fingerprint_bits=%zu",
+ tmp->sec, tmp->lambda, tmp->fingerprint_bits);
+
+ /* Construct Fingerprint from PasswordBase by prefixing with Sec zero
+ * octets and skipping the Sec_1b bits */
+ pos = &tmp->fingerprint[tmp->sec];
+ bits = tmp->fingerprint_bits - 8 * tmp->sec;
+ wpa_hexdump_key(MSG_DEBUG, "SAE-PK: PasswordBase", pw, pw_len);
+ while (bits > 0) {
+ if (val_bits < 8) {
+ sae_pk_buf_shift_left_1(pw, pw_len); /* Sec_1b */
+ val19 = sae_pk_get_be19(pw);
+ sae_pk_buf_shift_left_19(pw, pw_len);
+ val = (val << 19) | val19;
+ val_bits += 19;
+ }
+ if (val_bits >= 8) {
+ if (bits < 8)
+ break;
+ *pos++ = (val >> (val_bits - 8)) & 0xff;
+ val_bits -= 8;
+ bits -= 8;
+ }
+ }
+ if (bits > 0) {
+ val >>= val_bits - bits;
+ *pos++ = val << (8 - bits);
+ }
+ tmp->fingerprint_bytes = pos - tmp->fingerprint;
+ wpa_hexdump_key(MSG_DEBUG, "SAE-PK: Fingerprint",
+ tmp->fingerprint, tmp->fingerprint_bytes);
+ bin_clear_free(pw, pw_len);
+ return 0;
+}
+
+
+static size_t sae_group_2_hash_len(int group)
+{
+ switch (group) {
+ case 19:
+ return 32;
+ case 20:
+ return 48;
+ case 21:
+ return 64;
+ }
+
+ return 0;
+}
+
+
+void sae_deinit_pk(struct sae_pk *pk)
+{
+ if (pk) {
+ wpabuf_free(pk->m);
+ crypto_ec_key_deinit(pk->key);
+#ifdef CONFIG_TESTING_OPTIONS
+ crypto_ec_key_deinit(pk->sign_key_override);
+#endif /* CONFIG_TESTING_OPTIONS */
+ wpabuf_free(pk->pubkey);
+ os_free(pk);
+ }
+}
+
+
+struct sae_pk * sae_parse_pk(const char *val)
+{
+ struct sae_pk *pk;
+ const char *pos;
+#ifdef CONFIG_TESTING_OPTIONS
+ const char *pos2;
+#endif /* CONFIG_TESTING_OPTIONS */
+ size_t len;
+ unsigned char *der;
+ size_t der_len, b_len;
+
+ /* <m-as-hexdump>:<base64-encoded-DER-encoded-key> */
+
+ pos = os_strchr(val, ':');
+ if (!pos || (pos - val) & 0x01)
+ return NULL;
+ len = (pos - val) / 2;
+ if (len != SAE_PK_M_LEN) {
+ wpa_printf(MSG_INFO, "SAE: Unexpected Modifier M length %zu",
+ len);
+ return NULL;
+ }
+
+ pk = os_zalloc(sizeof(*pk));
+ if (!pk)
+ return NULL;
+ pk->m = wpabuf_alloc(len);
+ if (!pk->m || hexstr2bin(val, wpabuf_put(pk->m, len), len)) {
+ wpa_printf(MSG_INFO, "SAE: Failed to parse m");
+ goto fail;
+ }
+
+ pos++;
+ b_len = os_strlen(pos);
+#ifdef CONFIG_TESTING_OPTIONS
+ pos2 = os_strchr(pos, ':');
+ if (pos2) {
+ b_len = pos2 - pos;
+ pos2++;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ der = base64_decode(pos, b_len, &der_len);
+ if (!der) {
+ wpa_printf(MSG_INFO, "SAE: Failed to base64 decode PK key");
+ goto fail;
+ }
+
+ pk->key = crypto_ec_key_parse_priv(der, der_len);
+ bin_clear_free(der, der_len);
+ if (!pk->key)
+ goto fail;
+ pk->group = crypto_ec_key_group(pk->key);
+ pk->pubkey = crypto_ec_key_get_subject_public_key(pk->key);
+ if (!pk->pubkey)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (pos2) {
+ der = base64_decode(pos2, os_strlen(pos2), &der_len);
+ if (!der) {
+ wpa_printf(MSG_INFO,
+ "SAE: Failed to base64 decode PK key");
+ goto fail;
+ }
+
+ pk->sign_key_override = crypto_ec_key_parse_priv(der, der_len);
+ bin_clear_free(der, der_len);
+ if (!pk->sign_key_override)
+ goto fail;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return pk;
+fail:
+ sae_deinit_pk(pk);
+ return NULL;
+}
+
+
+int sae_hash(size_t hash_len, const u8 *data, size_t len, u8 *hash)
+{
+ if (hash_len == 32)
+ return sha256_vector(1, &data, &len, hash);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return sha384_vector(1, &data, &len, hash);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return sha512_vector(1, &data, &len, hash);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
+static int sae_pk_hash_sig_data(struct sae_data *sae, size_t hash_len,
+ bool ap, const u8 *m, size_t m_len,
+ const u8 *pubkey, size_t pubkey_len, u8 *hash)
+{
+ struct sae_temporary_data *tmp = sae->tmp;
+ struct wpabuf *sig_data;
+ u8 *pos;
+ int ret = -1;
+
+ /* Signed data for KeyAuth: eleAP || eleSTA || scaAP || scaSTA ||
+ * M || K_AP || AP-BSSID || STA-MAC */
+ sig_data = wpabuf_alloc(tmp->prime_len * 6 + m_len + pubkey_len +
+ 2 * ETH_ALEN);
+ if (!sig_data)
+ goto fail;
+ pos = wpabuf_put(sig_data, 2 * tmp->prime_len);
+ if (crypto_ec_point_to_bin(tmp->ec, ap ? tmp->own_commit_element_ecc :
+ tmp->peer_commit_element_ecc,
+ pos, pos + tmp->prime_len) < 0)
+ goto fail;
+ pos = wpabuf_put(sig_data, 2 * tmp->prime_len);
+ if (crypto_ec_point_to_bin(tmp->ec, ap ? tmp->peer_commit_element_ecc :
+ tmp->own_commit_element_ecc,
+ pos, pos + tmp->prime_len) < 0)
+ goto fail;
+ if (crypto_bignum_to_bin(ap ? tmp->own_commit_scalar :
+ sae->peer_commit_scalar,
+ wpabuf_put(sig_data, tmp->prime_len),
+ tmp->prime_len, tmp->prime_len) < 0 ||
+ crypto_bignum_to_bin(ap ? sae->peer_commit_scalar :
+ tmp->own_commit_scalar,
+ wpabuf_put(sig_data, tmp->prime_len),
+ tmp->prime_len, tmp->prime_len) < 0)
+ goto fail;
+ wpabuf_put_data(sig_data, m, m_len);
+ wpabuf_put_data(sig_data, pubkey, pubkey_len);
+ wpabuf_put_data(sig_data, ap ? tmp->own_addr : tmp->peer_addr,
+ ETH_ALEN);
+ wpabuf_put_data(sig_data, ap ? tmp->peer_addr : tmp->own_addr,
+ ETH_ALEN);
+ wpa_hexdump_buf_key(MSG_DEBUG, "SAE-PK: Data to be signed for KeyAuth",
+ sig_data);
+ if (sae_hash(hash_len, wpabuf_head(sig_data), wpabuf_len(sig_data),
+ hash) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: hash(data to be signed)",
+ hash, hash_len);
+ ret = 0;
+fail:
+ wpabuf_free(sig_data);
+ return ret;
+}
+
+
+int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf)
+{
+ struct sae_temporary_data *tmp = sae->tmp;
+ struct wpabuf *sig = NULL;
+ size_t need;
+ int ret = -1;
+ u8 *encr_mod;
+ size_t encr_mod_len;
+ const struct sae_pk *pk;
+ u8 hash[SAE_MAX_HASH_LEN];
+ size_t hash_len;
+ struct crypto_ec_key *key;
+
+ if (!tmp)
+ return -1;
+
+ pk = tmp->ap_pk;
+ if (!sae->pk || !pk)
+ return 0;
+
+ key = pk->key;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (tmp->omit_pk_elem)
+ return 0;
+ if (pk->sign_key_override) {
+ wpa_printf(MSG_INFO, "TESTING: Override SAE-PK signing key");
+ key = pk->sign_key_override;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (tmp->kek_len != 32 && tmp->kek_len != 48 && tmp->kek_len != 64) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: No KEK available for writing confirm");
+ return -1;
+ }
+
+ if (!tmp->ec) {
+ /* Only ECC groups are supported for SAE-PK in the current
+ * implementation. */
+ wpa_printf(MSG_INFO,
+ "SAE-PK: SAE commit did not use an ECC group");
+ return -1;
+ }
+
+ hash_len = sae_group_2_hash_len(pk->group);
+ if (sae_pk_hash_sig_data(sae, hash_len, true, wpabuf_head(pk->m),
+ wpabuf_len(pk->m), wpabuf_head(pk->pubkey),
+ wpabuf_len(pk->pubkey), hash) < 0)
+ goto fail;
+ sig = crypto_ec_key_sign(key, hash, hash_len);
+ if (!sig)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "SAE-PK: KeyAuth = Sig_AP()", sig);
+
+ /* TODO: fragmentation if any of the elements needs it for a group
+ * using sufficiently large primes (none of the currently supported
+ * ones do) */
+
+ encr_mod_len = wpabuf_len(pk->m) + AES_BLOCK_SIZE;
+ need = 4 + wpabuf_len(pk->pubkey) + 3 + wpabuf_len(sig) +
+ 6 + encr_mod_len;
+ if (wpabuf_tailroom(buf) < need) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: No room in message buffer for SAE-PK elements (%zu < %zu)",
+ wpabuf_tailroom(buf), need);
+ goto fail;
+ }
+
+ /* FILS Public Key element */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 2 + wpabuf_len(pk->pubkey));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_PUBLIC_KEY);
+ wpabuf_put_u8(buf, 2); /* Key Type: ECDSA public key */
+ wpabuf_put_buf(buf, pk->pubkey);
+
+ /* FILS Key Confirmation element (KeyAuth) */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(sig));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_KEY_CONFIRM);
+ /* KeyAuth = Sig_AP(eleAP || eleSTA || scaAP || scaSTA || M || K_AP ||
+ * AP-BSSID || STA-MAC) */
+ wpabuf_put_buf(buf, sig);
+
+ /* SAE-PK element */
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 4 + encr_mod_len);
+ wpabuf_put_be32(buf, SAE_PK_IE_VENDOR_TYPE);
+ /* EncryptedModifier = AES-SIV-Q(M); no AAD */
+ encr_mod = wpabuf_put(buf, encr_mod_len);
+ if (aes_siv_encrypt(tmp->kek, tmp->kek_len,
+ wpabuf_head(pk->m), wpabuf_len(pk->m),
+ 0, NULL, NULL, encr_mod) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
+ encr_mod, encr_mod_len);
+
+ ret = 0;
+fail:
+ wpabuf_free(sig);
+ return ret;
+
+}
+
+
+static bool sae_pk_valid_fingerprint(struct sae_data *sae,
+ const u8 *m, size_t m_len,
+ const u8 *k_ap, size_t k_ap_len, int group)
+{
+ struct sae_temporary_data *tmp = sae->tmp;
+ u8 *hash_data, *pos;
+ size_t hash_len, hash_data_len;
+ u8 hash[SAE_MAX_HASH_LEN];
+ int res;
+
+ if (!tmp->fingerprint_bytes) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: No PW available for K_AP fingerprint check");
+ return false;
+ }
+
+ /* Fingerprint = L(Hash(SSID || M || K_AP), 0, 8*Sec + 19*Lambda/4 - 5)
+ */
+
+ hash_len = sae_group_2_hash_len(group);
+ hash_data_len = tmp->ssid_len + m_len + k_ap_len;
+ hash_data = os_malloc(hash_data_len);
+ if (!hash_data)
+ return false;
+ pos = hash_data;
+ os_memcpy(pos, tmp->ssid, tmp->ssid_len);
+ pos += tmp->ssid_len;
+ os_memcpy(pos, m, m_len);
+ pos += m_len;
+ os_memcpy(pos, k_ap, k_ap_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "SAE-PK: SSID || M || K_AP",
+ hash_data, hash_data_len);
+ res = sae_hash(hash_len, hash_data, hash_data_len, hash);
+ bin_clear_free(hash_data, hash_data_len);
+ if (res < 0)
+ return false;
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Hash(SSID || M || K_AP)",
+ hash, hash_len);
+
+ if (tmp->fingerprint_bits > hash_len * 8) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: Not enough hash output bits for the fingerprint");
+ return false;
+ }
+ if (tmp->fingerprint_bits % 8) {
+ size_t extra;
+
+ /* Zero out the extra bits in the last octet */
+ extra = 8 - tmp->fingerprint_bits % 8;
+ pos = &hash[tmp->fingerprint_bits / 8];
+ *pos = (*pos >> extra) << extra;
+ }
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Fingerprint", hash,
+ tmp->fingerprint_bytes);
+ res = os_memcmp_const(hash, tmp->fingerprint, tmp->fingerprint_bytes);
+ if (res) {
+ wpa_printf(MSG_DEBUG, "SAE-PK: K_AP fingerprint mismatch");
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Expected fingerprint",
+ tmp->fingerprint, tmp->fingerprint_bytes);
+ return false;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE-PK: Valid K_AP fingerprint");
+ return true;
+}
+
+
+int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
+{
+ struct sae_temporary_data *tmp = sae->tmp;
+ const u8 *k_ap;
+ u8 m[SAE_PK_M_LEN];
+ size_t k_ap_len;
+ struct crypto_ec_key *key;
+ int res;
+ u8 hash[SAE_MAX_HASH_LEN];
+ size_t hash_len;
+ int group;
+ struct ieee802_11_elems elems;
+
+ if (!tmp)
+ return -1;
+ if (!sae->pk || tmp->ap_pk)
+ return 0;
+
+ if (tmp->kek_len != 32 && tmp->kek_len != 48 && tmp->kek_len != 64) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: No KEK available for checking confirm");
+ return -1;
+ }
+
+ if (!tmp->ec) {
+ /* Only ECC groups are supported for SAE-PK in the current
+ * implementation. */
+ wpa_printf(MSG_INFO,
+ "SAE-PK: SAE commit did not use an ECC group");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Received confirm IEs", ies, ies_len);
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_INFO, "SAE-PK: Failed to parse confirm IEs");
+ return -1;
+ }
+ if (!elems.fils_pk || !elems.fils_key_confirm || !elems.sae_pk) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: Not all mandatory IEs included in confirm");
+ return -1;
+ }
+
+ /* TODO: Fragment reassembly */
+
+ if (elems.sae_pk_len < SAE_PK_M_LEN + AES_BLOCK_SIZE) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: No room for EncryptedModifier in SAE-PK element");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
+ elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE);
+
+ if (aes_siv_decrypt(tmp->kek, tmp->kek_len,
+ elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE,
+ 0, NULL, NULL, m) < 0) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: Failed to decrypt EncryptedModifier");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "SAE-PK: Modifier M", m, SAE_PK_M_LEN);
+
+ if (elems.fils_pk[0] != 2) {
+ wpa_printf(MSG_INFO, "SAE-PK: Unsupported public key type %u",
+ elems.fils_pk[0]);
+ return -1;
+ }
+ k_ap_len = elems.fils_pk_len - 1;
+ k_ap = elems.fils_pk + 1;
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Received K_AP", k_ap, k_ap_len);
+ /* TODO: Check against the public key, if one is stored in the network
+ * profile */
+
+ key = crypto_ec_key_parse_pub(k_ap, k_ap_len);
+ if (!key) {
+ wpa_printf(MSG_INFO, "SAE-PK: Failed to parse K_AP");
+ return -1;
+ }
+
+ group = crypto_ec_key_group(key);
+ if (!sae_pk_valid_fingerprint(sae, m, SAE_PK_M_LEN, k_ap, k_ap_len,
+ group)) {
+ crypto_ec_key_deinit(key);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Received KeyAuth",
+ elems.fils_key_confirm, elems.fils_key_confirm_len);
+
+ hash_len = sae_group_2_hash_len(group);
+ if (sae_pk_hash_sig_data(sae, hash_len, false, m, SAE_PK_M_LEN,
+ k_ap, k_ap_len, hash) < 0) {
+ crypto_ec_key_deinit(key);
+ return -1;
+ }
+
+ res = crypto_ec_key_verify_signature(key, hash, hash_len,
+ elems.fils_key_confirm,
+ elems.fils_key_confirm_len);
+ crypto_ec_key_deinit(key);
+
+ if (res != 1) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: Invalid or incorrect signature in KeyAuth");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE-PK: Valid KeyAuth signature received");
+
+ /* TODO: Store validated public key into network profile */
+
+ return 0;
+}
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 1e7498a9..2b8c7f66 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -333,6 +333,7 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
* @ptk: Buffer for pairwise transient key
* @akmp: Negotiated AKM
* @cipher: Negotiated pairwise cipher
+ * @kdk_len: The length in octets that should be derived for KDK
* Returns: 0 on success, -1 on failure
*
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
@@ -348,12 +349,13 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
struct wpa_ptk *ptk, int akmp, int cipher,
- const u8 *z, size_t z_len)
+ const u8 *z, size_t z_len, size_t kdk_len)
{
#define MAX_Z_LEN 66 /* with NIST P-521 */
u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + MAX_Z_LEN];
size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN;
- u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
+ WPA_KDK_MAX_LEN];
size_t ptk_len;
#ifdef CONFIG_OWE
int owe_ptk_workaround = 0;
@@ -395,16 +397,24 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
data_len += z_len;
}
+ if (kdk_len > WPA_KDK_MAX_LEN) {
+ wpa_printf(MSG_ERROR,
+ "WPA: KDK len=%zu exceeds max supported len",
+ kdk_len);
+ return -1;
+ }
+
ptk->kck_len = wpa_kck_len(akmp, pmk_len);
ptk->kek_len = wpa_kek_len(akmp, pmk_len);
ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk->kdk_len = kdk_len;
if (ptk->tk_len == 0) {
wpa_printf(MSG_ERROR,
"WPA: Unsupported cipher (0x%x) used in PTK derivation",
cipher);
return -1;
}
- ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+ ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len + ptk->kdk_len;
if (wpa_key_mgmt_sha384(akmp)) {
#if defined(CONFIG_SUITEB192) || defined(CONFIG_FILS)
@@ -488,6 +498,12 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
+ if (kdk_len) {
+ os_memcpy(ptk->kdk, tmp + ptk->kck_len + ptk->kek_len +
+ ptk->tk_len, ptk->kdk_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KDK", ptk->kdk, ptk->kdk_len);
+ }
+
ptk->kek2_len = 0;
ptk->kck2_len = 0;
@@ -576,15 +592,16 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
const u8 *snonce, const u8 *anonce, const u8 *dhss,
size_t dhss_len, struct wpa_ptk *ptk,
u8 *ick, size_t *ick_len, int akmp, int cipher,
- u8 *fils_ft, size_t *fils_ft_len)
+ u8 *fils_ft, size_t *fils_ft_len, size_t kdk_len)
{
u8 *data, *pos;
size_t data_len;
u8 tmp[FILS_ICK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
- FILS_FT_MAX_LEN];
+ FILS_FT_MAX_LEN + WPA_KDK_MAX_LEN];
size_t key_data_len;
const char *label = "FILS PTK Derivation";
int ret = -1;
+ size_t offset;
/*
* FILS-Key-Data = PRF-X(PMK, "FILS PTK Derivation",
@@ -595,6 +612,9 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
* If doing FT initial mobility domain association:
* FILS-FT = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits,
* FILS-FT_bits)
+ * When a KDK is derived:
+ * KDK = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits + FILS-FT_bits,
+ * KDK_bits)
*/
data_len = 2 * ETH_ALEN + 2 * FILS_NONCE_LEN + dhss_len;
data = os_malloc(data_len);
@@ -623,6 +643,19 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
goto err;
key_data_len = *ick_len + ptk->kek_len + ptk->tk_len;
+ if (kdk_len) {
+ if (kdk_len > WPA_KDK_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "FILS: KDK len=%zu too big",
+ kdk_len);
+ goto err;
+ }
+
+ ptk->kdk_len = kdk_len;
+ key_data_len += kdk_len;
+ } else {
+ ptk->kdk_len = 0;
+ }
+
if (fils_ft && fils_ft_len) {
if (akmp == WPA_KEY_MGMT_FT_FILS_SHA256) {
*fils_ft_len = 32;
@@ -657,19 +690,27 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-Key-Data", tmp, key_data_len);
os_memcpy(ick, tmp, *ick_len);
+ offset = *ick_len;
wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, *ick_len);
- os_memcpy(ptk->kek, tmp + *ick_len, ptk->kek_len);
+ os_memcpy(ptk->kek, tmp + offset, ptk->kek_len);
wpa_hexdump_key(MSG_DEBUG, "FILS: KEK", ptk->kek, ptk->kek_len);
+ offset += ptk->kek_len;
- os_memcpy(ptk->tk, tmp + *ick_len + ptk->kek_len, ptk->tk_len);
+ os_memcpy(ptk->tk, tmp + offset, ptk->tk_len);
wpa_hexdump_key(MSG_DEBUG, "FILS: TK", ptk->tk, ptk->tk_len);
+ offset += ptk->tk_len;
if (fils_ft && fils_ft_len) {
- os_memcpy(fils_ft, tmp + *ick_len + ptk->kek_len + ptk->tk_len,
- *fils_ft_len);
+ os_memcpy(fils_ft, tmp + offset, *fils_ft_len);
wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-FT",
fils_ft, *fils_ft_len);
+ offset += *fils_ft_len;
+ }
+
+ if (ptk->kdk_len) {
+ os_memcpy(ptk->kdk, tmp + offset, ptk->kdk_len);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: KDK", ptk->kdk, ptk->kdk_len);
}
ptk->kek2_len = 0;
@@ -1127,6 +1168,266 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_PASN
+
+/*
+ * pasn_use_sha384 - Should SHA384 be used or SHA256
+ *
+ * @akmp: Authentication and key management protocol
+ * @cipher: The cipher suite
+ *
+ * According to IEEE P802.11az/D2.7, 12.12.7, the hash algorithm to use is the
+ * hash algorithm defined for the Base AKM (see Table 9-151 (AKM suite
+ * selectors)). When there is no Base AKM, the hash algorithm is selected based
+ * on the pairwise cipher suite provided in the RSNE by the AP in the second
+ * PASN frame. SHA-256 is used as the hash algorithm, except for the ciphers
+ * 00-0F-AC:9 and 00-0F-AC:10 for which SHA-384 is used.
+ */
+static bool pasn_use_sha384(int akmp, int cipher)
+{
+ return (akmp == WPA_KEY_MGMT_PASN && (cipher == WPA_CIPHER_CCMP_256 ||
+ cipher == WPA_CIPHER_GCMP_256)) ||
+ wpa_key_mgmt_sha384(akmp);
+}
+
+
+/**
+ * pasn_pmk_to_ptk - Calculate PASN PTK from PMK, addresses, etc.
+ * @pmk: Pairwise master key
+ * @pmk_len: Length of PMK
+ * @spa: Suppplicant address
+ * @bssid: AP BSSID
+ * @dhss: Is the shared secret (DHss) derived from the PASN ephemeral key
+ * exchange encoded as an octet string
+ * @dhss_len: The length of dhss in octets
+ * @ptk: Buffer for pairwise transient key
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * @kdk_len: the length in octets that should be derived for HTLK. Can be zero.
+ * Returns: 0 on success, -1 on failure
+ */
+int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
+ const u8 *spa, const u8 *bssid,
+ const u8 *dhss, size_t dhss_len,
+ struct wpa_ptk *ptk, int akmp, int cipher,
+ size_t kdk_len)
+{
+ u8 tmp[WPA_KCK_MAX_LEN + WPA_TK_MAX_LEN + WPA_KDK_MAX_LEN];
+ u8 *data;
+ size_t data_len, ptk_len;
+ int ret = -1;
+ const char *label = "PASN PTK Derivation";
+
+ if (!pmk || !pmk_len) {
+ wpa_printf(MSG_ERROR, "PASN: No PMK set for PTK derivation");
+ return -1;
+ }
+
+ if (!dhss || !dhss_len) {
+ wpa_printf(MSG_ERROR, "PASN: No DHss set for PTK derivation");
+ return -1;
+ }
+
+ /*
+ * PASN-PTK = KDF(PMK, “PASN PTK Derivation”, SPA || BSSID || DHss)
+ *
+ * KCK = L(PASN-PTK, 0, 256)
+ * TK = L(PASN-PTK, 256, TK_bits)
+ * KDK = L(PASN-PTK, 256 + TK_bits, kdk_len * 8)
+ */
+ data_len = 2 * ETH_ALEN + dhss_len;
+ data = os_zalloc(data_len);
+ if (!data)
+ return -1;
+
+ os_memcpy(data, spa, ETH_ALEN);
+ os_memcpy(data + ETH_ALEN, bssid, ETH_ALEN);
+ os_memcpy(data + 2 * ETH_ALEN, dhss, dhss_len);
+
+ ptk->kck_len = WPA_PASN_KCK_LEN;
+ ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk->kdk_len = kdk_len;
+ ptk->kek_len = 0;
+ ptk->kek2_len = 0;
+ ptk->kck2_len = 0;
+
+ if (ptk->tk_len == 0) {
+ wpa_printf(MSG_ERROR,
+ "PASN: Unsupported cipher (0x%x) used in PTK derivation",
+ cipher);
+ goto err;
+ }
+
+ ptk_len = ptk->kck_len + ptk->tk_len + ptk->kdk_len;
+ if (ptk_len > sizeof(tmp))
+ goto err;
+
+ if (pasn_use_sha384(akmp, cipher)) {
+ wpa_printf(MSG_DEBUG, "PASN: PTK derivation using SHA384");
+
+ if (sha384_prf(pmk, pmk_len, label, data, data_len, tmp,
+ ptk_len) < 0)
+ goto err;
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: PTK derivation using SHA256");
+
+ if (sha256_prf(pmk, pmk_len, label, data, data_len, tmp,
+ ptk_len) < 0)
+ goto err;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: PTK derivation: SPA=" MACSTR " BSSID=" MACSTR,
+ MAC2STR(spa), MAC2STR(bssid));
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: DHss", dhss, dhss_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: PMK", pmk, pmk_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: PASN-PTK", tmp, ptk_len);
+
+ os_memcpy(ptk->kck, tmp, WPA_PASN_KCK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: KCK:", ptk->kck, WPA_PASN_KCK_LEN);
+
+ os_memcpy(ptk->tk, tmp + WPA_PASN_KCK_LEN, ptk->tk_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: TK:", ptk->tk, ptk->tk_len);
+
+ if (kdk_len) {
+ os_memcpy(ptk->kdk, tmp + WPA_PASN_KCK_LEN + ptk->tk_len,
+ ptk->kdk_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: KDK:",
+ ptk->kdk, ptk->kdk_len);
+ }
+
+ forced_memzero(tmp, sizeof(tmp));
+ ret = 0;
+err:
+ bin_clear_free(data, data_len);
+ return ret;
+}
+
+
+/*
+ * pasn_mic_len - Returns the MIC length for PASN authentication
+ */
+u8 pasn_mic_len(int akmp, int cipher)
+{
+ if (pasn_use_sha384(akmp, cipher))
+ return 24;
+
+ return 16;
+}
+
+
+/**
+ * pasn_mic - Calculate PASN MIC
+ * @kck: The key confirmation key for the PASN PTKSA
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * @addr1: For the 2nd PASN frame supplicant address; for the 3rd frame the
+ * BSSID
+ * @addr2: For the 2nd PASN frame the BSSID; for the 3rd frame the supplicant
+ * address
+ * @data: For calculating the MIC for the 2nd PASN frame, this should hold the
+ * Beacon frame RSNE + RSNXE. For calculating the MIC for the 3rd PASN
+ * frame, this should hold the hash of the body of the PASN 1st frame.
+ * @data_len: The length of data
+ * @frame: The body of the PASN frame including the MIC element with the octets
+ * in the MIC field of the MIC element set to 0.
+ * @frame_len: The length of frame
+ * @mic: Buffer to hold the MIC on success. Should be big enough to handle the
+ * maximal MIC length
+ * Returns: 0 on success, -1 on failure
+ */
+int pasn_mic(const u8 *kck, int akmp, int cipher,
+ const u8 *addr1, const u8 *addr2,
+ const u8 *data, size_t data_len,
+ const u8 *frame, size_t frame_len, u8 *mic)
+{
+ u8 *buf;
+ u8 hash[SHA384_MAC_LEN];
+ size_t buf_len = 2 * ETH_ALEN + data_len + frame_len;
+ int ret = -1;
+
+ if (!kck) {
+ wpa_printf(MSG_ERROR, "PASN: No KCK for MIC calculation");
+ return -1;
+ }
+
+ if (!data || !data_len) {
+ wpa_printf(MSG_ERROR, "PASN: invalid data for MIC calculation");
+ return -1;
+ }
+
+ if (!frame || !frame_len) {
+ wpa_printf(MSG_ERROR, "PASN: invalid data for MIC calculation");
+ return -1;
+ }
+
+ buf = os_zalloc(buf_len);
+ if (!buf)
+ return -1;
+
+ os_memcpy(buf, addr1, ETH_ALEN);
+ os_memcpy(buf + ETH_ALEN, addr2, ETH_ALEN);
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: data", data, data_len);
+ os_memcpy(buf + 2 * ETH_ALEN, data, data_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: frame", frame, frame_len);
+ os_memcpy(buf + 2 * ETH_ALEN + data_len, frame, frame_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: KCK", kck, WPA_PASN_KCK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: buf", buf, buf_len);
+
+ if (pasn_use_sha384(akmp, cipher)) {
+ wpa_printf(MSG_DEBUG, "PASN: MIC using HMAC-SHA384");
+
+ if (hmac_sha384(kck, WPA_PASN_KCK_LEN, buf, buf_len, hash))
+ goto err;
+
+ os_memcpy(mic, hash, 24);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: mic: ", mic, 24);
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: MIC using HMAC-SHA256");
+
+ if (hmac_sha256(kck, WPA_PASN_KCK_LEN, buf, buf_len, hash))
+ goto err;
+
+ os_memcpy(mic, hash, 16);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: mic: ", mic, 16);
+ }
+
+ ret = 0;
+err:
+ bin_clear_free(buf, buf_len);
+ return ret;
+}
+
+
+/**
+ * pasn_auth_frame_hash - Computes a hash of an Authentication frame body
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * @data: Pointer to the Authentication frame body
+ * @len: Length of the Authentication frame body
+ * @hash: On return would hold the computed hash. Should be big enough to handle
+ * SHA384.
+ * Returns: 0 on success, -1 on failure
+ */
+int pasn_auth_frame_hash(int akmp, int cipher, const u8 *data, size_t len,
+ u8 *hash)
+{
+ if (pasn_use_sha384(akmp, cipher)) {
+ wpa_printf(MSG_DEBUG, "PASN: Frame hash using SHA-384");
+ return sha384_vector(1, &data, &len, hash);
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: Frame hash using SHA-256");
+ return sha256_vector(1, &data, &len, hash);
+ }
+}
+
+#endif /* CONFIG_PASN */
+
+
static int rsn_selector_to_bitfield(const u8 *s)
{
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
@@ -1203,6 +1504,10 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
#endif /* CONFIG_DPP */
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN)
return WPA_KEY_MGMT_OSEN;
+#ifdef CONFIG_PASN
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PASN)
+ return WPA_KEY_MGMT_PASN;
+#endif /* CONFIG_PASN */
return 0;
}
@@ -1216,7 +1521,8 @@ int wpa_cipher_valid_group(int cipher)
int wpa_cipher_valid_mgmt_group(int cipher)
{
- return cipher == WPA_CIPHER_AES_128_CMAC ||
+ return cipher == WPA_CIPHER_GTK_NOT_USED ||
+ cipher == WPA_CIPHER_AES_128_CMAC ||
cipher == WPA_CIPHER_BIP_GMAC_128 ||
cipher == WPA_CIPHER_BIP_GMAC_256 ||
cipher == WPA_CIPHER_BIP_CMAC_256;
@@ -1633,7 +1939,8 @@ int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
if (!use_sha384 && sha256_vector(2, addr, len, hash) < 0)
return -1;
os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
- os_memset(r0_key_data, 0, sizeof(r0_key_data));
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
+ forced_memzero(r0_key_data, sizeof(r0_key_data));
return 0;
}
@@ -1670,6 +1977,7 @@ int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
if (!use_sha384 && sha256_vector(4, addr, len, hash) < 0)
return -1;
os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
return 0;
}
@@ -1731,16 +2039,25 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
const u8 *snonce, const u8 *anonce,
const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
- struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
+ struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher,
+ size_t kdk_len)
{
u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
u8 *pos, hash[32];
const u8 *addr[6];
size_t len[6];
- u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
+ WPA_KDK_MAX_LEN];
size_t ptk_len, offset;
int use_sha384 = wpa_key_mgmt_sha384(akmp);
+ if (kdk_len > WPA_KDK_MAX_LEN) {
+ wpa_printf(MSG_ERROR,
+ "FT: KDK len=%zu exceeds max supported len",
+ kdk_len);
+ return -1;
+ }
+
/*
* PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
* BSSID || STA-ADDR)
@@ -1767,8 +2084,9 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
ptk->kek_len = wpa_kek_len(akmp, PMK_LEN);
ptk->kek2_len = wpa_kek2_len(akmp);
ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk->kdk_len = kdk_len;
ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len +
- ptk->kck2_len + ptk->kek2_len;
+ ptk->kck2_len + ptk->kek2_len + ptk->kdk_len;
#ifdef CONFIG_SHA384
if (use_sha384) {
@@ -1827,6 +2145,8 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
os_memcpy(ptk->kck2, tmp + offset, ptk->kck2_len);
offset += ptk->kck2_len;
os_memcpy(ptk->kek2, tmp + offset, ptk->kek2_len);
+ offset += ptk->kek2_len;
+ os_memcpy(ptk->kdk, tmp + offset, ptk->kdk_len);
wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
@@ -1836,10 +2156,13 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
if (ptk->kek2_len)
wpa_hexdump_key(MSG_DEBUG, "FT: KEK2",
ptk->kek2, ptk->kek2_len);
+ if (ptk->kdk_len)
+ wpa_hexdump_key(MSG_DEBUG, "FT: KDK", ptk->kdk, ptk->kdk_len);
+
wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
- os_memset(tmp, 0, sizeof(tmp));
+ forced_memzero(tmp, sizeof(tmp));
return 0;
}
@@ -2069,6 +2392,8 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
return "OWE";
case WPA_KEY_MGMT_DPP:
return "DPP";
+ case WPA_KEY_MGMT_PASN:
+ return "PASN";
default:
return "UNKNOWN";
}
@@ -2940,3 +3265,451 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
return ret;
}
+
+
+#ifdef CONFIG_PASN
+
+/*
+ * wpa_pasn_build_auth_header - Add the MAC header and initialize Authentication
+ * frame for PASN
+ *
+ * @buf: Buffer in which the header will be added
+ * @bssid: The BSSID of the AP
+ * @src: Source address
+ * @dst: Destination address
+ * @trans_seq: Authentication transaction sequence number
+ * @status: Authentication status
+ */
+void wpa_pasn_build_auth_header(struct wpabuf *buf, const u8 *bssid,
+ const u8 *src, const u8 *dst,
+ u8 trans_seq, u16 status)
+{
+ struct ieee80211_mgmt *auth;
+
+ wpa_printf(MSG_DEBUG, "PASN: Add authentication header. trans_seq=%u",
+ trans_seq);
+
+ auth = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
+ u.auth.variable));
+
+ auth->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_AUTH << 4));
+
+ os_memcpy(auth->da, dst, ETH_ALEN);
+ os_memcpy(auth->sa, src, ETH_ALEN);
+ os_memcpy(auth->bssid, bssid, ETH_ALEN);
+ auth->seq_ctrl = 0;
+
+ auth->u.auth.auth_alg = host_to_le16(WLAN_AUTH_PASN);
+ auth->u.auth.auth_transaction = host_to_le16(trans_seq);
+ auth->u.auth.status_code = host_to_le16(status);
+}
+
+
+/*
+ * wpa_pasn_add_rsne - Add an RSNE for PASN authentication
+ * @buf: Buffer in which the IE will be added
+ * @pmkid: Optional PMKID. Can be NULL.
+ * @akmp: Authentication and key management protocol
+ * @cipher: The cipher suite
+ */
+int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher)
+{
+ struct rsn_ie_hdr *hdr;
+ u32 suite;
+ u16 capab;
+ u8 *pos;
+ u8 rsne_len;
+
+ wpa_printf(MSG_DEBUG, "PASN: Add RSNE");
+
+ rsne_len = sizeof(*hdr) + RSN_SELECTOR_LEN +
+ 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN +
+ 2 + RSN_SELECTOR_LEN + 2 + (pmkid ? PMKID_LEN : 0);
+
+ if (wpabuf_tailroom(buf) < rsne_len)
+ return -1;
+ hdr = wpabuf_put(buf, rsne_len);
+ hdr->elem_id = WLAN_EID_RSN;
+ hdr->len = rsne_len - 2;
+ WPA_PUT_LE16(hdr->version, RSN_VERSION);
+ pos = (u8 *) (hdr + 1);
+
+ /* Group addressed data is not allowed */
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+ pos += RSN_SELECTOR_LEN;
+
+ /* Add the pairwise cipher */
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, cipher);
+ RSN_SELECTOR_PUT(pos, suite);
+ pos += RSN_SELECTOR_LEN;
+
+ /* Add the AKM suite */
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+
+ switch (akmp) {
+ case WPA_KEY_MGMT_PASN:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PASN);
+ break;
+#ifdef CONFIG_SAE
+ case WPA_KEY_MGMT_SAE:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+ break;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ case WPA_KEY_MGMT_FILS_SHA256:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
+ break;
+ case WPA_KEY_MGMT_FILS_SHA384:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
+ break;
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ case WPA_KEY_MGMT_FT_PSK:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
+ break;
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+ break;
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
+ break;
+#endif /* CONFIG_IEEE80211R */
+ default:
+ wpa_printf(MSG_ERROR, "PASN: Invalid AKMP=0x%x", akmp);
+ return -1;
+ }
+ pos += RSN_SELECTOR_LEN;
+
+ /* RSN Capabilities: PASN mandates both MFP capable and required */
+ capab = WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR;
+ WPA_PUT_LE16(pos, capab);
+ pos += 2;
+
+ if (pmkid) {
+ wpa_printf(MSG_DEBUG, "PASN: Adding PMKID");
+
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ os_memcpy(pos, pmkid, PMKID_LEN);
+ pos += PMKID_LEN;
+ } else {
+ WPA_PUT_LE16(pos, 0);
+ pos += 2;
+ }
+
+ /* Group addressed management is not allowed */
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+
+ return 0;
+}
+
+
+/*
+ * wpa_pasn_add_parameter_ie - Add PASN Parameters IE for PASN authentication
+ * @buf: Buffer in which the IE will be added
+ * @pasn_group: Finite Cyclic Group ID for PASN authentication
+ * @wrapped_data_format: Format of the data in the Wrapped Data IE
+ * @pubkey: A buffer holding the local public key. Can be NULL
+ * @comeback: A buffer holding the comeback token. Can be NULL
+ * @after: If comeback is set, defined the comeback time in seconds. -1 to not
+ * include the Comeback After field (frames from non-AP STA).
+ */
+void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
+ u8 wrapped_data_format,
+ struct wpabuf *pubkey,
+ struct wpabuf *comeback, int after)
+{
+ struct pasn_parameter_ie *params;
+
+ wpa_printf(MSG_DEBUG, "PASN: Add PASN Parameters element");
+
+ params = wpabuf_put(buf, sizeof(*params));
+
+ params->id = WLAN_EID_EXTENSION;
+ params->len = sizeof(*params) - 2;
+ params->id_ext = WLAN_EID_EXT_PASN_PARAMS;
+ params->control = 0;
+ params->wrapped_data_format = wrapped_data_format;
+
+ if (comeback) {
+ wpa_printf(MSG_DEBUG, "PASN: Adding comeback data");
+
+ /*
+ * 2 octets for the 'after' field + 1 octet for the length +
+ * actual cookie data
+ */
+ if (after >= 0)
+ params->len += 2;
+ params->len += 1 + wpabuf_len(comeback);
+ params->control |= WPA_PASN_CTRL_COMEBACK_INFO_PRESENT;
+
+ if (after >= 0)
+ wpabuf_put_le16(buf, after);
+ wpabuf_put_u8(buf, wpabuf_len(comeback));
+ wpabuf_put_buf(buf, comeback);
+ }
+
+ if (pubkey) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Adding public key and group ID %u",
+ pasn_group);
+
+ /*
+ * 2 octets for the finite cyclic group + 2 octets public key
+ * length + the actual key
+ */
+ params->len += 2 + 1 + wpabuf_len(pubkey);
+ params->control |= WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT;
+
+ wpabuf_put_le16(buf, pasn_group);
+ wpabuf_put_u8(buf, wpabuf_len(pubkey));
+ wpabuf_put_buf(buf, pubkey);
+ }
+}
+
+/*
+ * wpa_pasn_add_wrapped_data - Add a Wrapped Data IE to PASN Authentication
+ * frame. If needed, the Wrapped Data IE would be fragmented.
+ *
+ * @buf: Buffer in which the IE will be added
+ * @wrapped_data_buf: Buffer holding the wrapped data
+ */
+int wpa_pasn_add_wrapped_data(struct wpabuf *buf,
+ struct wpabuf *wrapped_data_buf)
+{
+ const u8 *data;
+ size_t data_len;
+ u8 len;
+
+ if (!wrapped_data_buf)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "PASN: Add wrapped data");
+
+ data = wpabuf_head_u8(wrapped_data_buf);
+ data_len = wpabuf_len(wrapped_data_buf);
+
+ /* nothing to add */
+ if (!data_len)
+ return 0;
+
+ if (data_len <= 254)
+ len = 1 + data_len;
+ else
+ len = 255;
+
+ if (wpabuf_tailroom(buf) < 3 + data_len)
+ return -1;
+
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, len);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
+ wpabuf_put_data(buf, data, len - 1);
+
+ data += len - 1;
+ data_len -= len - 1;
+
+ while (data_len) {
+ if (wpabuf_tailroom(buf) < 1 + data_len)
+ return -1;
+ wpabuf_put_u8(buf, WLAN_EID_FRAGMENT);
+ len = data_len > 255 ? 255 : data_len;
+ wpabuf_put_u8(buf, len);
+ wpabuf_put_data(buf, data, len);
+ data += len;
+ data_len -= len;
+ }
+
+ return 0;
+}
+
+
+/*
+ * wpa_pasn_validate_rsne - Validate PSAN specific data of RSNE
+ * @data: Parsed representation of an RSNE
+ * Returns -1 for invalid data; otherwise 0
+ */
+int wpa_pasn_validate_rsne(const struct wpa_ie_data *data)
+{
+ u16 capab = WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR;
+
+ if (data->proto != WPA_PROTO_RSN)
+ return -1;
+
+ if ((data->capabilities & capab) != capab) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid RSNE capabilities");
+ return -1;
+ }
+
+ if (!data->has_group || data->group_cipher != WPA_CIPHER_GTK_NOT_USED) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid group data cipher");
+ return -1;
+ }
+
+ if (!data->has_pairwise || !data->pairwise_cipher ||
+ (data->pairwise_cipher & (data->pairwise_cipher - 1))) {
+ wpa_printf(MSG_DEBUG, "PASN: No valid pairwise suite");
+ return -1;
+ }
+
+ switch (data->key_mgmt) {
+#ifdef CONFIG_SAE
+ case WPA_KEY_MGMT_SAE:
+ /* fall through */
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+ /* fall through */
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ case WPA_KEY_MGMT_FT_PSK:
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ /* fall through */
+#endif /* CONFIG_IEEE80211R */
+ case WPA_KEY_MGMT_PASN:
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "PASN: invalid key_mgmt: 0x%0x",
+ data->key_mgmt);
+ return -1;
+ }
+
+ if (data->mgmt_group_cipher != WPA_CIPHER_GTK_NOT_USED) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid group mgmt cipher");
+ return -1;
+ }
+
+ if (data->num_pmkid > 1) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid number of PMKIDs");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * wpa_pasn_parse_parameter_ie - Validates PASN Parameters IE
+ * @data: Pointer to the PASN Parameters IE (starting with the EID).
+ * @len: Length of the data in the PASN Parameters IE
+ * @from_ap: Whether this was received from an AP
+ * @pasn_params: On successful return would hold the parsed PASN parameters.
+ * Returns: -1 for invalid data; otherwise 0
+ *
+ * Note: On successful return, the pointers in &pasn_params point to the data in
+ * the IE and are not locally allocated (so they should not be freed etc.).
+ */
+int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len, bool from_ap,
+ struct wpa_pasn_params_data *pasn_params)
+{
+ struct pasn_parameter_ie *params = (struct pasn_parameter_ie *) data;
+ const u8 *pos = (const u8 *) (params + 1);
+
+ if (!pasn_params) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid params");
+ return -1;
+ }
+
+ if (!params || ((size_t) (params->len + 2) < sizeof(*params)) ||
+ len < sizeof(*params) || params->len + 2 != len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid parameters IE. len=(%u, %u)",
+ params ? params->len : 0, len);
+ return -1;
+ }
+
+ os_memset(pasn_params, 0, sizeof(*pasn_params));
+
+ switch (params->wrapped_data_format) {
+ case WPA_PASN_WRAPPED_DATA_NO:
+ case WPA_PASN_WRAPPED_DATA_SAE:
+ case WPA_PASN_WRAPPED_DATA_FILS_SK:
+ case WPA_PASN_WRAPPED_DATA_FT:
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "PASN: Invalid wrapped data format");
+ return -1;
+ }
+
+ pasn_params->wrapped_data_format = params->wrapped_data_format;
+
+ len -= sizeof(*params);
+
+ if (params->control & WPA_PASN_CTRL_COMEBACK_INFO_PRESENT) {
+ if (from_ap) {
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid Parameters IE: Truncated Comeback After");
+ return -1;
+ }
+ pasn_params->after = WPA_GET_LE16(pos);
+ pos += 2;
+ len -= 2;
+ }
+
+ if (len < 1 || len < 1 + *pos) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid Parameters IE: comeback len");
+ return -1;
+ }
+
+ pasn_params->comeback_len = *pos++;
+ len--;
+ pasn_params->comeback = pos;
+ len -= pasn_params->comeback_len;
+ pos += pasn_params->comeback_len;
+ }
+
+ if (params->control & WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT) {
+ if (len < 3 || len < 3 + pos[2]) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid Parameters IE: group and key");
+ return -1;
+ }
+
+ pasn_params->group = WPA_GET_LE16(pos);
+ pos += 2;
+ len -= 2;
+ pasn_params->pubkey_len = *pos++;
+ len--;
+ pasn_params->pubkey = pos;
+ len -= pasn_params->pubkey_len;
+ pos += pasn_params->pubkey_len;
+ }
+
+ if (len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid Parameters IE. Bytes left=%u", len);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab)
+{
+ size_t flen;
+
+ flen = (capab & 0xff00) ? 2 : 1;
+ if (!capab)
+ return; /* no supported extended RSN capabilities */
+ if (wpabuf_tailroom(buf) < 2 + flen)
+ return;
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
+
+ wpabuf_put_u8(buf, WLAN_EID_RSNX);
+ wpabuf_put_u8(buf, flen);
+ wpabuf_put_u8(buf, capab & 0x00ff);
+ capab >>= 8;
+ if (capab)
+ wpabuf_put_u8(buf, capab);
+}
+
+#endif /* CONFIG_PASN */
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 065dc711..c31e1a0f 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -19,6 +19,9 @@
#define WPA_KEY_RSC_LEN 8
#define WPA_GMK_LEN 32
#define WPA_GTK_MAX_LEN 32
+#define WPA_PASN_PMK_LEN 32
+#define WPA_PASN_MAX_MIC_LEN 24
+#define WPA_MAX_RSNXE_LEN 4
#define OWE_DH_GROUP 19
@@ -78,6 +81,9 @@ WPA_CIPHER_BIP_CMAC_256)
#define RSN_AUTH_KEY_MGMT_FT_FILS_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 16)
#define RSN_AUTH_KEY_MGMT_FT_FILS_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 17)
#define RSN_AUTH_KEY_MGMT_OWE RSN_SELECTOR(0x00, 0x0f, 0xac, 18)
+
+#define RSN_AUTH_KEY_MGMT_PASN RSN_SELECTOR(0x00, 0x0f, 0xac, 21)
+
#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
#define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01)
#define RSN_AUTH_KEY_MGMT_DPP RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x02)
@@ -211,8 +217,11 @@ struct wpa_eapol_key {
#define WPA_KCK_MAX_LEN 32
#define WPA_KEK_MAX_LEN 64
#define WPA_TK_MAX_LEN 32
+#define WPA_KDK_MAX_LEN 32
#define FILS_ICK_MAX_LEN 48
#define FILS_FT_MAX_LEN 48
+#define WPA_PASN_KCK_LEN 32
+#define WPA_PASN_MIC_MAX_LEN 24
/**
* struct wpa_ptk - WPA Pairwise Transient Key
@@ -224,11 +233,13 @@ struct wpa_ptk {
u8 tk[WPA_TK_MAX_LEN]; /* Temporal Key (TK) */
u8 kck2[WPA_KCK_MAX_LEN]; /* FT reasoc Key Confirmation Key (KCK2) */
u8 kek2[WPA_KEK_MAX_LEN]; /* FT reassoc Key Encryption Key (KEK2) */
+ u8 kdk[WPA_KDK_MAX_LEN]; /* Key Derivation Key */
size_t kck_len;
size_t kek_len;
size_t tk_len;
size_t kck2_len;
size_t kek2_len;
+ size_t kdk_len;
int installed; /* 1 if key has already been installed to driver */
};
@@ -378,7 +389,7 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
struct wpa_ptk *ptk, int akmp, int cipher,
- const u8 *z, size_t z_len);
+ const u8 *z, size_t z_len, size_t kdk_len);
int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
size_t dh_ss_len, u8 *pmk, size_t *pmk_len);
@@ -388,7 +399,7 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
const u8 *snonce, const u8 *anonce, const u8 *dhss,
size_t dhss_len, struct wpa_ptk *ptk,
u8 *ick, size_t *ick_len, int akmp, int cipher,
- u8 *fils_ft, size_t *fils_ft_len);
+ u8 *fils_ft, size_t *fils_ft_len, size_t kdk_len);
int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
const u8 *g_sta, size_t g_sta_len,
@@ -419,7 +430,8 @@ int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len,
int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len, const u8 *snonce,
const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
- struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher);
+ struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher,
+ size_t kdk_len);
#endif /* CONFIG_IEEE80211R */
struct wpa_ie_data {
@@ -507,6 +519,33 @@ struct wpa_ft_ies {
size_t rsnxe_len;
};
+/* IEEE P802.11az/D2.6 - 9.4.2.303 PASN Parameters element */
+#define WPA_PASN_CTRL_COMEBACK_INFO_PRESENT BIT(0)
+#define WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT BIT(1)
+
+#define WPA_PASN_WRAPPED_DATA_NO 0
+#define WPA_PASN_WRAPPED_DATA_FT 1
+#define WPA_PASN_WRAPPED_DATA_FILS_SK 2
+#define WPA_PASN_WRAPPED_DATA_SAE 3
+
+struct pasn_parameter_ie {
+ u8 id;
+ u8 len;
+ u8 id_ext;
+ u8 control; /* WPA_PASN_CTRL_* */
+ u8 wrapped_data_format; /* WPA_PASN_WRAPPED_DATA_* */
+} STRUCT_PACKED;
+
+struct wpa_pasn_params_data {
+ u8 wrapped_data_format;
+ u16 after;
+ u8 comeback_len;
+ const u8 *comeback;
+ u16 group;
+ u8 pubkey_len;
+ const u8 *pubkey;
+};
+
int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
int use_sha384);
@@ -591,4 +630,41 @@ int wpa_use_cmac(int akmp);
int wpa_use_aes_key_wrap(int akmp);
int fils_domain_name_hash(const char *domain, u8 *hash);
+int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
+ const u8 *spa, const u8 *bssid,
+ const u8 *dhss, size_t dhss_len,
+ struct wpa_ptk *ptk, int akmp, int cipher,
+ size_t kdk_len);
+
+u8 pasn_mic_len(int akmp, int cipher);
+
+int pasn_mic(const u8 *kck, int akmp, int cipher,
+ const u8 *addr1, const u8 *addr2,
+ const u8 *data, size_t data_len,
+ const u8 *frame, size_t frame_len, u8 *mic);
+
+int pasn_auth_frame_hash(int akmp, int cipher, const u8 *data, size_t len,
+ u8 *hash);
+
+void wpa_pasn_build_auth_header(struct wpabuf *buf, const u8 *bssid,
+ const u8 *src, const u8 *dst,
+ u8 trans_seq, u16 status);
+
+int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid,
+ int akmp, int cipher);
+
+void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
+ u8 wrapped_data_format,
+ struct wpabuf *pubkey,
+ struct wpabuf *comeback, int after);
+
+int wpa_pasn_add_wrapped_data(struct wpabuf *buf,
+ struct wpabuf *wrapped_data_buf);
+
+int wpa_pasn_validate_rsne(const struct wpa_ie_data *data);
+int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len, bool from_ap,
+ struct wpa_pasn_params_data *pasn_params);
+
+void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab);
+
#endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 354de285..126a7892 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -97,6 +97,10 @@ extern "C" {
"CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER "
/** Unprotected Beacon frame dropped */
#define WPA_EVENT_UNPROT_BEACON "CTRL-EVENT-UNPROT-BEACON "
+/** Decision made to do a within-ESS roam */
+#define WPA_EVENT_DO_ROAM "CTRL-EVENT-DO-ROAM "
+/** Decision made to skip a within-ESS roam */
+#define WPA_EVENT_SKIP_ROAM "CTRL-EVENT-SKIP-ROAM "
/** IP subnet status change notification
*
@@ -122,6 +126,8 @@ extern "C" {
#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
/** Frequency ranges that the driver recommends to avoid */
#define WPA_EVENT_AVOID_FREQ "CTRL-EVENT-AVOID-FREQ "
+/** Result of MSCS setup */
+#define WPA_EVENT_MSCS_RESULT "CTRL-EVENT-MSCS-RESULT "
/** WPS overlap detected in PBC mode */
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
/** Available WPS AP with active PBC found in scan results */
@@ -178,7 +184,11 @@ extern "C" {
#define DPP_EVENT_CONFOBJ_PSK "DPP-CONFOBJ-PSK "
#define DPP_EVENT_CONNECTOR "DPP-CONNECTOR "
#define DPP_EVENT_C_SIGN_KEY "DPP-C-SIGN-KEY "
+#define DPP_EVENT_PP_KEY "DPP-PP-KEY "
#define DPP_EVENT_NET_ACCESS_KEY "DPP-NET-ACCESS-KEY "
+#define DPP_EVENT_SERVER_NAME "DPP-SERVER-NAME "
+#define DPP_EVENT_CERTBAG "DPP-CERTBAG "
+#define DPP_EVENT_CACERT "DPP-CACERT "
#define DPP_EVENT_MISSING_CONNECTOR "DPP-MISSING-CONNECTOR "
#define DPP_EVENT_NETWORK_ID "DPP-NETWORK-ID "
#define DPP_EVENT_CONFIGURATOR_ID "DPP-CONFIGURATOR-ID "
@@ -192,6 +202,8 @@ extern "C" {
#define DPP_EVENT_CHIRP_STOPPED "DPP-CHIRP-STOPPED "
#define DPP_EVENT_MUD_URL "DPP-MUD-URL "
#define DPP_EVENT_BAND_SUPPORT "DPP-BAND-SUPPORT "
+#define DPP_EVENT_CSR "DPP-CSR "
+#define DPP_EVENT_CHIRP_RX "DPP-CHIRP-RX "
/* MESH events */
#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
@@ -259,7 +271,7 @@ extern "C" {
#define P2P_EVENT_P2PS_PROVISION_DONE "P2PS-PROV-DONE "
#define INTERWORKING_AP "INTERWORKING-AP "
-#define INTERWORKING_BLACKLISTED "INTERWORKING-BLACKLISTED "
+#define INTERWORKING_EXCLUDED "INTERWORKING-BLACKLISTED "
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
#define INTERWORKING_ALREADY_CONNECTED "INTERWORKING-ALREADY-CONNECTED "
#define INTERWORKING_SELECTED "INTERWORKING-SELECTED "
@@ -388,10 +400,20 @@ extern "C" {
/* Transition mode disabled indication - followed by bitmap */
#define TRANSITION_DISABLE "TRANSITION-DISABLE "
+/* OCV validation failure; parameters: addr=<src addr>
+ * frame=<saqueryreq/saqueryresp> error=<error string> */
+#define OCV_FAILURE "OCV-FAILURE "
+
+/* Event triggered for received management frame */
+#define AP_MGMT_FRAME_RECEIVED "AP-MGMT-FRAME-RECEIVED "
+
#ifndef BIT
#define BIT(x) (1U << (x))
#endif
+/* PASN authentication status */
+#define PASN_AUTH_STATUS "PASN-AUTH-STATUS "
+
/* BSS command information masks */
#define WPA_BSS_MASK_ALL 0xFFFDFFFF
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index c40e9556..ce099709 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -1,14 +1,3 @@
-all: libcrypto.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libcrypto.a
-
-install:
- @echo Nothing to be made.
-
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_CRYPTO_INTERNAL
CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
@@ -68,8 +57,4 @@ ifndef TEST_FUZZ
LIB_OBJS += random.o
endif
-
-libcrypto.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index de2b0773..7d2ebd61 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -918,4 +918,16 @@ struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
void crypto_ecdh_deinit(struct crypto_ecdh *ecdh);
size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh);
+struct crypto_ec_key;
+
+struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len);
+struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len);
+void crypto_ec_key_deinit(struct crypto_ec_key *key);
+struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key);
+struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
+ size_t len);
+int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
+ size_t len, const u8 *sig, size_t sig_len);
+int crypto_ec_key_group(struct crypto_ec_key *key);
+
#endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_module_tests.c b/src/crypto/crypto_module_tests.c
index 1cc73d8e..fafb688b 100644
--- a/src/crypto/crypto_module_tests.c
+++ b/src/crypto/crypto_module_tests.c
@@ -744,6 +744,155 @@ static int test_key_wrap(void)
}
+static int test_aes_ctr(void)
+{
+ int res = 0;
+
+#if defined(CONFIG_MESH) || defined(CONFIG_PSK)
+ /* CTR-AES*.Encrypt test vectors from NIST SP 800-38a */
+ const u8 key128[] = {
+ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+ };
+ const u8 counter128[] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ const u8 plain128[] = {
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+ };
+ const u8 cipher128[] = {
+ 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
+ 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
+ 0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff,
+ 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
+ 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e,
+ 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
+ 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1,
+ 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee
+ };
+ const u8 key192[] = {
+ 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52,
+ 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+ 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b
+ };
+ const u8 counter192[] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ const u8 plain192[] = {
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+ };
+ const u8 cipher192[] = {
+ 0x1a, 0xbc, 0x93, 0x24, 0x17, 0x52, 0x1c, 0xa2,
+ 0x4f, 0x2b, 0x04, 0x59, 0xfe, 0x7e, 0x6e, 0x0b,
+ 0x09, 0x03, 0x39, 0xec, 0x0a, 0xa6, 0xfa, 0xef,
+ 0xd5, 0xcc, 0xc2, 0xc6, 0xf4, 0xce, 0x8e, 0x94,
+ 0x1e, 0x36, 0xb2, 0x6b, 0xd1, 0xeb, 0xc6, 0x70,
+ 0xd1, 0xbd, 0x1d, 0x66, 0x56, 0x20, 0xab, 0xf7,
+ 0x4f, 0x78, 0xa7, 0xf6, 0xd2, 0x98, 0x09, 0x58,
+ 0x5a, 0x97, 0xda, 0xec, 0x58, 0xc6, 0xb0, 0x50
+ };
+ const u8 key256[] = {
+ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
+ 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+ 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
+ 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4
+ };
+ const u8 counter256[] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ const u8 plain256[] = {
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+ };
+ const u8 cipher256[] = {
+ 0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5,
+ 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28,
+ 0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a,
+ 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5,
+ 0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c,
+ 0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d,
+ 0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6,
+ 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6
+ };
+ size_t len;
+ u8 *tmp;
+
+ wpa_printf(MSG_DEBUG, "CTR-AES128.Encrypt");
+ len = sizeof(plain128);
+ tmp = os_malloc(len);
+ if (!tmp)
+ return -1;
+ os_memcpy(tmp, plain128, len);
+ if (aes_ctr_encrypt(key128, sizeof(key128), counter128, tmp, len) < 0) {
+ wpa_printf(MSG_ERROR, "aes_ctr_encrypt() failed");
+ res = -1;
+ } else if (os_memcmp(tmp, cipher128, len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "CTR-AES128.Encrypt test vector did not match");
+ res = -1;
+ }
+ os_free(tmp);
+
+ wpa_printf(MSG_DEBUG, "CTR-AES192.Encrypt");
+ len = sizeof(plain192);
+ tmp = os_malloc(len);
+ if (!tmp)
+ return -1;
+ os_memcpy(tmp, plain192, len);
+ if (aes_ctr_encrypt(key192, sizeof(key192), counter192, tmp, len) < 0) {
+ wpa_printf(MSG_ERROR, "aes_ctr_encrypt() failed");
+ res = -1;
+ } else if (os_memcmp(tmp, cipher192, len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "CTR-AES192.Encrypt test vector did not match");
+ res = -1;
+ }
+ os_free(tmp);
+
+ wpa_printf(MSG_DEBUG, "CTR-AES256.Encrypt");
+ len = sizeof(plain256);
+ tmp = os_malloc(len);
+ if (!tmp)
+ return -1;
+ os_memcpy(tmp, plain256, len);
+ if (aes_ctr_encrypt(key256, sizeof(key256), counter256, tmp, len) < 0) {
+ wpa_printf(MSG_ERROR, "aes_ctr_encrypt() failed");
+ res = -1;
+ } else if (os_memcmp(tmp, cipher256, len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "CTR-AES256.Encrypt test vector did not match");
+ res = -1;
+ }
+ os_free(tmp);
+#endif
+
+ return res;
+}
+
+
static int test_md5(void)
{
#ifndef CONFIG_FIPS
@@ -2154,6 +2303,7 @@ int crypto_module_tests(void)
test_cbc() ||
test_ecb() ||
test_key_wrap() ||
+ test_aes_ctr() ||
test_md5() ||
test_sha1() ||
test_sha256() ||
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 47b6ebbd..72f93c19 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -21,6 +21,7 @@
#endif /* CONFIG_OPENSSL_CMAC */
#ifdef CONFIG_ECC
#include <openssl/ec.h>
+#include <openssl/x509.h>
#endif /* CONFIG_ECC */
#include "common.h"
@@ -79,6 +80,14 @@ static void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
bin_clear_free(ctx, sizeof(*ctx));
}
+
+static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
+{
+ if (pkey->type != EVP_PKEY_EC)
+ return NULL;
+ return pkey->pkey.ec;
+}
+
#endif /* OpenSSL version < 1.1.0 */
static BIGNUM * get_group5_prime(void)
@@ -2174,4 +2183,164 @@ size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh)
return crypto_ec_prime_len(ecdh->ec);
}
+
+struct crypto_ec_key {
+ EVP_PKEY *pkey;
+ EC_KEY *eckey;
+};
+
+
+struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len)
+{
+ struct crypto_ec_key *key;
+
+ key = os_zalloc(sizeof(*key));
+ if (!key)
+ return NULL;
+
+ key->eckey = d2i_ECPrivateKey(NULL, &der, der_len);
+ if (!key->eckey) {
+ wpa_printf(MSG_INFO, "OpenSSL: d2i_ECPrivateKey() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ EC_KEY_set_conv_form(key->eckey, POINT_CONVERSION_COMPRESSED);
+
+ key->pkey = EVP_PKEY_new();
+ if (!key->pkey || EVP_PKEY_assign_EC_KEY(key->pkey, key->eckey) != 1) {
+ EC_KEY_free(key->eckey);
+ key->eckey = NULL;
+ goto fail;
+ }
+
+ return key;
+fail:
+ crypto_ec_key_deinit(key);
+ return NULL;
+}
+
+
+struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len)
+{
+ struct crypto_ec_key *key;
+
+ key = os_zalloc(sizeof(*key));
+ if (!key)
+ return NULL;
+
+ key->pkey = d2i_PUBKEY(NULL, &der, der_len);
+ if (!key->pkey) {
+ wpa_printf(MSG_INFO, "OpenSSL: d2i_PUBKEY() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ key->eckey = EVP_PKEY_get0_EC_KEY(key->pkey);
+ if (!key->eckey)
+ goto fail;
+ return key;
+fail:
+ crypto_ec_key_deinit(key);
+ return NULL;
+}
+
+
+void crypto_ec_key_deinit(struct crypto_ec_key *key)
+{
+ if (key) {
+ EVP_PKEY_free(key->pkey);
+ os_free(key);
+ }
+}
+
+
+struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
+{
+ unsigned char *der = NULL;
+ int der_len;
+ struct wpabuf *buf;
+
+ der_len = i2d_PUBKEY(key->pkey, &der);
+ if (der_len <= 0) {
+ wpa_printf(MSG_INFO, "OpenSSL: i2d_PUBKEY() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return NULL;
+ }
+
+ buf = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+ return buf;
+}
+
+
+struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
+ size_t len)
+{
+ EVP_PKEY_CTX *pkctx;
+ struct wpabuf *sig_der;
+ size_t sig_len;
+
+ sig_len = EVP_PKEY_size(key->pkey);
+ sig_der = wpabuf_alloc(sig_len);
+ if (!sig_der)
+ return NULL;
+
+ pkctx = EVP_PKEY_CTX_new(key->pkey, NULL);
+ if (!pkctx ||
+ EVP_PKEY_sign_init(pkctx) <= 0 ||
+ EVP_PKEY_sign(pkctx, wpabuf_put(sig_der, 0), &sig_len,
+ data, len) <= 0) {
+ wpabuf_free(sig_der);
+ sig_der = NULL;
+ } else {
+ wpabuf_put(sig_der, sig_len);
+ }
+
+ EVP_PKEY_CTX_free(pkctx);
+ return sig_der;
+}
+
+
+int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
+ size_t len, const u8 *sig, size_t sig_len)
+{
+ EVP_PKEY_CTX *pkctx;
+ int ret;
+
+ pkctx = EVP_PKEY_CTX_new(key->pkey, NULL);
+ if (!pkctx || EVP_PKEY_verify_init(pkctx) <= 0) {
+ EVP_PKEY_CTX_free(pkctx);
+ return -1;
+ }
+
+ ret = EVP_PKEY_verify(pkctx, sig, sig_len, data, len);
+ EVP_PKEY_CTX_free(pkctx);
+ if (ret == 1)
+ return 1; /* signature ok */
+ if (ret == 0)
+ return 0; /* incorrect signature */
+ return -1;
+}
+
+
+int crypto_ec_key_group(struct crypto_ec_key *key)
+{
+ const EC_GROUP *group;
+ int nid;
+
+ group = EC_KEY_get0_group(key->eckey);
+ if (!group)
+ return -1;
+ nid = EC_GROUP_get_curve_name(group);
+ switch (nid) {
+ case NID_X9_62_prime256v1:
+ return 19;
+ case NID_secp384r1:
+ return 20;
+ case NID_secp521r1:
+ return 21;
+ }
+ return -1;
+}
+
#endif /* CONFIG_ECC */
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index c8b1a824..09fb73b1 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -670,4 +670,18 @@ int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len);
*/
u16 tls_connection_get_cipher_suite(struct tls_connection *conn);
+/**
+ * tls_connection_get_peer_subject - Get peer subject
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Peer subject or %NULL if not authenticated or not available
+ */
+const char * tls_connection_get_peer_subject(struct tls_connection *conn);
+
+/**
+ * tls_connection_get_own_cert_used - Was own certificate used
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: true if own certificate was used during authentication
+ */
+bool tls_connection_get_own_cert_used(struct tls_connection *conn);
+
#endif /* TLS_H */
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 7ee371ab..086dfb31 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -136,6 +136,10 @@ static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
#include <log/log_event_list.h>
#define CERT_VALIDATION_FAILURE 210033
+#define ANDROID_KEYSTORE_PREFIX "keystore://"
+#define ANDROID_KEYSTORE_PREFIX_LEN os_strlen(ANDROID_KEYSTORE_PREFIX)
+#define ANDROID_KEYSTORE_ENCODED_PREFIX "keystores://"
+#define ANDROID_KEYSTORE_ENCODED_PREFIX_LEN os_strlen(ANDROID_KEYSTORE_ENCODED_PREFIX)
static void log_cert_validation_failure(const char *reason)
{
@@ -146,32 +150,37 @@ static void log_cert_validation_failure(const char *reason)
}
-static BIO * BIO_from_keystore(const char *key)
+static BIO* BIO_from_keystore(const char *alias)
{
BIO *bio = NULL;
uint8_t *value = NULL;
- int length = keystore_get(key, strlen(key), &value);
+ int length = keystore_get(alias, strlen(alias), &value);
if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
BIO_write(bio, value, length);
free(value);
return bio;
}
-
-static int tls_add_ca_from_keystore(X509_STORE *ctx, const char *key_alias)
+static int tls_add_ca_from_keystore(X509_STORE *ctx, const char *alias)
{
- BIO *bio = BIO_from_keystore(key_alias);
+ BIO *bio = BIO_from_keystore(alias);
STACK_OF(X509_INFO) *stack = NULL;
stack_index_t i;
+ int ret = 0;
- if (bio) {
- stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
- BIO_free(bio);
+ if (!bio) {
+ wpa_printf(MSG_ERROR, "OpenSSL: Failed to parse certificate: %s",
+ alias);
+ return -1;
}
+ // Keystore returns X.509 certificates in PEM encoding
+ stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+
if (!stack) {
- wpa_printf(MSG_WARNING, "TLS: Failed to parse certificate: %s",
- key_alias);
+ wpa_printf(MSG_ERROR, "OpenSSL: Failed to parse certificate: %s",
+ alias);
return -1;
}
@@ -179,33 +188,37 @@ static int tls_add_ca_from_keystore(X509_STORE *ctx, const char *key_alias)
X509_INFO *info = sk_X509_INFO_value(stack, i);
if (info->x509)
- X509_STORE_add_cert(ctx, info->x509);
+ if (!X509_STORE_add_cert(ctx, info->x509)) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to add Root CA certificate");
+ ret = -1;
+ break;
+ }
if (info->crl)
X509_STORE_add_crl(ctx, info->crl);
}
sk_X509_INFO_pop_free(stack, X509_INFO_free);
-
- return 0;
+ return ret;
}
static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx,
- const char *encoded_key_alias)
+ const char *encoded_alias)
{
int rc = -1;
- int len = os_strlen(encoded_key_alias);
+ int len = os_strlen(encoded_alias);
unsigned char *decoded_alias;
if (len & 1) {
wpa_printf(MSG_WARNING, "Invalid hex-encoded alias: %s",
- encoded_key_alias);
+ encoded_alias);
return rc;
}
decoded_alias = os_malloc(len / 2 + 1);
if (decoded_alias) {
- if (!hexstr2bin(encoded_key_alias, decoded_alias, len / 2)) {
+ if (!hexstr2bin(encoded_alias, decoded_alias, len / 2)) {
decoded_alias[len / 2] = '\0';
rc = tls_add_ca_from_keystore(
ctx, (const char *) decoded_alias);
@@ -279,6 +292,7 @@ struct tls_connection {
X509 *peer_cert;
X509 *peer_issuer;
X509 *peer_issuer_issuer;
+ char *peer_subject; /* peer subject info for authenticated peer */
unsigned char client_random[SSL3_RANDOM_SIZE];
unsigned char server_random[SSL3_RANDOM_SIZE];
@@ -1058,6 +1072,8 @@ void * tls_init(const struct tls_config *conf)
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
+ SSL_CTX_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+
#ifdef SSL_MODE_NO_AUTO_CHAIN
/* Number of deployed use cases assume the default OpenSSL behavior of
* auto chaining the local certificate is in use. BoringSSL removed this
@@ -1643,6 +1659,7 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
os_free(conn->domain_match);
os_free(conn->check_cert_subject);
os_free(conn->session_ticket);
+ os_free(conn->peer_subject);
os_free(conn);
}
@@ -2597,6 +2614,11 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
context->event_cb(context->cb_ctx,
TLS_CERT_CHAIN_SUCCESS, NULL);
+ if (depth == 0 && preverify_ok) {
+ os_free(conn->peer_subject);
+ conn->peer_subject = os_strdup(buf);
+ }
+
return preverify_ok;
}
@@ -2744,17 +2766,20 @@ static int tls_connection_ca_cert(struct tls_data *data,
#ifdef ANDROID
/* Single alias */
- if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
+ if (ca_cert && os_strncmp(ANDROID_KEYSTORE_PREFIX, ca_cert,
+ ANDROID_KEYSTORE_PREFIX_LEN) == 0) {
if (tls_add_ca_from_keystore(SSL_CTX_get_cert_store(ssl_ctx),
- &ca_cert[11]) < 0)
+ &ca_cert[ANDROID_KEYSTORE_PREFIX_LEN]) < 0)
return -1;
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
return 0;
}
/* Multiple aliases separated by space */
- if (ca_cert && os_strncmp("keystores://", ca_cert, 12) == 0) {
- char *aliases = os_strdup(&ca_cert[12]);
+ if (ca_cert && os_strncmp(ANDROID_KEYSTORE_ENCODED_PREFIX, ca_cert,
+ ANDROID_KEYSTORE_ENCODED_PREFIX_LEN) == 0) {
+ char *aliases = os_strdup(
+ &ca_cert[ANDROID_KEYSTORE_ENCODED_PREFIX_LEN]);
const char *delim = " ";
int rc = 0;
char *savedptr;
@@ -2765,10 +2790,10 @@ static int tls_connection_ca_cert(struct tls_data *data,
alias = strtok_r(aliases, delim, &savedptr);
for (; alias; alias = strtok_r(NULL, delim, &savedptr)) {
if (tls_add_ca_from_keystore_encoded(
- SSL_CTX_get_cert_store(ssl_ctx), alias)) {
- wpa_printf(MSG_WARNING,
- "OpenSSL: %s - Failed to add ca_cert %s from keystore",
- __func__, alias);
+ SSL_CTX_get_cert_store(ssl_ctx), alias)) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to add ca_cert %s from keystore",
+ alias);
rc = -1;
break;
}
@@ -3006,16 +3031,12 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
/* Explicit request to enable TLS versions even if needing to
* override systemwide policies. */
- if (flags & TLS_CONN_ENABLE_TLSv1_0) {
+ if (flags & TLS_CONN_ENABLE_TLSv1_0)
version = TLS1_VERSION;
- } else if (flags & TLS_CONN_ENABLE_TLSv1_1) {
- if (!(flags & TLS_CONN_DISABLE_TLSv1_0))
- version = TLS1_1_VERSION;
- } else if (flags & TLS_CONN_ENABLE_TLSv1_2) {
- if (!(flags & (TLS_CONN_DISABLE_TLSv1_0 |
- TLS_CONN_DISABLE_TLSv1_1)))
- version = TLS1_2_VERSION;
- }
+ else if (flags & TLS_CONN_ENABLE_TLSv1_1)
+ version = TLS1_1_VERSION;
+ else if (flags & TLS_CONN_ENABLE_TLSv1_2)
+ version = TLS1_2_VERSION;
if (!version) {
wpa_printf(MSG_DEBUG,
"OpenSSL: Invalid TLS version configuration");
@@ -3029,6 +3050,18 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
}
}
#endif /* >= 1.1.0 */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !defined(LIBRESSL_VERSION_NUMBER) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+ if ((flags & (TLS_CONN_ENABLE_TLSv1_0 | TLS_CONN_ENABLE_TLSv1_1)) &&
+ SSL_get_security_level(ssl) >= 2) {
+ /*
+ * Need to drop to security level 1 to allow TLS versions older
+ * than 1.2 to be used when explicitly enabled in configuration.
+ */
+ SSL_set_security_level(conn->ssl, 1);
+ }
+#endif
#ifdef CONFIG_SUITEB
#ifdef OPENSSL_IS_BORINGSSL
@@ -3198,7 +3231,11 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
if (conn == NULL)
return -1;
- if (verify_peer) {
+ if (verify_peer == 2) {
+ conn->ca_cert_verify = 1;
+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
+ SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
+ } else if (verify_peer) {
conn->ca_cert_verify = 1;
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
@@ -3259,39 +3296,71 @@ static int tls_connection_client_cert(struct tls_connection *conn,
"OK");
return 0;
} else if (client_cert_blob) {
+#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20901000L
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_certificate_ASN1 failed");
+#else
+ BIO *bio;
+ X509 *x509;
+
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_certificate_ASN1 failed");
+ bio = BIO_new(BIO_s_mem());
+ if (!bio)
+ return -1;
+ BIO_write(bio, client_cert_blob, client_cert_blob_len);
+ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ if (!x509 || SSL_use_certificate(conn->ssl, x509) != 1) {
+ X509_free(x509);
+ BIO_free(bio);
+ return -1;
+ }
+ X509_free(x509);
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Found PEM encoded certificate from blob");
+ while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL))) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Added an additional certificate into the chain");
+ SSL_add0_chain_cert(conn->ssl, x509);
+ }
+ BIO_free(bio);
+ return 0;
+#endif
}
if (client_cert == NULL)
return -1;
#ifdef ANDROID
- if (os_strncmp("keystore://", client_cert, 11) == 0) {
- BIO *bio = BIO_from_keystore(&client_cert[11]);
+ if (os_strncmp(ANDROID_KEYSTORE_PREFIX, client_cert,
+ ANDROID_KEYSTORE_PREFIX_LEN) == 0) {
+ BIO *bio = BIO_from_keystore(&client_cert[ANDROID_KEYSTORE_PREFIX_LEN]);
X509 *x509 = NULL;
- int ret = -1;
- if (bio) {
- x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ if (!bio) {
+ return -1;
}
- if (x509) {
- if (SSL_use_certificate(conn->ssl, x509) == 1)
- ret = 0;
+ // Keystore returns X.509 certificates in PEM encoding
+ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ if (!x509 || SSL_use_certificate(conn->ssl, x509) != 1) {
X509_free(x509);
+ BIO_free(bio);
+ wpa_printf(MSG_ERROR, "OpenSSL: Unknown certificate encoding");
+ return -1;
}
+ X509_free(x509);
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Found PEM encoded certificate from keystore: %s",
+ client_cert);
- /* Read additional certificates into the chain. */
- while (bio) {
- x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
- if (x509) {
- /* Takes ownership of x509 */
- SSL_add0_chain_cert(conn->ssl, x509);
- } else {
- BIO_free(bio);
- bio = NULL;
- }
+ // Read additional certificates into the chain
+ while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL))) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Added an additional certificate into the chain");
+ // Takes ownership of x509, no need to free it here
+ SSL_add0_chain_cert(conn->ssl, x509);
}
- return ret;
+ BIO_free(bio);
+ return 0;
}
#endif /* ANDROID */
@@ -3767,6 +3836,17 @@ static int tls_connection_private_key(struct tls_data *data,
break;
}
+#ifndef OPENSSL_NO_EC
+ if (SSL_use_PrivateKey_ASN1(EVP_PKEY_EC, conn->ssl,
+ (u8 *) private_key_blob,
+ private_key_blob_len) == 1) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: SSL_use_PrivateKey_ASN1(EVP_PKEY_EC) --> OK");
+ ok = 1;
+ break;
+ }
+#endif /* OPENSSL_NO_EC */
+
if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
(u8 *) private_key_blob,
private_key_blob_len) == 1) {
@@ -4503,10 +4583,18 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
return NULL;
res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
if (res < 0) {
- tls_show_errors(MSG_INFO, __func__,
- "Decryption failed - SSL_read");
- wpabuf_free(buf);
- return NULL;
+ int err = SSL_get_error(conn->ssl, res);
+
+ if (err == SSL_ERROR_WANT_READ) {
+ wpa_printf(MSG_DEBUG,
+ "SSL: SSL_connect - want more data");
+ res = 0;
+ } else {
+ tls_show_errors(MSG_INFO, __func__,
+ "Decryption failed - SSL_read");
+ wpabuf_free(buf);
+ return NULL;
+ }
}
wpabuf_put(buf, res);
@@ -5103,8 +5191,10 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
params->altsubject_match,
params->suffix_match,
params->domain_match,
- params->check_cert_subject))
+ params->check_cert_subject)) {
+ wpa_printf(MSG_ERROR, "TLS: Failed to set subject match");
return -1;
+ }
if (engine_id && ca_cert_id) {
if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
@@ -5112,16 +5202,20 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
} else if (tls_connection_ca_cert(data, conn, params->ca_cert,
params->ca_cert_blob,
params->ca_cert_blob_len,
- params->ca_path))
+ params->ca_path)) {
+ wpa_printf(MSG_ERROR, "TLS: Failed to parse Root CA certificate");
return -1;
+ }
if (engine_id && cert_id) {
if (tls_connection_engine_client_cert(conn, cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_client_cert(conn, params->client_cert,
params->client_cert_blob,
- params->client_cert_blob_len))
+ params->client_cert_blob_len)) {
+ wpa_printf(MSG_ERROR, "TLS: Failed to parse client certificate");
return -1;
+ }
if (engine_id && key_id) {
wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
@@ -5196,8 +5290,10 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
}
if (tls_set_conn_flags(conn, params->flags,
- params->openssl_ciphers) < 0)
+ params->openssl_ciphers) < 0) {
+ wpa_printf(MSG_ERROR, "TLS: Failed to set connection flags");
return -1;
+ }
#ifdef OPENSSL_IS_BORINGSSL
if (params->flags & TLS_CONN_REQUEST_OCSP) {
@@ -5283,6 +5379,9 @@ static void openssl_debug_dump_certificate(int i, X509 *cert)
ASN1_INTEGER *ser;
char serial_num[128];
+ if (!cert)
+ return;
+
X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
ser = X509_get_serialNumber(cert);
@@ -5667,3 +5766,19 @@ u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
return SSL_CIPHER_get_id(cipher) & 0xFFFF;
#endif
}
+
+
+const char * tls_connection_get_peer_subject(struct tls_connection *conn)
+{
+ if (conn)
+ return conn->peer_subject;
+ return NULL;
+}
+
+
+bool tls_connection_get_own_cert_used(struct tls_connection *conn)
+{
+ if (conn)
+ return SSL_get_certificate(conn->ssl) != NULL;
+ return false;
+}
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
index 11e65822..cf482bfc 100644
--- a/src/crypto/tls_wolfssl.c
+++ b/src/crypto/tls_wolfssl.c
@@ -19,6 +19,7 @@
#include <wolfssl/ssl.h>
#include <wolfssl/error-ssl.h>
#include <wolfssl/wolfcrypt/asn.h>
+#include <wolfssl/openssl/x509v3.h>
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
#define HAVE_AESGCM
@@ -468,7 +469,7 @@ static int tls_connection_client_cert(struct tls_connection *conn,
if (client_cert_blob) {
if (wolfSSL_use_certificate_chain_buffer_format(
conn->ssl, client_cert_blob, blob_len,
- SSL_FILETYPE_ASN1) < 0) {
+ SSL_FILETYPE_ASN1) != SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use client cert DER blob failed");
return -1;
@@ -478,13 +479,13 @@ static int tls_connection_client_cert(struct tls_connection *conn,
}
if (client_cert) {
- if (wolfSSL_use_certificate_chain_file(conn->ssl,
- client_cert) < 0) {
+ if (wolfSSL_use_certificate_chain_file(
+ conn->ssl, client_cert) != SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use client cert PEM file failed");
if (wolfSSL_use_certificate_chain_file_format(
conn->ssl, client_cert,
- SSL_FILETYPE_ASN1) < 0) {
+ SSL_FILETYPE_ASN1) != SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use client cert DER file failed");
return -1;
@@ -533,7 +534,7 @@ static int tls_connection_private_key(void *tls_ctx,
if (private_key_blob) {
if (wolfSSL_use_PrivateKey_buffer(conn->ssl,
private_key_blob, blob_len,
- SSL_FILETYPE_ASN1) < 0) {
+ SSL_FILETYPE_ASN1) <= 0) {
wpa_printf(MSG_INFO,
"SSL: use private DER blob failed");
} else {
@@ -544,11 +545,11 @@ static int tls_connection_private_key(void *tls_ctx,
if (!ok && private_key) {
if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_PEM) < 0) {
+ SSL_FILETYPE_PEM) <= 0) {
wpa_printf(MSG_INFO,
"SSL: use private key PEM file failed");
if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_ASN1) < 0)
+ SSL_FILETYPE_ASN1) <= 0)
{
wpa_printf(MSG_INFO,
"SSL: use private key DER file failed");
@@ -576,7 +577,7 @@ static int tls_connection_private_key(void *tls_ctx,
static int tls_match_alt_subject_component(WOLFSSL_X509 *cert, int type,
const char *value, size_t len)
{
- WOLFSSL_ASN1_OBJECT *gen;
+ WOLFSSL_GENERAL_NAME *gen;
void *ext;
int found = 0;
int i;
@@ -585,14 +586,15 @@ static int tls_match_alt_subject_component(WOLFSSL_X509 *cert, int type,
for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
gen = wolfSSL_sk_value(ext, i);
- if (gen->type != type)
+ if (!gen || gen->type != type)
continue;
- if (os_strlen((char *) gen->obj) == len &&
- os_memcmp(value, gen->obj, len) == 0)
+ if ((size_t) wolfSSL_ASN1_STRING_length(gen->d.ia5) == len &&
+ os_memcmp(value, wolfSSL_ASN1_STRING_data(gen->d.ia5),
+ len) == 0)
found++;
}
- wolfSSL_sk_ASN1_OBJECT_free(ext);
+ wolfSSL_sk_GENERAL_NAME_free(ext);
return found;
}
@@ -676,7 +678,7 @@ static int domain_suffix_match(const char *val, size_t len, const char *match,
static int tls_match_suffix_helper(WOLFSSL_X509 *cert, const char *match,
size_t match_len, int full)
{
- WOLFSSL_ASN1_OBJECT *gen;
+ WOLFSSL_GENERAL_NAME *gen;
void *ext;
int i;
int j;
@@ -690,21 +692,23 @@ static int tls_match_suffix_helper(WOLFSSL_X509 *cert, const char *match,
for (j = 0; ext && j < wolfSSL_sk_num(ext); j++) {
gen = wolfSSL_sk_value(ext, j);
- if (gen->type != ASN_DNS_TYPE)
+ if (!gen || gen->type != ASN_DNS_TYPE)
continue;
dns_name++;
wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
- gen->obj, os_strlen((char *)gen->obj));
- if (domain_suffix_match((const char *) gen->obj,
- os_strlen((char *) gen->obj), match,
- match_len, full) == 1) {
+ wolfSSL_ASN1_STRING_data(gen->d.ia5),
+ wolfSSL_ASN1_STRING_length(gen->d.ia5));
+ if (domain_suffix_match(
+ (const char *) wolfSSL_ASN1_STRING_data(gen->d.ia5),
+ wolfSSL_ASN1_STRING_length(gen->d.ia5), match,
+ match_len, full) == 1) {
wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
full ? "Match" : "Suffix match");
wolfSSL_sk_ASN1_OBJECT_free(ext);
return 1;
}
}
- wolfSSL_sk_ASN1_OBJECT_free(ext);
+ wolfSSL_sk_GENERAL_NAME_free(ext);
if (dns_name) {
wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
@@ -858,7 +862,7 @@ static void wolfssl_tls_cert_event(struct tls_connection *conn,
struct tls_context *context = conn->context;
char *alt_subject[TLS_MAX_ALT_SUBJECT];
int alt, num_alt_subject = 0;
- WOLFSSL_ASN1_OBJECT *gen;
+ WOLFSSL_GENERAL_NAME *gen;
void *ext;
int i;
#ifdef CONFIG_SHA256
@@ -899,12 +903,14 @@ static void wolfssl_tls_cert_event(struct tls_connection *conn,
if (num_alt_subject == TLS_MAX_ALT_SUBJECT)
break;
gen = wolfSSL_sk_value((void *) ext, i);
- if (gen->type != GEN_EMAIL &&
- gen->type != GEN_DNS &&
- gen->type != GEN_URI)
+ if (!gen ||
+ (gen->type != GEN_EMAIL &&
+ gen->type != GEN_DNS &&
+ gen->type != GEN_URI))
continue;
- pos = os_malloc(10 + os_strlen((char *) gen->obj) + 1);
+ pos = os_malloc(10 + wolfSSL_ASN1_STRING_length(gen->d.ia5) +
+ 1);
if (!pos)
break;
alt_subject[num_alt_subject++] = pos;
@@ -924,11 +930,12 @@ static void wolfssl_tls_cert_event(struct tls_connection *conn,
break;
}
- os_memcpy(pos, gen->obj, os_strlen((char *)gen->obj));
- pos += os_strlen((char *)gen->obj);
+ os_memcpy(pos, wolfSSL_ASN1_STRING_data(gen->d.ia5),
+ wolfSSL_ASN1_STRING_length(gen->d.ia5));
+ pos += wolfSSL_ASN1_STRING_length(gen->d.ia5);
*pos = '\0';
}
- wolfSSL_sk_ASN1_OBJECT_free(ext);
+ wolfSSL_sk_GENERAL_NAME_free(ext);
for (alt = 0; alt < num_alt_subject; alt++)
ev.peer_cert.altsubject[alt] = alt_subject[alt];
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 350c1cb5..5b2c71ca 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -197,6 +197,7 @@ struct he_capabilities {
u8 mac_cap[HE_MAX_MAC_CAPAB_SIZE];
u8 mcs[HE_MAX_MCS_CAPAB_SIZE];
u8 ppet[HE_MAX_PPET_CAPAB_SIZE];
+ u16 he_6ghz_capa;
};
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
@@ -1188,6 +1189,14 @@ struct wpa_driver_associate_params {
* fils_erp_rrk_len - Length of fils_erp_rrk in bytes
*/
size_t fils_erp_rrk_len;
+
+ /**
+ * 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;
};
enum hide_ssid {
@@ -1255,14 +1264,14 @@ struct wpa_driver_ap_params {
*
* This parameter can be used to set a specific Beacon frame data rate
* for the BSS. The interpretation of this value depends on the
- * rate_type (legacy: in 100 kbps units, HT: HT-MCS, VHT: VHT-MCS). If
- * beacon_rate == 0 and rate_type == 0 (BEACON_RATE_LEGACY), the default
- * Beacon frame data rate is used.
+ * rate_type (legacy: in 100 kbps units, HT: HT-MCS, VHT: VHT-MCS,
+ * HE: HE-MCS). If beacon_rate == 0 and rate_type == 0
+ * (BEACON_RATE_LEGACY), the default Beacon frame data rate is used.
*/
unsigned int beacon_rate;
/**
- * beacon_rate_type: Beacon data rate type (legacy/HT/VHT)
+ * beacon_rate_type: Beacon data rate type (legacy/HT/VHT/HE)
*/
enum beacon_rate_type rate_type;
@@ -1474,19 +1483,36 @@ struct wpa_driver_ap_params {
const struct wpabuf *civic;
/**
- * he_spr - Whether Spatial Reuse is enabled
+ * he_spr_ctrl - Spatial Reuse control field of SPR element
+ */
+ u8 he_spr_ctrl;
+
+ /**
+ * he_spr_non_srg_obss_pd_max_offset - Non-SRG Maximum TX power offset
*/
- int he_spr;
+ u8 he_spr_non_srg_obss_pd_max_offset;
/**
* he_spr_srg_obss_pd_min_offset - Minimum TX power offset
*/
- int he_spr_srg_obss_pd_min_offset;
+ u8 he_spr_srg_obss_pd_min_offset;
/**
* he_spr_srg_obss_pd_max_offset - Maximum TX power offset
*/
- int he_spr_srg_obss_pd_max_offset;
+ u8 he_spr_srg_obss_pd_max_offset;
+
+ /**
+ * he_spr_bss_color_bitmap - BSS color values used by members of the
+ * SRG.
+ */
+ u8 he_spr_bss_color_bitmap[8];
+
+ /**
+ * he_spr_partial_bssid_bitmap - Partial BSSID values used by members
+ * of the SRG.
+ */
+ u8 he_spr_partial_bssid_bitmap[8];
/**
* he_bss_color - Whether the BSS Color is disabled
@@ -1507,6 +1533,49 @@ struct wpa_driver_ap_params {
* twt_responder - Whether Target Wait Time responder is enabled
*/
int twt_responder;
+
+ /**
+ * 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;
+
+ /**
+ * FILS Discovery frame minimum interval in TUs
+ */
+ u32 fd_min_int;
+
+ /**
+ * FILS Discovery frame maximum interval in TUs (0 = FD frame disabled)
+ */
+ u32 fd_max_int;
+
+ /**
+ * FILS Discovery frame template data
+ */
+ u8 *fd_frame_tmpl;
+
+ /**
+ * FILS Discovery frame template length
+ */
+ size_t fd_frame_tmpl_len;
+
+ /**
+ * Unsolicited broadcast Probe Response interval in TUs
+ */
+ unsigned int unsol_bcast_probe_resp_interval;
+
+ /**
+ * Unsolicited broadcast Probe Response template data
+ */
+ u8 *unsol_bcast_probe_resp_tmpl;
+
+ /**
+ * Unsolicited broadcast Probe Response template length
+ */
+ size_t unsol_bcast_probe_resp_tmpl_len;
};
struct wpa_driver_mesh_bss_params {
@@ -1542,6 +1611,7 @@ struct wpa_driver_mesh_join_params {
#define WPA_DRIVER_MESH_FLAG_SAE_AUTH 0x00000004
#define WPA_DRIVER_MESH_FLAG_AMPE 0x00000008
unsigned int flags;
+ bool handle_dfs;
};
struct wpa_driver_set_key_params {
@@ -1930,6 +2000,25 @@ struct wpa_driver_capa {
/** Driver supports a separate control port RX for EAPOL frames */
#define WPA_DRIVER_FLAGS2_CONTROL_PORT_RX 0x0000000000000001ULL
+/** Driver supports TX status reports for EAPOL frames through control port */
+#define WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS 0x0000000000000002ULL
+/** Driver supports secure LTF */
+#define WPA_DRIVER_FLAGS2_SEC_LTF 0x0000000000000004ULL
+/** Driver supports secure RTT measurement exchange */
+#define WPA_DRIVER_FLAGS2_SEC_RTT 0x0000000000000008ULL
+/**
+ * Driver supports protection of range negotiation and measurement management
+ * frames
+ */
+#define WPA_DRIVER_FLAGS2_PROT_RANGE_NEG 0x0000000000000010ULL
+/** Driver supports Beacon frame TX rate configuration (HE rates) */
+#define WPA_DRIVER_FLAGS2_BEACON_RATE_HE 0x0000000000000020ULL
+/** Driver supports Beacon protection only in client mode */
+#define WPA_DRIVER_FLAGS2_BEACON_PROTECTION_CLIENT 0x0000000000000040ULL
+/** Driver supports Operating Channel Validation */
+#define WPA_DRIVER_FLAGS2_OCV 0x0000000000000080ULL
+/** Driver expects user space implementation of SME in AP mode */
+#define WPA_DRIVER_FLAGS2_AP_SME 0x0000000000000100ULL
u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -2429,6 +2518,13 @@ struct external_auth {
const u8 *pmkid;
};
+/* enum nested_attr - Used to specify if subcommand uses nested attributes */
+enum nested_attr {
+ NESTED_ATTR_NOT_USED = 0,
+ NESTED_ATTR_USED = 1,
+ NESTED_ATTR_UNSPECIFIED = 2,
+};
+
/**
* struct wpa_driver_ops - Driver interface API definition
*
@@ -3714,6 +3810,8 @@ struct wpa_driver_ops {
* @priv: Private driver interface data
* @vendor_id: Vendor id
* @subcmd: Vendor command id
+ * @nested_attr_flag: Specifies if vendor subcommand uses nested
+ * attributes or not
* @data: Vendor command parameters (%NULL if no parameters)
* @data_len: Data length
* @buf: Return buffer (%NULL to ignore reply)
@@ -3721,9 +3819,10 @@ struct wpa_driver_ops {
*
* This function handles vendor specific commands that are passed to
* the driver/device. The command is identified by vendor id and
- * command id. Parameters can be passed as argument to the command
- * in the data buffer. Reply (if any) will be filled in the supplied
- * return buffer.
+ * command id. The nested_attr_flag specifies whether the subcommand
+ * uses nested attributes or not. Parameters can be passed
+ * as argument to the command in the data buffer. Reply (if any) will be
+ * filled in the supplied return buffer.
*
* The exact driver behavior is driver interface and vendor specific. As
* an example, this will be converted to a vendor specific cfg80211
@@ -3731,6 +3830,7 @@ struct wpa_driver_ops {
*/
int (*vendor_cmd)(void *priv, unsigned int vendor_id,
unsigned int subcmd, const u8 *data, size_t data_len,
+ enum nested_attr nested_attr_flag,
struct wpabuf *buf);
/**
@@ -4246,12 +4346,12 @@ struct wpa_driver_ops {
int (*do_acs)(void *priv, struct drv_acs_params *params);
/**
- * set_band - Notify driver of band selection
+ * set_band - Notify driver of band(s) selection
* @priv: Private driver interface data
- * @band: The selected band(s)
+ * @band_mask: The selected band(s) bit mask (from enum set_band)
* Returns 0 on success, -1 on failure
*/
- int (*set_band)(void *priv, enum set_band band);
+ int (*set_band)(void *priv, u32 band_mask);
/**
* get_pref_freq_list - Get preferred frequency list for an interface
@@ -4384,13 +4484,13 @@ struct wpa_driver_ops {
int (*ignore_assoc_disallow)(void *priv, int ignore_disallow);
/**
- * set_bssid_blacklist - Set blacklist of BSSIDs to the driver
+ * set_bssid_tmp_disallow - Set disallowed BSSIDs to the driver
* @priv: Private driver interface data
- * @num_bssid: Number of blacklist BSSIDs
- * @bssids: List of blacklisted BSSIDs
+ * @num_bssid: Number of temporarily disallowed BSSIDs
+ * @bssids: List of temporarily disallowed BSSIDs
*/
- int (*set_bssid_blacklist)(void *priv, unsigned int num_bssid,
- const u8 *bssid);
+ int (*set_bssid_tmp_disallow)(void *priv, unsigned int num_bssid,
+ const u8 *bssid);
/**
* update_connect_params - Update the connection parameters
@@ -5048,6 +5148,34 @@ struct freq_survey {
#define SURVEY_HAS_CHAN_TIME_RX BIT(3)
#define SURVEY_HAS_CHAN_TIME_TX BIT(4)
+/**
+ * enum sta_connect_fail_reason_codes - STA connect failure reason code values
+ * @STA_CONNECT_FAIL_REASON_UNSPECIFIED: No reason code specified for
+ * connection failure.
+ * @STA_CONNECT_FAIL_REASON_NO_BSS_FOUND: No Probe Response frame received
+ * for unicast Probe Request frame.
+ * @STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL: STA failed to send auth request.
+ * @STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED: AP didn't send ACK for
+ * auth request.
+ * @STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED: Auth response is not
+ * received from AP.
+ * @STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL: STA failed to send
+ * Association Request frame.
+ * @STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED: AP didn't send ACK for
+ * Association Request frame.
+ * @STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED: Association Response
+ * frame is not received from AP.
+ */
+enum sta_connect_fail_reason_codes {
+ STA_CONNECT_FAIL_REASON_UNSPECIFIED = 0,
+ STA_CONNECT_FAIL_REASON_NO_BSS_FOUND = 1,
+ STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL = 2,
+ STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED = 3,
+ STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED = 4,
+ STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL = 5,
+ STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED = 6,
+ STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED = 7,
+};
/**
* union wpa_event_data - Additional data for wpa_supplicant_event() calls
@@ -5449,6 +5577,11 @@ union wpa_event_data {
* FILS ERP messages
*/
u16 fils_erp_next_seq_num;
+
+ /**
+ * reason_code - Connection failure reason code from the driver
+ */
+ enum sta_connect_fail_reason_codes reason_code;
} assoc_reject;
struct timeout_event {
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 5adee13a..00d970a6 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -16,7 +16,9 @@
#include "common/ieee802_11_defs.h"
#include "common/wpa_common.h"
+#include <ifaddrs.h>
#include <net/if.h>
+#include <net/if_dl.h>
#include <net/if_media.h>
#ifdef __NetBSD__
@@ -137,7 +139,9 @@ bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg,
ireq->i_data = arg;
if (ioctl(drv->global->sock, SIOCG80211, ireq) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCG80211, op=%u, "
+ int level = drv->if_removed ? MSG_DEBUG : MSG_ERROR;
+
+ wpa_printf(level, "ioctl[SIOCG80211, op=%u, "
"arg_len=%u]: %s", op, arg_len, strerror(errno));
return -1;
}
@@ -613,6 +617,108 @@ bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
return 0;
}
+#ifdef SO_RERROR
+static void
+bsd_route_overflow(int sock, void *ctx, struct bsd_driver_global *global)
+{
+ char event_buf[2048]; /* max size of a single route(4) msg */
+ int n;
+ struct ifaddrs *ifaddrs, *ifa;
+ struct bsd_driver_data *drv;
+ struct sockaddr_dl *sdl;
+ union wpa_event_data event;
+
+ /* We need to match the system state, so drain the route
+ * socket to avoid stale messages. */
+ do {
+ n = read(sock, event_buf, sizeof(event_buf));
+ } while (n != -1 || errno == ENOBUFS);
+
+ if (getifaddrs(&ifaddrs) == -1) {
+ wpa_printf(MSG_ERROR, "%s getifaddrs() failed: %s",
+ __func__, strerror(errno));
+ return;
+ }
+
+ /* add or update existing interfaces */
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL ||
+ ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+ sdl = (struct sockaddr_dl *) (void *) ifa->ifa_addr;
+ drv = bsd_get_drvname(global, ifa->ifa_name);
+ if (drv != NULL &&
+ (drv->ifindex != sdl->sdl_index || drv->if_removed)) {
+ wpa_printf(MSG_DEBUG,
+ "RTM_IFANNOUNCE: Interface '%s' added",
+ drv->ifname);
+ drv->ifindex = sdl->sdl_index;
+ drv->if_removed = 0;
+ event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+ os_strlcpy(event.interface_status.ifname, ifa->ifa_name,
+ sizeof(event.interface_status.ifname));
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ }
+ if (!drv &&
+ (drv = bsd_get_drvindex(global, sdl->sdl_index)) != NULL) {
+ /* Driver name is invalid */
+ wpa_printf(MSG_DEBUG,
+ "RTM_IFANNOUNCE: Interface '%s' removed",
+ drv->ifname);
+ drv->if_removed = 1;
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ os_strlcpy(event.interface_status.ifname, drv->ifname,
+ sizeof(event.interface_status.ifname));
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ }
+ }
+
+ /* punt missing interfaces and update flags */
+ dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) {
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL ||
+ ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+ sdl = (struct sockaddr_dl *) (void *) ifa->ifa_addr;
+ if (os_strcmp(drv->ifname, ifa->ifa_name) == 0)
+ break;
+ }
+ if (ifa == NULL && !drv->if_removed) {
+ wpa_printf(MSG_DEBUG,
+ "RTM_IFANNOUNCE: Interface '%s' removed",
+ drv->ifname);
+ drv->if_removed = 1;
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ os_strlcpy(event.interface_status.ifname, drv->ifname,
+ sizeof(event.interface_status.ifname));
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ }
+ if (!ifa)
+ continue;
+
+ if ((ifa->ifa_flags & IFF_UP) == 0 &&
+ (drv->flags & IFF_UP) != 0) {
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
+ drv->ifname);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
+ NULL);
+ } else if ((ifa->ifa_flags & IFF_UP) != 0 &&
+ (drv->flags & IFF_UP) == 0) {
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
+ drv->ifname);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+ NULL);
+ }
+ drv->flags = ifa->ifa_flags;
+ }
+
+ freeifaddrs(ifaddrs);
+}
+#endif /* SO_RERROR */
+
static void
bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
{
@@ -633,6 +739,10 @@ bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
if (errno != EINTR && errno != EAGAIN)
wpa_printf(MSG_ERROR, "%s read() failed: %s",
__func__, strerror(errno));
+#ifdef SO_RERROR
+ if (errno == ENOBUFS)
+ bsd_route_overflow(sock, ctx, sock_ctx);
+#endif /* SO_RERROR */
return;
}
@@ -1468,6 +1578,9 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv)
drv->global = priv;
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ /* Set the interface as removed until proven to work. */
+ drv->if_removed = 1;
+
if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
__func__, strerror(errno));
@@ -1495,6 +1608,9 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv)
if (bsd_get_iface_flags(drv) < 0)
goto fail;
+ /* Proven to work, lets go! */
+ drv->if_removed = 0;
+
drv->opmode = get80211opmode(drv);
dl_list_add(&drv->global->ifaces, &drv->list);
@@ -1560,14 +1676,15 @@ bsd_global_init(void *ctx)
global->ctx = ctx;
dl_list_init(&global->ifaces);
- global->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ global->sock = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (global->sock < 0) {
wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
strerror(errno));
goto fail1;
}
- global->route = socket(PF_ROUTE, SOCK_RAW, 0);
+ global->route = socket(PF_ROUTE,
+ SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (global->route < 0) {
wpa_printf(MSG_ERROR, "socket[PF_ROUTE,SOCK_RAW]: %s",
strerror(errno));
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 23a6a429..a7ebe956 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -328,6 +328,7 @@ const char * driver_flag2_to_string(u64 flag2)
#define DF2S(x) case WPA_DRIVER_FLAGS2_ ## x: return #x
switch (flag2) {
DF2S(CONTROL_PORT_RX);
+ DF2S(CONTROL_PORT_TX_STATUS);
}
return "UNKNOWN";
#undef DF2S
diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c
index 36a0757f..3dba13ce 100644
--- a/src/drivers/driver_macsec_linux.c
+++ b/src/drivers/driver_macsec_linux.c
@@ -712,6 +712,9 @@ static int macsec_drv_set_receive_lowest_pn(void *priv, struct receive_sa *sa)
if (!msg)
return ret;
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci)))
+ goto nla_put_failure;
+
nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
if (!nest)
goto nla_put_failure;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 51674f0f..5d4f71e0 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -37,7 +37,9 @@
#include "radiotap_iter.h"
#include "rfkill.h"
#include "driver_nl80211.h"
-
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+#include "common/brcm_vendor.h"
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
#ifndef NETLINK_CAP_ACK
#define NETLINK_CAP_ACK 10
@@ -278,6 +280,43 @@ static int ack_handler(struct nl_msg *msg, void *arg)
return NL_STOP;
}
+
+struct nl80211_ack_ext_arg {
+ int *err;
+ void *ext_data;
+};
+
+
+static int ack_handler_cookie(struct nl_msg *msg, void *arg)
+{
+ struct nl80211_ack_ext_arg *ext_arg = arg;
+ struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
+ u64 *cookie = ext_arg->ext_data;
+ struct nlattr *attrs;
+ size_t ack_len, attr_len;
+
+ *ext_arg->err = 0;
+ ack_len = sizeof(struct nlmsghdr) + sizeof(int) +
+ sizeof(struct nlmsghdr);
+ attrs = (struct nlattr *)
+ ((u8 *) nlmsg_data(nlmsg_hdr(msg)) + sizeof(struct nlmsghdr) +
+ sizeof(int));
+ if (nlmsg_hdr(msg)->nlmsg_len <= ack_len)
+ return NL_STOP;
+
+ attr_len = nlmsg_hdr(msg)->nlmsg_len - ack_len;
+
+ if(!(nlmsg_hdr(msg)->nlmsg_flags & NLM_F_ACK_TLVS))
+ return NL_STOP;
+
+ nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, attr_len, NULL);
+ if (tb[NLMSGERR_ATTR_COOKIE])
+ *cookie = nla_get_u64(tb[NLMSGERR_ATTR_COOKIE]);
+
+ return NL_STOP;
+}
+
+
static int finish_handler(struct nl_msg *msg, void *arg)
{
int *ret = arg;
@@ -352,7 +391,9 @@ static void nl80211_nlmsg_clear(struct nl_msg *msg)
static int send_and_recv(struct nl80211_global *global,
struct nl_sock *nl_handle, struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
- void *valid_data)
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *, void *),
+ void *ack_data)
{
struct nl_cb *cb;
int err = -ENOMEM, opt;
@@ -390,7 +431,15 @@ static int send_and_recv(struct nl80211_global *global,
nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
- nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+ if (ack_handler_custom) {
+ struct nl80211_ack_ext_arg *ext_arg = ack_data;
+
+ ext_arg->err = &err;
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM,
+ ack_handler_custom, ack_data);
+ } else {
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+ }
if (valid_handler)
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
@@ -420,8 +469,8 @@ static int send_and_recv(struct nl80211_global *global,
}
out:
nl_cb_put(cb);
- if (!valid_handler && valid_data == (void *) -1)
- nl80211_nlmsg_clear(msg);
+ /* Always clear the message as it can potentially contain keys */
+ nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return err;
}
@@ -430,10 +479,13 @@ static int send_and_recv(struct nl80211_global *global,
int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
- void *valid_data)
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *, void *),
+ void *ack_data)
{
return send_and_recv(drv->global, drv->global->nl, msg,
- valid_handler, valid_data);
+ valid_handler, valid_data,
+ ack_handler_custom, ack_data);
}
@@ -447,8 +499,14 @@ static int send_and_recv_msgs_owner(struct wpa_driver_nl80211_data *drv,
struct nl_sock *handle, int set_owner,
int (*valid_handler)(struct nl_msg *,
void *),
- void *valid_data)
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *,
+ void *),
+ void *ack_data)
{
+ if (!msg)
+ return -ENOMEM;
+
/* Control port over nl80211 needs the flags and attributes below.
*
* The Linux kernel has initial checks for them (in nl80211.c) like:
@@ -469,7 +527,8 @@ static int send_and_recv_msgs_owner(struct wpa_driver_nl80211_data *drv,
return -1;
return send_and_recv(drv->global, handle ? handle : drv->global->nl,
- msg, valid_handler, valid_data);
+ msg, valid_handler, valid_data,
+ ack_handler_custom, ack_data);
}
@@ -537,7 +596,8 @@ static int nl_get_multicast_id(struct nl80211_global *global,
return -1;
}
- ret = send_and_recv(global, global->nl, msg, family_handler, &res);
+ ret = send_and_recv(global, global->nl, msg, family_handler, &res,
+ NULL, NULL);
if (ret == 0)
ret = res.id;
return ret;
@@ -617,6 +677,7 @@ struct wiphy_idx_data {
int wiphy_idx;
enum nl80211_iftype nlmode;
u8 *macaddr;
+ u8 use_4addr;
};
@@ -639,6 +700,9 @@ static int netdev_info_handler(struct nl_msg *msg, void *arg)
os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
ETH_ALEN);
+ if (tb[NL80211_ATTR_4ADDR])
+ info->use_4addr = nla_get_u8(tb[NL80211_ATTR_4ADDR]);
+
return NL_SKIP;
}
@@ -654,7 +718,8 @@ int nl80211_get_wiphy_index(struct i802_bss *bss)
if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
return -1;
- if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+ if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
+ NULL, NULL) == 0)
return data.wiphy_idx;
return -1;
}
@@ -671,7 +736,8 @@ static enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
return NL80211_IFTYPE_UNSPECIFIED;
- if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+ if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
+ NULL, NULL) == 0)
return data.nlmode;
return NL80211_IFTYPE_UNSPECIFIED;
}
@@ -687,7 +753,23 @@ static int nl80211_get_macaddr(struct i802_bss *bss)
if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
return -1;
- return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data);
+ return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
+ NULL, NULL);
+}
+
+
+static int nl80211_get_4addr(struct i802_bss *bss)
+{
+ struct nl_msg *msg;
+ struct wiphy_idx_data data = {
+ .use_4addr = 0,
+ };
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)) ||
+ send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
+ NULL, NULL))
+ return -1;
+ return data.use_4addr;
}
@@ -707,7 +789,8 @@ static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
return -1;
}
- ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
+ ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL,
+ NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
"failed: ret=%d (%s)",
@@ -1200,6 +1283,10 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
NULL);
}
+ } else if (ifi->ifi_flags & IFF_UP) {
+ /* Re-read MAC address as it may have changed */
+ nl80211_refresh_mac(drv, ifi->ifi_index, 1);
+ return;
}
/*
@@ -1403,7 +1490,7 @@ try_again:
os_memset(&arg, 0, sizeof(arg));
arg.drv = drv;
ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
- &arg);
+ &arg, NULL, NULL);
if (ret == -EAGAIN) {
count++;
if (count >= 10) {
@@ -1437,7 +1524,7 @@ try_again:
os_memset(&arg, 0, sizeof(arg));
arg.drv = drv;
ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
- &arg);
+ &arg, NULL, NULL);
if (ret == -EAGAIN) {
count++;
if (count >= 10) {
@@ -1540,7 +1627,7 @@ int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
return -ENOBUFS;
}
- return send_and_recv_msgs(drv, msg, get_link_signal, sig);
+ return send_and_recv_msgs(drv, msg, get_link_signal, sig, NULL, NULL);
}
@@ -1597,7 +1684,8 @@ int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
sig_change->frequency = drv->assoc_freq;
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
- return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
+ return send_and_recv_msgs(drv, msg, get_link_noise, sig_change,
+ NULL, NULL);
}
@@ -1661,7 +1749,7 @@ static int nl80211_channel_info(void *priv, struct wpa_channel_info *ci)
struct nl_msg *msg;
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
- return send_and_recv_msgs(drv, msg, get_channel_info, ci);
+ return send_and_recv_msgs(drv, msg, get_channel_info, ci, NULL, NULL);
}
@@ -1710,7 +1798,7 @@ static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
nlmsg_free(msg);
return -EINVAL;
}
- if (send_and_recv_msgs(drv, msg, NULL, NULL))
+ if (send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL))
return -EINVAL;
return 0;
}
@@ -1746,7 +1834,8 @@ static int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
alpha2[0] = '\0';
- ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2);
+ ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2,
+ NULL, NULL);
if (!alpha2[0])
ret = -1;
@@ -2111,6 +2200,11 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
goto failed;
+ if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS) {
+ drv->control_port_ap = 1;
+ goto skip_wifi_status;
+ }
+
drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
if (drv->eapol_tx_sock < 0)
goto failed;
@@ -2121,17 +2215,20 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
&enabled, sizeof(enabled)) < 0) {
wpa_printf(MSG_DEBUG,
- "nl80211: wifi status sockopt failed\n");
+ "nl80211: wifi status sockopt failed: %s",
+ strerror(errno));
drv->data_tx_status = 0;
if (!drv->use_monitor)
drv->capa.flags &=
~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
} else {
- eloop_register_read_sock(drv->eapol_tx_sock,
+ eloop_register_read_sock(
+ drv->eapol_tx_sock,
wpa_driver_nl80211_handle_eapol_tx_status,
drv, NULL);
}
}
+skip_wifi_status:
if (drv->global) {
nl80211_check_global(drv->global);
@@ -2187,7 +2284,8 @@ static int nl80211_register_frame(struct i802_bss *bss,
return -1;
}
- ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
+ ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL,
+ NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
"failed (type=%u): ret=%d (%s)",
@@ -2253,6 +2351,14 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
(u8 *) "\x03\x00", 2, false);
}
+#ifdef CONFIG_PASN
+ /* register for PASN Authentication frames */
+ if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ nl80211_register_frame(bss, bss->nl_mgmt, type,
+ (u8 *) "\x07\x00", 2, false))
+ ret = -1;
+#endif /* CONFIG_PASN */
+
#ifdef CONFIG_INTERWORKING
/* QoS Map Configure */
if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
@@ -2372,7 +2478,8 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
ret = -1;
/* Radio Measurement - Radio Measurement Request */
- if (nl80211_register_action_frame(bss, (u8 *) "\x05\x00", 2) < 0)
+ if (!drv->no_rrm &&
+ nl80211_register_action_frame(bss, (u8 *) "\x05\x00", 2) < 0)
ret = -1;
/* Radio Measurement - Link Measurement Request */
@@ -2380,6 +2487,10 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
(nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
ret = -1;
+ /* Robust AV MSCS Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x13\x05", 2) < 0)
+ ret = -1;
+
nl80211_mgmt_handle_register_eloop(bss);
return ret;
@@ -2426,7 +2537,8 @@ static int nl80211_register_spurious_class3(struct i802_bss *bss)
int ret;
msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
- ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL);
+ ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL,
+ NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
"failed: ret=%d (%s)",
@@ -2580,7 +2692,7 @@ static void nl80211_del_p2pdev(struct i802_bss *bss)
int ret;
msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
- ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
bss->ifname, (long long unsigned int) bss->wdev_id,
@@ -2595,7 +2707,7 @@ static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
msg = nl80211_cmd_msg(bss, 0, start ? NL80211_CMD_START_P2P_DEVICE :
NL80211_CMD_STOP_P2P_DEVICE);
- ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
start ? "Start" : "Stop",
@@ -2666,7 +2778,8 @@ static void qca_vendor_test(struct wpa_driver_nl80211_data *drv)
}
nla_nest_end(msg, params);
- ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv);
+ ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv,
+ NULL, NULL);
wpa_printf(MSG_DEBUG,
"nl80211: QCA vendor test command returned %d (%s)",
ret, strerror(-ret));
@@ -2791,7 +2904,7 @@ static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss)
drv->ifindex);
nl80211_put_wiphy_data_ap(bss);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -2895,6 +3008,7 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
os_free(drv->filter_ssids);
os_free(drv->auth_ie);
+ os_free(drv->auth_data);
if (drv->in_interface_list)
dl_list_del(&drv->list);
@@ -2906,6 +3020,9 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
os_free(drv->iface_ext_capa[i].ext_capa_mask);
}
os_free(drv->first_bss);
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ os_free(drv->pending_roam_data);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
os_free(drv);
}
@@ -3033,6 +3150,98 @@ static int wpa_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
return num_suites;
}
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+static int wpa_driver_do_broadcom_acs(void *priv, struct drv_acs_params
+ *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *data;
+ int freq_list_len;
+ int ret = 0;
+ do {
+ freq_list_len =
+ int_array_len(params->freq_list);
+ wpa_printf(MSG_DEBUG, "%s: freq_list_len=%d",
+ __FUNCTION__, freq_list_len);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ if (!msg) {
+ wpa_printf(MSG_ERROR, "%s: *errof, no memory for msg", __FUNCTION__);
+ return ret;
+ }
+ if ((nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM))) {
+ wpa_printf(MSG_ERROR, "%s: *errof, NL80211_ATTR_VENDOR_ID",
+ __FUNCTION__);
+ nlmsg_free(msg);
+ return ret;
+ }
+
+ if ((nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, BRCM_VENDOR_SCMD_ACS))) {
+ wpa_printf(MSG_ERROR, "%s: *errof, NL80211_ATTR_VENDOR_SUBCMD",
+ __FUNCTION__);
+ nlmsg_free(msg);
+ return ret;
+ }
+ if (!(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA))) {
+ wpa_printf(MSG_ERROR, "%s: *errof, NL80211_ATTR_VENDOR_DATA", __FUNCTION__);
+ nlmsg_free(msg);
+ return ret;
+ }
+ if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HW_MODE, params->hw_mode))) {
+ wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_HW_MODE",
+ __FUNCTION__);
+ nlmsg_free(msg);
+ return ret;
+ }
+ if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT_ENABLED, params->ht_enabled))) {
+ wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_HT_ENABLED",
+ __FUNCTION__);
+ nlmsg_free(msg);
+ return ret;
+ }
+ if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED, params->ht40_enabled))) {
+ wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED",
+ __FUNCTION__);
+ nlmsg_free(msg);
+ return ret;
+ }
+ if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED, params->vht_enabled))) {
+ wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED",
+ __FUNCTION__);
+ nlmsg_free(msg);
+ return ret;
+ }
+ if ((nla_put_u16(msg, BRCM_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width))) {
+ wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_CHWIDTH",
+ __FUNCTION__);
+ nlmsg_free(msg);
+ return ret;
+ }
+ wpa_printf(MSG_DEBUG, "%s: ht40=%d, ch_width=%d\n",
+ __FUNCTION__, params->ht40_enabled, params->ch_width);
+ if ((freq_list_len > 0) && (nla_put(msg, BRCM_VENDOR_ATTR_ACS_FREQ_LIST,
+ sizeof(int) * freq_list_len, params->freq_list))) {
+ wpa_printf(MSG_ERROR, "%s: *error, BRCM_VENDOR_ATTR_ACS_FREQ_LIST,"
+ "list_len=%d\n", __FUNCTION__, freq_list_len);
+ nlmsg_free(msg);
+ return ret;
+ }
+ nla_nest_end(msg, data);
+ wpa_printf(MSG_DEBUG, "nl80211: ACS Params: HW_MODE: %d HT: %d HT40:"
+ " %d VHT: %d BW: %d\n",
+ params->hw_mode, params->ht_enabled, params->ht40_enabled,
+ params->vht_enabled, params->ch_width);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to invoke vendor"
+ " driver ACS function: %s\n",
+ strerror(errno));
+ }
+ } while (0);
+ return ret;
+}
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
#ifdef CONFIG_DRIVER_NL80211_QCA
static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
@@ -3053,7 +3262,7 @@ static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
nlmsg_free(msg);
return -1;
}
- ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Key management set key failed: ret=%d (%s)",
@@ -3065,6 +3274,36 @@ static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
#endif /* CONFIG_DRIVER_NL80211_QCA */
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+static int key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
+ const u8 *key, size_t key_len)
+{
+ struct nl_msg *msg;
+ int ret;
+ struct nlattr *params;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ BRCM_VENDOR_SUBCMD_SET_PMK) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put(msg, BRCM_ATTR_DRIVER_KEY_PMK, key_len, key)) {
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+ nla_nest_end(msg, params);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Key mgmt set key failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+
+ return ret;
+}
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+
static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
const u8 *key, size_t key_len,
const u8 *addr)
@@ -3093,7 +3332,7 @@ static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)",
ret, strerror(-ret));
@@ -3152,6 +3391,12 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
if (key_flag & KEY_FLAG_PMK) {
if (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)
return nl80211_set_pmk(drv, key, key_len, addr);
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ if (drv->vendor_set_pmk) {
+ wpa_printf(MSG_INFO, "nl80211: key_mgmt_set_key with key_len %lu", (unsigned long) key_len);
+ return key_mgmt_set_key(drv, key, key_len);
+ }
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
/* The driver does not have any offload mechanism for PMK, so
* there is no need to configure this key. */
return 0;
@@ -3259,7 +3504,7 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
goto fail;
}
- ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
ret = 0;
if (ret)
@@ -3321,7 +3566,7 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
goto fail;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG,
"nl80211: set_key default failed; err=%d %s",
@@ -3445,9 +3690,10 @@ int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
}
if (nl_connect)
- ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL);
+ ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL,
+ NULL, NULL);
else
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: MLME command failed: reason=%u ret=%d (%s)",
@@ -3543,6 +3789,16 @@ static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
}
}
+ os_free(drv->auth_data);
+ drv->auth_data = NULL;
+ drv->auth_data_len = 0;
+ if (params->auth_data) {
+ drv->auth_data = os_memdup(params->auth_data,
+ params->auth_data_len);
+ if (drv->auth_data)
+ drv->auth_data_len = params->auth_data_len;
+ }
+
for (i = 0; i < 4; i++) {
if (params->wep_key[i] && params->wep_key_len[i] &&
params->wep_key_len[i] <= 16) {
@@ -3695,7 +3951,7 @@ retry:
goto fail;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
@@ -3796,6 +4052,8 @@ int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv)
params.ie = drv->auth_ie;
params.ie_len = drv->auth_ie_len;
+ params.auth_data = drv->auth_data;
+ params.auth_data_len = drv->auth_data_len;
for (i = 0; i < 4; i++) {
if (drv->auth_wep_key_len[i]) {
@@ -3877,15 +4135,26 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
encrypt = 0;
}
- if (freq == 0 && drv->nlmode == NL80211_IFTYPE_STATION &&
- (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
- !(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ if (is_sta_interface(drv->nlmode) &&
WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
- freq = nl80211_get_assoc_freq(drv);
- wpa_printf(MSG_DEBUG,
- "nl80211: send_mlme - Use assoc_freq=%u for external auth",
- freq);
+ if (freq == 0 &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+ freq = nl80211_get_assoc_freq(drv);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_mlme - Use assoc_freq=%u for external auth",
+ freq);
+ }
+
+ /* Allow off channel for PASN authentication */
+ if (data_len >= IEEE80211_HDRLEN + 2 &&
+ WPA_GET_LE16(data + IEEE80211_HDRLEN) == WLAN_AUTH_PASN &&
+ !offchanok) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_mlme: allow off channel for PASN");
+ offchanok = 1;
+ }
}
if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
@@ -3973,7 +4242,7 @@ static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
return -ENOBUFS;
}
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -4017,7 +4286,7 @@ static int wpa_driver_nl80211_set_acl(void *priv,
}
nlmsg_free(acl);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
ret, strerror(-ret));
@@ -4069,7 +4338,7 @@ static int nl80211_set_mesh_config(void *priv,
return ret;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_ERROR,
"nl80211: Mesh config set failed: %d (%s)",
@@ -4081,11 +4350,12 @@ static int nl80211_set_mesh_config(void *priv,
#endif /* CONFIG_MESH */
-static int nl80211_put_beacon_rate(struct nl_msg *msg, const u64 flags,
+static int nl80211_put_beacon_rate(struct nl_msg *msg, u64 flags, u64 flags2,
struct wpa_driver_ap_params *params)
{
struct nlattr *bands, *band;
struct nl80211_txrate_vht vht_rate;
+ struct nl80211_txrate_he he_rate;
if (!params->freq ||
(params->beacon_rate == 0 &&
@@ -4102,7 +4372,10 @@ static int nl80211_put_beacon_rate(struct nl_msg *msg, const u64 flags,
band = nla_nest_start(msg, NL80211_BAND_2GHZ);
break;
case HOSTAPD_MODE_IEEE80211A:
- band = nla_nest_start(msg, NL80211_BAND_5GHZ);
+ if (is_6ghz_freq(params->freq->freq))
+ band = nla_nest_start(msg, NL80211_BAND_6GHZ);
+ else
+ band = nla_nest_start(msg, NL80211_BAND_5GHZ);
break;
case HOSTAPD_MODE_IEEE80211AD:
band = nla_nest_start(msg, NL80211_BAND_60GHZ);
@@ -4115,6 +4388,7 @@ static int nl80211_put_beacon_rate(struct nl_msg *msg, const u64 flags,
return -1;
os_memset(&vht_rate, 0, sizeof(vht_rate));
+ os_memset(&he_rate, 0, sizeof(he_rate));
switch (params->rate_type) {
case BEACON_RATE_LEGACY:
@@ -4167,6 +4441,22 @@ static int nl80211_put_beacon_rate(struct nl_msg *msg, const u64 flags,
wpa_printf(MSG_DEBUG, " * beacon_rate = VHT-MCS %u",
params->beacon_rate);
break;
+ case BEACON_RATE_HE:
+ if (!(flags2 & WPA_DRIVER_FLAGS2_BEACON_RATE_HE)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (HE)");
+ return -1;
+ }
+ he_rate.mcs[0] = BIT(params->beacon_rate);
+ if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
+ nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
+ nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate) ||
+ nla_put(msg, NL80211_TXRATE_HE, sizeof(he_rate), &he_rate))
+ return -1;
+ wpa_printf(MSG_DEBUG, " * beacon_rate = HE-MCS %u",
+ params->beacon_rate);
+ break;
}
nla_nest_end(msg, band);
@@ -4194,7 +4484,7 @@ static int nl80211_set_multicast_to_unicast(struct i802_bss *bss,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
switch (ret) {
case 0:
@@ -4222,6 +4512,93 @@ static int nl80211_set_multicast_to_unicast(struct i802_bss *bss,
}
+#ifdef CONFIG_SAE
+static int nl80211_put_sae_pwe(struct nl_msg *msg, int pwe)
+{
+ u8 sae_pwe;
+
+ wpa_printf(MSG_DEBUG, "nl802111: sae_pwe=%d", pwe);
+ if (pwe == 0)
+ sae_pwe = NL80211_SAE_PWE_HUNT_AND_PECK;
+ else if (pwe == 1)
+ sae_pwe = NL80211_SAE_PWE_HASH_TO_ELEMENT;
+ else if (pwe == 2)
+ sae_pwe = NL80211_SAE_PWE_BOTH;
+ else if (pwe == 3)
+ return 0; /* special test mode */
+ else
+ return -1;
+ if (nla_put_u8(msg, NL80211_ATTR_SAE_PWE, sae_pwe))
+ return -1;
+
+ return 0;
+}
+#endif /* CONFIG_SAE */
+
+
+#ifdef CONFIG_FILS
+static int nl80211_fils_discovery(struct i802_bss *bss, struct nl_msg *msg,
+ struct wpa_driver_ap_params *params)
+{
+ struct nlattr *attr;
+
+ if (!bss->drv->fils_discovery) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Driver does not support FILS Discovery frame transmission for %s",
+ bss->ifname);
+ return -1;
+ }
+
+ attr = nla_nest_start(msg, NL80211_ATTR_FILS_DISCOVERY);
+ if (!attr ||
+ nla_put_u32(msg, NL80211_FILS_DISCOVERY_ATTR_INT_MIN,
+ params->fd_min_int) ||
+ nla_put_u32(msg, NL80211_FILS_DISCOVERY_ATTR_INT_MAX,
+ params->fd_max_int) ||
+ (params->fd_frame_tmpl &&
+ nla_put(msg, NL80211_FILS_DISCOVERY_ATTR_TMPL,
+ params->fd_frame_tmpl_len, params->fd_frame_tmpl)))
+ return -1;
+
+ nla_nest_end(msg, attr);
+ return 0;
+}
+#endif /* CONFIG_FILS */
+
+
+#ifdef CONFIG_IEEE80211AX
+static int nl80211_unsol_bcast_probe_resp(struct i802_bss *bss,
+ struct nl_msg *msg,
+ struct wpa_driver_ap_params *params)
+{
+ struct nlattr *attr;
+
+ if (!bss->drv->unsol_bcast_probe_resp) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Driver does not support unsolicited broadcast Probe Response frame transmission for %s",
+ bss->ifname);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Unsolicited broadcast Probe Response frame interval: %u",
+ params->unsol_bcast_probe_resp_interval);
+ attr = nla_nest_start(msg, NL80211_ATTR_UNSOL_BCAST_PROBE_RESP);
+ if (!attr ||
+ nla_put_u32(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT,
+ params->unsol_bcast_probe_resp_interval) ||
+ (params->unsol_bcast_probe_resp_tmpl &&
+ nla_put(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL,
+ params->unsol_bcast_probe_resp_tmpl_len,
+ params->unsol_bcast_probe_resp_tmpl)))
+ return -1;
+
+ nla_nest_end(msg, attr);
+ return 0;
+}
+#endif /* CONFIG_IEEE80211AX */
+
+
static int wpa_driver_nl80211_set_ap(void *priv,
struct wpa_driver_ap_params *params)
{
@@ -4265,7 +4642,8 @@ static int wpa_driver_nl80211_set_ap(void *priv,
nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
params->tail) ||
nl80211_put_beacon_int(msg, params->beacon_int) ||
- nl80211_put_beacon_rate(msg, drv->capa.flags, params) ||
+ nl80211_put_beacon_rate(msg, drv->capa.flags, drv->capa.flags2,
+ params) ||
nl80211_put_dtim_period(msg, params->dtim_period) ||
nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
goto fail;
@@ -4443,17 +4821,34 @@ static int wpa_driver_nl80211_set_ap(void *priv,
}
#ifdef CONFIG_IEEE80211AX
- if (params->he_spr) {
+ if (params->he_spr_ctrl) {
struct nlattr *spr;
spr = nla_nest_start(msg, NL80211_ATTR_HE_OBSS_PD);
- wpa_printf(MSG_DEBUG, "nl80211: he_spr=%d", params->he_spr);
+ wpa_printf(MSG_DEBUG, "nl80211: he_spr_ctrl=0x%x",
+ params->he_spr_ctrl);
if (!spr ||
- nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
- params->he_spr_srg_obss_pd_min_offset) ||
- nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
- params->he_spr_srg_obss_pd_max_offset))
+ nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_SR_CTRL,
+ params->he_spr_ctrl) ||
+ ((params->he_spr_ctrl &
+ SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) &&
+ nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET,
+ params->he_spr_non_srg_obss_pd_max_offset)))
+ goto fail;
+
+ if ((params->he_spr_ctrl &
+ SPATIAL_REUSE_SRG_INFORMATION_PRESENT) &&
+ (nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
+ params->he_spr_srg_obss_pd_min_offset) ||
+ nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
+ params->he_spr_srg_obss_pd_max_offset) ||
+ nla_put(msg, NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP,
+ sizeof(params->he_spr_bss_color_bitmap),
+ params->he_spr_bss_color_bitmap) ||
+ nla_put(msg, NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP,
+ sizeof(params->he_spr_partial_bssid_bitmap),
+ params->he_spr_partial_bssid_bitmap)))
goto fail;
nla_nest_end(msg, spr);
@@ -4480,10 +4875,26 @@ static int wpa_driver_nl80211_set_ap(void *priv,
if (nla_put_flag(msg, NL80211_ATTR_TWT_RESPONDER))
goto fail;
}
+
+ if (params->unsol_bcast_probe_resp_interval &&
+ nl80211_unsol_bcast_probe_resp(bss, msg, params) < 0)
+ goto fail;
#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_SAE
+ if (((params->key_mgmt_suites & WPA_KEY_MGMT_SAE) ||
+ (params->key_mgmt_suites & WPA_KEY_MGMT_FT_SAE)) &&
+ nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
+ goto fail;
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_FILS
+ if (params->fd_max_int && nl80211_fils_discovery(bss, msg, params) < 0)
+ goto fail;
+#endif /* CONFIG_FILS */
+
ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1,
- NULL, NULL);
+ NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
ret, strerror(-ret));
@@ -4652,7 +5063,7 @@ static int nl80211_set_channel(struct i802_bss *bss,
return -1;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret == 0) {
bss->freq = freq->freq;
return 0;
@@ -4782,6 +5193,16 @@ static int wpa_driver_nl80211_sta_add(void *priv,
goto fail;
}
+ if (params->he_6ghz_capab) {
+ wpa_hexdump(MSG_DEBUG, " * he_6ghz_capab",
+ params->he_6ghz_capab,
+ sizeof(*params->he_6ghz_capab));
+ if (nla_put(msg, NL80211_ATTR_HE_6GHZ_CAPABILITY,
+ sizeof(*params->he_6ghz_capab),
+ params->he_6ghz_capab))
+ goto fail;
+ }
+
if (params->ext_capab) {
wpa_hexdump(MSG_DEBUG, " * ext_capab",
params->ext_capab, params->ext_capab_len);
@@ -4930,7 +5351,7 @@ static int wpa_driver_nl80211_sta_add(void *priv,
nla_nest_end(msg, wme);
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
@@ -5002,7 +5423,7 @@ static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
" --> %d (%s)",
bss->ifname, MAC2STR(addr), ret, strerror(-ret));
@@ -5033,7 +5454,7 @@ void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
}
msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
- if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+ if (send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL) == 0)
return;
wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
}
@@ -5113,7 +5534,11 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
goto fail;
- ret = send_and_recv_msgs(drv, msg, handler, arg);
+ if ((addr && iftype == NL80211_IFTYPE_P2P_DEVICE) &&
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
+ goto fail;
+
+ ret = send_and_recv_msgs(drv, msg, handler, arg, NULL, NULL);
msg = NULL;
if (ret) {
fail:
@@ -5268,8 +5693,10 @@ static int nl80211_tx_control_port(void *priv, const u8 *dest,
u16 proto, const u8 *buf, size_t len,
int no_encrypt)
{
+ struct nl80211_ack_ext_arg ext_arg;
struct i802_bss *bss = priv;
struct nl_msg *msg;
+ u64 cookie = 0;
int ret;
wpa_printf(MSG_DEBUG,
@@ -5288,11 +5715,22 @@ static int nl80211_tx_control_port(void *priv, const u8 *dest,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
- if (ret)
+ os_memset(&ext_arg, 0, sizeof(struct nl80211_ack_ext_arg));
+ ext_arg.ext_data = &cookie;
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL,
+ ack_handler_cookie, &ext_arg);
+ if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: tx_control_port failed: ret=%d (%s)",
ret, strerror(-ret));
+ } else {
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: tx_control_port cookie=0x%llx",
+ (long long unsigned int) cookie);
+ drv->eapol_tx_cookie = cookie;
+ }
return ret;
}
@@ -5444,7 +5882,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
goto fail;
- return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
fail:
nlmsg_free(msg);
return -ENOBUFS;
@@ -5466,7 +5904,7 @@ static int driver_nl80211_sta_set_airtime_weight(void *priv, const u8 *addr,
nla_put_u16(msg, NL80211_ATTR_AIRTIME_WEIGHT, weight))
goto fail;
- return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
fail:
nlmsg_free(msg);
return -ENOBUFS;
@@ -5512,7 +5950,7 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
ret = send_and_recv_msgs_owner(drv, msg,
get_connect_handle(drv->first_bss), 1,
- NULL, NULL);
+ NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
"(%s)", ret, strerror(-ret));
@@ -5646,7 +6084,7 @@ retry:
ret = send_and_recv_msgs_owner(drv, msg,
get_connect_handle(drv->first_bss), 1,
- NULL, NULL);
+ NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
@@ -6019,6 +6457,13 @@ static int wpa_driver_nl80211_try_connect(
nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_OPTIONAL))
goto fail;
+#ifdef CONFIG_SAE
+ if ((params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) &&
+ nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
+ goto fail;
+#endif /* CONFIG_SAE */
+
algs = 0;
if (params->auth_alg & WPA_AUTH_ALG_OPEN)
algs++;
@@ -6048,12 +6493,15 @@ skip_auth_type:
goto fail;
ret = send_and_recv_msgs_owner(drv, msg, nl_connect, 1, NULL,
- (void *) -1);
+ NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
"(%s)", ret, strerror(-ret));
} else {
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ drv->roam_indication_done = false;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
wpa_printf(MSG_DEBUG,
"nl80211: Connect request send successfully");
}
@@ -6164,7 +6612,7 @@ static int wpa_driver_nl80211_associate(
ret = send_and_recv_msgs_owner(drv, msg,
get_connect_handle(drv->first_bss), 1,
- NULL, NULL);
+ NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
@@ -6195,7 +6643,7 @@ static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
if (!msg || nla_put_u32(msg, NL80211_ATTR_IFTYPE, mode))
goto fail;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (!ret)
return 0;
@@ -6361,6 +6809,7 @@ void nl80211_restore_ap_mode(struct i802_bss *bss)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int was_ap = is_ap_interface(drv->nlmode);
+ int br_ifindex;
wpa_driver_nl80211_set_mode(bss, drv->ap_scan_as_station);
if (!was_ap && is_ap_interface(drv->ap_scan_as_station) &&
@@ -6375,6 +6824,8 @@ void nl80211_restore_ap_mode(struct i802_bss *bss)
"nl80211: Failed to add interface %s into bridge %s: %s",
bss->ifname, bss->brname, strerror(errno));
}
+ br_ifindex = if_nametoindex(bss->brname);
+ add_ifidx(drv, br_ifindex, drv->ifindex);
}
drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
}
@@ -6456,7 +6907,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (!ret)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)",
@@ -6521,7 +6972,7 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
memset(seq, 0, 6);
- return send_and_recv_msgs(drv, msg, get_key_handler, seq);
+ return send_and_recv_msgs(drv, msg, get_key_handler, seq, NULL, NULL);
}
@@ -6544,7 +6995,7 @@ static int i802_set_rts(void *priv, int rts)
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (!ret)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
@@ -6572,7 +7023,7 @@ static int i802_set_frag(void *priv, int frag)
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (!ret)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
@@ -6594,7 +7045,7 @@ static int i802_flush(void *priv)
* XXX: FIX! this needs to flush all VLANs too
*/
msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
- res = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ res = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
if (res) {
wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
"(%s)", res, strerror(-res));
@@ -6803,7 +7254,8 @@ static int i802_read_sta_data(struct i802_bss *bss,
return -ENOBUFS;
}
- return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data);
+ return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data,
+ NULL, NULL);
}
@@ -6860,7 +7312,7 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
nla_nest_end(msg, txq);
- res = send_and_recv_msgs(drv, msg, NULL, NULL);
+ res = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
wpa_printf(MSG_DEBUG,
"nl80211: TX queue param set: queue=%d aifs=%d cw_min=%d cw_max=%d burst_time=%d --> res=%d",
queue, aifs, cw_min, cw_max, burst_time, res);
@@ -6886,14 +7338,14 @@ static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
- ((drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) &&
+ (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) &&
nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) ||
nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
nlmsg_free(msg);
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret < 0) {
wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
@@ -7498,8 +7950,10 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
drv->global->if_add_wdevid = p2pdev_info.wdev_id;
drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
- if (!is_zero_ether_addr(p2pdev_info.macaddr))
+ if (!is_zero_ether_addr(p2pdev_info.macaddr)) {
os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
+ os_memcpy(drv->global->p2p_perm_addr, p2pdev_info.macaddr, ETH_ALEN);
+ }
wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
ifname,
(long long unsigned int) p2pdev_info.wdev_id);
@@ -7740,7 +8194,7 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
goto fail;
cookie = 0;
- ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
@@ -7816,6 +8270,28 @@ static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
os_memset(bss->rand_addr, 0, ETH_ALEN);
}
+#ifdef CONFIG_MESH
+ if (is_mesh_interface(drv->nlmode)) {
+ struct hostapd_hw_modes *modes;
+ u16 num_modes, flags;
+ u8 dfs_domain;
+ int i;
+
+ modes = nl80211_get_hw_feature_data(bss, &num_modes,
+ &flags, &dfs_domain);
+ if (dfs_domain != HOSTAPD_DFS_REGION_ETSI &&
+ ieee80211_is_dfs(bss->freq, modes, num_modes))
+ offchanok = 0;
+ if (modes) {
+ for (i = 0; i < num_modes; i++) {
+ os_free(modes[i].channels);
+ os_free(modes[i].rates);
+ }
+ os_free(modes);
+ }
+ }
+#endif /* CONFIG_MESH */
+
if (is_ap_interface(drv->nlmode) &&
(!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
(int) freq == bss->freq || drv->device_ap_sme ||
@@ -7847,7 +8323,7 @@ static void nl80211_frame_wait_cancel(struct i802_bss *bss, u64 cookie)
return;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
"(%s)", ret, strerror(-ret));
@@ -7895,7 +8371,7 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
}
cookie = 0;
- ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
if (ret == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
"0x%llx for freq=%u MHz duration=%u",
@@ -7935,7 +8411,7 @@ static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
return -1;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret == 0)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
@@ -8032,7 +8508,7 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
nla_nest_end(msg, bands);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
"(%s)", ret, strerror(-ret));
@@ -8129,7 +8605,7 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
}
nla_nest_end(msg, cqm);
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -8167,7 +8643,7 @@ static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
struct nl_msg *msg;
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
- return send_and_recv_msgs(drv, msg, get_channel_width, sig);
+ return send_and_recv_msgs(drv, msg, get_channel_width, sig, NULL, NULL);
}
@@ -8230,15 +8706,34 @@ static int nl80211_set_param(void *priv, const char *param)
if (os_strstr(param, "control_port=0")) {
drv->capa.flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
- drv->capa.flags2 &= ~WPA_DRIVER_FLAGS2_CONTROL_PORT_RX;
+ drv->capa.flags2 &= ~(WPA_DRIVER_FLAGS2_CONTROL_PORT_RX |
+ WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS);
+ drv->control_port_ap = 0;
}
if (os_strstr(param, "control_port_ap=1"))
drv->control_port_ap = 1;
+ if (os_strstr(param, "control_port_ap=0")) {
+ drv->capa.flags2 &= ~WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS;
+ drv->control_port_ap = 0;
+ }
+
if (os_strstr(param, "full_ap_client_state=0"))
drv->capa.flags &= ~WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
+ if (os_strstr(param, "no_rrm=1")) {
+ drv->no_rrm = 1;
+
+ if (!bss->in_deinit && !is_ap_interface(drv->nlmode) &&
+ !is_mesh_interface(drv->nlmode)) {
+ nl80211_mgmt_unsubscribe(bss, "no_rrm=1");
+ if (nl80211_mgmt_subscribe_non_ap(bss) < 0)
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to re-register Action frame processing - ignore for now");
+ }
+ }
+
return 0;
}
@@ -8353,7 +8848,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd,
return -ENOBUFS;
}
- return send_and_recv_msgs(bss->drv, msg, NULL, (void *) -1);
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
}
@@ -8418,7 +8913,7 @@ static int nl80211_flush_pmkid(void *priv)
msg = nl80211_bss_msg(bss, 0, NL80211_CMD_FLUSH_PMKSA);
if (!msg)
return -ENOBUFS;
- return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
}
@@ -8583,7 +9078,7 @@ static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
do {
wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
err = send_and_recv_msgs(drv, msg, survey_handler,
- survey_results);
+ survey_results, NULL, NULL);
} while (err > 0);
if (err)
@@ -8623,7 +9118,7 @@ static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
nla_nest_end(msg, replay_nested);
- ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret == -EOPNOTSUPP) {
wpa_printf(MSG_DEBUG,
"nl80211: Driver does not support rekey offload");
@@ -8690,7 +9185,7 @@ static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
return;
}
- ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
MACSTR " failed: ret=%d (%s)",
@@ -8716,7 +9211,7 @@ static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
return -ENOBUFS;
}
- ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
if (ret < 0) {
wpa_printf(MSG_DEBUG,
"nl80211: Setting PS state %s failed: %d (%s)",
@@ -8776,7 +9271,7 @@ static int nl80211_start_radar_detection(void *priv,
return -1;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret == 0)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
@@ -8823,7 +9318,7 @@ static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
nla_put(msg, NL80211_ATTR_IE, len, buf))
goto fail;
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
fail:
nlmsg_free(msg);
@@ -8873,7 +9368,7 @@ static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
return -ENOBUFS;
}
- res = send_and_recv_msgs(drv, msg, NULL, NULL);
+ res = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
wpa_printf(MSG_DEBUG, "nl80211: TDLS_OPER: oper=%d mac=" MACSTR
" --> res=%d (%s)", nl80211_oper, MAC2STR(peer), res,
strerror(-res));
@@ -8907,7 +9402,7 @@ nl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
return ret;
}
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -8933,7 +9428,7 @@ nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
return -ENOBUFS;
}
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
#endif /* CONFIG TDLS */
@@ -9076,7 +9571,7 @@ static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
"err=%d (%s)", ret, strerror(-ret));
@@ -9104,7 +9599,7 @@ static int nl80211_update_dh_ie(void *priv, const u8 *peer_mac,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: update_dh_ie failed err=%d (%s)",
@@ -9309,7 +9804,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG) &&
nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx) == 0) {
if (send_and_recv_msgs(drv, msg, nl80211_get_country,
- alpha2) == 0 &&
+ alpha2, NULL, NULL) == 0 &&
alpha2[0]) {
res = os_snprintf(pos, end - pos, "country=%s\n",
alpha2);
@@ -9460,7 +9955,7 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
goto fail;
nla_nest_end(msg, beacon_csa);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
ret, strerror(-ret));
@@ -9501,7 +9996,7 @@ static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: add_ts failed err=%d (%s)",
ret, strerror(-ret));
@@ -9528,7 +10023,7 @@ static int nl80211_del_ts(void *priv, u8 tsid, const u8 *addr)
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: del_ts failed err=%d (%s)",
ret, strerror(-ret));
@@ -9589,14 +10084,35 @@ static int vendor_reply_handler(struct nl_msg *msg, void *arg)
}
+static bool is_cmd_with_nested_attrs(unsigned int vendor_id,
+ unsigned int subcmd)
+{
+ if (vendor_id != OUI_QCA)
+ return true;
+
+ switch (subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
+ case QCA_NL80211_VENDOR_SUBCMD_STATS_EXT:
+ case QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI:
+ case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY:
+ case QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS:
+ case QCA_NL80211_VENDOR_SUBCMD_NAN:
+ return false;
+ default:
+ return true;
+ }
+}
+
+
static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
unsigned int subcmd, const u8 *data,
- size_t data_len, struct wpabuf *buf)
+ size_t data_len, enum nested_attr nested_attr,
+ struct wpabuf *buf)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int ret;
+ int ret, nla_flag;
#ifdef CONFIG_TESTING_OPTIONS
if (vendor_id == 0xffffffff) {
@@ -9613,7 +10129,8 @@ static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
* of send_and_recv_msgs(). */
ret = send_and_recv_msgs_owner(drv, msg,
get_connect_handle(bss), 0,
- cmd_reply_handler, buf);
+ cmd_reply_handler, buf,
+ NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
ret);
@@ -9621,14 +10138,24 @@ static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
}
#endif /* CONFIG_TESTING_OPTIONS */
+ if (nested_attr == NESTED_ATTR_USED)
+ nla_flag = NLA_F_NESTED;
+ else if (nested_attr == NESTED_ATTR_UNSPECIFIED &&
+ is_cmd_with_nested_attrs(vendor_id, subcmd))
+ nla_flag = NLA_F_NESTED;
+ else
+ nla_flag = 0;
+
if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, vendor_id) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd) ||
(data &&
- nla_put(msg, NL80211_ATTR_VENDOR_DATA, data_len, data)))
+ nla_put(msg, nla_flag | NL80211_ATTR_VENDOR_DATA,
+ data_len, data)))
goto fail;
- ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf);
+ ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf,
+ NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: vendor command failed err=%d",
ret);
@@ -9657,7 +10184,7 @@ static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
@@ -9692,7 +10219,8 @@ static int nl80211_get_wowlan(void *priv)
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_WOWLAN);
- ret = send_and_recv_msgs(drv, msg, get_wowlan_handler, &wowlan_enabled);
+ ret = send_and_recv_msgs(drv, msg, get_wowlan_handler, &wowlan_enabled,
+ NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status failed");
return 0;
@@ -9739,7 +10267,7 @@ static int nl80211_set_wowlan(void *priv,
nla_nest_end(msg, wowlan_triggers);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
@@ -9778,7 +10306,7 @@ static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
}
nla_nest_end(msg, params);
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -9806,15 +10334,15 @@ static int nl80211_disable_fils(void *priv, int disable)
}
nla_nest_end(msg, params);
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
/* Reserved QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID value for wpa_supplicant */
#define WPA_SUPPLICANT_CLIENT_ID 1
-static int nl80211_set_bssid_blacklist(void *priv, unsigned int num_bssid,
- const u8 *bssid)
+static int nl80211_set_bssid_tmp_disallow(void *priv, unsigned int num_bssid,
+ const u8 *bssid)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -9822,7 +10350,8 @@ static int nl80211_set_bssid_blacklist(void *priv, unsigned int num_bssid,
struct nlattr *params, *nlbssids, *attr;
unsigned int i;
- wpa_printf(MSG_DEBUG, "nl80211: Set blacklist BSSID (num=%u)",
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set temporarily disallowed BSSIDs (num=%u)",
num_bssid);
if (!drv->roam_vendor_cmd_avail)
@@ -9862,7 +10391,7 @@ static int nl80211_set_bssid_blacklist(void *priv, unsigned int num_bssid,
nla_nest_end(msg, nlbssids);
nla_nest_end(msg, params);
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
fail:
nlmsg_free(msg);
@@ -9900,7 +10429,7 @@ static int nl80211_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
}
nla_nest_end(msg, params);
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
#endif /* CONFIG_DRIVER_NL80211_QCA */
@@ -9911,10 +10440,45 @@ static int nl80211_set_mac_addr(void *priv, const u8 *addr)
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int new_addr = addr != NULL;
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ struct nl_msg *msg;
+ struct nlattr *params;
+ int ret;
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+ wpa_printf(MSG_DEBUG, "Enter: %s", __FUNCTION__);
if (TEST_FAIL())
return -1;
+ if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ if (!addr ) {
+ addr = drv->global->p2p_perm_addr;
+ }
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ BRCM_VENDOR_SUBCMD_SET_MAC) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put(msg, BRCM_ATTR_DRIVER_MAC_ADDR, ETH_ALEN, addr)) {
+ wpa_printf(MSG_ERROR, "failed to put p2p randmac");
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+ nla_nest_end(msg, params);
+ ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_ERROR, "nl80211: p2p set macaddr failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+ memcpy(bss->addr, addr, ETH_ALEN);
+ return ret;
+#else
+ return -ENOTSUP;
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+ }
if (!addr)
addr = drv->perm_addr;
@@ -9924,27 +10488,26 @@ static int nl80211_set_mac_addr(void *priv, const u8 *addr)
if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, addr) < 0)
{
wpa_printf(MSG_DEBUG,
- "nl80211: failed to set_mac_addr for %s to " MACSTR,
- bss->ifname, MAC2STR(addr));
+ "nl80211: failed to set_mac_addr for %s to " MACSTR,
+ bss->ifname, MAC2STR(addr));
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
- 1) < 0) {
+ 1) < 0) {
wpa_printf(MSG_DEBUG,
- "nl80211: Could not restore interface UP after failed set_mac_addr");
+ "nl80211: Could not restore interface UP after failed set_mac_addr");
}
return -1;
}
wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR,
- bss->ifname, MAC2STR(addr));
+ bss->ifname, MAC2STR(addr));
drv->addr_changed = new_addr;
os_memcpy(bss->addr, addr, ETH_ALEN);
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0)
{
wpa_printf(MSG_DEBUG,
- "nl80211: Could not restore interface UP after set_mac_addr");
+ "nl80211: Could not restore interface UP after set_mac_addr");
}
-
return 0;
}
@@ -10038,6 +10601,9 @@ static int nl80211_join_mesh(struct i802_bss *bss,
wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags);
+ if (params->handle_dfs && nla_put_flag(msg, NL80211_ATTR_HANDLE_DFS))
+ goto fail;
+
container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
if (!container)
goto fail;
@@ -10069,7 +10635,7 @@ static int nl80211_join_mesh(struct i802_bss *bss,
goto fail;
ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1,
- NULL, NULL);
+ NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
@@ -10127,7 +10693,7 @@ static int wpa_driver_nl80211_leave_mesh(void *priv)
wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 0,
- NULL, NULL);
+ NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
ret, strerror(-ret));
@@ -10161,7 +10727,7 @@ static int nl80211_probe_mesh_link(void *priv, const u8 *addr, const u8 *eth,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: mesh link probe to " MACSTR
" failed: ret=%d (%s)",
@@ -10573,7 +11139,7 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
params->hw_mode, params->ht_enabled, params->ht40_enabled,
params->vht_enabled, params->ch_width, params->edmg_enabled);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Failed to invoke driver ACS function: %s",
@@ -10583,44 +11149,55 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
}
-static int nl80211_set_band(void *priv, enum set_band band)
+static int nl80211_set_band(void *priv, u32 band_mask)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct nlattr *data;
int ret;
- enum qca_set_band qca_band;
+ enum qca_set_band qca_band_value;
+ u32 qca_band_mask = QCA_SETBAND_AUTO;
- if (!drv->setband_vendor_cmd_avail)
+ if (!drv->setband_vendor_cmd_avail ||
+ (band_mask > (WPA_SETBAND_2G | WPA_SETBAND_5G | WPA_SETBAND_6G)))
return -1;
- switch (band) {
- case WPA_SETBAND_AUTO:
- qca_band = QCA_SETBAND_AUTO;
- break;
- case WPA_SETBAND_5G:
- qca_band = QCA_SETBAND_5G;
- break;
- case WPA_SETBAND_2G:
- qca_band = QCA_SETBAND_2G;
- break;
- default:
- return -1;
- }
+ if (band_mask & WPA_SETBAND_5G)
+ qca_band_mask |= QCA_SETBAND_5G;
+ if (band_mask & WPA_SETBAND_2G)
+ qca_band_mask |= QCA_SETBAND_2G;
+ if (band_mask & WPA_SETBAND_6G)
+ qca_band_mask |= QCA_SETBAND_6G;
+
+ /*
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE is a legacy interface hence make
+ * it suite to its values (AUTO/5G/2G) for backwards compatibility.
+ */
+ qca_band_value = ((qca_band_mask & QCA_SETBAND_5G) &&
+ (qca_band_mask & QCA_SETBAND_2G)) ?
+ QCA_SETBAND_AUTO :
+ qca_band_mask & ~QCA_SETBAND_6G;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: QCA_BAND_MASK = 0x%x, QCA_BAND_VALUE = %d",
+ qca_band_mask, qca_band_value);
if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
QCA_NL80211_VENDOR_SUBCMD_SETBAND) ||
!(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
- nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE, qca_band)) {
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE,
+ qca_band_value) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_MASK,
+ qca_band_mask)) {
nlmsg_free(msg);
return -ENOBUFS;
}
nla_nest_end(msg, data);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Driver setband function failed: %s",
@@ -10753,7 +11330,8 @@ static int nl80211_get_pref_freq_list(void *priv,
nla_nest_end(msg, params);
os_memset(freq_list, 0, *num * sizeof(freq_list[0]));
- ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, &param);
+ ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, &param,
+ NULL, NULL);
if (ret) {
wpa_printf(MSG_ERROR,
"%s: err in send_and_recv_msgs", __func__);
@@ -10805,7 +11383,7 @@ static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq)
}
nla_nest_end(msg, params);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_ERROR, "%s: err in send_and_recv_msgs",
@@ -10861,7 +11439,7 @@ static int nl80211_p2p_lo_start(void *priv, unsigned int freq,
goto fail;
nla_nest_end(msg, container);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG,
@@ -10896,7 +11474,7 @@ static int nl80211_p2p_lo_stop(void *priv)
return -1;
}
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -10935,7 +11513,7 @@ static int nl80211_set_tdls_mode(void *priv, int tdls_external_control)
nla_nest_end(msg, params);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_ERROR,
@@ -11128,7 +11706,7 @@ nl80211_get_bss_transition_status(void *priv, struct wpa_bss_trans_info *params)
ret = send_and_recv_msgs(drv, msg,
nl80211_get_bss_transition_status_handler,
- info);
+ info, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_ERROR,
@@ -11181,7 +11759,7 @@ static int nl80211_ignore_assoc_disallow(void *priv, int ignore_disallow)
nla_nest_end(msg, attr);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_ERROR,
@@ -11244,6 +11822,10 @@ static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags)
char path[128];
int ret;
+ /* P2P-Device has no netdev that can (or should) be configured here */
+ if (nl80211_get_ifmode(bss) == NL80211_IFTYPE_P2P_DEVICE)
+ return 0;
+
wpa_printf(MSG_DEBUG, "nl80211: Data frame filter flags=0x%x",
filter_flags);
@@ -11384,7 +11966,7 @@ static int nl80211_update_connection_params(
nl80211_put_fils_connect_params(drv, params, msg))
goto fail;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret)
wpa_dbg(drv->ctx, MSG_DEBUG,
@@ -11427,7 +12009,7 @@ static int nl80211_send_external_auth_status(void *priv,
(params->bssid &&
nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid)))
goto fail;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG,
@@ -11467,8 +12049,13 @@ static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname,
bss->added_if_into_bridge = 0;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
+ if (ret && val && nl80211_get_4addr(bss) == 1) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: 4addr mode was already enabled");
+ ret = 0;
+ }
if (!ret) {
if (bridge_ifname[0] && val &&
i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0)
@@ -11633,10 +12220,13 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.get_bss_transition_status = nl80211_get_bss_transition_status,
.ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
#endif /* CONFIG_MBO */
- .set_bssid_blacklist = nl80211_set_bssid_blacklist,
+ .set_bssid_tmp_disallow = nl80211_set_bssid_tmp_disallow,
.add_sta_node = nl80211_add_sta_node,
#endif /* CONFIG_DRIVER_NL80211_QCA */
.configure_data_frame_filters = nl80211_configure_data_frame_filters,
+#if defined(CONFIG_DRIVER_NL80211_BRCM)
+ .do_acs = wpa_driver_do_broadcom_acs,
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
.get_ext_capab = nl80211_get_ext_capab,
.update_connect_params = nl80211_update_connection_params,
.send_external_auth_status = nl80211_send_external_auth_status,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 895f9d72..e7fe1802 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -33,8 +33,8 @@ struct nl80211_global {
struct nl_sock *nl;
int nl80211_id;
int ioctl_sock; /* socket for ioctl() use */
-
struct nl_sock *nl_event;
+ u8 p2p_perm_addr[ETH_ALEN];
};
struct nl80211_wiphy_data {
@@ -173,6 +173,10 @@ struct wpa_driver_nl80211_data {
unsigned int add_sta_node_vendor_cmd_avail:1;
unsigned int control_port_ap:1;
unsigned int multicast_registrations:1;
+ unsigned int no_rrm:1;
+ unsigned int get_sta_info_vendor_cmd_avail:1;
+ unsigned int fils_discovery:1;
+ unsigned int unsol_bcast_probe_resp:1;
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
@@ -180,6 +184,7 @@ struct wpa_driver_nl80211_data {
#define MAX_SEND_FRAME_COOKIES 20
u64 send_frame_cookies[MAX_SEND_FRAME_COOKIES];
unsigned int num_send_frame_cookies;
+ u64 eapol_tx_cookie;
unsigned int last_mgmt_freq;
@@ -206,6 +211,8 @@ struct wpa_driver_nl80211_data {
int auth_alg;
u8 *auth_ie;
size_t auth_ie_len;
+ u8 *auth_data;
+ size_t auth_data_len;
u8 auth_wep_key[4][16];
size_t auth_wep_key_len[4];
int auth_wep_tx_keyidx;
@@ -218,6 +225,15 @@ struct wpa_driver_nl80211_data {
* (NL80211_CMD_VENDOR). 0 if no pending scan request.
*/
int last_scan_cmd;
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ unsigned int vendor_set_pmk:1; /* for legacy set_pmk method before NL80211_CMD_SET_PMK */
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ bool roam_indication_done;
+ u8 *pending_roam_data;
+ size_t pending_roam_data_len;
+ struct os_reltime pending_roam_ind_time;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
};
struct nl_msg;
@@ -230,7 +246,9 @@ struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd);
int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
- void *valid_data);
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *, void *),
+ void *ack_data);
struct nl_sock * get_connect_handle(struct i802_bss *bss);
int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
const char *ifname, enum nl80211_iftype iftype,
@@ -284,6 +302,10 @@ int android_pno_start(struct i802_bss *bss,
int android_pno_stop(struct i802_bss *bss);
extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
size_t buf_len);
+extern int wpa_driver_nl80211_driver_event(struct wpa_driver_nl80211_data *drv,
+ u32 vendor_id, u32 subcmd,
+ u8 *data, size_t len);
+
#ifdef ANDROID_P2P
int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 3e8dcef2..82087624 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -17,7 +17,9 @@
#include "common/qca-vendor.h"
#include "common/qca-vendor-attr.h"
#include "driver_nl80211.h"
-
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+#include "common/brcm_vendor.h"
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
static int protocol_feature_handler(struct nl_msg *msg, void *arg)
{
@@ -49,7 +51,8 @@ static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
return 0;
}
- if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
+ if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat,
+ NULL, NULL) == 0)
return feat;
return 0;
@@ -558,6 +561,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_VHT;
if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_RATE_HE))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_BEACON_RATE_HE;
+
+ if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_SET_SCAN_DWELL))
capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL;
@@ -619,6 +626,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH))
capa->flags2 |= WPA_DRIVER_FLAGS2_CONTROL_PORT_RX;
+ if (ext_feature_isset(
+ ext_features, len,
+ NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS;
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_VLAN_OFFLOAD))
@@ -639,6 +650,22 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS))
info->drv->multicast_registrations = 1;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_FILS_DISCOVERY))
+ info->drv->fils_discovery = 1;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP))
+ info->drv->unsol_bcast_probe_resp = 1;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_BEACON_PROTECTION_CLIENT;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_OCV;
}
@@ -989,10 +1016,30 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
case QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE:
drv->add_sta_node_vendor_cmd_avail = 1;
break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO:
+ drv->get_sta_info_vendor_cmd_avail = 1;
+ break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
}
-
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ if (vinfo->vendor_id == OUI_BRCM) {
+ wpa_printf(MSG_MSGDUMP, "vendor:%x cmd:0x%x\n",
+ vinfo->vendor_id, vinfo->subcmd);
+ switch (vinfo->subcmd) {
+ case BRCM_VENDOR_SCMD_ACS:
+ drv->capa.flags |= WPA_DRIVER_FLAGS_ACS_OFFLOAD;
+ drv->capa.flags |=
+ WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY;
+ break;
+ case BRCM_VENDOR_SUBCMD_SET_PMK:
+ drv->vendor_set_pmk = 1;
+ break;
+ default:
+ break;
+ }
+ }
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
vinfo->vendor_id, vinfo->subcmd);
}
@@ -1052,7 +1099,7 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
return -1;
}
- if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
+ if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info, NULL, NULL))
return -1;
if (info->auth_supported)
@@ -1158,7 +1205,8 @@ static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv)
return;
}
- ret = send_and_recv_msgs(drv, msg, dfs_info_handler, &dfs_capability);
+ ret = send_and_recv_msgs(drv, msg, dfs_info_handler, &dfs_capability,
+ NULL, NULL);
if (!ret && dfs_capability)
drv->capa.flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
}
@@ -1245,7 +1293,8 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
os_memset(&info, 0, sizeof(info));
info.capa = &drv->capa;
- ret = send_and_recv_msgs(drv, msg, features_info_handler, &info);
+ ret = send_and_recv_msgs(drv, msg, features_info_handler, &info,
+ NULL, NULL);
if (ret || !info.flags)
return;
@@ -1360,6 +1409,7 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
if (!info.device_ap_sme) {
drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_AP_SME;
/*
* No AP SME is currently assumed to also indicate no AP MLME
@@ -1790,6 +1840,13 @@ static void phy_info_iftype_copy(struct he_capabilities *he_capab,
nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]),
len);
}
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA]) {
+ u16 capa;
+
+ capa = nla_get_u16(tb[NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA]);
+ he_capab->he_6ghz_capa = le_to_host16(capa);
+ }
}
@@ -1932,7 +1989,10 @@ wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
for (m = 0; m < *num_modes; m++) {
if (!modes[m].num_channels)
continue;
- if (modes[m].channels[0].freq < 4000) {
+ if (modes[m].channels[0].freq < 2000) {
+ modes[m].num_channels = 0;
+ continue;
+ } else if (modes[m].channels[0].freq < 4000) {
modes[m].mode = HOSTAPD_MODE_IEEE80211B;
for (i = 0; i < modes[m].num_rates; i++) {
if (modes[m].rates[i] > 200) {
@@ -1946,6 +2006,24 @@ wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
modes[m].mode = HOSTAPD_MODE_IEEE80211A;
}
+ /* Remove unsupported bands */
+ m = 0;
+ while (m < *num_modes) {
+ if (modes[m].mode == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Remove unsupported mode");
+ os_free(modes[m].channels);
+ os_free(modes[m].rates);
+ if (m + 1 < *num_modes)
+ os_memmove(&modes[m], &modes[m + 1],
+ sizeof(struct hostapd_hw_modes) *
+ (*num_modes - (m + 1)));
+ (*num_modes)--;
+ continue;
+ }
+ m++;
+ }
+
/* If only 802.11g mode is included, use it to construct matching
* 802.11b mode data. */
@@ -2320,7 +2398,8 @@ static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
}
}
- return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
+ return send_and_recv_msgs(drv, msg, nl80211_get_reg, results,
+ NULL, NULL);
}
@@ -2409,7 +2488,8 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags,
return NULL;
}
- if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
+ if (send_and_recv_msgs(drv, msg, phy_info_handler, &result,
+ NULL, NULL) == 0) {
struct hostapd_hw_modes *modes;
nl80211_set_regulatory_flags(drv, &result);
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 1a5f8998..81f688a5 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -18,6 +18,14 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "driver_nl80211.h"
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+#include "common/brcm_vendor.h"
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+
+static void
+nl80211_control_port_frame_tx_status(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len,
+ struct nlattr *ack, struct nlattr *cookie);
static const char * nl80211_command_to_string(enum nl80211_commands cmd)
@@ -138,6 +146,8 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
C2S(NL80211_CMD_CONTROL_PORT_FRAME)
C2S(NL80211_CMD_UPDATE_OWE_INFO)
C2S(NL80211_CMD_UNPROT_BEACON)
+ C2S(NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS)
+
default:
return "NL80211_CMD_UNKNOWN";
}
@@ -288,6 +298,94 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
}
+#ifdef CONFIG_DRIVER_NL80211_QCA
+
+static int qca_drv_connect_fail_reason_code_handler(struct nl_msg *msg,
+ void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct nlattr *tb_sta_info[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ u32 *reason_code = arg;
+
+ *reason_code = 0;
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_VENDOR_DATA]) {
+ wpa_printf(MSG_ERROR, "%s: Vendor data not found", __func__);
+ return NL_SKIP;
+ }
+
+ nla_parse(tb_sta_info, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX,
+ nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
+ nla_len(tb[NL80211_ATTR_VENDOR_DATA]), NULL);
+
+ if (!tb_sta_info[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE]) {
+ wpa_printf(MSG_INFO, "%s: Vendor attr not found", __func__);
+ return NL_SKIP;
+ }
+
+ *reason_code = nla_get_u32(tb_sta_info[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE]);
+
+ return NL_SKIP;
+}
+
+
+static enum qca_sta_connect_fail_reason_codes
+drv_get_connect_fail_reason_code(struct wpa_driver_nl80211_data *drv)
+{
+ enum qca_sta_connect_fail_reason_codes reason_code;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ if (!msg || nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO)) {
+ nlmsg_free(msg);
+ return 0;
+ }
+
+ ret = send_and_recv_msgs(drv, msg,
+ qca_drv_connect_fail_reason_code_handler,
+ &reason_code, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Get connect fail reason_code failed: ret=%d (%s)",
+ ret, strerror(-ret));
+
+ return reason_code;
+}
+
+
+static enum sta_connect_fail_reason_codes
+convert_connect_fail_reason_codes(enum qca_sta_connect_fail_reason_codes
+ reason_code)
+{
+ switch (reason_code) {
+ case QCA_STA_CONNECT_FAIL_REASON_NO_BSS_FOUND:
+ return STA_CONNECT_FAIL_REASON_NO_BSS_FOUND;
+ case QCA_STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL:
+ return STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL;
+ case QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED:
+ return STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED;
+ case QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED:
+ return STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED;
+ case QCA_STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL:
+ return STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL;
+ case QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED:
+ return STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED;
+ case QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED:
+ return STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED;
+ default:
+ return STA_CONNECT_FAIL_REASON_UNSPECIFIED;
+ }
+}
+
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
enum nl80211_commands cmd, struct nlattr *status,
struct nlattr *addr, struct nlattr *req_ie,
@@ -377,6 +475,17 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
if (fils_erp_next_seq_num)
event.assoc_reject.fils_erp_next_seq_num =
nla_get_u16(fils_erp_next_seq_num);
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ if (drv->get_sta_info_vendor_cmd_avail) {
+ enum qca_sta_connect_fail_reason_codes reason_code;
+
+ reason_code = drv_get_connect_fail_reason_code(drv);
+ event.assoc_reject.reason_code =
+ convert_connect_fail_reason_codes(reason_code);
+ }
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
return;
}
@@ -705,6 +814,16 @@ static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
WLAN_FC_GET_STYPE(fc), (long long unsigned int) cookie_val,
cookie ? "" : "(N/A)", ack != NULL);
+ if (cookie_val && cookie_val == drv->eapol_tx_cookie &&
+ len >= ETH_HLEN &&
+ WPA_GET_BE16(frame + 2 * ETH_ALEN) == ETH_P_PAE) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Work around misdelivered control port TX status for EAPOL");
+ nl80211_control_port_frame_tx_status(drv, frame, len, ack,
+ cookie);
+ return;
+ }
+
if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
return;
@@ -1266,7 +1385,6 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
enum nl80211_cqm_rssi_threshold_event event;
union wpa_event_data ed;
- struct wpa_signal_info sig;
int res;
if (tb[NL80211_ATTR_CQM] == NULL ||
@@ -1333,19 +1451,27 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
return;
}
- res = nl80211_get_link_signal(drv, &sig);
+ /*
+ * nl80211_get_link_signal() and nl80211_get_link_noise() set default
+ * values in case querying the driver fails.
+ */
+ res = nl80211_get_link_signal(drv, &ed.signal_change);
if (res == 0) {
- ed.signal_change.current_signal = sig.current_signal;
- ed.signal_change.current_txrate = sig.current_txrate;
wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d",
- sig.current_signal, sig.current_txrate);
+ ed.signal_change.current_signal,
+ ed.signal_change.current_txrate);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Querying the driver for signal info failed");
}
- res = nl80211_get_link_noise(drv, &sig);
+ res = nl80211_get_link_noise(drv, &ed.signal_change);
if (res == 0) {
- ed.signal_change.current_noise = sig.current_noise;
wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
- sig.current_noise);
+ ed.signal_change.current_noise);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Querying the driver for noise info failed");
}
wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
@@ -1712,7 +1838,96 @@ static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
}
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+static void brcm_nl80211_acs_select_ch(struct wpa_driver_nl80211_data
+ *drv, const u8 *data, size_t len)
+{
+ struct nlattr *tb[BRCM_VENDOR_ATTR_ACS_LAST + 1];
+ union wpa_event_data event;
+ wpa_printf(MSG_DEBUG, "nl80211: vendor ACS channel selection vendor even received");
+
+ if (nla_parse(tb, BRCM_VENDOR_ATTR_ACS_LAST, (struct nlattr*) data, len, NULL)
+ || (!tb[BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ])
+ || (!tb[BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ])) {
+ return;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ if (tb[BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ]) {
+ event.acs_selected_channels.pri_freq =
+ nla_get_u32(tb[BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ]);
+ }
+
+ wpa_printf(MSG_MSGDUMP, "got pri_freq=%d\n",
+ event.acs_selected_channels.pri_freq );
+
+ if (tb[BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ]) {
+ event.acs_selected_channels.sec_freq =
+ nla_get_u32(tb[BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ]);
+ }
+
+ wpa_printf(MSG_MSGDUMP, "got sec_freq=%d\n",
+ event.acs_selected_channels.sec_freq );
+ if (tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]) {
+ event.acs_selected_channels.vht_seg0_center_ch =
+ nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
+ }
+
+ if (tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]) {
+ event.acs_selected_channels.vht_seg1_center_ch =
+ nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
+ }
+ if (tb[BRCM_VENDOR_ATTR_ACS_CHWIDTH]) {
+ event.acs_selected_channels.ch_width =
+ nla_get_u16(tb[BRCM_VENDOR_ATTR_ACS_CHWIDTH]);
+ }
+ if (tb[BRCM_VENDOR_ATTR_ACS_HW_MODE]) {
+ event.acs_selected_channels.hw_mode =
+ nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_HW_MODE]);
+ if ((event.acs_selected_channels.hw_mode == NUM_HOSTAPD_MODES)
+ || (event.acs_selected_channels.hw_mode
+ == HOSTAPD_MODE_IEEE80211ANY)) {
+ wpa_printf(MSG_ERROR, "nl80211: Invalid hw_mode %d in ACS selection event",
+ event.acs_selected_channels.hw_mode);
+ return;
+ }
+ }
+
+ wpa_printf(MSG_INFO, "nl80211: ACS Results: PCH: %d SCH: %d BW: %d"
+ " VHT0: %d VHT1: %d HW_MODE: %d",
+ event.acs_selected_channels.pri_freq,
+ event.acs_selected_channels.sec_freq,
+ event.acs_selected_channels.ch_width,
+ event.acs_selected_channels.vht_seg0_center_ch,
+ event.acs_selected_channels.vht_seg1_center_ch,
+ event.acs_selected_channels.hw_mode);
+ wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED,
+ &event);
+ return;
+}
+
+static void nl80211_vendor_event_brcm( struct wpa_driver_nl80211_data *drv,
+ u32 subcmd, u8 *data, size_t len)
+{
+ union wpa_event_data event;
+ const struct nlattr *iter;
+ int rem = len;
+
+ wpa_printf(MSG_MSGDUMP, "got vendor event %d", subcmd);
+ memset(&event, 0, sizeof(event));
+ switch (subcmd) {
+ case BRCM_VENDOR_EVENT_ACS:
+ wpa_printf(MSG_DEBUG, "nl80211: Received VENDOR_EVENT_ACS");
+ brcm_nl80211_acs_select_ch(drv, data, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event %u", subcmd);
+ break;
+ }
+
+}
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
#ifdef CONFIG_DRIVER_NL80211_QCA
static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
@@ -1820,7 +2035,7 @@ try_2_4_or_5:
return 2407 + 5 * chan;
if (chan == 14)
return 2484;
- if (chan >= 36 && chan <= 169)
+ if (chan >= 36 && chan <= 177)
return 5000 + 5 * chan;
return 0;
@@ -1948,6 +2163,27 @@ static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv,
}
+static void
+qca_nl80211_key_mgmt_auth_handler(struct wpa_driver_nl80211_data *drv,
+ const u8 *data, size_t len)
+{
+ if (!drv->roam_indication_done) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Pending roam indication, delay processing roam+auth vendor event");
+ os_get_reltime(&drv->pending_roam_ind_time);
+
+ os_free(drv->pending_roam_data);
+ drv->pending_roam_data = os_memdup(data, len);
+ if (!drv->pending_roam_data)
+ return;
+ drv->pending_roam_data_len = len;
+ return;
+ }
+ drv->roam_indication_done = false;
+ qca_nl80211_key_mgmt_auth(drv, data, len);
+}
+
+
static void qca_nl80211_dfs_offload_radar_event(
struct wpa_driver_nl80211_data *drv, u32 subcmd, u8 *msg, int length)
{
@@ -2205,7 +2441,7 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
qca_nl80211_avoid_freq(drv, data, len);
break;
case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH:
- qca_nl80211_key_mgmt_auth(drv, data, len);
+ qca_nl80211_key_mgmt_auth_handler(drv, data, len);
break;
case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
qca_nl80211_acs_select_ch(drv, data, len);
@@ -2270,10 +2506,21 @@ static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
return;
}
+#ifdef ANDROID
+#ifdef ANDROID_LIB_EVENT
+ wpa_driver_nl80211_driver_event(drv, vendor_id, subcmd, data, len);
+#endif /* ANDROID_LIB_EVENT */
+#endif /* ANDROID */
+
switch (vendor_id) {
case OUI_QCA:
nl80211_vendor_event_qca(drv, subcmd, data, len);
break;
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ case OUI_BRCM:
+ nl80211_vendor_event_brcm(drv, subcmd, data, len);
+ break;
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
default:
wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
break;
@@ -2564,6 +2811,29 @@ static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv,
}
+static void
+nl80211_control_port_frame_tx_status(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len,
+ struct nlattr *ack, struct nlattr *cookie)
+{
+ union wpa_event_data event;
+
+ if (!cookie || len < ETH_HLEN)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Control port TX status (ack=%d), cookie=%llu",
+ ack != NULL, (long long unsigned int) nla_get_u64(cookie));
+
+ os_memset(&event, 0, sizeof(event));
+ event.eapol_tx_status.dst = frame;
+ event.eapol_tx_status.data = frame + ETH_HLEN;
+ event.eapol_tx_status.data_len = len - ETH_HLEN;
+ event.eapol_tx_status.ack = ack != NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
+}
+
+
static void do_process_drv_event(struct i802_bss *bss, int cmd,
struct nlattr **tb)
{
@@ -2574,17 +2844,36 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
cmd, nl80211_command_to_string(cmd), bss->ifname);
+#ifdef CONFIG_DRIVER_NL80211_QCA
if (cmd == NL80211_CMD_ROAM &&
(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
+ if (drv->pending_roam_data) {
+ struct os_reltime now, age;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &drv->pending_roam_ind_time, &age);
+ if (age.sec == 0 && age.usec < 100000) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Process pending roam+auth vendor event");
+ qca_nl80211_key_mgmt_auth(
+ drv, drv->pending_roam_data,
+ drv->pending_roam_data_len);
+ }
+ os_free(drv->pending_roam_data);
+ drv->pending_roam_data = NULL;
+ return;
+ }
/*
* Device will use roam+auth vendor event to indicate
* roaming, so ignore the regular roam event.
*/
+ drv->roam_indication_done = true;
wpa_printf(MSG_DEBUG,
"nl80211: Ignore roam event (cmd=%d), device will use vendor event roam+auth",
cmd);
return;
}
+#endif /* CONFIG_DRIVER_NL80211_QCA */
if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
(cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
@@ -2782,6 +3071,15 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
mlme_event_unprot_beacon(drv, nla_data(frame),
nla_len(frame));
break;
+ case NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS:
+ if (!frame)
+ break;
+ nl80211_control_port_frame_tx_status(drv,
+ nla_data(frame),
+ nla_len(frame),
+ tb[NL80211_ATTR_ACK],
+ tb[NL80211_ATTR_COOKIE]);
+ break;
default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index dc91a290..233175d1 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -82,7 +82,8 @@ static int nl80211_get_noise_for_scan_results(
os_memset(info, 0, sizeof(*info));
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
- return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, info);
+ return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, info,
+ NULL, NULL);
}
@@ -94,7 +95,7 @@ static int nl80211_abort_scan(struct i802_bss *bss)
wpa_printf(MSG_DEBUG, "nl80211: Abort scan");
msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ABORT_SCAN);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Abort scan failed: ret=%d (%s)",
ret, strerror(-ret));
@@ -125,7 +126,7 @@ static int nl80211_abort_vendor_scan(struct wpa_driver_nl80211_data *drv,
nla_nest_end(msg, params);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_INFO,
@@ -365,7 +366,7 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss,
goto fail;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
@@ -618,7 +619,7 @@ int wpa_driver_nl80211_sched_scan(void *priv,
params->sched_scan_start_delay))
goto fail;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
/* TODO: if we get an error here, we should fall back to normal scan */
@@ -655,7 +656,7 @@ int wpa_driver_nl80211_stop_sched_scan(void *priv)
#endif /* ANDROID */
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Sched scan stop failed: ret=%d (%s)",
@@ -944,7 +945,7 @@ try_again:
arg.drv = drv;
arg.res = res;
- ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+ ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg, NULL, NULL);
if (ret == -EAGAIN) {
count++;
if (count >= 10) {
@@ -1028,7 +1029,8 @@ void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
ctx.idx = 0;
msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
if (msg)
- send_and_recv_msgs(drv, msg, nl80211_dump_scan_handler, &ctx);
+ send_and_recv_msgs(drv, msg, nl80211_dump_scan_handler, &ctx,
+ NULL, NULL);
}
@@ -1221,7 +1223,8 @@ int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
nla_nest_end(msg, attr);
- ret = send_and_recv_msgs(drv, msg, scan_cookie_handler, &cookie);
+ ret = send_and_recv_msgs(drv, msg, scan_cookie_handler, &cookie,
+ NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG,
@@ -1284,7 +1287,7 @@ int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len)
nla_nest_end(msg, attr);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_ERROR,
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 55a98ef8..a03d4a03 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -26,6 +26,10 @@ NEED_LIBNL=y
CONFIG_LIBNL3_ROUTE=y
endif
+ifdef CONFIG_DRIVER_NL80211_BRCM
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_BRCM
+endif
+
ifdef CONFIG_DRIVER_MACSEC_QCA
DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_QCA
DRV_OBJS += ../src/drivers/driver_macsec_qca.o
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 5a32a242..10eab6a9 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -41,6 +41,9 @@ DRV_OBJS += src/drivers/driver_nl80211_scan.c
ifdef CONFIG_DRIVER_NL80211_QCA
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_QCA
endif
+ifdef CONFIG_DRIVER_NL80211_BRCM
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_BRCM
+endif
NEED_SME=y
NEED_AP_MLME=y
NEED_NETLINK=y
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 5e500d74..ac78da99 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -183,18 +183,27 @@
*
* By setting @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK flag drivers
* can indicate they support offloading EAPOL handshakes for WPA/WPA2
- * preshared key authentication. In %NL80211_CMD_CONNECT the preshared
- * key should be specified using %NL80211_ATTR_PMK. Drivers supporting
- * this offload may reject the %NL80211_CMD_CONNECT when no preshared
- * key material is provided, for example when that driver does not
- * support setting the temporal keys through %CMD_NEW_KEY.
+ * preshared key authentication in station mode. In %NL80211_CMD_CONNECT
+ * the preshared key should be specified using %NL80211_ATTR_PMK. Drivers
+ * supporting this offload may reject the %NL80211_CMD_CONNECT when no
+ * preshared key material is provided, for example when that driver does
+ * not support setting the temporal keys through %NL80211_CMD_NEW_KEY.
*
* Similarly @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X flag can be
* set by drivers indicating offload support of the PTK/GTK EAPOL
- * handshakes during 802.1X authentication. In order to use the offload
- * the %NL80211_CMD_CONNECT should have %NL80211_ATTR_WANT_1X_4WAY_HS
- * attribute flag. Drivers supporting this offload may reject the
- * %NL80211_CMD_CONNECT when the attribute flag is not present.
+ * handshakes during 802.1X authentication in station mode. In order to
+ * use the offload the %NL80211_CMD_CONNECT should have
+ * %NL80211_ATTR_WANT_1X_4WAY_HS attribute flag. Drivers supporting this
+ * offload may reject the %NL80211_CMD_CONNECT when the attribute flag is
+ * not present.
+ *
+ * By setting @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK flag drivers
+ * can indicate they support offloading EAPOL handshakes for WPA/WPA2
+ * preshared key authentication in AP mode. In %NL80211_CMD_START_AP
+ * the preshared key should be specified using %NL80211_ATTR_PMK. Drivers
+ * supporting this offload may reject the %NL80211_CMD_START_AP when no
+ * preshared key material is provided, for example when that driver does
+ * not support setting the temporal keys through %NL80211_CMD_NEW_KEY.
*
* For 802.1X the PMK or PMK-R0 are set by providing %NL80211_ATTR_PMK
* using %NL80211_CMD_SET_PMK. For offloaded FT support also
@@ -243,9 +252,13 @@
* DOC: SAE authentication offload
*
* By setting @NL80211_EXT_FEATURE_SAE_OFFLOAD flag drivers can indicate they
- * support offloading SAE authentication for WPA3-Personal networks. In
- * %NL80211_CMD_CONNECT the password for SAE should be specified using
- * %NL80211_ATTR_SAE_PASSWORD.
+ * support offloading SAE authentication for WPA3-Personal networks in station
+ * mode. Similarly @NL80211_EXT_FEATURE_SAE_OFFLOAD_AP flag can be set by
+ * drivers indicating the offload support in AP mode.
+ *
+ * The password for SAE should be specified using %NL80211_ATTR_SAE_PASSWORD in
+ * %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP for station and AP mode
+ * respectively.
*/
/**
@@ -296,13 +309,14 @@
* to get a list of all present wiphys.
* @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
* %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
- * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the
- * attributes determining the channel width; this is used for setting
- * monitor mode channel), %NL80211_ATTR_WIPHY_RETRY_SHORT,
- * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
- * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
- * However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
- * instead, the support here is for backward compatibility only.
+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
+ * %NL80211_ATTR_WIPHY_FREQ_OFFSET (and the attributes determining the
+ * channel width; this is used for setting monitor mode channel),
+ * %NL80211_ATTR_WIPHY_RETRY_SHORT, %NL80211_ATTR_WIPHY_RETRY_LONG,
+ * %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, and/or
+ * %NL80211_ATTR_WIPHY_RTS_THRESHOLD. However, for setting the channel,
+ * see %NL80211_CMD_SET_CHANNEL instead, the support here is for backward
+ * compatibility only.
* @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
* or rename notification. Has attributes %NL80211_ATTR_WIPHY and
* %NL80211_ATTR_WIPHY_NAME.
@@ -351,7 +365,8 @@
* %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_INACTIVITY_TIMEOUT,
* %NL80211_ATTR_ACL_POLICY and %NL80211_ATTR_MAC_ADDRS.
* The channel to use can be set on the interface or be given using the
- * %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width.
+ * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_FREQ_OFFSET, and the
+ * attributes determining channel width.
* @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
* @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
* @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
@@ -361,7 +376,7 @@
* @NL80211_CMD_SET_STATION: Set station attributes for station identified by
* %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
- * the interface identified by %NL80211_ATTR_IFINDEX.
+ * interface identified by %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
* or, if no MAC address given, all stations, on the interface identified
* by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and
@@ -381,7 +396,7 @@
* @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by
* %NL80211_ATTR_MAC.
* @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
- * the interface identified by %NL80211_ATTR_IFINDEX.
+ * interface identified by %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
* or, if no MAC address given, all mesh paths, on the interface identified
* by %NL80211_ATTR_IFINDEX.
@@ -536,11 +551,12 @@
* interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and
* BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify
* the SSID (mainly for association, but is included in authentication
- * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used
- * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE
- * is used to specify the authentication type. %NL80211_ATTR_IE is used to
- * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs)
- * to be added to the frame.
+ * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ +
+ * %NL80211_ATTR_WIPHY_FREQ_OFFSET is used to specify the frequence of the
+ * channel in MHz. %NL80211_ATTR_AUTH_TYPE is used to specify the
+ * authentication type. %NL80211_ATTR_IE is used to define IEs
+ * (VendorSpecificInfo, but also including RSN IE and FT IEs) to be added
+ * to the frame.
* When used as an event, this reports reception of an Authentication
* frame in station and IBSS modes when the local MLME processed the
* frame, i.e., it was for the local STA and was received in correct
@@ -595,8 +611,9 @@
* requests to connect to a specified network but without separating
* auth and assoc steps. For this, you need to specify the SSID in a
* %NL80211_ATTR_SSID attribute, and can optionally specify the association
- * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
- * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE,
+ * %NL80211_ATTR_USE_MFP, %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ,
+ * %NL80211_ATTR_WIPHY_FREQ_OFFSET, %NL80211_ATTR_CONTROL_PORT,
* %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
* %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and
@@ -634,13 +651,9 @@
* authentication/association or not receiving a response from the AP.
* Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as
* well to remain backwards compatible.
- * When establishing a security association, drivers that support 4 way
- * handshake offload should send %NL80211_CMD_PORT_AUTHORIZED event when
- * the 4 way handshake is completed successfully.
* @NL80211_CMD_ROAM: Notification indicating the card/driver roamed by itself.
- * When a security association was established with the new AP (e.g. if
- * the FT protocol was used for roaming or the driver completed the 4 way
- * handshake), this event should be followed by an
+ * When a security association was established on an 802.1X network using
+ * fast transition, this event should be followed by an
* %NL80211_CMD_PORT_AUTHORIZED event.
* @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
* userspace that a connection was dropped by the AP or due to other
@@ -744,7 +757,8 @@
* of any other interfaces, and other interfaces will again take
* precedence when they are used.
*
- * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
+ * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface
+ * (no longer supported).
*
* @NL80211_CMD_SET_MULTICAST_TO_UNICAST: Configure if this AP should perform
* multicast to unicast conversion. When enabled, all multicast packets
@@ -790,7 +804,7 @@
* various triggers. These triggers can be configured through this
* command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
* more background information, see
- * http://wireless.kernel.org/en/users/Documentation/WoWLAN.
+ * https://wireless.wiki.kernel.org/en/users/Documentation/WoWLAN.
* The @NL80211_CMD_SET_WOWLAN command can also be used as a notification
* from the driver reporting the wakeup reason. In this case, the
* @NL80211_ATTR_WOWLAN_TRIGGERS attribute will contain the reason
@@ -930,7 +944,7 @@
* @NL80211_CMD_SET_COALESCE: Configure coalesce rules or clear existing rules.
*
* @NL80211_CMD_CHANNEL_SWITCH: Perform a channel switch by announcing the
- * the new channel information (Channel Switch Announcement - CSA)
+ * new channel information (Channel Switch Announcement - CSA)
* in the beacon for some time (as defined in the
* %NL80211_ATTR_CH_SWITCH_COUNT parameter) and then change to the
* new channel. Userspace provides the new channel information (using
@@ -1054,13 +1068,11 @@
* @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously
* configured PMK for the authenticator address identified by
* %NL80211_ATTR_MAC.
- * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates that the 4 way
- * handshake was completed successfully by the driver. The BSSID is
- * specified with %NL80211_ATTR_MAC. Drivers that support 4 way handshake
- * offload should send this event after indicating 802.11 association with
- * %NL80211_CMD_CONNECT or %NL80211_CMD_ROAM. If the 4 way handshake failed
- * %NL80211_CMD_DISCONNECT should be indicated instead.
- *
+ * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates an 802.1X FT roam was
+ * completed successfully. Drivers that support 4 way handshake offload
+ * should send this event after indicating 802.1X FT assocation with
+ * %NL80211_CMD_ROAM. If the 4 way handshake failed %NL80211_CMD_DISCONNECT
+ * should be indicated instead.
* @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request
* and RX notification. This command is used both as a request to transmit
* a control port frame and as a notification that a control port frame
@@ -1109,7 +1121,7 @@
* randomization may be enabled and configured by specifying the
* %NL80211_ATTR_MAC and %NL80211_ATTR_MAC_MASK attributes.
* If a timeout is requested, use the %NL80211_ATTR_TIMEOUT attribute.
- * A u64 cookie for further %NL80211_ATTR_COOKIE use is is returned in
+ * A u64 cookie for further %NL80211_ATTR_COOKIE use is returned in
* the netlink extended ack message.
*
* To cancel a measurement, close the socket that requested it.
@@ -1160,6 +1172,16 @@
* dropped because it did not include a valid MME MIC while beacon
* protection was enabled (BIGTK configured in station mode).
*
+ * @NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS: Report TX status of a control
+ * port frame transmitted with %NL80211_CMD_CONTROL_PORT_FRAME.
+ * %NL80211_ATTR_COOKIE identifies the TX command and %NL80211_ATTR_FRAME
+ * includes the contents of the frame. %NL80211_ATTR_ACK flag is included
+ * if the recipient acknowledged the frame.
+ *
+ * @NL80211_CMD_SET_SAR_SPECS: SAR power limitation configuration is
+ * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to
+ * specify the wiphy index to be applied to.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1388,6 +1410,10 @@ enum nl80211_commands {
NL80211_CMD_UNPROT_BEACON,
+ NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS,
+
+ NL80211_CMD_SET_SAR_SPECS,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1433,7 +1459,8 @@ enum nl80211_commands {
* of &enum nl80211_chan_width, describing the channel width. See the
* documentation of the enum for more information.
* @NL80211_ATTR_CENTER_FREQ1: Center frequency of the first part of the
- * channel, used for anything but 20 MHz bandwidth
+ * channel, used for anything but 20 MHz bandwidth. In S1G this is the
+ * operating channel center frequency.
* @NL80211_ATTR_CENTER_FREQ2: Center frequency of the second part of the
* channel, used only for 80+80 MHz bandwidth
* @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
@@ -1498,7 +1525,7 @@ enum nl80211_commands {
* rates as defined by IEEE 802.11 7.3.2.2 but without the length
* restriction (at most %NL80211_MAX_SUPP_RATES).
* @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
- * to, or the AP interface the station was originally added to to.
+ * to, or the AP interface the station was originally added to.
* @NL80211_ATTR_STA_INFO: information about a station, part of station info
* given for %NL80211_CMD_GET_STATION, nested attribute containing
* info as possible, see &enum nl80211_sta_info.
@@ -1730,8 +1757,9 @@ enum nl80211_commands {
* specify just a single bitrate, which is to be used for the beacon.
* The driver must also specify support for this with the extended
* features NL80211_EXT_FEATURE_BEACON_RATE_LEGACY,
- * NL80211_EXT_FEATURE_BEACON_RATE_HT and
- * NL80211_EXT_FEATURE_BEACON_RATE_VHT.
+ * NL80211_EXT_FEATURE_BEACON_RATE_HT,
+ * NL80211_EXT_FEATURE_BEACON_RATE_VHT and
+ * NL80211_EXT_FEATURE_BEACON_RATE_HE.
*
* @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
* at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME.
@@ -1935,8 +1963,15 @@ enum nl80211_commands {
* @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
* probe-response frame. The DA field in the 802.11 header is zero-ed out,
* to be filled by the FW.
- * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable
- * this feature. Currently, only supported in mac80211 drivers.
+ * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable
+ * this feature during association. This is a flag attribute.
+ * Currently only supported in mac80211 drivers.
+ * @NL80211_ATTR_DISABLE_VHT: Force VHT capable interfaces to disable
+ * this feature during association. This is a flag attribute.
+ * Currently only supported in mac80211 drivers.
+ * @NL80211_ATTR_DISABLE_HE: Force HE capable interfaces to disable
+ * this feature during association. This is a flag attribute.
+ * Currently only supported in mac80211 drivers.
* @NL80211_ATTR_HT_CAPABILITY_MASK: Specify which bits of the
* ATTR_HT_CAPABILITY to which attention should be paid.
* Currently, only mac80211 NICs support this feature.
@@ -2057,13 +2092,14 @@ enum nl80211_commands {
* until the channel switch event.
* @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission
* must be blocked on the current channel (before the channel switch
- * operation).
+ * operation). Also included in the channel switch started event if quiet
+ * was requested by the AP.
* @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information
* for the time while performing a channel switch.
- * @NL80211_ATTR_CSA_C_OFF_BEACON: An array of offsets (u16) to the channel
- * switch counters in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
- * @NL80211_ATTR_CSA_C_OFF_PRESP: An array of offsets (u16) to the channel
- * switch counters in the probe response (%NL80211_ATTR_PROBE_RESP).
+ * @NL80211_ATTR_CNTDWN_OFFS_BEACON: An array of offsets (u16) to the channel
+ * switch or color change counters in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
+ * @NL80211_ATTR_CNTDWN_OFFS_PRESP: An array of offsets (u16) to the channel
+ * switch or color change counters in the probe response (%NL80211_ATTR_PROBE_RESP).
*
* @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32.
* As specified in the &enum nl80211_rxmgmt_flags.
@@ -2071,7 +2107,7 @@ enum nl80211_commands {
* @NL80211_ATTR_STA_SUPPORTED_CHANNELS: array of supported channels.
*
* @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported
- * supported operating classes.
+ * operating classes.
*
* @NL80211_ATTR_HANDLE_DFS: A flag indicating whether user space
* controls DFS operation in IBSS mode. If the flag is included in
@@ -2349,10 +2385,11 @@ enum nl80211_commands {
*
* @NL80211_ATTR_PMK: attribute for passing PMK key material. Used with
* %NL80211_CMD_SET_PMKSA for the PMKSA identified by %NL80211_ATTR_PMKID.
- * For %NL80211_CMD_CONNECT it is used to provide PSK for offloading 4-way
- * handshake for WPA/WPA2-PSK networks. For 802.1X authentication it is
- * used with %NL80211_CMD_SET_PMK. For offloaded FT support this attribute
- * specifies the PMK-R0 if NL80211_ATTR_PMKR0_NAME is included as well.
+ * For %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP it is used to provide
+ * PSK for offloading 4-way handshake for WPA/WPA2-PSK networks. For 802.1X
+ * authentication it is used with %NL80211_CMD_SET_PMK. For offloaded FT
+ * support this attribute specifies the PMK-R0 if NL80211_ATTR_PMKR0_NAME
+ * is included as well.
*
* @NL80211_ATTR_SCHED_SCAN_MULTI: flag attribute which user-space shall use to
* indicate that it supports multiple active scheduled scan requests.
@@ -2382,7 +2419,7 @@ enum nl80211_commands {
* nl80211_txq_stats)
* @NL80211_ATTR_TXQ_LIMIT: Total packet limit for the TXQ queues for this phy.
* The smaller of this and the memory limit is enforced.
- * @NL80211_ATTR_TXQ_MEMORY_LIMIT: Total memory memory limit (in bytes) for the
+ * @NL80211_ATTR_TXQ_MEMORY_LIMIT: Total memory limit (in bytes) for the
* TXQ queues for this phy. The smaller of this and the packet limit is
* enforced.
* @NL80211_ATTR_TXQ_QUANTUM: TXQ scheduler quantum (bytes). Number of bytes
@@ -2480,9 +2517,45 @@ enum nl80211_commands {
* entry without having to force a disconnection after the PMK timeout. If
* no roaming occurs between the reauth threshold and PMK expiration,
* disassociation is still forced.
- *
* @NL80211_ATTR_RECEIVE_MULTICAST: multicast flag for the
* %NL80211_CMD_REGISTER_FRAME command, see the description there.
+ * @NL80211_ATTR_WIPHY_FREQ_OFFSET: offset of the associated
+ * %NL80211_ATTR_WIPHY_FREQ in positive KHz. Only valid when supplied with
+ * an %NL80211_ATTR_WIPHY_FREQ_OFFSET.
+ * @NL80211_ATTR_CENTER_FREQ1_OFFSET: Center frequency offset in KHz for the
+ * first channel segment specified in %NL80211_ATTR_CENTER_FREQ1.
+ * @NL80211_ATTR_SCAN_FREQ_KHZ: nested attribute with KHz frequencies
+ *
+ * @NL80211_ATTR_HE_6GHZ_CAPABILITY: HE 6 GHz Band Capability element (from
+ * association request when used with NL80211_CMD_NEW_STATION).
+ *
+ * @NL80211_ATTR_FILS_DISCOVERY: Optional parameter to configure FILS
+ * discovery. It is a nested attribute, see
+ * &enum nl80211_fils_discovery_attributes.
+ *
+ * @NL80211_ATTR_UNSOL_BCAST_PROBE_RESP: Optional parameter to configure
+ * unsolicited broadcast probe response. It is a nested attribute, see
+ * &enum nl80211_unsol_bcast_probe_resp_attributes.
+ *
+ * @NL80211_ATTR_S1G_CAPABILITY: S1G Capability information element (from
+ * association request when used with NL80211_CMD_NEW_STATION)
+ * @NL80211_ATTR_S1G_CAPABILITY_MASK: S1G Capability Information element
+ * override mask. Used with NL80211_ATTR_S1G_CAPABILITY in
+ * NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT.
+ *
+ * @NL80211_ATTR_SAE_PWE: Indicates the mechanism(s) allowed for SAE PWE
+ * derivation in WPA3-Personal networks which are using SAE authentication.
+ * This is a u8 attribute that encapsulates one of the values from
+ * &enum nl80211_sae_pwe_mechanism.
+ *
+ * @NL80211_ATTR_SAR_SPEC: SAR power limitation specification when
+ * used with %NL80211_CMD_SET_SAR_SPECS. The message contains fields
+ * of %nl80211_sar_attrs which specifies the sar type and related
+ * sar specs. Sar specs contains array of %nl80211_sar_specs_attrs.
+ *
+ * @NL80211_ATTR_RECONNECT_REQUESTED: flag attribute, used with deauth and
+ * disassoc events to indicate that an immediate reconnect to the AP
+ * is desired.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2790,8 +2863,8 @@ enum nl80211_attrs {
NL80211_ATTR_CH_SWITCH_COUNT,
NL80211_ATTR_CH_SWITCH_BLOCK_TX,
NL80211_ATTR_CSA_IES,
- NL80211_ATTR_CSA_C_OFF_BEACON,
- NL80211_ATTR_CSA_C_OFF_PRESP,
+ NL80211_ATTR_CNTDWN_OFFS_BEACON,
+ NL80211_ATTR_CNTDWN_OFFS_PRESP,
NL80211_ATTR_RXMGMT_FLAGS,
@@ -2960,6 +3033,26 @@ enum nl80211_attrs {
NL80211_ATTR_PMK_REAUTH_THRESHOLD,
NL80211_ATTR_RECEIVE_MULTICAST,
+ NL80211_ATTR_WIPHY_FREQ_OFFSET,
+ NL80211_ATTR_CENTER_FREQ1_OFFSET,
+ NL80211_ATTR_SCAN_FREQ_KHZ,
+
+ NL80211_ATTR_HE_6GHZ_CAPABILITY,
+
+ NL80211_ATTR_FILS_DISCOVERY,
+
+ NL80211_ATTR_UNSOL_BCAST_PROBE_RESP,
+
+ NL80211_ATTR_S1G_CAPABILITY,
+ NL80211_ATTR_S1G_CAPABILITY_MASK,
+
+ NL80211_ATTR_SAE_PWE,
+
+ NL80211_ATTR_RECONNECT_REQUESTED,
+
+ NL80211_ATTR_SAR_SPEC,
+
+ NL80211_ATTR_DISABLE_HE,
/* add attributes here, update the policy in nl80211.c */
@@ -2973,6 +3066,8 @@ enum nl80211_attrs {
#define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
#define NL80211_ATTR_SAE_DATA NL80211_ATTR_AUTH_DATA
+#define NL80211_ATTR_CSA_C_OFF_BEACON NL80211_ATTR_CNTDWN_OFFS_BEACON
+#define NL80211_ATTR_CSA_C_OFF_PRESP NL80211_ATTR_CNTDWN_OFFS_PRESP
/*
* Allow user space programs to use #ifdef on new attributes by defining them
@@ -3151,6 +3246,18 @@ enum nl80211_he_gi {
};
/**
+ * enum nl80211_he_ltf - HE long training field
+ * @NL80211_RATE_INFO_HE_1xLTF: 3.2 usec
+ * @NL80211_RATE_INFO_HE_2xLTF: 6.4 usec
+ * @NL80211_RATE_INFO_HE_4xLTF: 12.8 usec
+ */
+enum nl80211_he_ltf {
+ NL80211_RATE_INFO_HE_1XLTF,
+ NL80211_RATE_INFO_HE_2XLTF,
+ NL80211_RATE_INFO_HE_4XLTF,
+};
+
+/**
* enum nl80211_he_ru_alloc - HE RU allocation values
* @NL80211_RATE_INFO_HE_RU_ALLOC_26: 26-tone RU allocation
* @NL80211_RATE_INFO_HE_RU_ALLOC_52: 52-tone RU allocation
@@ -3344,6 +3451,8 @@ enum nl80211_sta_bss_param {
* @NL80211_STA_INFO_AIRTIME_LINK_METRIC: airtime link metric for mesh station
* @NL80211_STA_INFO_ASSOC_AT_BOOTTIME: Timestamp (CLOCK_BOOTTIME, nanoseconds)
* of STA's association
+ * @NL80211_STA_INFO_CONNECTED_TO_AS: set to true if STA has a path to a
+ * authentication server (u8, 0 or 1)
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -3391,6 +3500,7 @@ enum nl80211_sta_info {
NL80211_STA_INFO_AIRTIME_WEIGHT,
NL80211_STA_INFO_AIRTIME_LINK_METRIC,
NL80211_STA_INFO_ASSOC_AT_BOOTTIME,
+ NL80211_STA_INFO_CONNECTED_TO_AS,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -3539,6 +3649,8 @@ enum nl80211_mpath_info {
* defined in HE capabilities IE
* @NL80211_BAND_IFTYPE_ATTR_MAX: highest band HE capability attribute currently
* defined
+ * @NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA: HE 6GHz band capabilities (__le16),
+ * given for all 6 GHz band channels
* @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
*/
enum nl80211_band_iftype_attr {
@@ -3549,6 +3661,7 @@ enum nl80211_band_iftype_attr {
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
+ NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA,
/* keep last */
__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST,
@@ -3682,6 +3795,17 @@ enum nl80211_wmm_rule {
* (see &enum nl80211_wmm_rule)
* @NL80211_FREQUENCY_ATTR_NO_HE: HE operation is not allowed on this channel
* in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_OFFSET: frequency offset in KHz
+ * @NL80211_FREQUENCY_ATTR_1MHZ: 1 MHz operation is allowed
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_2MHZ: 2 MHz operation is allowed
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_4MHZ: 4 MHz operation is allowed
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_8MHZ: 8 MHz operation is allowed
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_16MHZ: 16 MHz operation is allowed
+ * on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -3712,6 +3836,12 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_NO_10MHZ,
NL80211_FREQUENCY_ATTR_WMM,
NL80211_FREQUENCY_ATTR_NO_HE,
+ NL80211_FREQUENCY_ATTR_OFFSET,
+ NL80211_FREQUENCY_ATTR_1MHZ,
+ NL80211_FREQUENCY_ATTR_2MHZ,
+ NL80211_FREQUENCY_ATTR_4MHZ,
+ NL80211_FREQUENCY_ATTR_8MHZ,
+ NL80211_FREQUENCY_ATTR_16MHZ,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -4005,6 +4135,7 @@ enum nl80211_user_reg_hint_type {
* receiving frames destined to the local BSS
* @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
* currently defined
+ * @NL80211_SURVEY_INFO_FREQUENCY_OFFSET: center frequency offset in KHz
* @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
*/
enum nl80211_survey_info {
@@ -4020,6 +4151,7 @@ enum nl80211_survey_info {
NL80211_SURVEY_INFO_TIME_SCAN,
NL80211_SURVEY_INFO_PAD,
NL80211_SURVEY_INFO_TIME_BSS_RX,
+ NL80211_SURVEY_INFO_FREQUENCY_OFFSET,
/* keep last */
__NL80211_SURVEY_INFO_AFTER_LAST,
@@ -4205,6 +4337,16 @@ enum nl80211_mesh_power_mode {
* field. If left unset then the mesh formation field will only
* advertise such if there is an active root mesh path.
*
+ * @NL80211_MESHCONF_NOLEARN: Try to avoid multi-hop path discovery (e.g.
+ * PREQ/PREP for HWMP) if the destination is a direct neighbor. Note that
+ * this might not be the optimal decision as a multi-hop route might be
+ * better. So if using this setting you will likely also want to disable
+ * dot11MeshForwarding and use another mesh routing protocol on top.
+ *
+ * @NL80211_MESHCONF_CONNECTED_TO_AS: If set to true then this mesh STA
+ * will advertise that it is connected to a authentication server
+ * in the mesh formation field.
+ *
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
*/
enum nl80211_meshconf_params {
@@ -4238,6 +4380,8 @@ enum nl80211_meshconf_params {
NL80211_MESHCONF_AWAKE_WINDOW,
NL80211_MESHCONF_PLINK_TIMEOUT,
NL80211_MESHCONF_CONNECTED_TO_GATE,
+ NL80211_MESHCONF_NOLEARN,
+ NL80211_MESHCONF_CONNECTED_TO_AS,
/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -4406,6 +4550,11 @@ enum nl80211_key_mode {
* attribute must be provided as well
* @NL80211_CHAN_WIDTH_5: 5 MHz OFDM channel
* @NL80211_CHAN_WIDTH_10: 10 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_1: 1 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_2: 2 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_4: 4 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_8: 8 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_16: 16 MHz OFDM channel
*/
enum nl80211_chan_width {
NL80211_CHAN_WIDTH_20_NOHT,
@@ -4416,6 +4565,11 @@ enum nl80211_chan_width {
NL80211_CHAN_WIDTH_160,
NL80211_CHAN_WIDTH_5,
NL80211_CHAN_WIDTH_10,
+ NL80211_CHAN_WIDTH_1,
+ NL80211_CHAN_WIDTH_2,
+ NL80211_CHAN_WIDTH_4,
+ NL80211_CHAN_WIDTH_8,
+ NL80211_CHAN_WIDTH_16,
};
/**
@@ -4426,11 +4580,15 @@ enum nl80211_chan_width {
* @NL80211_BSS_CHAN_WIDTH_20: control channel is 20 MHz wide or compatible
* @NL80211_BSS_CHAN_WIDTH_10: control channel is 10 MHz wide
* @NL80211_BSS_CHAN_WIDTH_5: control channel is 5 MHz wide
+ * @NL80211_BSS_CHAN_WIDTH_1: control channel is 1 MHz wide
+ * @NL80211_BSS_CHAN_WIDTH_2: control channel is 2 MHz wide
*/
enum nl80211_bss_scan_width {
NL80211_BSS_CHAN_WIDTH_20,
NL80211_BSS_CHAN_WIDTH_10,
NL80211_BSS_CHAN_WIDTH_5,
+ NL80211_BSS_CHAN_WIDTH_1,
+ NL80211_BSS_CHAN_WIDTH_2,
};
/**
@@ -4482,6 +4640,7 @@ enum nl80211_bss_scan_width {
* @NL80211_BSS_CHAIN_SIGNAL: per-chain signal strength of last BSS update.
* Contains a nested array of signal strength attributes (u8, dBm),
* using the nesting index as the antenna number.
+ * @NL80211_BSS_FREQUENCY_OFFSET: frequency offset in KHz
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -4506,6 +4665,7 @@ enum nl80211_bss {
NL80211_BSS_PARENT_TSF,
NL80211_BSS_PARENT_BSSID,
NL80211_BSS_CHAIN_SIGNAL,
+ NL80211_BSS_FREQUENCY_OFFSET,
/* keep last */
__NL80211_BSS_AFTER_LAST,
@@ -4669,6 +4829,10 @@ enum nl80211_key_attributes {
* @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection,
* see &struct nl80211_txrate_vht
* @NL80211_TXRATE_GI: configure GI, see &enum nl80211_txrate_gi
+ * @NL80211_TXRATE_HE: HE rates allowed for TX rate selection,
+ * see &struct nl80211_txrate_he
+ * @NL80211_TXRATE_HE_GI: configure HE GI, 0.8us, 1.6us and 3.2us.
+ * @NL80211_TXRATE_HE_LTF: configure HE LTF, 1XLTF, 2XLTF and 4XLTF.
* @__NL80211_TXRATE_AFTER_LAST: internal
* @NL80211_TXRATE_MAX: highest TX rate attribute
*/
@@ -4678,6 +4842,9 @@ enum nl80211_tx_rate_attributes {
NL80211_TXRATE_HT,
NL80211_TXRATE_VHT,
NL80211_TXRATE_GI,
+ NL80211_TXRATE_HE,
+ NL80211_TXRATE_HE_GI,
+ NL80211_TXRATE_HE_LTF,
/* keep last */
__NL80211_TXRATE_AFTER_LAST,
@@ -4695,6 +4862,15 @@ struct nl80211_txrate_vht {
__u16 mcs[NL80211_VHT_NSS_MAX];
};
+#define NL80211_HE_NSS_MAX 8
+/**
+ * struct nl80211_txrate_he - HE MCS/NSS txrate bitmap
+ * @mcs: MCS bitmap table for each NSS (array index 0 for 1 stream, etc.)
+ */
+struct nl80211_txrate_he {
+ __u16 mcs[NL80211_HE_NSS_MAX];
+};
+
enum nl80211_txrate_gi {
NL80211_TXRATE_DEFAULT_GI,
NL80211_TXRATE_FORCE_SGI,
@@ -4707,6 +4883,7 @@ enum nl80211_txrate_gi {
* @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
* @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz)
* @NL80211_BAND_6GHZ: around 6 GHz band (5.9 - 7.2 GHz)
+ * @NL80211_BAND_S1GHZ: around 900MHz, supported by S1G PHYs
* @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
* since newer kernel versions may support more bands
*/
@@ -4715,6 +4892,7 @@ enum nl80211_band {
NL80211_BAND_5GHZ,
NL80211_BAND_60GHZ,
NL80211_BAND_6GHZ,
+ NL80211_BAND_S1GHZ,
NUM_NL80211_BANDS,
};
@@ -4816,6 +4994,17 @@ enum nl80211_tid_config {
NL80211_TID_CONFIG_DISABLE,
};
+/* enum nl80211_tx_rate_setting - TX rate configuration type
+ * @NL80211_TX_RATE_AUTOMATIC: automatically determine TX rate
+ * @NL80211_TX_RATE_LIMITED: limit the TX rate by the TX rate parameter
+ * @NL80211_TX_RATE_FIXED: fix TX rate to the TX rate parameter
+ */
+enum nl80211_tx_rate_setting {
+ NL80211_TX_RATE_AUTOMATIC,
+ NL80211_TX_RATE_LIMITED,
+ NL80211_TX_RATE_FIXED,
+};
+
/* enum nl80211_tid_config_attr - TID specific configuration.
* @NL80211_TID_CONFIG_ATTR_PAD: pad attribute for 64-bit values
* @NL80211_TID_CONFIG_ATTR_VIF_SUPP: a bitmap (u64) of attributes supported
@@ -4823,12 +5012,10 @@ enum nl80211_tid_config {
* (%NL80211_TID_CONFIG_ATTR_TIDS, %NL80211_TID_CONFIG_ATTR_OVERRIDE).
* @NL80211_TID_CONFIG_ATTR_PEER_SUPP: same as the previous per-vif one, but
* per peer instead.
- * @NL80211_TID_CONFIG_ATTR_OVERRIDE: flag attribute, if no peer
- * is selected, if set indicates that the new configuration overrides
- * all previous peer configurations, otherwise previous peer specific
- * configurations should be left untouched. If peer is selected then
- * it will reset particular TID configuration of that peer and it will
- * not accept other TID config attributes along with peer.
+ * @NL80211_TID_CONFIG_ATTR_OVERRIDE: flag attribue, if set indicates
+ * that the new configuration overrides all previous peer
+ * configurations, otherwise previous peer specific configurations
+ * should be left untouched.
* @NL80211_TID_CONFIG_ATTR_TIDS: a bitmask value of TIDs (bit 0 to 7)
* Its type is u16.
* @NL80211_TID_CONFIG_ATTR_NOACK: Configure ack policy for the TID.
@@ -4844,12 +5031,23 @@ enum nl80211_tid_config {
* &NL80211_CMD_SET_TID_CONFIG. Its type is u8, min value is 1 and
* the max value is advertised by the driver in this attribute on
* output in wiphy capabilities.
- * @NL80211_TID_CONFIG_ATTR_AMPDU_CTRL: Enable/Disable aggregation for the TIDs
- * specified in %NL80211_TID_CONFIG_ATTR_TIDS. Its type is u8, using
- * the values from &nl80211_tid_config.
+ * @NL80211_TID_CONFIG_ATTR_AMPDU_CTRL: Enable/Disable MPDU aggregation
+ * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS.
+ * Its type is u8, using the values from &nl80211_tid_config.
* @NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL: Enable/Disable RTS_CTS for the TIDs
* specified in %NL80211_TID_CONFIG_ATTR_TIDS. It is u8 type, using
* the values from &nl80211_tid_config.
+ * @NL80211_TID_CONFIG_ATTR_AMSDU_CTRL: Enable/Disable MSDU aggregation
+ * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS.
+ * Its type is u8, using the values from &nl80211_tid_config.
+ * @NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE: This attribute will be useful
+ * to notfiy the driver that what type of txrate should be used
+ * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS. using
+ * the values form &nl80211_tx_rate_setting.
+ * @NL80211_TID_CONFIG_ATTR_TX_RATE: Data frame TX rate mask should be applied
+ * with the parameters passed through %NL80211_ATTR_TX_RATES.
+ * configuration is applied to the data frame for the tid to that connected
+ * station.
*/
enum nl80211_tid_config_attr {
__NL80211_TID_CONFIG_ATTR_INVALID,
@@ -4863,6 +5061,9 @@ enum nl80211_tid_config_attr {
NL80211_TID_CONFIG_ATTR_RETRY_LONG,
NL80211_TID_CONFIG_ATTR_AMPDU_CTRL,
NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL,
+ NL80211_TID_CONFIG_ATTR_AMSDU_CTRL,
+ NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE,
+ NL80211_TID_CONFIG_ATTR_TX_RATE,
/* keep last */
__NL80211_TID_CONFIG_ATTR_AFTER_LAST,
@@ -5340,6 +5541,8 @@ enum plink_actions {
#define NL80211_KCK_LEN 16
#define NL80211_KEK_LEN 16
+#define NL80211_KCK_EXT_LEN 24
+#define NL80211_KEK_EXT_LEN 32
#define NL80211_REPLAY_CTR_LEN 8
/**
@@ -5348,6 +5551,7 @@ enum plink_actions {
* @NL80211_REKEY_DATA_KEK: key encryption key (binary)
* @NL80211_REKEY_DATA_KCK: key confirmation key (binary)
* @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary)
+ * @NL80211_REKEY_DATA_AKM: AKM data (OUI, suite type)
* @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal)
* @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal)
*/
@@ -5356,6 +5560,7 @@ enum nl80211_rekey_data {
NL80211_REKEY_DATA_KEK,
NL80211_REKEY_DATA_KCK,
NL80211_REKEY_DATA_REPLAY_CTR,
+ NL80211_REKEY_DATA_AKM,
/* keep last */
NUM_NL80211_REKEY_DATA,
@@ -5576,7 +5781,7 @@ enum nl80211_feature_flags {
* enum nl80211_ext_feature_index - bit index of extended features.
* @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates.
* @NL80211_EXT_FEATURE_RRM: This driver supports RRM. When featured, user can
- * can request to use RRM (see %NL80211_ATTR_USE_RRM) with
+ * request to use RRM (see %NL80211_ATTR_USE_RRM) with
* %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests, which will set
* the ASSOC_REQ_USE_RRM flag in the association request even if
* NL80211_FEATURE_QUIET is not advertized.
@@ -5705,6 +5910,33 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS: management frame registrations
* are possible for multicast frames and those will be reported properly.
*
+ * @NL80211_EXT_FEATURE_SCAN_FREQ_KHZ: This driver supports receiving and
+ * reporting scan request with %NL80211_ATTR_SCAN_FREQ_KHZ. In order to
+ * report %NL80211_ATTR_SCAN_FREQ_KHZ, %NL80211_SCAN_FLAG_FREQ_KHZ must be
+ * included in the scan request.
+ *
+ * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS: The driver
+ * can report tx status for control port over nl80211 tx operations.
+ *
+ * @NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION: Driver supports Operating
+ * Channel Validation (OCV) when using driver's SME for RSNA handshakes.
+ *
+ * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK: Device wants to do 4-way
+ * handshake with PSK in AP mode (PSK is passed as part of the start AP
+ * command).
+ *
+ * @NL80211_EXT_FEATURE_SAE_OFFLOAD_AP: Device wants to do SAE authentication
+ * in AP mode (SAE password is passed as part of the start AP command).
+ *
+ * @NL80211_EXT_FEATURE_FILS_DISCOVERY: Driver/device supports FILS discovery
+ * frames transmission
+ *
+ * @NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP: Driver/device supports
+ * unsolicited broadcast probe response transmission
+ *
+ * @NL80211_EXT_FEATURE_BEACON_RATE_HE: Driver supports beacon rate
+ * configuration (AP/mesh) with HE rates.
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -5758,6 +5990,14 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_DEL_IBSS_STA,
NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS,
NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT,
+ NL80211_EXT_FEATURE_SCAN_FREQ_KHZ,
+ NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS,
+ NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK,
+ NL80211_EXT_FEATURE_SAE_OFFLOAD_AP,
+ NL80211_EXT_FEATURE_FILS_DISCOVERY,
+ NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP,
+ NL80211_EXT_FEATURE_BEACON_RATE_HE,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -5869,6 +6109,11 @@ enum nl80211_timeout_reason {
* @NL80211_SCAN_FLAG_MIN_PREQ_CONTENT: minimize probe request content to
* only have supported rates and no additional capabilities (unless
* added by userspace explicitly.)
+ * @NL80211_SCAN_FLAG_FREQ_KHZ: report scan results with
+ * %NL80211_ATTR_SCAN_FREQ_KHZ. This also means
+ * %NL80211_ATTR_SCAN_FREQUENCIES will not be included.
+ * @NL80211_SCAN_FLAG_COLOCATED_6GHZ: scan for colocated APs reported by
+ * 2.4/5 GHz APs
*/
enum nl80211_scan_flags {
NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
@@ -5884,6 +6129,8 @@ enum nl80211_scan_flags {
NL80211_SCAN_FLAG_HIGH_ACCURACY = 1<<10,
NL80211_SCAN_FLAG_RANDOM_SN = 1<<11,
NL80211_SCAN_FLAG_MIN_PREQ_CONTENT = 1<<12,
+ NL80211_SCAN_FLAG_FREQ_KHZ = 1<<13,
+ NL80211_SCAN_FLAG_COLOCATED_6GHZ = 1<<14,
};
/**
@@ -5971,7 +6218,7 @@ enum nl80211_dfs_state {
};
/**
- * enum enum nl80211_protocol_features - nl80211 protocol features
+ * enum nl80211_protocol_features - nl80211 protocol features
* @NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP: nl80211 supports splitting
* wiphy dumps (if requested by the application with the attribute
* %NL80211_ATTR_SPLIT_WIPHY_DUMP. Also supported is filtering the
@@ -6786,6 +7033,13 @@ enum nl80211_peer_measurement_ftm_resp {
*
* @NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET: the OBSS PD minimum tx power offset.
* @NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET: the OBSS PD maximum tx power offset.
+ * @NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET: the non-SRG OBSS PD maximum
+ * tx power offset.
+ * @NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP: bitmap that indicates the BSS color
+ * values used by members of the SRG.
+ * @NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP: bitmap that indicates the partial
+ * BSSID values used by members of the SRG.
+ * @NL80211_HE_OBSS_PD_ATTR_SR_CTRL: The SR Control field of SRP element.
*
* @__NL80211_HE_OBSS_PD_ATTR_LAST: Internal
* @NL80211_HE_OBSS_PD_ATTR_MAX: highest OBSS PD attribute.
@@ -6795,6 +7049,10 @@ enum nl80211_obss_pd_attributes {
NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
+ NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET,
+ NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP,
+ NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP,
+ NL80211_HE_OBSS_PD_ATTR_SR_CTRL,
/* keep last */
__NL80211_HE_OBSS_PD_ATTR_LAST,
@@ -6848,4 +7106,175 @@ enum nl80211_iftype_akm_attributes {
NL80211_IFTYPE_AKM_ATTR_MAX = __NL80211_IFTYPE_AKM_ATTR_LAST - 1,
};
+/**
+ * enum nl80211_fils_discovery_attributes - FILS discovery configuration
+ * from IEEE Std 802.11ai-2016, Annex C.3 MIB detail.
+ *
+ * @__NL80211_FILS_DISCOVERY_ATTR_INVALID: Invalid
+ *
+ * @NL80211_FILS_DISCOVERY_ATTR_INT_MIN: Minimum packet interval (u32, TU).
+ * Allowed range: 0..10000 (TU = Time Unit)
+ * @NL80211_FILS_DISCOVERY_ATTR_INT_MAX: Maximum packet interval (u32, TU).
+ * Allowed range: 0..10000 (TU = Time Unit)
+ * @NL80211_FILS_DISCOVERY_ATTR_TMPL: Template data for FILS discovery action
+ * frame including the headers.
+ *
+ * @__NL80211_FILS_DISCOVERY_ATTR_LAST: Internal
+ * @NL80211_FILS_DISCOVERY_ATTR_MAX: highest attribute
+ */
+enum nl80211_fils_discovery_attributes {
+ __NL80211_FILS_DISCOVERY_ATTR_INVALID,
+
+ NL80211_FILS_DISCOVERY_ATTR_INT_MIN,
+ NL80211_FILS_DISCOVERY_ATTR_INT_MAX,
+ NL80211_FILS_DISCOVERY_ATTR_TMPL,
+
+ /* keep last */
+ __NL80211_FILS_DISCOVERY_ATTR_LAST,
+ NL80211_FILS_DISCOVERY_ATTR_MAX = __NL80211_FILS_DISCOVERY_ATTR_LAST - 1
+};
+
+/*
+ * FILS discovery template minimum length with action frame headers and
+ * mandatory fields.
+ */
+#define NL80211_FILS_DISCOVERY_TMPL_MIN_LEN 42
+
+/**
+ * enum nl80211_unsol_bcast_probe_resp_attributes - Unsolicited broadcast probe
+ * response configuration. Applicable only in 6GHz.
+ *
+ * @__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INVALID: Invalid
+ *
+ * @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT: Maximum packet interval (u32, TU).
+ * Allowed range: 0..20 (TU = Time Unit). IEEE P802.11ax/D6.0
+ * 26.17.2.3.2 (AP behavior for fast passive scanning).
+ * @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL: Unsolicited broadcast probe response
+ * frame template (binary).
+ *
+ * @__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST: Internal
+ * @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX: highest attribute
+ */
+enum nl80211_unsol_bcast_probe_resp_attributes {
+ __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INVALID,
+
+ NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT,
+ NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL,
+
+ /* keep last */
+ __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST,
+ NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX =
+ __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST - 1
+};
+
+/**
+ * enum nl80211_sae_pwe_mechanism - The mechanism(s) allowed for SAE PWE
+ * derivation. Applicable only when WPA3-Personal SAE authentication is
+ * used.
+ *
+ * @NL80211_SAE_PWE_UNSPECIFIED: not specified, used internally to indicate that
+ * attribute is not present from userspace.
+ * @NL80211_SAE_PWE_HUNT_AND_PECK: hunting-and-pecking loop only
+ * @NL80211_SAE_PWE_HASH_TO_ELEMENT: hash-to-element only
+ * @NL80211_SAE_PWE_BOTH: both hunting-and-pecking loop and hash-to-element
+ * can be used.
+ */
+enum nl80211_sae_pwe_mechanism {
+ NL80211_SAE_PWE_UNSPECIFIED,
+ NL80211_SAE_PWE_HUNT_AND_PECK,
+ NL80211_SAE_PWE_HASH_TO_ELEMENT,
+ NL80211_SAE_PWE_BOTH,
+};
+
+/**
+ * enum nl80211_sar_type - type of SAR specs
+ *
+ * @NL80211_SAR_TYPE_POWER: power limitation specified in 0.25dBm unit
+ *
+ */
+enum nl80211_sar_type {
+ NL80211_SAR_TYPE_POWER,
+
+ /* add new type here */
+
+ /* Keep last */
+ NUM_NL80211_SAR_TYPE,
+};
+
+/**
+ * enum nl80211_sar_attrs - Attributes for SAR spec
+ *
+ * @NL80211_SAR_ATTR_TYPE: the SAR type as defined in &enum nl80211_sar_type.
+ *
+ * @NL80211_SAR_ATTR_SPECS: Nested array of SAR power
+ * limit specifications. Each specification contains a set
+ * of %nl80211_sar_specs_attrs.
+ *
+ * For SET operation, it contains array of %NL80211_SAR_ATTR_SPECS_POWER
+ * and %NL80211_SAR_ATTR_SPECS_RANGE_INDEX.
+ *
+ * For sar_capa dump, it contains array of
+ * %NL80211_SAR_ATTR_SPECS_START_FREQ
+ * and %NL80211_SAR_ATTR_SPECS_END_FREQ.
+ *
+ * @__NL80211_SAR_ATTR_LAST: Internal
+ * @NL80211_SAR_ATTR_MAX: highest sar attribute
+ *
+ * These attributes are used with %NL80211_CMD_SET_SAR_SPEC
+ */
+enum nl80211_sar_attrs {
+ __NL80211_SAR_ATTR_INVALID,
+
+ NL80211_SAR_ATTR_TYPE,
+ NL80211_SAR_ATTR_SPECS,
+
+ __NL80211_SAR_ATTR_LAST,
+ NL80211_SAR_ATTR_MAX = __NL80211_SAR_ATTR_LAST - 1,
+};
+
+/**
+ * enum nl80211_sar_specs_attrs - Attributes for SAR power limit specs
+ *
+ * @NL80211_SAR_ATTR_SPECS_POWER: Required (s32)value to specify the actual
+ * power limit value in units of 0.25 dBm if type is
+ * NL80211_SAR_TYPE_POWER. (i.e., a value of 44 represents 11 dBm).
+ * 0 means userspace doesn't have SAR limitation on this associated range.
+ *
+ * @NL80211_SAR_ATTR_SPECS_RANGE_INDEX: Required (u32) value to specify the
+ * index of exported freq range table and the associated power limitation
+ * is applied to this range.
+ *
+ * Userspace isn't required to set all the ranges advertised by WLAN driver,
+ * and userspace can skip some certain ranges. These skipped ranges don't
+ * have SAR limitations, and they are same as setting the
+ * %NL80211_SAR_ATTR_SPECS_POWER to any unreasonable high value because any
+ * value higher than regulatory allowed value just means SAR power
+ * limitation is removed, but it's required to set at least one range.
+ * It's not allowed to set duplicated range in one SET operation.
+ *
+ * Every SET operation overwrites previous SET operation.
+ *
+ * @NL80211_SAR_ATTR_SPECS_START_FREQ: Required (u32) value to specify the start
+ * frequency of this range edge when registering SAR capability to wiphy.
+ * It's not a channel center frequency. The unit is kHz.
+ *
+ * @NL80211_SAR_ATTR_SPECS_END_FREQ: Required (u32) value to specify the end
+ * frequency of this range edge when registering SAR capability to wiphy.
+ * It's not a channel center frequency. The unit is kHz.
+ *
+ * @__NL80211_SAR_ATTR_SPECS_LAST: Internal
+ * @NL80211_SAR_ATTR_SPECS_MAX: highest sar specs attribute
+ */
+enum nl80211_sar_specs_attrs {
+ __NL80211_SAR_ATTR_SPECS_INVALID,
+
+ NL80211_SAR_ATTR_SPECS_POWER,
+ NL80211_SAR_ATTR_SPECS_RANGE_INDEX,
+ NL80211_SAR_ATTR_SPECS_START_FREQ,
+ NL80211_SAR_ATTR_SPECS_END_FREQ,
+
+ __NL80211_SAR_ATTR_SPECS_LAST,
+ NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/eap_common/Makefile b/src/eap_common/Makefile
index f00b438c..fd058a09 100644
--- a/src/eap_common/Makefile
+++ b/src/eap_common/Makefile
@@ -1,13 +1,3 @@
-all: libeap_common.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libeap_common.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
LIB_OBJS= \
chap.o \
eap_common.o \
@@ -25,7 +15,4 @@ LIB_OBJS= \
eap_wsc_common.o \
ikev2_common.o
-libeap_common.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/eap_common/eap_sim_common.c b/src/eap_common/eap_sim_common.c
index 4a932440..ea38e6aa 100644
--- a/src/eap_common/eap_sim_common.c
+++ b/src/eap_common/eap_sim_common.c
@@ -1209,10 +1209,23 @@ void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
}
}
+static const u8 * get_last_char(const u8 *val, size_t len, char c)
+{
+ while (len > 0) {
+ const u8 *pos = &val[len - 1];
+
+ if (*pos == (u8) c)
+ return pos;
+ len--;
+ }
+
+ return NULL;
+}
int eap_sim_anonymous_username(const u8 *id, size_t id_len)
{
static const char *anonymous_id_prefix = "anonymous@";
+ const u8 *decorated;
size_t anonymous_id_len = os_strlen(anonymous_id_prefix);
if (id_len > anonymous_id_len &&
@@ -1226,5 +1239,14 @@ int eap_sim_anonymous_username(const u8 *id, size_t id_len)
if (id_len > 1 && id[0] == '@')
return 1; /* '@realm' */
+ /* RFC 7542 decorated username, for example:
+ * homerealm.example.org!anonymous@otherrealm.example.net */
+ decorated = get_last_char(id, id_len, '!');
+ if (decorated) {
+ decorated++;
+ return eap_sim_anonymous_username(decorated,
+ id + id_len - decorated);
+ }
return 0;
}
+
diff --git a/src/eap_peer/.gitignore b/src/eap_peer/.gitignore
new file mode 100644
index 00000000..140f8cf8
--- /dev/null
+++ b/src/eap_peer/.gitignore
@@ -0,0 +1 @@
+*.so
diff --git a/src/eap_peer/Makefile b/src/eap_peer/Makefile
index 6531ccd5..bdbead6a 100644
--- a/src/eap_peer/Makefile
+++ b/src/eap_peer/Makefile
@@ -1,23 +1,13 @@
-all: libeap_peer.a
-
-clean:
- rm -f *~ *.o *.so *.d *.gcno *.gcda *.gcov libeap_peer.a
-
-install:
- if ls *.so >/dev/null 2>&1; then \
- install -d $(DESTDIR)$(LIBDIR)/wpa_supplicant && \
- cp *.so $(DESTDIR)$(LIBDIR)/wpa_supplicant \
- ; fi
-
-include ../lib.rules
-
CFLAGS += -DIEEE8021X_EAPOL
LIB_OBJS= \
eap.o \
eap_methods.o
-libeap_peer.a: $(LIB_OBJS)
- $(AR) crT $@ $?
+include ../lib.rules
--include $(OBJS:%.o=%.d)
+install:
+ if ls *.so >/dev/null 2>&1; then \
+ install -d $(DESTDIR)$(LIBDIR)/wpa_supplicant && \
+ cp *.so $(DESTDIR)$(LIBDIR)/wpa_supplicant \
+ ; fi
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index e57461a3..8c475f13 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -442,19 +442,28 @@ static int eap_aka_learn_ids(struct eap_sm *sm, struct eap_aka_data *data,
static int eap_aka_add_id_msg(struct eap_aka_data *data,
- const struct wpabuf *msg)
+ const struct wpabuf *msg1,
+ const struct wpabuf *msg2)
{
- if (msg == NULL)
+ size_t len;
+
+ if (!msg1)
return -1;
+ len = wpabuf_len(msg1);
+ if (msg2)
+ len += wpabuf_len(msg2);
- if (data->id_msgs == NULL) {
- data->id_msgs = wpabuf_dup(msg);
- return data->id_msgs == NULL ? -1 : 0;
+ if (!data->id_msgs) {
+ data->id_msgs = wpabuf_alloc(len);
+ if (!data->id_msgs)
+ return -1;
+ } else if (wpabuf_resize(&data->id_msgs, len) < 0) {
+ return -1;
}
- if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
- return -1;
- wpabuf_put_buf(data->id_msgs, msg);
+ wpabuf_put_buf(data->id_msgs, msg1);
+ if (msg2)
+ wpabuf_put_buf(data->id_msgs, msg2);
return 0;
}
@@ -799,8 +808,13 @@ static struct wpabuf * eap_aka_process_identity(struct eap_sm *sm,
buf = eap_aka_response_identity(sm, data, id, attr->id_req);
if (data->prev_id != id) {
- eap_aka_add_id_msg(data, reqData);
- eap_aka_add_id_msg(data, buf);
+ if (eap_aka_add_id_msg(data, reqData, buf) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-AKA: Failed to store ID messages");
+ wpabuf_free(buf);
+ return eap_aka_client_error(
+ data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
data->prev_id = id;
}
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 7c370436..12e30df2 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -803,6 +803,10 @@ static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
if (res)
return res;
+ if (wpabuf_len(in_decrypted) == 0) {
+ wpabuf_free(in_decrypted);
+ return 1;
+ }
continue_req:
wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
@@ -1081,7 +1085,11 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
}
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
- char *label;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_PEAP };
+ const u8 *context = NULL;
+ size_t context_len = 0;
+
wpa_printf(MSG_DEBUG,
"EAP-PEAP: TLS done, proceed to Phase 2");
eap_peap_free_key(data);
@@ -1091,16 +1099,25 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
* PEAPv1 implementations seem to be using the old
* label, "client EAP encryption", instead. Use the old
* label by default, but allow it to be configured with
- * phase1 parameter peaplabel=1. */
- if (data->force_new_label)
+ * phase1 parameter peaplabel=1.
+ *
+ * When using TLS 1.3, draft-ietf-emu-tls-eap-types
+ * defines a new set of label and context parameters.
+ */
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else if (data->force_new_label) {
label = "client PEAP encryption";
- else
+ } else {
label = "client EAP encryption";
+ }
wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
"key derivation", label);
data->key_data =
eap_peer_tls_derive_key(sm, &data->ssl, label,
- NULL, 0,
+ context, context_len,
EAP_TLS_KEY_LEN +
EAP_EMSK_LEN);
if (data->key_data) {
diff --git a/src/eap_peer/eap_teap.c b/src/eap_peer/eap_teap.c
index 76179a32..e8cc7844 100644
--- a/src/eap_peer/eap_teap.c
+++ b/src/eap_peer/eap_teap.c
@@ -1388,6 +1388,15 @@ static int eap_teap_process_decrypted(struct eap_sm *sm,
"EAP-TEAP: PAC used - server may decide to skip inner authentication");
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_COND_SUCC;
+ } else if (data->result_success_done &&
+ tls_connection_get_own_cert_used(data->ssl.conn) &&
+ eap_teap_derive_msk(data) == 0) {
+ /* Assume the server might accept authentication without going
+ * through inner authentication. */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Client certificate used - server may decide to skip inner authentication");
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_COND_SUCC;
}
if (tlv.pac) {
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index ad079a7b..0d479f1c 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -302,15 +302,11 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
return NULL;
}
- if (res == 2) {
- /* Application data included in the handshake message (used by
- * EAP-TLS 1.3 to indicate conclusion of the exchange). */
- wpa_hexdump_buf(MSG_DEBUG, "EAP-TLS: Received Application Data",
- resp);
- wpa_hexdump_buf(MSG_DEBUG, "EAP-TLS: Remaining tls_out data",
- data->ssl.tls_out);
+ /* draft-ietf-emu-eap-tls13-13 Section 2.5 */
+ if (res == 2 && data->ssl.tls_v13 && wpabuf_len(resp) == 1 &&
+ *wpabuf_head_u8(resp) == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TLS: ACKing Commitment Message");
eap_peer_tls_reset_output(&data->ssl);
- /* Send an ACK to allow the server to complete exchange */
res = 1;
}
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index ab106787..0e00801d 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -278,7 +278,7 @@ static int eap_tls_init_connection(struct eap_sm *sm,
}
if (res) {
wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
- "parameters");
+ "parameters, error code: %d", res);
tls_connection_deinit(data->ssl_ctx, data->conn);
data->conn = NULL;
return -1;
@@ -413,9 +413,9 @@ u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
struct tls_random keys;
u8 *out;
- if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
+ if (data->tls_v13) {
u8 *id, *method_id;
- const u8 context[] = { EAP_TYPE_TLS };
+ const u8 context[] = { eap_type };
/* Session-Id = <EAP-Type> || Method-Id
* Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 642d179c..c4019154 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -268,10 +268,22 @@ static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
static int eap_ttls_v0_derive_key(struct eap_sm *sm,
struct eap_ttls_data *data)
{
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_TTLS };
+ const u8 *context = NULL;
+ size_t context_len = 0;
+
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ label = "ttls keying material";
+ }
+
eap_ttls_free_key(data);
- data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
- "ttls keying material",
- NULL, 0,
+ data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, label,
+ context, context_len,
EAP_TLS_KEY_LEN +
EAP_EMSK_LEN);
if (!data->key_data) {
@@ -1441,6 +1453,7 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
if ((in_data == NULL || wpabuf_len(in_data) == 0) &&
data->phase2_start) {
+start:
return eap_ttls_phase2_start(sm, data, ret, identifier,
out_data);
}
@@ -1455,6 +1468,20 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
if (retval)
goto done;
+ if (wpabuf_len(in_decrypted) == 0) {
+ wpabuf_free(in_decrypted);
+ goto start;
+ }
+
+ /* draft-ietf-emu-eap-tls13-13 Section 2.5 */
+ if (data->ssl.tls_v13 && wpabuf_len(in_decrypted) == 1 &&
+ *wpabuf_head_u8(in_decrypted) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: ACKing EAP-TLS Commitment Message");
+ eap_peer_tls_reset_output(&data->ssl);
+ wpabuf_free(in_decrypted);
+ return 1;
+ }
continue_req:
data->phase2_start = 0;
diff --git a/src/eap_peer/ikev2.c b/src/eap_peer/ikev2.c
index 7bd97b1b..c2e6c5df 100644
--- a/src/eap_peer/ikev2.c
+++ b/src/eap_peer/ikev2.c
@@ -201,7 +201,8 @@ static int ikev2_parse_proposal(struct ikev2_proposal_data *prop,
const u8 *pos, const u8 *end)
{
const u8 *pend, *ppos;
- int proposal_len, i;
+ int proposal_len;
+ unsigned int i, num;
const struct ikev2_proposal *p;
if (end - pos < (int) sizeof(*p)) {
@@ -269,12 +270,13 @@ static int ikev2_parse_proposal(struct ikev2_proposal_data *prop,
return -1;
}
- if (p->num_transforms == 0) {
+ num = p->num_transforms;
+ if (num == 0 || num > 255) {
wpa_printf(MSG_INFO, "IKEV2: At least one transform required");
return -1;
}
- for (i = 0; i < (int) p->num_transforms; i++) {
+ for (i = 0; i < num; i++) {
int tlen = ikev2_parse_transform(prop, ppos, pend);
if (tlen < 0)
return -1;
@@ -411,7 +413,7 @@ static int ikev2_process_kei(struct ikev2_responder_data *data,
wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEi Diffie-Hellman Public Value",
data->i_dh_public);
-
+
return 0;
}
diff --git a/src/eap_server/Makefile b/src/eap_server/Makefile
index 1172b724..cc9b76d6 100644
--- a/src/eap_server/Makefile
+++ b/src/eap_server/Makefile
@@ -1,13 +1,3 @@
-all: libeap_server.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libeap_server.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_HS20
LIB_OBJS= \
@@ -15,7 +5,4 @@ LIB_OBJS= \
eap_server_identity.o \
eap_server_methods.o
-libeap_server.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index f234f6fa..f526e8bf 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -325,13 +325,27 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
u8 *tk;
u8 isk[32], imck[60];
int res;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_PEAP };
+ const u8 *context = NULL;
+ size_t context_len = 0;
+
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ /* TODO: PEAPv1 - different label in some cases */
+ label = "client EAP encryption";
+ }
/*
* Tunnel key (TK) is the first 60 octets of the key generated by
* phase 1 of PEAP (based on TLS).
*/
- tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
- NULL, 0, EAP_TLS_KEY_LEN);
+ tk = eap_server_tls_derive_key(sm, &data->ssl, label,
+ context, context_len,
+ EAP_TLS_KEY_LEN);
if (tk == NULL)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
@@ -498,7 +512,25 @@ static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,
encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
os_free(hdr);
- return encr_req;
+ if (!data->ssl.tls_v13 ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn)) {
+ wpabuf_free(data->ssl.tls_out);
+ data->ssl.tls_out_pos = 0;
+ return encr_req;
+ }
+
+ if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr_req)) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-PEAP: Failed to resize output buffer");
+ wpabuf_free(encr_req);
+ return NULL;
+ }
+ wpabuf_put_buf(data->ssl.tls_out, encr_req);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "EAP-PEAP: Data appended to the message", encr_req);
+ os_free(encr_req);
+
+ return data->ssl.tls_out;
}
@@ -547,8 +579,6 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id);
break;
case SUCCESS_REQ:
- wpabuf_free(data->ssl.tls_out);
- data->ssl.tls_out_pos = 0;
data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
1);
break;
@@ -1300,6 +1330,10 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_peap_data *data = priv;
u8 *eapKeyData;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_PEAP };
+ const u8 *context = NULL;
+ size_t context_len = 0;
if (data->state != SUCCESS)
return NULL;
@@ -1332,9 +1366,17 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
return eapKeyData;
}
- /* TODO: PEAPv1 - different label in some cases */
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ /* TODO: PEAPv1 - different label in some cases */
+ label = "client EAP encryption";
+ }
+
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "client EAP encryption", NULL, 0,
+ label, context, context_len,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN);
@@ -1353,6 +1395,10 @@ static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_peap_data *data = priv;
u8 *eapKeyData, *emsk;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_PEAP };
+ const u8 *context = NULL;
+ size_t context_len = 0;
if (data->state != SUCCESS)
return NULL;
@@ -1362,9 +1408,17 @@ static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
return NULL;
}
- /* TODO: PEAPv1 - different label in some cases */
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ /* TODO: PEAPv1 - different label in some cases */
+ label = "client EAP encryption";
+ }
+
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "client EAP encryption", NULL, 0,
+ label, context, context_len,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
emsk = os_memdup(eapKeyData + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
diff --git a/src/eap_server/eap_server_teap.c b/src/eap_server/eap_server_teap.c
index d7b1b099..691b44a8 100644
--- a/src/eap_server/eap_server_teap.c
+++ b/src/eap_server/eap_server_teap.c
@@ -64,7 +64,7 @@ struct eap_teap_data {
struct wpabuf *pending_phase2_resp;
struct wpabuf *server_outer_tlvs;
struct wpabuf *peer_outer_tlvs;
- u8 *identity; /* from PAC-Opaque */
+ u8 *identity; /* from PAC-Opaque or client certificate */
size_t identity_len;
int eap_seq;
int tnc_started;
@@ -365,7 +365,9 @@ static void * eap_teap_init(struct eap_sm *sm)
data->teap_version = EAP_TEAP_VERSION;
data->state = START;
- if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_TYPE_TEAP)) {
+ if (eap_server_tls_ssl_init(sm, &data->ssl,
+ sm->cfg->eap_teap_auth == 2 ? 2 : 0,
+ EAP_TYPE_TEAP)) {
wpa_printf(MSG_INFO, "EAP-TEAP: Failed to initialize SSL.");
eap_teap_reset(sm, data);
return NULL;
@@ -502,6 +504,19 @@ static int eap_teap_phase1_done(struct eap_sm *sm, struct eap_teap_data *data)
wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 1 done, starting Phase 2");
+ if (!data->identity && sm->cfg->eap_teap_auth == 2) {
+ const char *subject;
+
+ subject = tls_connection_get_peer_subject(data->ssl.conn);
+ if (subject) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Peer subject from Phase 1 client certificate: '%s'",
+ subject);
+ data->identity = (u8 *) os_strdup(subject);
+ data->identity_len = os_strlen(subject);
+ }
+ }
+
data->tls_cs = tls_connection_get_cipher_suite(data->ssl.conn);
wpa_printf(MSG_DEBUG, "EAP-TEAP: TLS cipher suite 0x%04x",
data->tls_cs);
@@ -1775,9 +1790,10 @@ static int eap_teap_process_phase2_start(struct eap_sm *sm,
next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
eap_teap_state(data, PHASE2_METHOD);
- } else if (sm->cfg->eap_teap_pac_no_inner) {
+ } else if (sm->cfg->eap_teap_pac_no_inner ||
+ sm->cfg->eap_teap_auth == 2) {
wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Used PAC and identity already known - skip inner auth");
+ "EAP-TEAP: Used PAC or client certificate and identity already known - skip inner auth");
data->skipped_inner_auth = 1;
/* FIX: Need to derive CMK here. However, how is that
* supposed to be done? RFC 7170 does not tell that for
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 769fd1fe..00a496f2 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -266,39 +266,6 @@ static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
eap_tls_state(data, FAILURE);
return;
}
-
- if (data->ssl.tls_v13 &&
- tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn)) {
- struct wpabuf *plain, *encr;
-
- wpa_printf(MSG_DEBUG,
- "EAP-TLS: Send empty application data to indicate end of exchange");
- /* FIX: This should be an empty application data based on
- * draft-ietf-emu-eap-tls13-05, but OpenSSL does not allow zero
- * length payload (SSL_write() documentation explicitly
- * describes this as not allowed), so work around that for now
- * by sending out a payload of one octet. Hopefully the draft
- * specification will change to allow this so that no crypto
- * library changes are needed. */
- plain = wpabuf_alloc(1);
- if (!plain)
- return;
- wpabuf_put_u8(plain, 0);
- encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
- wpabuf_free(plain);
- if (!encr)
- return;
- if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) {
- wpa_printf(MSG_INFO,
- "EAP-TLS: Failed to resize output buffer");
- wpabuf_free(encr);
- return;
- }
- wpabuf_put_buf(data->ssl.tls_out, encr);
- wpa_hexdump_buf(MSG_DEBUG,
- "EAP-TLS: Data appended to the message", encr);
- wpabuf_free(encr);
- }
}
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index b38f1e0b..a9b53b1a 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -146,10 +146,10 @@ u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
{
struct tls_random keys;
u8 *out;
- const u8 context[] = { EAP_TYPE_TLS };
- if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
+ if (data->tls_v13) {
u8 *id, *method_id;
+ const u8 context[] = { eap_type };
/* Session-Id = <EAP-Type> || Method-Id
* Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
@@ -366,6 +366,56 @@ int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
sm->serial_num = tls_connection_peer_serial_num(
sm->cfg->ssl_ctx, data->conn);
+ /*
+ * https://tools.ietf.org/html/draft-ietf-emu-eap-tls13#section-2.5
+ *
+ * We need to signal the other end that TLS negotiation is done. We
+ * can't send a zero-length application data message, so we send
+ * application data which is one byte of zero.
+ *
+ * Note this is only done for when there is no application data to be
+ * sent. So this is done always for EAP-TLS but notibly not for PEAP
+ * even on resumption.
+ */
+ if (data->tls_v13 &&
+ tls_connection_established(sm->cfg->ssl_ctx, data->conn)) {
+ struct wpabuf *plain, *encr;
+
+ switch (sm->currentMethod) {
+ case EAP_TYPE_PEAP:
+ break;
+ default:
+ if (!tls_connection_resumed(sm->cfg->ssl_ctx,
+ data->conn))
+ break;
+ /* fallthrough */
+ case EAP_TYPE_TLS:
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Send Commitment Message");
+
+ plain = wpabuf_alloc(1);
+ if (!plain)
+ return -1;
+ wpabuf_put_u8(plain, 0);
+ encr = eap_server_tls_encrypt(sm, data, plain);
+ wpabuf_free(plain);
+ if (!encr)
+ return -1;
+ if (wpabuf_resize(&data->tls_out, wpabuf_len(encr)) < 0)
+ {
+ wpa_printf(MSG_INFO,
+ "EAP-TLS: Failed to resize output buffer");
+ wpabuf_free(encr);
+ return -1;
+ }
+ wpabuf_put_buf(data->tls_out, encr);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "EAP-TLS: Data appended to the message",
+ encr);
+ wpabuf_free(encr);
+ }
+ }
+
return 0;
}
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 2f0c041d..b8935224 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -1271,13 +1271,25 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_ttls_data *data = priv;
u8 *eapKeyData;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_TTLS };
+ const u8 *context = NULL;
+ size_t context_len = 0;
if (data->state != SUCCESS)
return NULL;
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ label = "ttls keying material";
+ }
+
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "ttls keying material", NULL, 0,
- EAP_TLS_KEY_LEN);
+ label, context, context_len,
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
*len = EAP_TLS_KEY_LEN;
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
@@ -1313,12 +1325,24 @@ static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_ttls_data *data = priv;
u8 *eapKeyData, *emsk;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_TTLS };
+ const u8 *context = NULL;
+ size_t context_len = 0;
if (data->state != SUCCESS)
return NULL;
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ label = "ttls keying material";
+ }
+
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "ttls keying material", NULL, 0,
+ label, context, context_len,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
emsk = os_malloc(EAP_EMSK_LEN);
diff --git a/src/eapol_auth/Makefile b/src/eapol_auth/Makefile
index 7b927a12..c82042f4 100644
--- a/src/eapol_auth/Makefile
+++ b/src/eapol_auth/Makefile
@@ -1,16 +1,2 @@
-all: libeapol_auth.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libeapol_auth.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
LIB_OBJS = eapol_auth_sm.o eapol_auth_dump.o
-
-libeapol_auth.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/eapol_supp/Makefile b/src/eapol_supp/Makefile
index 80db9d48..67a11857 100644
--- a/src/eapol_supp/Makefile
+++ b/src/eapol_supp/Makefile
@@ -1,18 +1,5 @@
-all: libeapol_supp.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libeapol_supp.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DIEEE8021X_EAPOL
LIB_OBJS = eapol_supp_sm.o
-libeapol_supp.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/l2_packet/Makefile b/src/l2_packet/Makefile
index 47925b79..c616626b 100644
--- a/src/l2_packet/Makefile
+++ b/src/l2_packet/Makefile
@@ -1,16 +1,3 @@
-all: libl2_packet.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libl2_packet.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
LIB_OBJS = l2_packet_linux.o
-libl2_packet.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/lib.rules b/src/lib.rules
index a4631544..947617b0 100644
--- a/src/lib.rules
+++ b/src/lib.rules
@@ -1,10 +1,8 @@
-ifndef CC
-CC=gcc
-endif
-
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
-endif
+_LIBMK := $(lastword $(wordlist 1,$(shell expr $(words $(MAKEFILE_LIST)) - 1),$(MAKEFILE_LIST)))
+_LIBNAME := $(notdir $(patsubst %/,%,$(dir $(abspath $(_LIBMK)))))
+ALL := $(OUT)lib$(_LIBNAME).a
+LIB_RULES := $(lastword $(MAKEFILE_LIST))
+include $(dir $(LIB_RULES))build.rules
ifdef TEST_FUZZ
CFLAGS += -DCONFIG_NO_RANDOM_POOL
@@ -14,18 +12,18 @@ endif
CFLAGS += $(FUZZ_CFLAGS)
CFLAGS += -I.. -I../utils
+_OBJS_VAR := LIB_OBJS
+include ../objs.mk
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-ifeq ($(QUIET), 1)
-Q=@
-E=true
-endif
+$(ALL): $(LIB_OBJS)
+ @$(E) " AR $(notdir $@)"
+ $(Q)$(AR) crT $@ $?
+
+install-default:
+ @echo Nothing to be made.
+
+%: %-default
+ @true
-%.o: %.c
- $(Q)$(CC) -c -o $@ $(CFLAGS) $<
- @$(E) " CC " $<
+clean: common-clean
+ $(Q)rm -f *~ *.o *.d *.gcno *.gcda *.gcov $(ALL)
diff --git a/src/objs.mk b/src/objs.mk
new file mode 100644
index 00000000..a3040b21
--- /dev/null
+++ b/src/objs.mk
@@ -0,0 +1,3 @@
+$(_OBJS_VAR) := $(call BUILDOBJ,$($(_OBJS_VAR)))
+-include $(filter-out %.a,$($(_OBJS_VAR):%.o=%.d))
+_DIRS += $(dir $($(_OBJS_VAR)))
diff --git a/src/p2p/Makefile b/src/p2p/Makefile
index 5587fcf2..4d161800 100644
--- a/src/p2p/Makefile
+++ b/src/p2p/Makefile
@@ -1,13 +1,3 @@
-all: libp2p.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libp2p.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_WIFI_DISPLAY
CFLAGS += -DCONFIG_WPS_NFC
@@ -23,7 +13,4 @@ LIB_OBJS= \
p2p_sd.o \
p2p_utils.o
-libp2p.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 1dc5b92a..8b443d6e 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -668,6 +668,8 @@ static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies,
if (wpabuf_resize(&dev->info.vendor_elems, 2 + len) < 0)
break;
wpabuf_put_data(dev->info.vendor_elems, pos - 2, 2 + len);
+ if (wpabuf_size(dev->info.vendor_elems) > 2000)
+ break;
}
}
@@ -2923,6 +2925,14 @@ void p2p_group_formation_failed(struct p2p_data *p2p)
}
+bool is_p2p_6ghz_disabled(struct p2p_data *p2p)
+{
+ if (p2p)
+ return p2p->cfg->p2p_6ghz_disable;
+ return false;
+}
+
+
struct p2p_data * p2p_init(const struct p2p_config *cfg)
{
struct p2p_data *p2p;
@@ -3512,12 +3522,17 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
}
-void p2p_scan_res_handled(struct p2p_data *p2p)
+void p2p_scan_res_handled(struct p2p_data *p2p, unsigned int delay)
{
if (!p2p->p2p_scan_running) {
p2p_dbg(p2p, "p2p_scan was not running, but scan results received");
}
p2p->p2p_scan_running = 0;
+
+ /* Use this delay only when p2p_find doesn't set it */
+ if (!p2p->search_delay)
+ p2p->search_delay = delay;
+
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
if (p2p_run_after_scan(p2p))
@@ -3984,6 +3999,7 @@ static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p)
}
p2p_dbg(p2p, "Go to Listen state while waiting for the peer to become ready for GO Negotiation");
+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
p2p_listen_in_find(p2p, 0);
}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 2dae6c6e..762bd40b 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -501,6 +501,11 @@ struct p2p_config {
struct p2p_channel *pref_chan;
/**
+ * p2p_6ghz_disable - Disable 6GHz for P2P operations
+ */
+ bool p2p_6ghz_disable;
+
+ /**
* pri_dev_type - Primary Device Type (see WPS)
*/
u8 pri_dev_type[8];
@@ -1620,6 +1625,7 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
/**
* p2p_scan_res_handled - Indicate end of scan results
* @p2p: P2P module context from p2p_init()
+ * @delay: Search delay for next scan in ms
*
* This function is called to indicate that all P2P scan results from a scan
* have been reported with zero or more calls to p2p_scan_res_handler(). This
@@ -1627,7 +1633,7 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
* struct p2p_config::p2p_scan() call if none of the p2p_scan_res_handler()
* calls stopped iteration.
*/
-void p2p_scan_res_handled(struct p2p_data *p2p);
+void p2p_scan_res_handled(struct p2p_data *p2p, unsigned int delay);
enum p2p_send_action_result {
P2P_SEND_ACTION_SUCCESS /* Frame was send and acknowledged */,
@@ -2100,6 +2106,8 @@ void p2p_update_channel_list(struct p2p_data *p2p,
const struct p2p_channels *chan,
const struct p2p_channels *cli_chan);
+bool is_p2p_6ghz_disabled(struct p2p_data *p2p);
+
/**
* p2p_set_best_channels - Update best channel information
* @p2p: P2P module context from p2p_init()
diff --git a/src/radius/Makefile b/src/radius/Makefile
index 3ad4751d..8cfb33d3 100644
--- a/src/radius/Makefile
+++ b/src/radius/Makefile
@@ -1,14 +1,3 @@
-all: libradius.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libradius.a
-
-install:
- @echo Nothing to be made.
-
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_IPV6
LIB_OBJS= \
@@ -17,7 +6,4 @@ LIB_OBJS= \
radius_das.o \
radius_server.o
-libradius.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 630c0f9d..fb814818 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -225,6 +225,9 @@ struct radius_msg;
/* Default size to be allocated for attribute array */
#define RADIUS_DEFAULT_ATTR_COUNT 16
+/* Maximum message length for incoming RADIUS messages, as stated in RFC 2865
+ * Section 3 ("Packet Format").*/
+#define RADIUS_MAX_MSG_LEN 4096
/* MAC address ASCII format for IEEE 802.1X use
* (draft-congdon-radius-8021x-20.txt) */
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 2b7a604e..bfcb9442 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -816,7 +816,9 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
struct hostapd_radius_servers *conf = radius->conf;
RadiusType msg_type = (RadiusType) sock_ctx;
int len, roundtrip;
- unsigned char buf[3000];
+ unsigned char buf[RADIUS_MAX_MSG_LEN];
+ struct msghdr msghdr = {0};
+ struct iovec iov;
struct radius_msg *msg;
struct radius_hdr *hdr;
struct radius_rx_handler *handlers;
@@ -836,15 +838,22 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
rconf = conf->auth_server;
}
- len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
+ iov.iov_base = buf;
+ iov.iov_len = RADIUS_MAX_MSG_LEN;
+ msghdr.msg_iov = &iov;
+ msghdr.msg_iovlen = 1;
+ msghdr.msg_flags = 0;
+ len = recvmsg(sock, &msghdr, MSG_DONTWAIT);
if (len < 0) {
- wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
+ wpa_printf(MSG_INFO, "recvmsg[RADIUS]: %s", strerror(errno));
return;
}
+
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
"server", len);
- if (len == sizeof(buf)) {
+
+ if (msghdr.msg_flags & MSG_TRUNC) {
wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
return;
}
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 971fe91b..e02c2154 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -35,11 +35,6 @@
*/
#define RADIUS_MAX_SESSION 1000
-/**
- * RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages
- */
-#define RADIUS_MAX_MSG_LEN 3000
-
static const struct eapol_callbacks radius_server_eapol_cb;
struct radius_client;
diff --git a/src/rsn_supp/Makefile b/src/rsn_supp/Makefile
index eea0efba..d14d736c 100644
--- a/src/rsn_supp/Makefile
+++ b/src/rsn_supp/Makefile
@@ -1,13 +1,3 @@
-all: librsn_supp.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov librsn_supp.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_IEEE80211R
CFLAGS += -DCONFIG_TDLS
CFLAGS += -DCONFIG_WNM
@@ -21,7 +11,4 @@ LIB_OBJS= \
wpa.o \
wpa_ie.o
-librsn_supp.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index e46c89a6..b124dd94 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -272,7 +272,8 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
entry->fils_cache_id_set ? entry->fils_cache_id : NULL,
entry->pmk, entry->pmk_len,
pmksa->sm->dot11RSNAConfigPMKLifetime,
- pmksa->sm->dot11RSNAConfigPMKReauthThreshold);
+ pmksa->sm->dot11RSNAConfigPMKReauthThreshold,
+ entry->akmp);
return entry;
}
@@ -488,6 +489,9 @@ void pmksa_cache_clear_current(struct wpa_sm *sm)
{
if (sm == NULL)
return;
+ if (sm->cur_pmksa)
+ wpa_printf(MSG_DEBUG,
+ "RSN: Clear current PMKSA entry selection");
sm->cur_pmksa = NULL;
}
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index d4d1307a..1a38bf6b 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -349,7 +349,8 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
* PMKIDs again, so report the existing data now. */
if (p) {
wpa_sm_add_pmkid(sm, NULL, candidate->bssid, p->pmkid,
- NULL, p->pmk, p->pmk_len, 0, 0);
+ NULL, p->pmk, p->pmk_len, 0, 0,
+ p->akmp);
}
dl_list_del(&candidate->list);
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 7b47e3ac..7c4ef191 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -1155,7 +1155,7 @@ skip_rsnie:
rbuf = os_zalloc(buf_len + 1);
if (rbuf == NULL) {
wpa_tdls_peer_free(sm, peer);
- return -1;
+ return -2;
}
pos = rbuf;
@@ -1174,7 +1174,7 @@ skip_rsnie:
"TDLS: Failed to get random data for initiator Nonce");
os_free(rbuf);
wpa_tdls_peer_free(sm, peer);
- return -1;
+ return -2;
}
peer->tk_set = 0; /* A new nonce results in a new TK */
wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake",
@@ -1926,7 +1926,10 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
peer->initiator = 1;
wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0);
- wpa_tdls_send_tpk_m1(sm, peer);
+ if (wpa_tdls_send_tpk_m1(sm, peer) == -2) {
+ peer = NULL;
+ goto error;
+ }
}
if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) &&
@@ -2654,6 +2657,7 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
{
struct wpa_tdls_peer *peer;
int tdls_prohibited = sm->tdls_prohibited;
+ int res;
if (sm->tdls_disabled || !sm->tdls_supported)
return -1;
@@ -2693,8 +2697,10 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
peer->tpk_in_progress = 1;
- if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
- wpa_tdls_disable_peer_link(sm, peer);
+ res = wpa_tdls_send_tpk_m1(sm, peer);
+ if (res < 0) {
+ if (res != -2)
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
@@ -2807,6 +2813,11 @@ int wpa_tdls_init(struct wpa_sm *sm)
if (sm == NULL)
return -1;
+ if (sm->l2_tdls) {
+ l2_packet_deinit(sm->l2_tdls);
+ sm->l2_tdls = NULL;
+ }
+
sm->l2_tdls = l2_packet_init(sm->bridge_ifname ? sm->bridge_ifname :
sm->ifname,
sm->own_addr,
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index b9b1f0fc..ede782cb 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -22,6 +22,7 @@
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
#include "common/dpp.h"
+#include "common/wpa_ctrl.h"
#include "eap_common/eap_defs.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "drivers/driver.h"
@@ -31,7 +32,8 @@
#include "pmksa_cache.h"
#include "wpa_i.h"
#include "wpa_ie.h"
-
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
static const u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
@@ -578,7 +580,7 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
const u8 *z = NULL;
- size_t z_len = 0;
+ size_t z_len = 0, kdk_len;
int akmp;
#ifdef CONFIG_IEEE80211R
@@ -602,10 +604,19 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
akmp |= WPA_KEY_MGMT_PSK_SHA256;
}
#endif /* CONFIG_OWE */
+
+ if (sm->force_kdk_derivation ||
+ (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 &&
+ sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
sm->own_addr, sm->bssid, sm->snonce,
key->key_nonce, ptk, akmp,
- sm->pairwise_cipher, z, z_len);
+ sm->pairwise_cipher, z, z_len,
+ kdk_len);
}
@@ -756,6 +767,14 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
"Failed to get channel info for OCI element in EAPOL-Key 2/4");
goto failed;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_eapol) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency, sm->oci_freq_override_eapol);
+ ci.frequency = sm->oci_freq_override_eapol;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (ocv_insert_oci_kde(&ci, &pos) < 0)
goto failed;
@@ -939,6 +958,9 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
return -1;
}
+ wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher,
+ sm->dot11RSNAConfigPMKLifetime, &sm->ptk);
+
/* TK is not needed anymore in supplicant */
os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
sm->ptk.tk_len = 0;
@@ -1297,7 +1319,8 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
{
size_t len;
- if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
+ if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) ||
+ sm->mgmt_group_cipher == WPA_CIPHER_GTK_NOT_USED)
return 0;
if (ie->igtk) {
@@ -1550,11 +1573,12 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
return -1;
}
- if ((sm->ap_rsnxe && !ie->rsnxe) ||
- (!sm->ap_rsnxe && ie->rsnxe) ||
- (sm->ap_rsnxe && ie->rsnxe &&
- (sm->ap_rsnxe_len != ie->rsnxe_len ||
- os_memcmp(sm->ap_rsnxe, ie->rsnxe, sm->ap_rsnxe_len) != 0))) {
+ if (sm->proto == WPA_PROTO_RSN &&
+ ((sm->ap_rsnxe && !ie->rsnxe) ||
+ (!sm->ap_rsnxe && ie->rsnxe) ||
+ (sm->ap_rsnxe && ie->rsnxe &&
+ (sm->ap_rsnxe_len != ie->rsnxe_len ||
+ os_memcmp(sm->ap_rsnxe, ie->rsnxe, sm->ap_rsnxe_len) != 0)))) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: RSNXE mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp",
@@ -1656,6 +1680,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
}
if (ie.igtk &&
+ sm->mgmt_group_cipher != WPA_CIPHER_GTK_NOT_USED &&
wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) &&
ie.igtk_len != WPA_IGTK_KDE_PREFIX_LEN +
(unsigned int) wpa_cipher_key_len(sm->mgmt_group_cipher)) {
@@ -1708,9 +1733,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "%s",
- ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=eapol-key-m3 error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
return;
}
}
@@ -1826,6 +1852,7 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
{
int maxkeylen;
struct wpa_eapol_ie_parse ie;
+ u16 gtk_len;
wpa_hexdump_key(MSG_DEBUG, "RSN: msg 1/2 key data",
keydata, keydatalen);
@@ -1841,7 +1868,20 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
"WPA: No GTK IE in Group Key msg 1/2");
return -1;
}
- maxkeylen = gd->gtk_len = ie.gtk_len - 2;
+ gtk_len = ie.gtk_len;
+ if (gtk_len < 2) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Invalid GTK KDE length (%u) in Group Key msg 1/2",
+ gtk_len);
+ return -1;
+ }
+ gtk_len -= 2;
+ if (gtk_len > sizeof(gd->gtk)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Too long GTK in GTK KDE (len=%u)", gtk_len);
+ return -1;
+ }
+ maxkeylen = gd->gtk_len = gtk_len;
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm)) {
@@ -1855,31 +1895,26 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "%s",
- ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=eapol-key-g1 error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
return -1;
}
}
#endif /* CONFIG_OCV */
if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
- gd->gtk_len, maxkeylen,
+ gtk_len, maxkeylen,
&gd->key_rsc_len, &gd->alg))
return -1;
wpa_hexdump_key(MSG_DEBUG, "RSN: received GTK in group key handshake",
- ie.gtk, ie.gtk_len);
+ ie.gtk, 2 + gtk_len);
gd->keyidx = ie.gtk[0] & 0x3;
gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
!!(ie.gtk[0] & BIT(2)));
- if (ie.gtk_len - 2 > sizeof(gd->gtk)) {
- wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
- "RSN: Too long GTK in GTK IE (len=%lu)",
- (unsigned long) ie.gtk_len - 2);
- return -1;
- }
- os_memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2);
+ os_memcpy(gd->gtk, ie.gtk + 2, gtk_len);
if (ieee80211w_set_keys(sm, &ie) < 0)
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -2028,6 +2063,15 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
os_free(rbuf);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_eapol_g2) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency,
+ sm->oci_freq_override_eapol_g2);
+ ci.frequency = sm->oci_freq_override_eapol_g2;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
pos = key_mic + mic_len + 2; /* Key Data */
if (ocv_insert_oci_kde(&ci, &pos) < 0) {
@@ -2431,13 +2475,16 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
u8 *tmp = NULL;
int ret = -1;
u8 *mic, *key_data;
- size_t mic_len, keyhdrlen;
+ size_t mic_len, keyhdrlen, pmk_len;
#ifdef CONFIG_IEEE80211R
sm->ft_completed = 0;
#endif /* CONFIG_IEEE80211R */
- mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
+ pmk_len = sm->pmk_len;
+ if (!pmk_len && sm->cur_pmksa)
+ pmk_len = sm->cur_pmksa->pmk_len;
+ mic_len = wpa_mic_len(sm->key_mgmt, pmk_len);
keyhdrlen = sizeof(*key) + mic_len + 2;
if (len < sizeof(*hdr) + keyhdrlen) {
@@ -3151,6 +3198,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->p2p = config->p2p;
sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation;
sm->owe_ptk_workaround = config->owe_ptk_workaround;
+ sm->force_kdk_derivation = config->force_kdk_derivation;
#ifdef CONFIG_FILS
if (config->fils_cache_id) {
sm->fils_cache_id_set = 1;
@@ -3173,6 +3221,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->wpa_rsc_relaxation = 0;
sm->owe_ptk_workaround = 0;
sm->beacon_prot = 0;
+ sm->force_kdk_derivation = false;
}
}
@@ -3278,6 +3327,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_SAE_PWE:
sm->sae_pwe = value;
break;
+ case WPA_PARAM_SAE_PK:
+ sm->sae_pk = value;
+ break;
case WPA_PARAM_DENY_PTK0_REKEY:
sm->wpa_deny_ptk0_rekey = value;
break;
@@ -3291,6 +3343,18 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_FT_RSNXE_USED:
sm->ft_rsnxe_used = value;
break;
+ case WPA_PARAM_OCI_FREQ_EAPOL:
+ sm->oci_freq_override_eapol = value;
+ break;
+ case WPA_PARAM_OCI_FREQ_EAPOL_G2:
+ sm->oci_freq_override_eapol_g2 = value;
+ break;
+ case WPA_PARAM_OCI_FREQ_FT_ASSOC:
+ sm->oci_freq_override_ft_assoc = value;
+ break;
+ case WPA_PARAM_OCI_FREQ_FILS_ASSOC:
+ sm->oci_freq_override_fils_assoc = value;
+ break;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_DPP2
case WPA_PARAM_DPP_PFS:
@@ -3735,6 +3799,16 @@ int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
}
+struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm,
+ const u8 *aa,
+ const u8 *pmkid,
+ const void *network_ctx,
+ int akmp)
+{
+ return pmksa_cache_get(sm->pmksa, aa, pmkid, network_ctx, akmp);
+}
+
+
void wpa_sm_drop_sa(struct wpa_sm *sm)
{
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
@@ -3755,6 +3829,11 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
sm->pmk_r0_len = 0;
os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
sm->pmk_r1_len = 0;
+#ifdef CONFIG_PASN
+ os_free(sm->pasn_r1kh);
+ sm->pasn_r1kh = NULL;
+ sm->n_pasn_r1kh = 0;
+#endif /* CONFIG_PASN */
#endif /* CONFIG_IEEE80211R */
}
@@ -3786,6 +3865,46 @@ void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0);
}
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+void wpa_sm_install_pmk(struct wpa_sm *sm)
+{
+ /* In case the driver wants to handle re-assocs, pass it down the PMK. */
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->pairwise_cipher), NULL, 0, 0, NULL, 0,
+ (u8*)sm->pmk, sm->pmk_len, KEY_FLAG_PMK) < 0) {
+ wpa_hexdump(MSG_DEBUG, "PSK: Install PMK to the driver for driver reassociations",
+ (u8*)sm->pmk, sm->pmk_len);
+ /* No harm if the driver doesn't support. */
+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Failed to set PMK to the driver");
+ }
+}
+
+void wpa_sm_notify_brcm_ft_reassoc(struct wpa_sm *sm, const u8 *bssid)
+{
+ u8 buf[256];
+ struct wpa_supplicant *wpa_s = sm->ctx->ctx;
+
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: BRCM FT Reassociation event - clear replay counter");
+ os_memcpy(sm->bssid, bssid, ETH_ALEN);
+ os_memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN);
+ sm->rx_replay_counter_set = 0;
+
+ if (wpa_drv_driver_cmd(wpa_s, "GET_FTKEY", (char *)buf, sizeof(buf)) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+ "WPA: Failed to get FT KEY information");
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+
+ } else {
+ /* update kck and kek */
+ os_memcpy(sm->ptk.kck, buf, 16);
+ os_memcpy(sm->ptk.kek, buf + 16, 16);
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: Updated KCK and KEK after FT reassoc");
+ }
+}
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
#ifdef CONFIG_WNM
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
@@ -4065,7 +4184,7 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
const u8 *g_sta = NULL;
size_t g_sta_len = 0;
const u8 *g_ap = NULL;
- size_t g_ap_len = 0;
+ size_t g_ap_len = 0, kdk_len;
struct wpabuf *pub = NULL;
os_memcpy(sm->bssid, bssid, ETH_ALEN);
@@ -4293,13 +4412,21 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
goto fail;
}
+ if (sm->force_kdk_derivation ||
+ (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 &&
+ sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
if (fils_pmk_to_ptk(sm->pmk, sm->pmk_len, sm->own_addr, sm->bssid,
sm->fils_nonce, sm->fils_anonce,
dh_ss ? wpabuf_head(dh_ss) : NULL,
dh_ss ? wpabuf_len(dh_ss) : 0,
&sm->ptk, ick, &ick_len,
sm->key_mgmt, sm->pairwise_cipher,
- sm->fils_ft, &sm->fils_ft_len) < 0) {
+ sm->fils_ft, &sm->fils_ft_len,
+ kdk_len) < 0) {
wpa_printf(MSG_DEBUG, "FILS: Failed to derive PTK");
goto fail;
}
@@ -4430,10 +4557,6 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
return -1;
}
sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
- wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0",
- sm->pmk_r0, sm->pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
- sm->pmk_r0_name, WPA_PMK_NAME_LEN);
wpa_printf(MSG_DEBUG, "FILS+FT: R1KH-ID: " MACSTR,
MAC2STR(sm->r1kh_id));
pos = wpabuf_put(buf, WPA_PMK_NAME_LEN);
@@ -4442,8 +4565,6 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMKR1Name");
return -1;
}
- wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
- WPA_PMK_NAME_LEN);
os_memcpy(pos, sm->pmk_r1_name, WPA_PMK_NAME_LEN);
if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
@@ -4554,6 +4675,15 @@ struct wpabuf * fils_build_assoc_req(struct wpa_sm *sm, const u8 **kek,
wpabuf_free(buf);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_fils_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency,
+ sm->oci_freq_override_fils_assoc);
+ ci.frequency = sm->oci_freq_override_fils_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
pos = wpabuf_put(buf, OCV_OCI_EXTENDED_LEN);
if (ocv_insert_extended_oci(&ci, pos) < 0) {
@@ -4758,8 +4888,10 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
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, "FILS: %s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=fils-assoc error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
goto fail;
}
}
@@ -4849,6 +4981,9 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
goto fail;
}
+ wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher,
+ sm->dot11RSNAConfigPMKLifetime, &sm->ptk);
+
/* TODO: TK could be cleared after auth frame exchange now that driver
* takes care of association frame encryption/decryption. */
/* TK is not needed anymore in supplicant */
@@ -5121,3 +5256,14 @@ void wpa_sm_set_dpp_z(struct wpa_sm *sm, const struct wpabuf *z)
}
}
#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_PASN
+void wpa_pasn_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ const u8 *pmkid, const u8 *bssid, int key_mgmt)
+{
+ sm->cur_pmksa = pmksa_cache_add(sm->pmksa, pmk, pmk_len, pmkid, NULL, 0,
+ bssid, sm->own_addr, NULL,
+ key_mgmt, 0);
+}
+#endif /* CONFIG_PASN */
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index dfc156b5..95c58f63 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -43,7 +43,7 @@ struct wpa_sm_ctx {
int (*add_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
const u8 *pmkid, const u8 *fils_cache_id,
const u8 *pmk, size_t pmk_len, u32 pmk_lifetime,
- u8 pmk_reauth_threshold);
+ u8 pmk_reauth_threshold, int akmp);
int (*remove_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
const u8 *pmkid, const u8 *fils_cache_id);
void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
@@ -87,6 +87,8 @@ struct wpa_sm_ctx {
const u8 *pkt, size_t pkt_len);
int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
void (*transition_disable)(void *ctx, u8 bitmap);
+ void (*store_ptk)(void *ctx, u8 *addr, int cipher,
+ u32 life_time, const struct wpa_ptk *ptk);
};
@@ -103,11 +105,16 @@ enum wpa_sm_conf_params {
WPA_PARAM_MFP,
WPA_PARAM_OCV,
WPA_PARAM_SAE_PWE,
+ WPA_PARAM_SAE_PK,
WPA_PARAM_DENY_PTK0_REKEY,
WPA_PARAM_EXT_KEY_ID,
WPA_PARAM_USE_EXT_KEY_ID,
WPA_PARAM_FT_RSNXE_USED,
WPA_PARAM_DPP_PFS,
+ WPA_PARAM_OCI_FREQ_EAPOL,
+ WPA_PARAM_OCI_FREQ_EAPOL_G2,
+ WPA_PARAM_OCI_FREQ_FT_ASSOC,
+ WPA_PARAM_OCI_FREQ_FILS_ASSOC,
};
struct rsn_supp_config {
@@ -125,6 +132,7 @@ struct rsn_supp_config {
int owe_ptk_workaround;
const u8 *fils_cache_id;
int beacon_prot;
+ bool force_kdk_derivation;
};
#ifndef CONFIG_NO_WPA
@@ -184,6 +192,11 @@ void wpa_sm_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
const void *network_ctx);
void wpa_sm_drop_sa(struct wpa_sm *sm);
+struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm,
+ const u8 *aa,
+ const u8 *pmkid,
+ const void *network_ctx,
+ int akmp);
int wpa_sm_has_ptk(struct wpa_sm *sm);
int wpa_sm_has_ptk_installed(struct wpa_sm *sm);
@@ -193,6 +206,11 @@ void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx);
int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf);
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+void wpa_sm_install_pmk(struct wpa_sm *sm);
+void wpa_sm_notify_brcm_ft_reassoc(struct wpa_sm *sm, const u8 *bssid);
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+
void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter);
void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
const u8 *ptk_kck, size_t ptk_kck_len,
@@ -360,6 +378,13 @@ static inline void wpa_sm_drop_sa(struct wpa_sm *sm)
{
}
+static inline struct rsn_pmksa_cache_entry *
+wpa_sm_pmksa_cache_get(struct wpa_sm *sm, const u8 *aa, const u8 *pmkid,
+ const void *network_ctx, int akmp)
+{
+ return NULL;
+}
+
static inline int wpa_sm_has_ptk(struct wpa_sm *sm)
{
return 0;
@@ -405,10 +430,20 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
const u8 *ric_ies, size_t ric_ies_len);
int wpa_ft_is_completed(struct wpa_sm *sm);
void wpa_reset_ft_completed(struct wpa_sm *sm);
+void wpa_set_ft_completed(struct wpa_sm *sm);
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
size_t ies_len, const u8 *src_addr);
int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
const u8 *mdie);
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+int wpa_ft_is_ft_protocol(struct wpa_sm *sm);
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#ifdef CONFIG_PASN
+
+int wpa_pasn_ft_derive_pmk_r1(struct wpa_sm *sm, int akmp, const u8 *r1kh_id,
+ u8 *pmk_r1, size_t *pmk_r1_len, u8 *pmk_r1_name);
+
+#endif /* CONFIG_PASN */
#else /* CONFIG_IEEE80211R */
@@ -442,10 +477,21 @@ static inline int wpa_ft_is_completed(struct wpa_sm *sm)
return 0;
}
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+static inline int wpa_ft_is_ft_protocol(struct wpa_sm *sm)
+{
+ return 0;
+}
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+
static inline void wpa_reset_ft_completed(struct wpa_sm *sm)
{
}
+static inline void wpa_set_ft_completed(struct wpa_sm *sm)
+{
+}
+
static inline int
wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
const u8 *src_addr)
@@ -453,6 +499,16 @@ wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
return -1;
}
+#ifdef CONFIG_PASN
+
+int wpa_pasn_ft_derive_pmk_r1(struct wpa_sm *sm, int akmp, const u8 *r1kh_id,
+ u8 *pmk_r1, size_t *pmk_r1_len, u8 *pmk_r1_name)
+{
+ return -1;
+}
+
+#endif /* CONFIG_PASN */
+
#endif /* CONFIG_IEEE80211R */
@@ -501,5 +557,7 @@ int owe_process_assoc_resp(struct wpa_sm *sm, const u8 *bssid,
void wpa_sm_set_reset_fils_completed(struct wpa_sm *sm, int set);
void wpa_sm_set_fils_cache_id(struct wpa_sm *sm, const u8 *fils_cache_id);
void wpa_sm_set_dpp_z(struct wpa_sm *sm, const struct wpabuf *z);
+void wpa_pasn_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ const u8 *pmkid, const u8 *bssid, int key_mgmt);
#endif /* WPA_H */
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 3e51cf2a..caad7608 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -15,6 +15,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
+#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "wpa.h"
#include "wpa_i.h"
@@ -23,6 +24,15 @@
#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_PASN
+static void wpa_ft_pasn_store_r1kh(struct wpa_sm *sm, const u8 *bssid);
+#else /* CONFIG_PASN */
+static void wpa_ft_pasn_store_r1kh(struct wpa_sm *sm, const u8 *bssid)
+{
+}
+#endif /* CONFIG_PASN */
+
+
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
@@ -30,7 +40,7 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
const u8 *anonce = key->key_nonce;
int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
const u8 *mpmk;
- size_t mpmk_len;
+ size_t mpmk_len, kdk_len;
if (sm->xxkey_len > 0) {
mpmk = sm->xxkey;
@@ -50,20 +60,25 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, sm->pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name",
- sm->pmk_r0_name, WPA_PMK_NAME_LEN);
sm->pmk_r1_len = sm->pmk_r0_len;
if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name,
sm->r1kh_id, sm->own_addr, sm->pmk_r1,
sm->pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, sm->pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
- WPA_PMK_NAME_LEN);
+
+ wpa_ft_pasn_store_r1kh(sm, src_addr);
+
+ if (sm->force_kdk_derivation ||
+ (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 &&
+ sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, anonce,
sm->own_addr, sm->bssid, sm->pmk_r1_name, ptk,
- ptk_name, sm->key_mgmt, sm->pairwise_cipher);
+ ptk_name, sm->key_mgmt, sm->pairwise_cipher,
+ kdk_len);
}
@@ -358,6 +373,14 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
os_free(buf);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_ft_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency, sm->oci_freq_override_ft_assoc);
+ ci.frequency = sm->oci_freq_override_ft_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
*pos++ = FTIE_SUBELEM_OCI;
*pos++ = OCV_OCI_LEN;
@@ -445,6 +468,8 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
return -1;
}
+ wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher,
+ sm->dot11RSNAConfigPMKLifetime, &sm->ptk);
return 0;
}
@@ -521,7 +546,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
int ret;
const u8 *bssid;
const u8 *kck;
- size_t kck_len;
+ size_t kck_len, kdk_len;
int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
const u8 *anonce, *snonce;
@@ -641,15 +666,23 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
sm->pmk_r1_name) < 0)
return -1;
sm->pmk_r1_len = sm->pmk_r0_len;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, sm->pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
- sm->pmk_r1_name, WPA_PMK_NAME_LEN);
bssid = target_ap;
+
+ wpa_ft_pasn_store_r1kh(sm, bssid);
+
+ if (sm->force_kdk_derivation ||
+ (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 &&
+ sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce,
anonce, sm->own_addr, bssid,
sm->pmk_r1_name, &sm->ptk, ptk_name, sm->key_mgmt,
- sm->pairwise_cipher) < 0)
+ sm->pairwise_cipher,
+ kdk_len) < 0)
return -1;
if (wpa_key_mgmt_fils(sm->key_mgmt)) {
@@ -710,6 +743,18 @@ int wpa_ft_is_completed(struct wpa_sm *sm)
return sm->ft_completed;
}
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+int wpa_ft_is_ft_protocol(struct wpa_sm *sm)
+{
+ if (sm == NULL)
+ return 0;
+
+ if (!wpa_key_mgmt_ft(sm->key_mgmt))
+ return 0;
+
+ return sm->ft_protocol;
+}
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
void wpa_reset_ft_completed(struct wpa_sm *sm)
{
@@ -718,6 +763,12 @@ void wpa_reset_ft_completed(struct wpa_sm *sm)
}
+void wpa_set_ft_completed(struct wpa_sm *sm)
+{
+ if (sm != NULL)
+ sm->ft_completed = 1;
+}
+
static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
size_t gtk_elem_len)
{
@@ -1167,8 +1218,10 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
if (ocv_verify_tx_params(parse.oci, parse.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(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=ft-assoc error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
return -1;
}
}
@@ -1236,4 +1289,88 @@ int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
return 0;
}
+
+#ifdef CONFIG_PASN
+
+static struct pasn_ft_r1kh * wpa_ft_pasn_get_r1kh(struct wpa_sm *sm,
+ const u8 *bssid)
+{
+ size_t i;
+
+ for (i = 0; i < sm->n_pasn_r1kh; i++)
+ if (os_memcmp(sm->pasn_r1kh[i].bssid, bssid, ETH_ALEN) == 0)
+ return &sm->pasn_r1kh[i];
+
+ return NULL;
+}
+
+
+static void wpa_ft_pasn_store_r1kh(struct wpa_sm *sm, const u8 *bssid)
+{
+ struct pasn_ft_r1kh *tmp = wpa_ft_pasn_get_r1kh(sm, bssid);
+
+ if (tmp)
+ return;
+
+ tmp = os_realloc_array(sm->pasn_r1kh, sm->n_pasn_r1kh + 1,
+ sizeof(*tmp));
+ if (!tmp) {
+ wpa_printf(MSG_DEBUG, "PASN: FT: Failed to store R1KH");
+ return;
+ }
+
+ sm->pasn_r1kh = tmp;
+ tmp = &sm->pasn_r1kh[sm->n_pasn_r1kh];
+
+ wpa_printf(MSG_DEBUG, "PASN: FT: Store R1KH for " MACSTR,
+ MAC2STR(bssid));
+
+ os_memcpy(tmp->bssid, bssid, ETH_ALEN);
+ os_memcpy(tmp->r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN);
+
+ sm->n_pasn_r1kh++;
+}
+
+
+int wpa_pasn_ft_derive_pmk_r1(struct wpa_sm *sm, int akmp, const u8 *bssid,
+ u8 *pmk_r1, size_t *pmk_r1_len, u8 *pmk_r1_name)
+{
+ struct pasn_ft_r1kh *r1kh_entry;
+
+ if (sm->key_mgmt != (unsigned int) akmp) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FT: Key management mismatch: %u != %u",
+ sm->key_mgmt, akmp);
+ return -1;
+ }
+
+ r1kh_entry = wpa_ft_pasn_get_r1kh(sm, bssid);
+ if (!r1kh_entry) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FT: Cannot find R1KH-ID for " MACSTR,
+ MAC2STR(bssid));
+ return -1;
+ }
+
+ /*
+ * Note: PMK R0 etc. were already derived and are maintained by the
+ * state machine, and as the same key hierarchy is used, there is no
+ * need to derive them again, so only derive PMK R1 etc.
+ */
+ if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name,
+ r1kh_entry->r1kh_id, sm->own_addr, pmk_r1,
+ pmk_r1_name) < 0)
+ return -1;
+
+ *pmk_r1_len = sm->pmk_r0_len;
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: FT: PMK-R1", pmk_r1, sm->pmk_r0_len);
+ wpa_hexdump(MSG_DEBUG, "PASN: FT: PMKR1Name", pmk_r1_name,
+ WPA_PMK_NAME_LEN);
+
+ return 0;
+}
+
+#endif /* CONFIG_PASN */
+
#endif /* CONFIG_IEEE80211R */
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index f7d9f625..1dc96396 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -14,6 +14,11 @@
struct wpa_tdls_peer;
struct wpa_eapol_key;
+struct pasn_ft_r1kh {
+ u8 bssid[ETH_ALEN];
+ u8 r1kh_id[FT_R1KH_ID_LEN];
+};
+
/**
* struct wpa_sm - Internal WPA state machine data
*/
@@ -73,6 +78,12 @@ struct wpa_sm {
* to be used */
int keyidx_active; /* Key ID for the active TK */
+ /*
+ * If set Key Derivation Key should be derived as part of PMK to
+ * PTK derivation regardless of advertised capabilities.
+ */
+ bool force_kdk_derivation;
+
u8 own_addr[ETH_ALEN];
const char *ifname;
const char *bridge_ifname;
@@ -96,6 +107,11 @@ struct wpa_sm {
int ocv; /* Operating Channel Validation */
int sae_pwe; /* SAE PWE generation options */
+ unsigned int sae_pk:1; /* whether SAE-PK is used */
+ unsigned int secure_ltf:1;
+ unsigned int secure_rtt:1;
+ unsigned int prot_range_neg:1;
+
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
size_t assoc_wpa_ie_len;
u8 *assoc_rsnxe; /* Own RSNXE from (Re)AssocReq */
@@ -145,6 +161,17 @@ struct wpa_sm {
u8 mdie_ft_capab; /* FT Capability and Policy from target AP MDIE */
u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */
size_t assoc_resp_ies_len;
+#ifdef CONFIG_PASN
+ /*
+ * Currently, the WPA state machine stores the PMK-R1, PMK-R1-Name and
+ * R1KH-ID only for the current association. As PMK-R1 is required to
+ * perform PASN authentication with FT, store the R1KH-ID for previous
+ * associations, which would later be used to derive the PMK-R1 as part
+ * of the PASN authentication flow.
+ */
+ struct pasn_ft_r1kh *pasn_r1kh;
+ unsigned int n_pasn_r1kh;
+#endif /* CONFIG_PASN */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_P2P
@@ -154,6 +181,10 @@ struct wpa_sm {
#ifdef CONFIG_TESTING_OPTIONS
struct wpabuf *test_assoc_ie;
int ft_rsnxe_used;
+ unsigned int oci_freq_override_eapol;
+ unsigned int oci_freq_override_eapol_g2;
+ unsigned int oci_freq_override_ft_assoc;
+ unsigned int oci_freq_override_fils_assoc;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_FILS
@@ -267,12 +298,12 @@ static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *cache_id, const u8 *pmk,
size_t pmk_len, u32 pmk_lifetime,
- u8 pmk_reauth_threshold)
+ u8 pmk_reauth_threshold, int akmp)
{
WPA_ASSERT(sm->ctx->add_pmkid);
return sm->ctx->add_pmkid(sm->ctx->ctx, network_ctx, bssid, pmkid,
cache_id, pmk, pmk_len, pmk_lifetime,
- pmk_reauth_threshold);
+ pmk_reauth_threshold, akmp);
}
static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, void *network_ctx,
@@ -436,6 +467,14 @@ static inline void wpa_sm_transition_disable(struct wpa_sm *sm, u8 bitmap)
sm->ctx->transition_disable(sm->ctx->ctx, bitmap);
}
+static inline void wpa_sm_store_ptk(struct wpa_sm *sm,
+ u8 *addr, int cipher,
+ u32 life_time, struct wpa_ptk *ptk)
+{
+ if (sm->ctx->store_ptk)
+ sm->ctx->store_ptk(sm->ctx->ctx, addr, cipher, life_time,
+ ptk);
+}
int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
int ver, const u8 *dest, u16 proto,
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 9068781b..3ba722f5 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -354,20 +354,38 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
{
u8 *pos = rsnxe;
+ u16 capab = 0;
+ size_t flen;
+
+ if (wpa_key_mgmt_sae(sm->key_mgmt) &&
+ (sm->sae_pwe == 1 || sm->sae_pwe == 2 || sm->sae_pk)) {
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (sm->sae_pk)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+ }
- if (!wpa_key_mgmt_sae(sm->key_mgmt))
- return 0; /* SAE not in use */
- if (sm->sae_pwe != 1 && sm->sae_pwe != 2)
- return 0; /* no supported extended RSN capabilities */
+ if (sm->secure_ltf)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+ if (sm->secure_rtt)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+ if (sm->prot_range_neg)
+ capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
- if (rsnxe_len < 3)
+ flen = (capab & 0xff00) ? 2 : 1;
+ if (!capab)
+ return 0; /* no supported extended RSN capabilities */
+ if (rsnxe_len < 2 + flen)
return -1;
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
*pos++ = WLAN_EID_RSNX;
- *pos++ = 1;
- /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
- * used for now */
- *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+ *pos++ = flen;
+ *pos++ = capab & 0x00ff;
+ capab >>= 8;
+ if (capab)
+ *pos++ = capab;
return pos - rsnxe;
}
diff --git a/src/tls/Makefile b/src/tls/Makefile
index 52a890a1..c84fbe85 100644
--- a/src/tls/Makefile
+++ b/src/tls/Makefile
@@ -1,14 +1,3 @@
-all: libtls.a
-
-clean:
- rm -f *~ *.o *.d libtls.a
-
-install:
- @echo Nothing to be made.
-
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
CFLAGS += -DCONFIG_CRYPTO_INTERNAL
CFLAGS += -DCONFIG_TLSV11
@@ -33,8 +22,4 @@ LIB_OBJS= \
tlsv1_server_write.o \
x509v3.o
-
-libtls.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/tls/rsa.c b/src/tls/rsa.c
index 3525eb99..1b01f584 100644
--- a/src/tls/rsa.c
+++ b/src/tls/rsa.c
@@ -285,7 +285,7 @@ int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,
if (use_private) {
/*
- * Decrypt (or sign) using Chinese remainer theorem to speed
+ * Decrypt (or sign) using Chinese remainder theorem to speed
* up calculation. This is equivalent to tmp = tmp^d mod n
* (which would require more CPU to calculate directly).
*
diff --git a/src/utils/Makefile b/src/utils/Makefile
index 1ee2bee6..d995b817 100644
--- a/src/utils/Makefile
+++ b/src/utils/Makefile
@@ -1,14 +1,3 @@
-all: libutils.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libutils.a
-
-install:
- @echo Nothing to be made.
-
-
-include ../lib.rules
-
#CFLAGS += -DWPA_TRACE
CFLAGS += -DCONFIG_IPV6
CFLAGS += -DCONFIG_DEBUG_FILE
@@ -17,6 +6,7 @@ LIB_OBJS= \
base64.o \
bitfield.o \
common.o \
+ config.o \
crc32.o \
ip_addr.o \
json.o \
@@ -37,7 +27,4 @@ LIB_OBJS += edit.o
#LIB_OBJS += pcsc_funcs.o
-libutils.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/utils/base64.c b/src/utils/base64.c
index a17d2d36..0d121c19 100644
--- a/src/utils/base64.c
+++ b/src/utils/base64.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include <stdint.h>
+#include "utils/common.h"
#include "os.h"
#include "base64.h"
@@ -18,6 +19,10 @@ static const char base64_url_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+#define BASE64_PAD BIT(0)
+#define BASE64_LF BIT(1)
+
+
static char * base64_gen_encode(const unsigned char *src, size_t len,
size_t *out_len, const char *table, int add_pad)
{
@@ -29,7 +34,7 @@ static char * base64_gen_encode(const unsigned char *src, size_t len,
if (len >= SIZE_MAX / 4)
return NULL;
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
- if (add_pad)
+ if (add_pad & BASE64_LF)
olen += olen / 72; /* line feeds */
olen++; /* nul termination */
if (olen < len)
@@ -49,7 +54,7 @@ static char * base64_gen_encode(const unsigned char *src, size_t len,
*pos++ = table[in[2] & 0x3f];
in += 3;
line_len += 4;
- if (add_pad && line_len >= 72) {
+ if ((add_pad & BASE64_LF) && line_len >= 72) {
*pos++ = '\n';
line_len = 0;
}
@@ -59,19 +64,19 @@ static char * base64_gen_encode(const unsigned char *src, size_t len,
*pos++ = table[(in[0] >> 2) & 0x3f];
if (end - in == 1) {
*pos++ = table[((in[0] & 0x03) << 4) & 0x3f];
- if (add_pad)
+ if (add_pad & BASE64_PAD)
*pos++ = '=';
} else {
*pos++ = table[(((in[0] & 0x03) << 4) |
(in[1] >> 4)) & 0x3f];
*pos++ = table[((in[1] & 0x0f) << 2) & 0x3f];
}
- if (add_pad)
+ if (add_pad & BASE64_PAD)
*pos++ = '=';
line_len += 4;
}
- if (add_pad && line_len)
+ if ((add_pad & BASE64_LF) && line_len)
*pos++ = '\n';
*pos = '\0';
@@ -164,7 +169,14 @@ static unsigned char * base64_gen_decode(const char *src, size_t len,
*/
char * base64_encode(const void *src, size_t len, size_t *out_len)
{
- return base64_gen_encode(src, len, out_len, base64_table, 1);
+ return base64_gen_encode(src, len, out_len, base64_table,
+ BASE64_PAD | BASE64_LF);
+}
+
+
+char * base64_encode_no_lf(const void *src, size_t len, size_t *out_len)
+{
+ return base64_gen_encode(src, len, out_len, base64_table, BASE64_PAD);
}
diff --git a/src/utils/base64.h b/src/utils/base64.h
index 6216f44e..d545b293 100644
--- a/src/utils/base64.h
+++ b/src/utils/base64.h
@@ -10,6 +10,7 @@
#define BASE64_H
char * base64_encode(const void *src, size_t len, size_t *out_len);
+char * base64_encode_no_lf(const void *src, size_t len, size_t *out_len);
unsigned char * base64_decode(const char *src, size_t len, size_t *out_len);
char * base64_url_encode(const void *src, size_t len, size_t *out_len);
unsigned char * base64_url_decode(const char *src, size_t len, size_t *out_len);
diff --git a/src/utils/config.c b/src/utils/config.c
new file mode 100644
index 00000000..22aa2216
--- /dev/null
+++ b/src/utils/config.c
@@ -0,0 +1,97 @@
+/*
+ * Configuration parsing
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/config.h"
+#include "common.h"
+
+
+static int newline_terminated(const char *buf, size_t buflen)
+{
+ size_t len = os_strlen(buf);
+ if (len == 0)
+ return 0;
+ if (len == buflen - 1 && buf[buflen - 1] != '\r' &&
+ buf[len - 1] != '\n')
+ return 0;
+ return 1;
+}
+
+
+static void skip_line_end(FILE *stream)
+{
+ char buf[100];
+ while (fgets(buf, sizeof(buf), stream)) {
+ buf[sizeof(buf) - 1] = '\0';
+ if (newline_terminated(buf, sizeof(buf)))
+ return;
+ }
+}
+
+
+char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
+ char **_pos)
+{
+ char *pos, *end, *sstart;
+
+ while (fgets(s, size, stream)) {
+ (*line)++;
+ s[size - 1] = '\0';
+ if (!newline_terminated(s, size)) {
+ /*
+ * The line was truncated - skip rest of it to avoid
+ * confusing error messages.
+ */
+ wpa_printf(MSG_INFO, "Long line in configuration file "
+ "truncated");
+ skip_line_end(stream);
+ }
+ pos = s;
+
+ /* Skip white space from the beginning of line. */
+ while (*pos == ' ' || *pos == '\t' || *pos == '\r')
+ pos++;
+
+ /* Skip comment lines and empty lines */
+ if (*pos == '#' || *pos == '\n' || *pos == '\0')
+ continue;
+
+ /*
+ * Remove # comments unless they are within a double quoted
+ * string.
+ */
+ sstart = os_strchr(pos, '"');
+ if (sstart)
+ sstart = os_strrchr(sstart + 1, '"');
+ if (!sstart)
+ sstart = pos;
+ end = os_strchr(sstart, '#');
+ if (end)
+ *end-- = '\0';
+ else
+ end = pos + os_strlen(pos) - 1;
+
+ /* Remove trailing white space. */
+ while (end > pos &&
+ (*end == '\n' || *end == ' ' || *end == '\t' ||
+ *end == '\r'))
+ *end-- = '\0';
+
+ if (*pos == '\0')
+ continue;
+
+ if (_pos)
+ *_pos = pos;
+ return pos;
+ }
+
+ if (_pos)
+ *_pos = NULL;
+ return NULL;
+}
diff --git a/src/utils/config.h b/src/utils/config.h
new file mode 100644
index 00000000..074a88a5
--- /dev/null
+++ b/src/utils/config.h
@@ -0,0 +1,29 @@
+/*
+ * Configuration parsing
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef UTILS_CONFIG_H
+#define UTILS_CONFIG_H
+
+/**
+ * wpa_config_get_line - Read the next configuration file line
+ * @s: Buffer for the line
+ * @size: The buffer length
+ * @stream: File stream to read from
+ * @line: Pointer to a variable storing the file line number
+ * @_pos: Buffer for the pointer to the beginning of data on the text line or
+ * %NULL if not needed (returned value used instead)
+ * Returns: Pointer to the beginning of data on the text line or %NULL if no
+ * more text lines are available.
+ *
+ * This function reads the next non-empty line from the configuration file and
+ * removes comments. The returned string is guaranteed to be null-terminated.
+ */
+char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
+ char **_pos);
+
+#endif /* UTILS_CONFIG_H */
diff --git a/src/utils/ext_password.c b/src/utils/ext_password.c
index 5615bd72..cbf92de8 100644
--- a/src/utils/ext_password.c
+++ b/src/utils/ext_password.c
@@ -20,6 +20,9 @@ static const struct ext_password_backend *backends[] = {
#ifdef CONFIG_EXT_PASSWORD_TEST
&ext_password_test,
#endif /* CONFIG_EXT_PASSWORD_TEST */
+#ifdef CONFIG_EXT_PASSWORD_FILE
+ &ext_password_file,
+#endif /* CONFIG_EXT_PASSWORD_FILE */
NULL
};
diff --git a/src/utils/ext_password_file.c b/src/utils/ext_password_file.c
new file mode 100644
index 00000000..4bb0095f
--- /dev/null
+++ b/src/utils/ext_password_file.c
@@ -0,0 +1,136 @@
+/*
+ * External backend for file-backed passwords
+ * Copyright (c) 2021, Patrick Steinhardt <ps@pks.im>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/common.h"
+#include "utils/config.h"
+#include "ext_password_i.h"
+
+
+/**
+ * Data structure for the file-backed password backend.
+ */
+struct ext_password_file_data {
+ char *path; /* path of the password file */
+};
+
+
+/**
+ * ext_password_file_init - Initialize file-backed password backend
+ * @params: Parameters passed by the user.
+ * Returns: Pointer to the initialized backend.
+ *
+ * This function initializes a new file-backed password backend. The user is
+ * expected to initialize this backend with the parameters being the path of
+ * the file that contains the passwords.
+ */
+static void * ext_password_file_init(const char *params)
+{
+ struct ext_password_file_data *data;
+
+ if (!params) {
+ wpa_printf(MSG_ERROR, "EXT PW FILE: no path given");
+ return NULL;
+ }
+
+ data = os_zalloc(sizeof(*data));
+ if (!data)
+ return NULL;
+
+ data->path = os_strdup(params);
+ if (!data->path) {
+ os_free(data);
+ return NULL;
+ }
+
+ return data;
+}
+
+
+/**
+ * ext_password_file_deinit - Deinitialize file-backed password backend
+ * @ctx: The file-backed password backend
+ *
+ * This function frees all data associated with the file-backed password
+ * backend.
+ */
+static void ext_password_file_deinit(void *ctx)
+{
+ struct ext_password_file_data *data = ctx;
+
+ str_clear_free(data->path);
+ os_free(data);
+}
+
+/**
+ * ext_password_file_get - Retrieve password from the file-backed password backend
+ * @ctx: The file-backed password backend
+ * @name: Name of the password to retrieve
+ * Returns: Buffer containing the password if one was found or %NULL.
+ *
+ * This function tries to find a password identified by name in the password
+ * file. The password is expected to be stored in `NAME=PASSWORD` format.
+ * Comments and empty lines in the file are ignored. Invalid lines will cause
+ * an error message, but will not cause the function to fail.
+ */
+static struct wpabuf * ext_password_file_get(void *ctx, const char *name)
+{
+ struct ext_password_file_data *data = ctx;
+ struct wpabuf *password = NULL;
+ char buf[512], *pos;
+ int line = 0;
+ FILE *f;
+
+ f = fopen(data->path, "r");
+ if (!f) {
+ wpa_printf(MSG_ERROR,
+ "EXT PW FILE: could not open file '%s': %s",
+ data->path, strerror(errno));
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EXT PW FILE: get(%s)", name);
+
+ while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
+ char *sep = os_strchr(pos, '=');
+
+ if (!sep) {
+ wpa_printf(MSG_ERROR, "Invalid password line %d.",
+ line);
+ continue;
+ }
+
+ if (!sep[1]) {
+ wpa_printf(MSG_ERROR, "No password for line %d.", line);
+ continue;
+
+ }
+
+ if (os_strncmp(name, pos, sep - pos) != 0)
+ continue;
+
+ password = wpabuf_alloc_copy(sep + 1, os_strlen(sep + 1));
+ goto done;
+ }
+
+ wpa_printf(MSG_ERROR, "Password for '%s' was not found.", name);
+
+done:
+ forced_memzero(buf, sizeof(buf));
+ fclose(f);
+ return password;
+}
+
+
+const struct ext_password_backend ext_password_file = {
+ .name = "file",
+ .init = ext_password_file_init,
+ .deinit = ext_password_file_deinit,
+ .get = ext_password_file_get,
+};
diff --git a/src/utils/ext_password_i.h b/src/utils/ext_password_i.h
index 948eaf54..872ccd19 100644
--- a/src/utils/ext_password_i.h
+++ b/src/utils/ext_password_i.h
@@ -26,4 +26,8 @@ struct wpabuf * ext_password_alloc(size_t len);
extern const struct ext_password_backend ext_password_test;
#endif /* CONFIG_EXT_PASSWORD_TEST */
+#ifdef CONFIG_EXT_PASSWORD_FILE
+extern const struct ext_password_backend ext_password_file;
+#endif /* CONFIG_EXT_PASSWORD_FILE */
+
#endif /* EXT_PASSWORD_I_H */
diff --git a/src/utils/json.c b/src/utils/json.c
index 5a0edf21..dd12f1b6 100644
--- a/src/utils/json.c
+++ b/src/utils/json.c
@@ -528,6 +528,28 @@ struct wpabuf * json_get_member_base64url(struct json_token *json,
}
+struct wpabuf * json_get_member_base64(struct json_token *json,
+ const char *name)
+{
+ struct json_token *token;
+ unsigned char *buf;
+ size_t buflen;
+ struct wpabuf *ret;
+
+ token = json_get_member(json, name);
+ if (!token || token->type != JSON_STRING)
+ return NULL;
+ buf = base64_decode(token->string, os_strlen(token->string), &buflen);
+ if (!buf)
+ return NULL;
+ ret = wpabuf_alloc_ext_data(buf, buflen);
+ if (!ret)
+ os_free(buf);
+
+ return ret;
+}
+
+
static const char * json_type_str(enum json_type type)
{
switch (type) {
@@ -620,6 +642,20 @@ int json_add_base64url(struct wpabuf *json, const char *name, const void *val,
}
+int json_add_base64(struct wpabuf *json, const char *name, const void *val,
+ size_t len)
+{
+ char *b64;
+
+ b64 = base64_encode_no_lf(val, len, NULL);
+ if (!b64)
+ return -1;
+ json_add_string(json, name, b64);
+ os_free(b64);
+ return 0;
+}
+
+
void json_start_object(struct wpabuf *json, const char *name)
{
if (name)
diff --git a/src/utils/json.h b/src/utils/json.h
index ca4a2e47..8448bb0c 100644
--- a/src/utils/json.h
+++ b/src/utils/json.h
@@ -37,6 +37,8 @@ void json_free(struct json_token *json);
struct json_token * json_get_member(struct json_token *json, const char *name);
struct wpabuf * json_get_member_base64url(struct json_token *json,
const char *name);
+struct wpabuf * json_get_member_base64(struct json_token *json,
+ const char *name);
void json_print_tree(struct json_token *root, char *buf, size_t buflen);
void json_add_int(struct wpabuf *json, const char *name, int val);
void json_add_string(struct wpabuf *json, const char *name, const char *val);
@@ -44,6 +46,8 @@ int json_add_string_escape(struct wpabuf *json, const char *name,
const void *val, size_t len);
int json_add_base64url(struct wpabuf *json, const char *name, const void *val,
size_t len);
+int json_add_base64(struct wpabuf *json, const char *name, const void *val,
+ size_t len);
void json_start_object(struct wpabuf *json, const char *name);
void json_end_object(struct wpabuf *json);
void json_start_array(struct wpabuf *json, const char *name);
diff --git a/src/utils/list.h b/src/utils/list.h
index 85aa5e39..aa62c088 100644
--- a/src/utils/list.h
+++ b/src/utils/list.h
@@ -46,12 +46,12 @@ static inline void dl_list_del(struct dl_list *item)
item->prev = NULL;
}
-static inline int dl_list_empty(struct dl_list *list)
+static inline int dl_list_empty(const struct dl_list *list)
{
return list->next == list;
}
-static inline unsigned int dl_list_len(struct dl_list *list)
+static inline unsigned int dl_list_len(const struct dl_list *list)
{
struct dl_list *item;
int count = 0;
@@ -76,8 +76,8 @@ static inline unsigned int dl_list_len(struct dl_list *list)
dl_list_entry((list)->prev, type, member))
#define dl_list_for_each(item, list, type, member) \
- for (item = dl_list_first((list), type, member); \
- item && item != dl_list_entry((list), type, member); \
+ for (item = dl_list_entry((list)->next, type, member); \
+ &item->member != (list); \
item = dl_list_entry(item->member.next, type, member))
#define dl_list_for_each_safe(item, n, list, type, member) \
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index ae2f8029..a90428ff 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -41,7 +41,7 @@ static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list);
struct os_alloc_trace {
unsigned int magic;
- struct dl_list list;
+ struct dl_list list __attribute__((aligned(16)));
size_t len;
WPA_TRACE_INFO
} __attribute__((aligned(16)));
diff --git a/src/utils/platform.h b/src/utils/platform.h
index 813987eb..b2ad856b 100644
--- a/src/utils/platform.h
+++ b/src/utils/platform.h
@@ -1,21 +1,18 @@
+/*
+ * Platform definitions for Radiotap parser
+ * Copyright (c) 2021, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
#ifndef PLATFORM_H
#define PLATFORM_H
#include "includes.h"
#include "common.h"
-#define le16_to_cpu le_to_host16
-#define le32_to_cpu le_to_host32
-
-#define get_unaligned(p) \
-({ \
- struct packed_dummy_struct { \
- typeof(*(p)) __val; \
- } __attribute__((packed)) *__ptr = (void *) (p); \
- \
- __ptr->__val; \
-})
-#define get_unaligned_le16(p) le16_to_cpu(get_unaligned((le16 *)(p)))
-#define get_unaligned_le32(p) le32_to_cpu(get_unaligned((le32 *)(p)))
+#define get_unaligned_le16(p) WPA_GET_LE16((void *) (p))
+#define get_unaligned_le32(p) WPA_GET_LE32((void *) (p))
#endif /* PLATFORM_H */
diff --git a/src/utils/radiotap.c b/src/utils/radiotap.c
index 71996eb7..6dfe2981 100644
--- a/src/utils/radiotap.c
+++ b/src/utils/radiotap.c
@@ -8,10 +8,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See COPYING for more details.
+ * Alternatively, this software may be distributed under the terms of ISC
+ * license, see COPYING for more details.
*/
#include "platform.h"
#include "radiotap_iter.h"
@@ -39,6 +37,8 @@ static const struct radiotap_align_size rtap_namespace_sizes[] = {
[IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
[IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
[IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
+ [IEEE80211_RADIOTAP_VHT] = { .align = 2, .size = 12, },
+ [IEEE80211_RADIOTAP_TIMESTAMP] = { .align = 8, .size = 12, },
/*
* add more here as they are defined in radiotap.h
*/
@@ -111,7 +111,7 @@ int ieee80211_radiotap_iterator_init(
iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header);
iterator->_next_ns_data = NULL;
iterator->_reset_on_ext = 0;
- iterator->_next_bitmap = &radiotap_header->it_present;
+ iterator->_next_bitmap = (le32 *) (((u8 *) radiotap_header) + offsetof(struct ieee80211_radiotap_header, it_present));
iterator->_next_bitmap++;
iterator->_vns = vns;
iterator->current_namespace = &radiotap_ns;
@@ -222,7 +222,7 @@ static int find_override(struct ieee80211_radiotap_iterator *iterator,
* present fields. @this_arg can be changed by the caller (eg,
* incremented to move inside a compound argument like
* IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
- * little-endian format whatever the endianess of your CPU.
+ * little-endian format whatever the endianness of your CPU.
*
* Alignment Gotcha:
* You must take care when dereferencing iterator.this_arg
diff --git a/src/utils/radiotap.h b/src/utils/radiotap.h
index 460af23d..488d5a3b 100644
--- a/src/utils/radiotap.h
+++ b/src/utils/radiotap.h
@@ -1,190 +1,51 @@
-/*-
- * Copyright (c) 2003, 2004 David Young. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of David Young may not be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
- * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- */
-
/*
- * Modifications to fit into the linux IEEE 802.11 stack,
- * Mike Kershaw (dragorn@kismetwireless.net)
+ * Copyright (c) 2017 Intel Deutschland GmbH
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#ifndef __RADIOTAP_H
+#define __RADIOTAP_H
-#ifndef IEEE80211RADIOTAP_H
-#define IEEE80211RADIOTAP_H
-
-#include <stdint.h>
-
-/* Base version of the radiotap packet header data */
-#define PKTHDR_RADIOTAP_VERSION 0
-
-/* A generic radio capture format is desirable. There is one for
- * Linux, but it is neither rigidly defined (there were not even
- * units given for some fields) nor easily extensible.
- *
- * I suggest the following extensible radio capture format. It is
- * based on a bitmap indicating which fields are present.
- *
- * I am trying to describe precisely what the application programmer
- * should expect in the following, and for that reason I tell the
- * units and origin of each measurement (where it applies), or else I
- * use sufficiently weaselly language ("is a monotonically nondecreasing
- * function of...") that I cannot set false expectations for lawyerly
- * readers.
- */
-
-/* The radio capture header precedes the 802.11 header.
- * All data in the header is little endian on all platforms.
+/**
+ * struct ieee82011_radiotap_header - base radiotap header
*/
struct ieee80211_radiotap_header {
- uint8_t it_version; /* Version 0. Only increases
- * for drastic changes,
- * introduction of compatible
- * new fields does not count.
- */
+ /**
+ * @it_version: radiotap version, always 0
+ */
+ uint8_t it_version;
+
+ /**
+ * @it_pad: padding (or alignment)
+ */
uint8_t it_pad;
- le16 it_len; /* length of the whole
- * header in bytes, including
- * it_version, it_pad,
- * it_len, and data fields.
- */
- le32 it_present; /* A bitmap telling which
- * fields are present. Set bit 31
- * (0x80000000) to extend the
- * bitmap by another 32 bits.
- * Additional extensions are made
- * by setting bit 31.
- */
-};
-/* Name Data type Units
- * ---- --------- -----
- *
- * IEEE80211_RADIOTAP_TSFT __le64 microseconds
- *
- * Value in microseconds of the MAC's 64-bit 802.11 Time
- * Synchronization Function timer when the first bit of the
- * MPDU arrived at the MAC. For received frames, only.
- *
- * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap
- *
- * Tx/Rx frequency in MHz, followed by flags (see below).
- *
- * IEEE80211_RADIOTAP_FHSS uint16_t see below
- *
- * For frequency-hopping radios, the hop set (first byte)
- * and pattern (second byte).
- *
- * IEEE80211_RADIOTAP_RATE u8 500kb/s
- *
- * Tx/Rx data rate
- *
- * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
- * one milliwatt (dBm)
- *
- * RF signal power at the antenna, decibel difference from
- * one milliwatt.
- *
- * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
- * one milliwatt (dBm)
- *
- * RF noise power at the antenna, decibel difference from one
- * milliwatt.
- *
- * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
- *
- * RF signal power at the antenna, decibel difference from an
- * arbitrary, fixed reference.
- *
- * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
- *
- * RF noise power at the antenna, decibel difference from an
- * arbitrary, fixed reference point.
- *
- * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless
- *
- * Quality of Barker code lock. Unitless. Monotonically
- * nondecreasing with "better" lock strength. Called "Signal
- * Quality" in datasheets. (Is there a standard way to measure
- * this?)
- *
- * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless
- *
- * Transmit power expressed as unitless distance from max
- * power set at factory calibration. 0 is max power.
- * Monotonically nondecreasing with lower power levels.
- *
- * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB)
- *
- * Transmit power expressed as decibel distance from max power
- * set at factory calibration. 0 is max power. Monotonically
- * nondecreasing with lower power levels.
- *
- * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
- * one milliwatt (dBm)
- *
- * Transmit power expressed as dBm (decibels from a 1 milliwatt
- * reference). This is the absolute power level measured at
- * the antenna port.
- *
- * IEEE80211_RADIOTAP_FLAGS u8 bitmap
- *
- * Properties of transmitted and received frames. See flags
- * defined below.
- *
- * IEEE80211_RADIOTAP_ANTENNA u8 antenna index
- *
- * Unitless indication of the Rx/Tx antenna for this packet.
- * The first antenna is antenna 0.
- *
- * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap
- *
- * Properties of received frames. See flags defined below.
- *
- * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap
- *
- * Properties of transmitted frames. See flags defined below.
- *
- * IEEE80211_RADIOTAP_RTS_RETRIES u8 data
- *
- * Number of rts retries a transmitted frame used.
- *
- * IEEE80211_RADIOTAP_DATA_RETRIES u8 data
- *
- * Number of unicast retries a transmitted frame used.
- *
- * IEEE80211_RADIOTAP_MCS u8, u8, u8 unitless
- *
- * Contains a bitmap of known fields/flags, the flags, and
- * the MCS index.
- *
- * IEEE80211_RADIOTAP_AMPDU_STATUS u32, u16, u8, u8 unitlesss
- *
- * Contains the AMPDU information for the subframe.
- */
-enum ieee80211_radiotap_type {
+ /**
+ * @it_len: overall radiotap header length
+ */
+ le16 it_len;
+
+ /**
+ * @it_present: (first) present word
+ */
+ le32 it_present;
+} STRUCT_PACKED;
+
+/* version is always 0 */
+#define PKTHDR_RADIOTAP_VERSION 0
+
+/* see the radiotap website for the descriptions */
+enum ieee80211_radiotap_presence {
IEEE80211_RADIOTAP_TSFT = 0,
IEEE80211_RADIOTAP_FLAGS = 1,
IEEE80211_RADIOTAP_RATE = 2,
@@ -203,9 +64,11 @@ enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_TX_FLAGS = 15,
IEEE80211_RADIOTAP_RTS_RETRIES = 16,
IEEE80211_RADIOTAP_DATA_RETRIES = 17,
-
+ /* 18 is XChannel, but it's not defined yet */
IEEE80211_RADIOTAP_MCS = 19,
IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
+ IEEE80211_RADIOTAP_VHT = 21,
+ IEEE80211_RADIOTAP_TIMESTAMP = 22,
/* valid in every it_present bitmap, even vendor namespaces */
IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
@@ -213,79 +76,125 @@ enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_EXT = 31
};
-/* Channel flags. */
-#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
-#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
-#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
-#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
-#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
-#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
-#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
-#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
+/* for IEEE80211_RADIOTAP_FLAGS */
+enum ieee80211_radiotap_flags {
+ IEEE80211_RADIOTAP_F_CFP = 0x01,
+ IEEE80211_RADIOTAP_F_SHORTPRE = 0x02,
+ IEEE80211_RADIOTAP_F_WEP = 0x04,
+ IEEE80211_RADIOTAP_F_FRAG = 0x08,
+ IEEE80211_RADIOTAP_F_FCS = 0x10,
+ IEEE80211_RADIOTAP_F_DATAPAD = 0x20,
+ IEEE80211_RADIOTAP_F_BADFCS = 0x40,
+};
+
+/* for IEEE80211_RADIOTAP_CHANNEL */
+enum ieee80211_radiotap_channel_flags {
+ IEEE80211_CHAN_CCK = 0x0020,
+ IEEE80211_CHAN_OFDM = 0x0040,
+ IEEE80211_CHAN_2GHZ = 0x0080,
+ IEEE80211_CHAN_5GHZ = 0x0100,
+ IEEE80211_CHAN_DYN = 0x0400,
+ IEEE80211_CHAN_HALF = 0x4000,
+ IEEE80211_CHAN_QUARTER = 0x8000,
+};
+
+/* for IEEE80211_RADIOTAP_RX_FLAGS */
+enum ieee80211_radiotap_rx_flags {
+ IEEE80211_RADIOTAP_F_RX_BADPLCP = 0x0002,
+};
+
+/* for IEEE80211_RADIOTAP_TX_FLAGS */
+enum ieee80211_radiotap_tx_flags {
+ IEEE80211_RADIOTAP_F_TX_FAIL = 0x0001,
+ IEEE80211_RADIOTAP_F_TX_CTS = 0x0002,
+ IEEE80211_RADIOTAP_F_TX_RTS = 0x0004,
+ IEEE80211_RADIOTAP_F_TX_NOACK = 0x0008,
+};
+
+/* for IEEE80211_RADIOTAP_MCS "have" flags */
+enum ieee80211_radiotap_mcs_have {
+ IEEE80211_RADIOTAP_MCS_HAVE_BW = 0x01,
+ IEEE80211_RADIOTAP_MCS_HAVE_MCS = 0x02,
+ IEEE80211_RADIOTAP_MCS_HAVE_GI = 0x04,
+ IEEE80211_RADIOTAP_MCS_HAVE_FMT = 0x08,
+ IEEE80211_RADIOTAP_MCS_HAVE_FEC = 0x10,
+ IEEE80211_RADIOTAP_MCS_HAVE_STBC = 0x20,
+};
-/* For IEEE80211_RADIOTAP_FLAGS */
-#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
- * during CFP
- */
-#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
- * with short
- * preamble
- */
-#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
- * with WEP encryption
- */
-#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
- * with fragmentation
- */
-#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */
-#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between
- * 802.11 header and payload
- * (to 32-bit boundary)
- */
-#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* frame failed FCS check */
+enum ieee80211_radiotap_mcs_flags {
+ IEEE80211_RADIOTAP_MCS_BW_MASK = 0x03,
+ IEEE80211_RADIOTAP_MCS_BW_20 = 0,
+ IEEE80211_RADIOTAP_MCS_BW_40 = 1,
+ IEEE80211_RADIOTAP_MCS_BW_20L = 2,
+ IEEE80211_RADIOTAP_MCS_BW_20U = 3,
+
+ IEEE80211_RADIOTAP_MCS_SGI = 0x04,
+ IEEE80211_RADIOTAP_MCS_FMT_GF = 0x08,
+ IEEE80211_RADIOTAP_MCS_FEC_LDPC = 0x10,
+ IEEE80211_RADIOTAP_MCS_STBC_MASK = 0x60,
+ IEEE80211_RADIOTAP_MCS_STBC_1 = 1,
+ IEEE80211_RADIOTAP_MCS_STBC_2 = 2,
+ IEEE80211_RADIOTAP_MCS_STBC_3 = 3,
+ IEEE80211_RADIOTAP_MCS_STBC_SHIFT = 5,
+};
-/* For IEEE80211_RADIOTAP_RX_FLAGS */
-#define IEEE80211_RADIOTAP_F_RX_BADPLCP 0x0002 /* bad PLCP */
+/* for IEEE80211_RADIOTAP_AMPDU_STATUS */
+enum ieee80211_radiotap_ampdu_flags {
+ IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN = 0x0001,
+ IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN = 0x0002,
+ IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN = 0x0004,
+ IEEE80211_RADIOTAP_AMPDU_IS_LAST = 0x0008,
+ IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR = 0x0010,
+ IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN = 0x0020,
+};
-/* For IEEE80211_RADIOTAP_TX_FLAGS */
-#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
- * retries */
-#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
-#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
-#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* don't expect an ACK */
+/* for IEEE80211_RADIOTAP_VHT */
+enum ieee80211_radiotap_vht_known {
+ IEEE80211_RADIOTAP_VHT_KNOWN_STBC = 0x0001,
+ IEEE80211_RADIOTAP_VHT_KNOWN_TXOP_PS_NA = 0x0002,
+ IEEE80211_RADIOTAP_VHT_KNOWN_GI = 0x0004,
+ IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS = 0x0008,
+ IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM = 0x0010,
+ IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED = 0x0020,
+ IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH = 0x0040,
+ IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID = 0x0080,
+ IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID = 0x0100,
+};
-/* For IEEE80211_RADIOTAP_AMPDU_STATUS */
-#define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001
-#define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN 0x0002
-#define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN 0x0004
-#define IEEE80211_RADIOTAP_AMPDU_IS_LAST 0x0008
-#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010
-#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020
+enum ieee80211_radiotap_vht_flags {
+ IEEE80211_RADIOTAP_VHT_FLAG_STBC = 0x01,
+ IEEE80211_RADIOTAP_VHT_FLAG_TXOP_PS_NA = 0x02,
+ IEEE80211_RADIOTAP_VHT_FLAG_SGI = 0x04,
+ IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9 = 0x08,
+ IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM = 0x10,
+ IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED = 0x20,
+};
-/* For IEEE80211_RADIOTAP_MCS */
-#define IEEE80211_RADIOTAP_MCS_HAVE_BW 0x01
-#define IEEE80211_RADIOTAP_MCS_HAVE_MCS 0x02
-#define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04
-#define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08
-#define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10
-#define IEEE80211_RADIOTAP_MCS_HAVE_STBC 0x20
-#define IEEE80211_RADIOTAP_MCS_HAVE_NESS 0x40
-#define IEEE80211_RADIOTAP_MCS_NESS_BIT1 0x80
+enum ieee80211_radiotap_vht_coding {
+ IEEE80211_RADIOTAP_CODING_LDPC_USER0 = 0x01,
+ IEEE80211_RADIOTAP_CODING_LDPC_USER1 = 0x02,
+ IEEE80211_RADIOTAP_CODING_LDPC_USER2 = 0x04,
+ IEEE80211_RADIOTAP_CODING_LDPC_USER3 = 0x08,
+};
+/* for IEEE80211_RADIOTAP_TIMESTAMP */
+enum ieee80211_radiotap_timestamp_unit_spos {
+ IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MASK = 0x000F,
+ IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MS = 0x0000,
+ IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US = 0x0001,
+ IEEE80211_RADIOTAP_TIMESTAMP_UNIT_NS = 0x0003,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_MASK = 0x00F0,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_BEGIN_MDPU = 0x0000,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ = 0x0010,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_PPDU = 0x0020,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_MPDU = 0x0030,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_UNKNOWN = 0x00F0,
+};
-#define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03
-#define IEEE80211_RADIOTAP_MCS_BW_20 0
-#define IEEE80211_RADIOTAP_MCS_BW_40 1
-#define IEEE80211_RADIOTAP_MCS_BW_20L 2
-#define IEEE80211_RADIOTAP_MCS_BW_20U 3
-#define IEEE80211_RADIOTAP_MCS_SGI 0x04
-#define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08
-#define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10
-#define IEEE80211_RADIOTAP_MCS_STBC_MASK 0x60
-#define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5
-#define IEEE80211_RADIOTAP_MCS_STBC_1 1
-#define IEEE80211_RADIOTAP_MCS_STBC_2 2
-#define IEEE80211_RADIOTAP_MCS_STBC_3 3
-#define IEEE80211_RADIOTAP_MCS_NESS_BIT0 0x80
+enum ieee80211_radiotap_timestamp_flags {
+ IEEE80211_RADIOTAP_TIMESTAMP_FLAG_64BIT = 0x00,
+ IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT = 0x01,
+ IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY = 0x02,
+};
-#endif /* IEEE80211_RADIOTAP_H */
+#endif /* __RADIOTAP_H */
diff --git a/src/utils/wpabuf.h b/src/utils/wpabuf.h
index 01da41b3..b2a54b22 100644
--- a/src/utils/wpabuf.h
+++ b/src/utils/wpabuf.h
@@ -71,6 +71,21 @@ static inline size_t wpabuf_tailroom(const struct wpabuf *buf)
}
/**
+ * wpabuf_cmp - Check if two buffers contain the same data
+ * @a: wpabuf buffer
+ * @b: wpabuf buffer
+ * Returns: 0 if the two buffers contain the same data and non-zero otherwise
+ */
+static inline int wpabuf_cmp(const struct wpabuf *a, const struct wpabuf *b)
+{
+ if (!a && !b)
+ return 0;
+ if (a && b && wpabuf_size(a) == wpabuf_size(b))
+ return os_memcmp(a->buf, b->buf, wpabuf_size(a));
+ return -1;
+}
+
+/**
* wpabuf_head - Get pointer to the head of the buffer data
* @buf: wpabuf buffer
* Returns: Pointer to the head of the buffer data
diff --git a/src/wps/Makefile b/src/wps/Makefile
index 4806fe8d..cddc6865 100644
--- a/src/wps/Makefile
+++ b/src/wps/Makefile
@@ -1,13 +1,3 @@
-all: libwps.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libwps.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_P2P
CFLAGS += -DCONFIG_WPS_OOB
CFLAGS += -DCONFIG_WPS_NFC
@@ -35,7 +25,4 @@ LIB_OBJS= \
wps_upnp_ssdp.o \
wps_upnp_web.o
-libwps.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 93888b01..6a12255c 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -873,6 +873,11 @@ int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
const u8 *oob_dev_pw,
size_t oob_dev_pw_len);
void wps_registrar_flush(struct wps_registrar *reg);
+int wps_registrar_update_multi_ap(struct wps_registrar *reg,
+ const u8 *multi_ap_backhaul_ssid,
+ size_t multi_ap_backhaul_ssid_len,
+ const u8 *multi_ap_backhaul_network_key,
+ size_t multi_ap_backhaul_network_key_len);
int wps_build_credential_wrap(struct wpabuf *msg,
const struct wps_credential *cred);
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index 6bded143..31d2e50e 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -1298,7 +1298,7 @@ wps_er_init(struct wps_context *wps, const char *ifname, const char *filter)
"with %s", filter);
}
if (get_netif_info(er->ifname, &er->ip_addr, &er->ip_addr_text,
- er->mac_addr)) {
+ NULL, er->mac_addr)) {
wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
"for %s. Does it have IP address?", er->ifname);
wps_er_deinit(er, NULL, NULL);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 9e1ee36d..0db93674 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -3669,6 +3669,35 @@ int wps_registrar_config_ap(struct wps_registrar *reg,
}
+int wps_registrar_update_multi_ap(struct wps_registrar *reg,
+ const u8 *multi_ap_backhaul_ssid,
+ size_t multi_ap_backhaul_ssid_len,
+ const u8 *multi_ap_backhaul_network_key,
+ size_t multi_ap_backhaul_network_key_len)
+{
+ if (multi_ap_backhaul_ssid) {
+ os_memcpy(reg->multi_ap_backhaul_ssid,
+ multi_ap_backhaul_ssid, multi_ap_backhaul_ssid_len);
+ reg->multi_ap_backhaul_ssid_len = multi_ap_backhaul_ssid_len;
+ }
+
+ os_free(reg->multi_ap_backhaul_network_key);
+ reg->multi_ap_backhaul_network_key = NULL;
+ reg->multi_ap_backhaul_network_key_len = 0;
+ if (multi_ap_backhaul_network_key) {
+ reg->multi_ap_backhaul_network_key =
+ os_memdup(multi_ap_backhaul_network_key,
+ multi_ap_backhaul_network_key_len);
+ if (!reg->multi_ap_backhaul_network_key)
+ return -1;
+ reg->multi_ap_backhaul_network_key_len =
+ multi_ap_backhaul_network_key_len;
+ }
+
+ return 0;
+}
+
+
#ifdef CONFIG_WPS_NFC
int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index 6e10e4bc..ff58cb93 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -303,6 +303,14 @@ static void subscr_addr_free_all(struct subscription *s)
}
+static int local_network_addr(struct upnp_wps_device_sm *sm,
+ struct sockaddr_in *addr)
+{
+ return (addr->sin_addr.s_addr & sm->netmask.s_addr) ==
+ (sm->ip_addr & sm->netmask.s_addr);
+}
+
+
/* subscr_addr_add_url -- add address(es) for one url to subscription */
static void subscr_addr_add_url(struct subscription *s, const char *url,
size_t url_len)
@@ -320,9 +328,14 @@ static void subscr_addr_add_url(struct subscription *s, const char *url,
int rerr;
size_t host_len, path_len;
- /* url MUST begin with http: */
- if (url_len < 7 || os_strncasecmp(url, "http://", 7))
+ /* URL MUST begin with HTTP scheme. In addition, limit the length of
+ * the URL to 700 characters which is around the limit that was
+ * implicitly enforced for more than 10 years due to a bug in
+ * generating the event messages. */
+ if (url_len < 7 || os_strncasecmp(url, "http://", 7) || url_len > 700) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Reject an unacceptable URL");
goto fail;
+ }
url += 7;
url_len -= 7;
@@ -381,6 +394,7 @@ static void subscr_addr_add_url(struct subscription *s, const char *url,
for (rp = result; rp; rp = rp->ai_next) {
struct subscr_addr *a;
+ struct sockaddr_in *addr = (struct sockaddr_in *) rp->ai_addr;
/* Limit no. of address to avoid denial of service attack */
if (dl_list_len(&s->addr_list) >= MAX_ADDR_PER_SUBSCRIPTION) {
@@ -389,6 +403,13 @@ static void subscr_addr_add_url(struct subscription *s, const char *url,
break;
}
+ if (!local_network_addr(s->sm, addr)) {
+ wpa_printf(MSG_INFO,
+ "WPS UPnP: Ignore a delivery URL that points to another network %s",
+ inet_ntoa(addr->sin_addr));
+ continue;
+ }
+
a = os_zalloc(sizeof(*a) + alloc_len);
if (a == NULL)
break;
@@ -841,7 +862,7 @@ fail:
}
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
#include <sys/sysctl.h>
#include <net/route.h>
#include <net/if_dl.h>
@@ -882,7 +903,7 @@ static int eth_get(const char *device, u8 ea[ETH_ALEN])
}
return 0;
}
-#endif /* __FreeBSD__ */
+#endif /* __FreeBSD__ || __APPLE__ */
/**
@@ -890,11 +911,12 @@ static int eth_get(const char *device, u8 ea[ETH_ALEN])
* @net_if: Selected network interface name
* @ip_addr: Buffer for returning IP address in network byte order
* @ip_addr_text: Buffer for returning a pointer to allocated IP address text
+ * @netmask: Buffer for returning netmask or %NULL if not needed
* @mac: Buffer for returning MAC address
* Returns: 0 on success, -1 on failure
*/
int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
- u8 mac[ETH_ALEN])
+ struct in_addr *netmask, u8 mac[ETH_ALEN])
{
struct ifreq req;
int sock = -1;
@@ -920,6 +942,19 @@ int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
in_addr.s_addr = *ip_addr;
os_snprintf(*ip_addr_text, 16, "%s", inet_ntoa(in_addr));
+ if (netmask) {
+ os_memset(&req, 0, sizeof(req));
+ os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
+ if (ioctl(sock, SIOCGIFNETMASK, &req) < 0) {
+ wpa_printf(MSG_ERROR,
+ "WPS UPnP: SIOCGIFNETMASK failed: %d (%s)",
+ errno, strerror(errno));
+ goto fail;
+ }
+ addr = (struct sockaddr_in *) &req.ifr_addr;
+ netmask->s_addr = addr->sin_addr.s_addr;
+ }
+
#ifdef __linux__
os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
if (ioctl(sock, SIOCGIFHWADDR, &req) < 0) {
@@ -928,7 +963,7 @@ int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
goto fail;
}
os_memcpy(mac, req.ifr_addr.sa_data, 6);
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
if (eth_get(net_if, mac) < 0) {
wpa_printf(MSG_ERROR, "WPS UPnP: Failed to get MAC address");
goto fail;
@@ -1026,11 +1061,15 @@ static int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if)
/* Determine which IP and mac address we're using */
if (get_netif_info(net_if, &sm->ip_addr, &sm->ip_addr_text,
- sm->mac_addr)) {
+ &sm->netmask, sm->mac_addr)) {
wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
"for %s. Does it have IP address?", net_if);
goto fail;
}
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Local IP address %s netmask %s hwaddr "
+ MACSTR,
+ sm->ip_addr_text, inet_ntoa(sm->netmask),
+ MAC2STR(sm->mac_addr));
/* Listen for incoming TCP connections so that others
* can fetch our "xml files" from us.
diff --git a/src/wps/wps_upnp_ap.c b/src/wps/wps_upnp_ap.c
index cca39053..b6c9478f 100644
--- a/src/wps/wps_upnp_ap.c
+++ b/src/wps/wps_upnp_ap.c
@@ -76,8 +76,10 @@ int upnp_er_set_selected_registrar(struct wps_registrar *reg,
void upnp_er_remove_notification(struct wps_registrar *reg,
struct subscription *s)
{
+ bool was_sel_reg = s->selected_registrar;
+
s->selected_registrar = 0;
eloop_cancel_timeout(upnp_er_set_selected_timeout, s, reg);
- if (reg)
+ if (reg && was_sel_reg)
wps_registrar_selected_registrar_changed(reg, 0);
}
diff --git a/src/wps/wps_upnp_event.c b/src/wps/wps_upnp_event.c
index d7e6edcc..c0d9e41d 100644
--- a/src/wps/wps_upnp_event.c
+++ b/src/wps/wps_upnp_event.c
@@ -147,7 +147,8 @@ static struct wpabuf * event_build_message(struct wps_event_ *e)
struct wpabuf *buf;
char *b;
- buf = wpabuf_alloc(1000 + wpabuf_len(e->data));
+ buf = wpabuf_alloc(1000 + os_strlen(e->addr->path) +
+ wpabuf_len(e->data));
if (buf == NULL)
return NULL;
wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path);
@@ -293,7 +294,7 @@ static int event_send_start(struct subscription *s)
buf = event_build_message(e);
if (buf == NULL) {
- event_retry(e, 0);
+ event_addr_failure(e);
return -1;
}
@@ -301,7 +302,7 @@ static int event_send_start(struct subscription *s)
event_http_cb, e);
if (e->http_event == NULL) {
wpabuf_free(buf);
- event_retry(e, 0);
+ event_addr_failure(e);
return -1;
}
diff --git a/src/wps/wps_upnp_i.h b/src/wps/wps_upnp_i.h
index e87a9323..6ead7b4e 100644
--- a/src/wps/wps_upnp_i.h
+++ b/src/wps/wps_upnp_i.h
@@ -128,6 +128,7 @@ struct upnp_wps_device_sm {
u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */
char *ip_addr_text; /* IP address of network i.f. we use */
unsigned ip_addr; /* IP address of network i.f. we use (host order) */
+ struct in_addr netmask;
int multicast_sd; /* send multicast messages over this socket */
int ssdp_sd; /* receive discovery UPD packets on socket */
int ssdp_sd_registered; /* nonzero if we must unregister */
@@ -158,7 +159,7 @@ struct subscription * subscription_find(struct upnp_wps_device_sm *sm,
const u8 uuid[UUID_LEN]);
void subscr_addr_delete(struct subscr_addr *a);
int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
- u8 mac[ETH_ALEN]);
+ struct in_addr *netmask, u8 mac[ETH_ALEN]);
/* wps_upnp_ssdp.c */
void msearchreply_state_machine_stop(struct advertisement_state_machine *a);
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index c665c740..553302cd 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -60,11 +60,19 @@ ifeq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),)
L_CFLAGS += -DANDROID_LIB_STUB
endif
+ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB_EVENT),)
+L_CFLAGS += -DANDROID_LIB_EVENT
+endif
+
# Disable roaming in wpa_supplicant
ifdef CONFIG_NO_ROAMING
L_CFLAGS += -DCONFIG_NO_ROAMING
endif
+ifeq ($(WIFI_PRIV_CMD_UPDATE_MBO_CELL_STATUS), enabled)
+L_CFLAGS += -DENABLE_PRIV_CMD_UPDATE_MBO_CELL_STATUS
+endif
+
# Use Android specific directory for control interface sockets
L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/vendor/wifi/wpa/sockets\"
L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/vendor/wifi/wpa/sockets\"
@@ -117,6 +125,7 @@ OBJS += notify.c
OBJS += bss.c
OBJS += eap_register.c
OBJS += src/utils/common.c
+OBJS += src/utils/config.c
OBJS += src/utils/wpa_debug.c
OBJS += src/utils/wpabuf.c
OBJS += src/utils/bitfield.c
@@ -125,6 +134,7 @@ 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
@@ -262,6 +272,10 @@ 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
@@ -393,6 +407,17 @@ L_CFLAGS += -DCONFIG_WIFI_DISPLAY
OBJS += wifi_display.c
endif
+ifdef CONFIG_PASN
+L_CFLAGS += -DCONFIG_PASN
+L_CFLAGS += -DCONFIG_PTKSA_CACHE
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+OBJS += src/common/ptksa_cache.c
+OBJS += pasn_supplicant.c
+endif
+
ifdef CONFIG_HS20
OBJS += hs20_supplicant.c
L_CFLAGS += -DCONFIG_HS20
@@ -1501,7 +1526,7 @@ endif
ifdef CONFIG_CTRL_IFACE_HIDL
WPA_SUPPLICANT_USE_HIDL=y
L_CFLAGS += -DCONFIG_HIDL -DCONFIG_CTRL_IFACE_HIDL
-HIDL_INTERFACE_VERSION := 1.3
+HIDL_INTERFACE_VERSION := 1.4
endif
ifdef CONFIG_READLINE
@@ -1629,6 +1654,12 @@ L_CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
NEED_EXT_PASSWORD=y
endif
+ifdef CONFIG_EXT_PASSWORD_FILE
+OBJS += src/utils/ext_password_file.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD_FILE
+NEED_EXT_PASSWORD=y
+endif
+
ifdef NEED_EXT_PASSWORD
OBJS += src/utils/ext_password.c
L_CFLAGS += -DCONFIG_EXT_PASSWORD
@@ -1659,7 +1690,7 @@ endif
OBJS += src/drivers/driver_common.c
-OBJS += wpa_supplicant.c events.c blacklist.c wpas_glue.c scan.c
+OBJS += wpa_supplicant.c events.c bssid_ignore.c wpas_glue.c scan.c
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.c
OBJS_t += src/radius/radius_client.c
OBJS_t += src/radius/radius.c
@@ -1760,9 +1791,10 @@ LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.0
LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.1
LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.2
LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.3
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.4
LOCAL_SHARED_LIBRARIES += libhidlbase libutils libbase
LOCAL_STATIC_LIBRARIES += libwpa_hidl
-LOCAL_VINTF_FRAGMENTS := hidl/$(HIDL_INTERFACE_VERSION)/manifest.xml
+LOCAL_VINTF_FRAGMENTS := hidl/$(HIDL_INTERFACE_VERSION)/android.hardware.wifi.supplicant.xml
ifeq ($(WIFI_HIDL_UNIFIED_SUPPLICANT_SERVICE_RC_ENTRY), true)
LOCAL_INIT_RC=hidl/$(HIDL_INTERFACE_VERSION)/android.hardware.wifi.supplicant-service.rc
endif
@@ -1834,6 +1866,7 @@ LOCAL_SHARED_LIBRARIES := \
android.hardware.wifi.supplicant@1.1 \
android.hardware.wifi.supplicant@1.2 \
android.hardware.wifi.supplicant@1.3 \
+ android.hardware.wifi.supplicant@1.4 \
libbase \
libhidlbase \
libutils \
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index f82e5e0e..a06a93b2 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -533,7 +533,7 @@ ChangeLog for wpa_supplicant
* fixed MSCHAP UTF-8 to UCS-2 conversion for three-byte encoding;
this fixes password with include UTF-8 characters that use
three-byte encoding EAP methods that use NtPasswordHash
- * fixed couple of sequencies where radio work items could get stuck,
+ * fixed couple of sequences where radio work items could get stuck,
e.g., when rfkill blocking happens during scanning or when
scan-for-auth workaround is used
* P2P enhancements/fixes
@@ -627,7 +627,7 @@ ChangeLog for wpa_supplicant
* added 'dup_network <id_s> <id_d> <name>' command; this can be used to
clone the psk field without having toextract it from wpa_supplicant
* fixed GSM authentication on USIM
- * added support for usin epoll in eloop (CONFIG_ELOOP_EPOLL=y)
+ * added support for using epoll in eloop (CONFIG_ELOOP_EPOLL=y)
* fixed some concurrent virtual interface cases with dedicated P2P
management interface to not catch events from removed interface (this
could result in the management interface getting disabled)
@@ -1113,7 +1113,7 @@ ChangeLog for wpa_supplicant
workarounds.
- Add support for AuthorizedMACs attribute.
* TDLS:
- - Propogate TDLS related nl80211 capability flags from kernel and
+ - Propagate TDLS related nl80211 capability flags from kernel and
add them as driver capability flags. If the driver doesn't support
capabilities, assume TDLS is supported internally. When TDLS is
explicitly not supported, disable all user facing TDLS operations.
@@ -2221,7 +2221,7 @@ ChangeLog for wpa_supplicant
* added support for EAP-SIM pseudonyms and fast re-authentication
* added support for EAP-TLS/PEAP/TTLS fast re-authentication (TLS
session resumption)
- * added support for EAP-SIM with two challanges
+ * added support for EAP-SIM with two challenges
(phase1="sim_min_num_chal=3" can be used to require three challenges)
* added support for configuring DH/DSA parameters for an ephemeral DH
key exchange (EAP-TLS/PEAP/TTLS) using new configuration parameters
@@ -2332,7 +2332,7 @@ ChangeLog for wpa_supplicant
ctrl_interface_group can be used to select which group gets access to
the control interface;
wpa_cli: by default, try to connect to the first interface available
- in /var/run/wpa_supplicant; this path can be overriden with -p option
+ in /var/run/wpa_supplicant; this path can be overridden with -p option
and an interface can be selected with -i option (i.e., in most common
cases, wpa_cli does not need to get any arguments)
* added support for LEAP
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index b35d11e4..87db2cd2 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1,11 +1,24 @@
-ifndef CC
-CC=gcc
+BINALL=wpa_supplicant wpa_cli
+
+ifndef CONFIG_NO_WPA_PASSPHRASE
+BINALL += wpa_passphrase
endif
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
+ALL = $(BINALL)
+ALL += systemd/wpa_supplicant.service
+ALL += systemd/wpa_supplicant@.service
+ALL += systemd/wpa_supplicant-nl80211@.service
+ALL += systemd/wpa_supplicant-wired@.service
+ALL += dbus/fi.w1.wpa_supplicant1.service
+ifdef CONFIG_BUILD_WPA_CLIENT_SO
+ALL += libwpa_client.so
endif
+EXTRA_TARGETS=dynamic_eap_methods
+
+CONFIG_FILE=.config
+include ../src/build.rules
+
ifdef LIBS
# If LIBS is set with some global build system defaults, clone those for
# LIBS_c and LIBS_p to cover wpa_passphrase and wpa_cli as well.
@@ -26,8 +39,6 @@ CFLAGS += $(EXTRA_CFLAGS)
CFLAGS += -I$(abspath ../src)
CFLAGS += -I$(abspath ../src/utils)
--include .config
-
ifndef CONFIG_NO_GITVER
# Add VERSION_STR postfix for builds from a git repository
ifeq ($(wildcard ../.git),../.git)
@@ -44,34 +55,6 @@ CONFIG_WPS_TESTING=y
CONFIG_TDLS_TESTING=y
endif
-BINALL=wpa_supplicant wpa_cli
-
-ifndef CONFIG_NO_WPA_PASSPHRASE
-BINALL += wpa_passphrase
-endif
-
-ALL = $(BINALL)
-ALL += systemd/wpa_supplicant.service
-ALL += systemd/wpa_supplicant@.service
-ALL += systemd/wpa_supplicant-nl80211@.service
-ALL += systemd/wpa_supplicant-wired@.service
-ALL += dbus/fi.w1.wpa_supplicant1.service
-ifdef CONFIG_BUILD_WPA_CLIENT_SO
-ALL += libwpa_client.so
-endif
-
-
-all: verify_config $(ALL) dynamic_eap_methods
-
-verify_config:
- @if [ ! -r .config ]; then \
- echo 'Building wpa_supplicant requires a configuration file'; \
- echo '(.config). See README for more instructions. You can'; \
- echo 'run "cp defconfig .config" to create an example'; \
- echo 'configuration.'; \
- exit 1; \
- fi
-
mkconfig:
@if [ -f .config ]; then \
echo '.config exists - did not replace it'; \
@@ -100,6 +83,7 @@ OBJS += notify.o
OBJS += bss.o
OBJS += eap_register.o
OBJS += ../src/utils/common.o
+OBJS += ../src/utils/config.o
OBJS += ../src/utils/wpa_debug.o
OBJS += ../src/utils/wpabuf.o
OBJS += ../src/utils/bitfield.o
@@ -107,6 +91,7 @@ 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
@@ -267,6 +252,10 @@ 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
@@ -406,6 +395,17 @@ CFLAGS += -DCONFIG_WIFI_DISPLAY
OBJS += wifi_display.o
endif
+ifdef CONFIG_PASN
+CFLAGS += -DCONFIG_PASN
+CFLAGS += -DCONFIG_PTKSA_CACHE
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+OBJS += ../src/common/ptksa_cache.o
+OBJS += pasn_supplicant.o
+endif
+
ifdef CONFIG_HS20
OBJS += hs20_supplicant.o
CFLAGS += -DCONFIG_HS20
@@ -1755,6 +1755,12 @@ CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
NEED_EXT_PASSWORD=y
endif
+ifdef CONFIG_EXT_PASSWORD_FILE
+OBJS += ../src/utils/ext_password_file.o
+CFLAGS += -DCONFIG_EXT_PASSWORD_FILE
+NEED_EXT_PASSWORD=y
+endif
+
ifdef NEED_EXT_PASSWORD
OBJS += ../src/utils/ext_password.o
CFLAGS += -DCONFIG_EXT_PASSWORD
@@ -1797,7 +1803,7 @@ endif
OBJS += ../src/drivers/driver_common.o
OBJS_priv += ../src/drivers/driver_common.o
-OBJS += wpa_supplicant.o events.o blacklist.o wpas_glue.o scan.o
+OBJS += wpa_supplicant.o events.o bssid_ignore.o wpas_glue.o scan.o
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o
OBJS_t += ../src/radius/radius_client.o
OBJS_t += ../src/radius/radius.o
@@ -1866,53 +1872,40 @@ ifdef CONFIG_NO_TKIP
CFLAGS += -DCONFIG_NO_TKIP
endif
-ifndef LDO
-LDO=$(CC)
-endif
-
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-ifeq ($(QUIET), 1)
-Q=@
-E=true
-endif
-
dynamic_eap_methods: $(EAPDYN)
-../src/drivers/build.wpa_supplicant:
- @if [ -f ../src/drivers/build.hostapd ]; then \
- $(MAKE) -C ../src/drivers clean; \
- fi
- @touch ../src/drivers/build.wpa_supplicant
-
-BCHECK=../src/drivers/build.wpa_supplicant
-
+_OBJS_VAR := OBJS_priv
+include ../src/objs.mk
wpa_priv: $(BCHECK) $(OBJS_priv)
$(Q)$(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS)
@$(E) " LD " $@
-$(OBJS_c) $(OBJS_t) $(OBJS_t2) $(OBJS) $(BCHECK) $(EXTRA_progs): .config
-
+_OBJS_VAR := OBJS
+include ../src/objs.mk
wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs)
$(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
@$(E) " LD " $@
+_OBJS_VAR := OBJS_t
+include ../src/objs.mk
eapol_test: $(OBJS_t)
$(Q)$(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS)
@$(E) " LD " $@
+_OBJS_VAR := OBJS_t2
+include ../src/objs.mk
preauth_test: $(OBJS_t2)
$(Q)$(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS)
@$(E) " LD " $@
+_OBJS_VAR := OBJS_p
+include ../src/objs.mk
wpa_passphrase: $(OBJS_p)
$(Q)$(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p) $(LIBS)
@$(E) " LD " $@
+_OBJS_VAR := OBJS_c
+include ../src/objs.mk
wpa_cli: $(OBJS_c)
$(Q)$(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
@$(E) " LD " $@
@@ -1926,6 +1919,8 @@ LIBCTRLSO += ../src/utils/os_$(CONFIG_OS).c
LIBCTRLSO += ../src/utils/common.c
LIBCTRLSO += ../src/utils/wpa_debug.c
+_OBJS_VAR := LIBCTRL
+include ../src/objs.mk
libwpa_client.a: $(LIBCTRL)
$(Q)rm -f $@
$(Q)$(AR) crs $@ $?
@@ -1935,14 +1930,19 @@ libwpa_client.so: $(LIBCTRLSO)
@$(E) " CC $@ ($^)"
$(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -fPIC $^
-libwpa_test1: libwpa_test.o libwpa_client.a
- $(Q)$(LDO) $(LDFLAGS) -o libwpa_test1 libwpa_test.o libwpa_client.a $(LIBS_c)
+OBJS_wpatest := libwpa_test.o
+_OBJS_VAR := OBJS_wpatest
+include ../src/objs.mk
+libwpa_test1: $(OBJS_wpatest) libwpa_client.a
+ $(Q)$(LDO) $(LDFLAGS) -o libwpa_test1 $(OBJS_wpatest) libwpa_client.a $(LIBS_c)
@$(E) " LD " $@
-libwpa_test2: libwpa_test.o libwpa_client.so
- $(Q)$(LDO) $(LDFLAGS) -o libwpa_test2 libwpa_test.o -L. -lwpa_client $(LIBS_c)
+libwpa_test2: $(OBJS_wpatest) libwpa_client.so
+ $(Q)$(LDO) $(LDFLAGS) -o libwpa_test2 $(OBJS_wpatest) -L. -lwpa_client $(LIBS_c)
@$(E) " LD " $@
+_OBJS_VAR := OBJS_nfc
+include ../src/objs.mk
nfc_pw_token: $(OBJS_nfc)
$(Q)$(LDO) $(LDFLAGS) -o nfc_pw_token $(OBJS_nfc) $(LIBS)
@$(E) " LD " $@
@@ -1979,16 +1979,6 @@ eap_eke.so: ../src/eap_peer/eap_eke.c ../src/eap_common/eap_eke_common.c
$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
-D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
-ifdef CONFIG_CODE_COVERAGE
-%.o: %.c
- @$(E) " CC " $<
- $(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<)
-else
-%.o: %.c
- $(Q)$(CC) -c -o $@ $(CFLAGS) $<
- @$(E) " CC " $<
-endif
-
%.service: %.service.in
$(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
@$(E) " sed" $<
@@ -2030,15 +2020,16 @@ FIPSLD=$(FIPSDIR)/bin/fipsld
fips:
$(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)"
-lcov-html: wpa_supplicant.gcda
- lcov -c -d .. > lcov.info
+.PHONY: lcov-html
+lcov-html: $(call BUILDOBJ,wpa_supplicant.gcda)
+ lcov -c -d $(BUILDDIR) > lcov.info
genhtml lcov.info --output-directory lcov-html
-clean:
+clean: common-clean
$(MAKE) -C ../src clean
$(MAKE) -C dbus clean
rm -f core *~ *.o *.d *.gcno *.gcda *.gcov
- rm -f eap_*.so $(ALL) $(WINALL) eapol_test preauth_test
+ rm -f eap_*.so $(WINALL) eapol_test preauth_test
rm -f wpa_priv
rm -f nfc_pw_token
rm -f lcov.info
@@ -2046,5 +2037,3 @@ clean:
rm -f libwpa_client.a
rm -f libwpa_client.so
rm -f libwpa_test1 libwpa_test2
-
--include $(OBJS:%.o=%.d)
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index bbc86b13..391912e9 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -383,7 +383,7 @@ cp wpa_cli wpa_supplicant /usr/local/bin
You will need to make a configuration file, e.g.,
/etc/wpa_supplicant.conf, with network configuration for the networks
you are going to use. Configuration file section below includes
-explanation fo the configuration file format and includes various
+explanation of the configuration file format and includes various
examples. Once the configuration is ready, you can test whether the
configuration work by first running wpa_supplicant with following
command to start it on foreground with debugging enabled:
@@ -778,7 +778,7 @@ wpa_cli commands
disconnect = disconnect and wait for reassociate command before connecting
scan = request new BSS scan
scan_results = get latest scan results
- get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies
+ get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilities
terminate = terminate wpa_supplicant
quit = exit wpa_cli
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index 33428710..484e4cbf 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -78,7 +78,7 @@ hs20=1
# Parameters for controlling scanning
-# Homogenous ESS identifier
+# Homogeneous ESS identifier
# If this is set, scans will be used to request response only from BSSes
# belonging to the specified Homogeneous ESS. This is used only if interworking
# is enabled.
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 5f8c8f6c..3c0431b7 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -533,8 +533,9 @@ CONFIG_ERP=y
# Opportunistic Wireless Encryption (OWE)
CONFIG_OWE=y
-# Easy Connect (Device Provisioning Protocol - DPP R1)
+# Easy Connect (Device Provisioning Protocol - DPP R1 & R2)
CONFIG_DPP=y
+CONFIG_DPP2=y
# WPA3-Personal (SAE)
CONFIG_SAE=y
@@ -556,4 +557,7 @@ CONFIG_SUITEB192=y
# be completely removed in a future release.
CONFIG_WEP=y
+# WPA3-Personal (SAE) PK (Public Key) mode
+CONFIG_SAE_PK=y
+
include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index c89b80f6..807e36d0 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -44,6 +44,7 @@ static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
static bool is_chanwidth160_supported(struct hostapd_hw_modes *mode,
struct hostapd_config *conf)
{
@@ -63,6 +64,7 @@ static bool is_chanwidth160_supported(struct hostapd_hw_modes *mode,
return true;
return false;
}
+#endif /* CONFIG_P2P */
static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
@@ -74,30 +76,37 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
u8 center_chan = 0;
u8 channel = conf->channel;
#endif /* CONFIG_P2P */
+ u8 freq_seg_idx;
if (!conf->secondary_channel)
goto no_vht;
/* Use the maximum oper channel width if it's given. */
if (ssid->max_oper_chwidth)
- conf->vht_oper_chwidth = ssid->max_oper_chwidth;
+ hostapd_set_oper_chwidth(conf, ssid->max_oper_chwidth);
- ieee80211_freq_to_chan(ssid->vht_center_freq2,
- &conf->vht_oper_centr_freq_seg1_idx);
+ if (hostapd_get_oper_chwidth(conf) == CHANWIDTH_80P80MHZ) {
+ ieee80211_freq_to_chan(ssid->vht_center_freq2,
+ &freq_seg_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(conf, freq_seg_idx);
+ }
if (!ssid->p2p_group) {
- if (!ssid->vht_center_freq1 ||
- conf->vht_oper_chwidth == CHANWIDTH_USE_HT)
+ if (!ssid->vht_center_freq1)
goto no_vht;
ieee80211_freq_to_chan(ssid->vht_center_freq1,
- &conf->vht_oper_centr_freq_seg0_idx);
- wpa_printf(MSG_DEBUG, "VHT seg0 index %d for AP",
- conf->vht_oper_centr_freq_seg0_idx);
+ &freq_seg_idx);
+ hostapd_set_oper_centr_freq_seg0_idx(conf, freq_seg_idx);
+
+ wpa_printf(MSG_DEBUG,
+ "VHT seg0 index %d and seg1 index %d for AP",
+ hostapd_get_oper_centr_freq_seg0_idx(conf),
+ hostapd_get_oper_centr_freq_seg1_idx(conf));
return;
}
#ifdef CONFIG_P2P
- switch (conf->vht_oper_chwidth) {
+ switch (hostapd_get_oper_chwidth(conf)) {
case CHANWIDTH_80MHZ:
case CHANWIDTH_80P80MHZ:
center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
@@ -117,14 +126,14 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
* try oper_cwidth 160 MHz first then VHT 80 MHz, if 160 MHz is
* not supported.
*/
- conf->vht_oper_chwidth = CHANWIDTH_160MHZ;
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ);
center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
if (center_chan && is_chanwidth160_supported(mode, conf)) {
wpa_printf(MSG_DEBUG,
"VHT center channel %u for auto-selected 160 MHz bandwidth",
center_chan);
} else {
- conf->vht_oper_chwidth = CHANWIDTH_80MHZ;
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ);
center_chan = wpas_p2p_get_vht80_center(wpa_s, mode,
channel);
wpa_printf(MSG_DEBUG,
@@ -136,9 +145,9 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
if (!center_chan)
goto no_vht;
- conf->vht_oper_centr_freq_seg0_idx = center_chan;
+ hostapd_set_oper_centr_freq_seg0_idx(conf, center_chan);
wpa_printf(MSG_DEBUG, "VHT seg0 index %d for P2P GO",
- conf->vht_oper_centr_freq_seg0_idx);
+ hostapd_get_oper_centr_freq_seg0_idx(conf));
return;
#endif /* CONFIG_P2P */
@@ -146,9 +155,27 @@ no_vht:
wpa_printf(MSG_DEBUG,
"No VHT higher bandwidth support for the selected channel %d",
conf->channel);
- conf->vht_oper_centr_freq_seg0_idx =
- conf->channel + conf->secondary_channel * 2;
- conf->vht_oper_chwidth = CHANWIDTH_USE_HT;
+ hostapd_set_oper_centr_freq_seg0_idx(
+ conf, conf->channel + conf->secondary_channel * 2);
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
+}
+
+
+static struct hostapd_hw_modes *
+wpa_supplicant_find_hw_mode(struct wpa_supplicant *wpa_s,
+ enum hostapd_hw_mode hw_mode)
+{
+ struct hostapd_hw_modes *mode = NULL;
+ int i;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ if (wpa_s->hw.modes[i].mode == hw_mode) {
+ mode = &wpa_s->hw.modes[i];
+ break;
+ }
+ }
+
+ return mode;
}
@@ -165,9 +192,6 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
return -1;
}
- /* TODO: enable HT40 if driver supports it;
- * drop to 11b if driver does not support 11g */
-
/*
* Enable HT20 if the driver supports it, by setting conf->ieee80211n
* and a mask of allowed capabilities within conf->ht_capab.
@@ -176,17 +200,28 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
*/
if (wpa_s->hw.modes) {
struct hostapd_hw_modes *mode = NULL;
- int i, no_ht = 0;
+ int no_ht = 0;
wpa_printf(MSG_DEBUG,
"Determining HT/VHT options based on driver capabilities (freq=%u chan=%u)",
ssid->frequency, conf->channel);
- for (i = 0; i < wpa_s->hw.num_modes; i++) {
- if (wpa_s->hw.modes[i].mode == conf->hw_mode) {
- mode = &wpa_s->hw.modes[i];
- break;
- }
+ mode = wpa_supplicant_find_hw_mode(wpa_s, conf->hw_mode);
+
+ /* May drop to IEEE 802.11b if the driver does not support IEEE
+ * 802.11g */
+ if (!mode && conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
+ wpa_printf(MSG_INFO,
+ "Try downgrade to IEEE 802.11b as 802.11g is not supported by the current hardware");
+ mode = wpa_supplicant_find_hw_mode(wpa_s,
+ conf->hw_mode);
+ }
+
+ if (!mode) {
+ wpa_printf(MSG_ERROR,
+ "No match between requested and supported hw modes found");
+ return -1;
}
#ifdef CONFIG_HT_OVERRIDES
@@ -211,6 +246,14 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET),
ssid->ht40);
conf->ieee80211n = 1;
+
+ if (ssid->ht40 &&
+ (mode->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ conf->secondary_channel = ssid->ht40;
+ else
+ conf->secondary_channel = 0;
+
#ifdef CONFIG_P2P
if (ssid->p2p_group &&
conf->hw_mode == HOSTAPD_MODE_IEEE80211A &&
@@ -223,6 +266,16 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG,
"HT secondary channel offset %d for P2P group",
conf->secondary_channel);
+ } else if (ssid->p2p_group && conf->secondary_channel &&
+ conf->hw_mode != HOSTAPD_MODE_IEEE80211A) {
+ /* This ended up trying to configure invalid
+ * 2.4 GHz channels (e.g., HT40+ on channel 11)
+ * in some cases, so clear the secondary channel
+ * configuration now to avoid such cases that
+ * would lead to group formation failures. */
+ wpa_printf(MSG_DEBUG,
+ "Disable HT secondary channel for P2P group on 2.4 GHz");
+ conf->secondary_channel = 0;
}
#endif /* CONFIG_P2P */
@@ -252,16 +305,19 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
HT_CAP_INFO_TX_STBC |
HT_CAP_INFO_MAX_AMSDU_SIZE);
+ /* check this before VHT, because setting oper chan
+ * width and friends is the same call for HE and VHT
+ * and checks if conf->ieee8021ax == 1 */
+ if (mode->he_capab[wpas_mode_to_ieee80211_mode(
+ ssid->mode)].he_supported &&
+ ssid->he)
+ conf->ieee80211ax = 1;
+
if (mode->vht_capab && ssid->vht) {
conf->ieee80211ac = 1;
conf->vht_capab |= mode->vht_capab;
wpas_conf_ap_vht(wpa_s, ssid, conf, mode);
}
-
- if (mode->he_capab[wpas_mode_to_ieee80211_mode(
- ssid->mode)].he_supported &&
- ssid->he)
- conf->ieee80211ax = 1;
}
}
@@ -751,12 +807,17 @@ static void wpas_ap_configured_cb(void *ctx)
return;
}
+ if (wpa_s->current_ssid) {
+ int acs = 0;
#ifdef CONFIG_ACS
- if (wpa_s->current_ssid && wpa_s->current_ssid->acs) {
- wpa_s->assoc_freq = wpa_s->ap_iface->freq;
- wpa_s->current_ssid->frequency = wpa_s->ap_iface->freq;
+ acs = wpa_s->current_ssid->acs;
+#endif
+ if (acs || (wpa_s->assoc_freq && wpa_s->ap_iface->freq &&
+ wpa_s->assoc_freq != wpa_s->ap_iface->freq)) {
+ wpa_s->assoc_freq = wpa_s->ap_iface->freq;
+ wpa_s->current_ssid->frequency = wpa_s->ap_iface->freq;
+ }
}
-#endif /* CONFIG_ACS */
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
@@ -879,6 +940,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;
@@ -1436,10 +1500,17 @@ int ap_switch_channel(struct wpa_supplicant *wpa_s,
struct csa_settings *settings)
{
#ifdef NEED_AP_MLME
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = NULL;
+
+ if (wpa_s->ap_iface)
+ iface = wpa_s->ap_iface;
+ else if (wpa_s->ifmsh)
+ iface = wpa_s->ifmsh;
+
+ if (!iface || !iface->bss[0])
return -1;
- return hostapd_switch_channel(wpa_s->ap_iface->bss[0], settings);
+ return hostapd_switch_channel(iface->bss[0], settings);
#else /* NEED_AP_MLME */
return -1;
#endif /* NEED_AP_MLME */
diff --git a/wpa_supplicant/blacklist.c b/wpa_supplicant/blacklist.c
deleted file mode 100644
index e53dc38b..00000000
--- a/wpa_supplicant/blacklist.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * wpa_supplicant - Temporary BSSID blacklist
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "wpa_supplicant_i.h"
-#include "blacklist.h"
-
-/**
- * wpa_blacklist_get - Get the blacklist entry for a BSSID
- * @wpa_s: Pointer to wpa_supplicant data
- * @bssid: BSSID
- * Returns: Matching blacklist entry for the BSSID or %NULL if not found
- */
-struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
- const u8 *bssid)
-{
- struct wpa_blacklist *e;
-
- if (wpa_s == NULL || bssid == NULL)
- return NULL;
-
- e = wpa_s->blacklist;
- while (e) {
- if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0)
- return e;
- e = e->next;
- }
-
- return NULL;
-}
-
-
-/**
- * wpa_blacklist_add - Add an BSSID to the blacklist
- * @wpa_s: Pointer to wpa_supplicant data
- * @bssid: BSSID to be added to the blacklist
- * Returns: Current blacklist count on success, -1 on failure
- *
- * This function adds the specified BSSID to the blacklist or increases the
- * blacklist count if the BSSID was already listed. It should be called when
- * an association attempt fails either due to the selected BSS rejecting
- * association or due to timeout.
- *
- * This blacklist is used to force %wpa_supplicant to go through all available
- * BSSes before retrying to associate with an BSS that rejected or timed out
- * association. It does not prevent the listed BSS from being used; it only
- * changes the order in which they are tried.
- */
-int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
-{
- struct wpa_blacklist *e;
-
- if (wpa_s == NULL || bssid == NULL)
- return -1;
-
- e = wpa_blacklist_get(wpa_s, bssid);
- if (e) {
- e->count++;
- wpa_printf(MSG_DEBUG, "BSSID " MACSTR " blacklist count "
- "incremented to %d",
- MAC2STR(bssid), e->count);
- return e->count;
- }
-
- e = os_zalloc(sizeof(*e));
- if (e == NULL)
- return -1;
- os_memcpy(e->bssid, bssid, ETH_ALEN);
- e->count = 1;
- e->next = wpa_s->blacklist;
- wpa_s->blacklist = e;
- wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR " into blacklist",
- MAC2STR(bssid));
-
- return e->count;
-}
-
-
-/**
- * wpa_blacklist_del - Remove an BSSID from the blacklist
- * @wpa_s: Pointer to wpa_supplicant data
- * @bssid: BSSID to be removed from the blacklist
- * Returns: 0 on success, -1 on failure
- */
-int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
-{
- struct wpa_blacklist *e, *prev = NULL;
-
- if (wpa_s == NULL || bssid == NULL)
- return -1;
-
- e = wpa_s->blacklist;
- while (e) {
- if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) {
- if (prev == NULL) {
- wpa_s->blacklist = e->next;
- } else {
- prev->next = e->next;
- }
- wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
- "blacklist", MAC2STR(bssid));
- os_free(e);
- return 0;
- }
- prev = e;
- e = e->next;
- }
- return -1;
-}
-
-
-/**
- * wpa_blacklist_clear - Clear the blacklist of all entries
- * @wpa_s: Pointer to wpa_supplicant data
- */
-void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
-{
- struct wpa_blacklist *e, *prev;
- int max_count = 0;
-
- e = wpa_s->blacklist;
- wpa_s->blacklist = NULL;
- while (e) {
- if (e->count > max_count)
- max_count = e->count;
- prev = e;
- e = e->next;
- wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
- "blacklist (clear)", MAC2STR(prev->bssid));
- os_free(prev);
- }
-
- wpa_s->extra_blacklist_count += max_count;
-}
diff --git a/wpa_supplicant/blacklist.h b/wpa_supplicant/blacklist.h
deleted file mode 100644
index ae06986f..00000000
--- a/wpa_supplicant/blacklist.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * wpa_supplicant - Temporary BSSID blacklist
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef BLACKLIST_H
-#define BLACKLIST_H
-
-struct wpa_blacklist {
- struct wpa_blacklist *next;
- u8 bssid[ETH_ALEN];
- int count;
-};
-
-struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
- const u8 *bssid);
-int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid);
-int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid);
-void wpa_blacklist_clear(struct wpa_supplicant *wpa_s);
-
-#endif /* BLACKLIST_H */
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 127f43e5..e13783ce 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -19,18 +19,6 @@
#include "scan.h"
#include "bss.h"
-
-#define WPA_BSS_FREQ_CHANGED_FLAG BIT(0)
-#define WPA_BSS_SIGNAL_CHANGED_FLAG BIT(1)
-#define WPA_BSS_PRIVACY_CHANGED_FLAG BIT(2)
-#define WPA_BSS_MODE_CHANGED_FLAG BIT(3)
-#define WPA_BSS_WPAIE_CHANGED_FLAG BIT(4)
-#define WPA_BSS_RSNIE_CHANGED_FLAG BIT(5)
-#define WPA_BSS_WPS_CHANGED_FLAG BIT(6)
-#define WPA_BSS_RATES_CHANGED_FLAG BIT(7)
-#define WPA_BSS_IES_CHANGED_FLAG BIT(8)
-
-
static void wpa_bss_set_hessid(struct wpa_bss *bss)
{
#ifdef CONFIG_INTERWORKING
@@ -351,10 +339,31 @@ static int wpa_bss_is_wps_candidate(struct wpa_supplicant *wpa_s,
}
+static bool is_p2p_pending_bss(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss)
+{
+#ifdef CONFIG_P2P
+ u8 addr[ETH_ALEN];
+
+ if (os_memcmp(bss->bssid, wpa_s->pending_join_iface_addr,
+ ETH_ALEN) == 0)
+ return true;
+ if (!is_zero_ether_addr(wpa_s->pending_join_dev_addr) &&
+ p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len, addr) == 0 &&
+ os_memcmp(addr, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0)
+ return true;
+#endif /* CONFIG_P2P */
+ return false;
+}
+
+
static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
struct wpa_ssid *ssid;
+ if (is_p2p_pending_bss(wpa_s, bss))
+ return 1;
+
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
if (ssid->ssid == NULL || ssid->ssid_len == 0)
continue;
@@ -443,7 +452,7 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
bss->ssid_len = ssid_len;
bss->ie_len = res->ie_len;
bss->beacon_ie_len = res->beacon_ie_len;
- os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
+ os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len);
wpa_bss_set_hessid(bss);
if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
@@ -546,7 +555,7 @@ static u32 wpa_bss_compare_res(const struct wpa_bss *old,
changes |= WPA_BSS_MODE_CHANGED_FLAG;
if (old->ie_len == new_res->ie_len &&
- os_memcmp(old + 1, new_res + 1, old->ie_len) == 0)
+ os_memcmp(wpa_bss_ie_ptr(old), new_res + 1, old->ie_len) == 0)
return changes;
changes |= WPA_BSS_IES_CHANGED_FLAG;
@@ -567,8 +576,8 @@ static u32 wpa_bss_compare_res(const struct wpa_bss *old,
}
-static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
- const struct wpa_bss *bss)
+void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
+ const struct wpa_bss *bss)
{
if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
wpas_notify_bss_freq_changed(wpa_s, bss->id);
@@ -670,7 +679,7 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
#endif /* CONFIG_P2P */
if (bss->ie_len + bss->beacon_ie_len >=
res->ie_len + res->beacon_ie_len) {
- os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
+ os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len);
bss->ie_len = res->ie_len;
bss->beacon_ie_len = res->beacon_ie_len;
} else {
@@ -691,7 +700,7 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
wpa_s->current_bss = nbss;
wpa_bss_update_pending_connect(wpa_s, bss, nbss);
bss = nbss;
- os_memcpy(bss + 1, res + 1,
+ os_memcpy(bss->ies, res + 1,
res->ie_len + res->beacon_ie_len);
bss->ie_len = res->ie_len;
bss->beacon_ie_len = res->beacon_ie_len;
@@ -1053,7 +1062,7 @@ struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, *found = NULL;
dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
u8 addr[ETH_ALEN];
- if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
+ if (p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len,
addr) != 0 ||
os_memcmp(addr, dev_addr, ETH_ALEN) != 0)
continue;
@@ -1117,7 +1126,22 @@ struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
*/
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
{
- return get_ie((const u8 *) (bss + 1), bss->ie_len, ie);
+ return get_ie(wpa_bss_ie_ptr(bss), bss->ie_len, ie);
+}
+
+
+/**
+ * wpa_bss_get_ie_ext - Fetch a specified extended IE from a BSS entry
+ * @bss: BSS table entry
+ * @ext: Information element extension identifier (WLAN_EID_EXT_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ */
+const u8 * wpa_bss_get_ie_ext(const struct wpa_bss *bss, u8 ext)
+{
+ return get_ie_ext(wpa_bss_ie_ptr(bss), bss->ie_len, ext);
}
@@ -1132,18 +1156,15 @@ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
*/
const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
{
- const u8 *end, *pos;
+ const u8 *ies;
+ const struct element *elem;
- pos = (const u8 *) (bss + 1);
- end = pos + bss->ie_len;
+ ies = wpa_bss_ie_ptr(bss);
- while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
- break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- return pos;
- pos += 2 + pos[1];
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, bss->ie_len) {
+ if (elem->datalen >= 4 &&
+ vendor_type == WPA_GET_BE32(elem->data))
+ return &elem->id;
}
return NULL;
@@ -1165,22 +1186,20 @@ const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
u32 vendor_type)
{
- const u8 *end, *pos;
+ const u8 *ies;
+ const struct element *elem;
if (bss->beacon_ie_len == 0)
return NULL;
- pos = (const u8 *) (bss + 1);
- pos += bss->ie_len;
- end = pos + bss->beacon_ie_len;
+ ies = wpa_bss_ie_ptr(bss);
+ ies += bss->ie_len;
- while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
- break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- return pos;
- pos += 2 + pos[1];
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies,
+ bss->beacon_ie_len) {
+ if (elem->datalen >= 4 &&
+ vendor_type == WPA_GET_BE32(elem->data))
+ return &elem->id;
}
return NULL;
@@ -1207,16 +1226,21 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
if (buf == NULL)
return NULL;
- pos = (const u8 *) (bss + 1);
+ pos = wpa_bss_ie_ptr(bss);
end = pos + bss->ie_len;
while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
+ u8 ie, len;
+
+ ie = pos[0];
+ len = pos[1];
+ if (len > end - pos - 2)
break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
- pos += 2 + pos[1];
+ pos += 2;
+ if (ie == WLAN_EID_VENDOR_SPECIFIC && len >= 4 &&
+ vendor_type == WPA_GET_BE32(pos))
+ wpabuf_put_data(buf, pos + 4, len - 4);
+ pos += len;
}
if (wpabuf_len(buf) == 0) {
@@ -1251,7 +1275,7 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
if (buf == NULL)
return NULL;
- pos = (const u8 *) (bss + 1);
+ pos = wpa_bss_ie_ptr(bss);
pos += bss->ie_len;
end = pos + bss->beacon_ie_len;
@@ -1337,7 +1361,7 @@ int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
#ifdef CONFIG_FILS
-const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss)
+const u8 * wpa_bss_get_fils_cache_id(const struct wpa_bss *bss)
{
const u8 *ie;
@@ -1354,6 +1378,8 @@ const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss)
int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab)
{
+ if (!bss)
+ return 0;
return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB),
capab);
}
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 07167617..4078b9b9 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -20,9 +20,20 @@ struct wpa_scan_res;
#define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
#define WPA_BSS_OWE_TRANSITION BIT(7)
+#define WPA_BSS_FREQ_CHANGED_FLAG BIT(0)
+#define WPA_BSS_SIGNAL_CHANGED_FLAG BIT(1)
+#define WPA_BSS_PRIVACY_CHANGED_FLAG BIT(2)
+#define WPA_BSS_MODE_CHANGED_FLAG BIT(3)
+#define WPA_BSS_WPAIE_CHANGED_FLAG BIT(4)
+#define WPA_BSS_RSNIE_CHANGED_FLAG BIT(5)
+#define WPA_BSS_WPS_CHANGED_FLAG BIT(6)
+#define WPA_BSS_RATES_CHANGED_FLAG BIT(7)
+#define WPA_BSS_IES_CHANGED_FLAG BIT(8)
+
struct wpa_bss_anqp_elem {
struct dl_list list;
u16 infoid;
+ bool protected_response; /* received in a protected GAS response */
struct wpabuf *payload;
};
@@ -111,8 +122,16 @@ struct wpa_bss {
size_t beacon_ie_len;
/* followed by ie_len octets of IEs */
/* followed by beacon_ie_len octets of IEs */
+ u8 ies[];
};
+static inline const u8 * wpa_bss_ie_ptr(const struct wpa_bss *bss)
+{
+ return bss->ies;
+}
+
+void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
+ const struct wpa_bss *bss);
void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res,
@@ -137,6 +156,7 @@ struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id);
struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
unsigned int idf, unsigned int idl);
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
+const u8 * wpa_bss_get_ie_ext(const struct wpa_bss *bss, u8 ext);
const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
u32 vendor_type);
@@ -148,7 +168,7 @@ int wpa_bss_get_max_rate(const struct wpa_bss *bss);
int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
-const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss);
+const u8 * wpa_bss_get_fils_cache_id(const struct wpa_bss *bss);
int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab);
static inline int bss_is_dmg(const struct wpa_bss *bss)
@@ -169,7 +189,7 @@ static inline int bss_is_pbss(struct wpa_bss *bss)
static inline void wpa_bss_update_level(struct wpa_bss *bss, int new_level)
{
- if (bss != NULL && new_level < 0)
+ if (bss != NULL && new_level > -WPA_INVALID_NOISE && new_level < 0)
bss->level = new_level;
}
diff --git a/wpa_supplicant/bssid_ignore.c b/wpa_supplicant/bssid_ignore.c
new file mode 100644
index 00000000..e3785779
--- /dev/null
+++ b/wpa_supplicant/bssid_ignore.c
@@ -0,0 +1,221 @@
+/*
+ * wpa_supplicant - List of temporarily ignored BSSIDs
+ * Copyright (c) 2003-2021, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "bssid_ignore.h"
+
+/**
+ * wpa_bssid_ignore_get - Get the ignore list entry for a BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Matching entry for the BSSID or %NULL if not found
+ */
+struct wpa_bssid_ignore * wpa_bssid_ignore_get(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+ struct wpa_bssid_ignore *e;
+
+ if (wpa_s == NULL || bssid == NULL)
+ return NULL;
+
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->was_recently_reconfigured) {
+ wpa_bssid_ignore_clear(wpa_s);
+ wpa_s->current_ssid->was_recently_reconfigured = false;
+ return NULL;
+ }
+
+ wpa_bssid_ignore_update(wpa_s);
+
+ e = wpa_s->bssid_ignore;
+ while (e) {
+ if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0)
+ return e;
+ e = e->next;
+ }
+
+ return NULL;
+}
+
+
+/**
+ * wpa_bssid_ignore_add - Add an BSSID to the ignore list
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be added to the ignore list
+ * Returns: Current ignore list count on success, -1 on failure
+ *
+ * This function adds the specified BSSID to the ignore list or increases the
+ * ignore count if the BSSID was already listed. It should be called when
+ * an association attempt fails either due to the selected BSS rejecting
+ * association or due to timeout.
+ *
+ * This ignore list is used to force %wpa_supplicant to go through all available
+ * BSSes before retrying to associate with an BSS that rejected or timed out
+ * association. It does not prevent the listed BSS from being used; it only
+ * changes the order in which they are tried.
+ */
+int wpa_bssid_ignore_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wpa_bssid_ignore *e;
+ struct os_reltime now;
+
+ if (wpa_s == NULL || bssid == NULL)
+ return -1;
+
+ e = wpa_bssid_ignore_get(wpa_s, bssid);
+ os_get_reltime(&now);
+ if (e) {
+ e->start = now;
+ e->count++;
+ if (e->count > 5)
+ e->timeout_secs = 1800;
+ else if (e->count == 5)
+ e->timeout_secs = 600;
+ else if (e->count == 4)
+ e->timeout_secs = 120;
+ else if (e->count == 3)
+ e->timeout_secs = 60;
+ else
+ e->timeout_secs = 10;
+ wpa_printf(MSG_INFO, "BSSID " MACSTR
+ " ignore list count incremented to %d, ignoring for %d seconds",
+ MAC2STR(bssid), e->count, e->timeout_secs);
+ return e->count;
+ }
+
+ e = os_zalloc(sizeof(*e));
+ if (e == NULL)
+ return -1;
+ os_memcpy(e->bssid, bssid, ETH_ALEN);
+ e->count = 1;
+ e->timeout_secs = 10;
+ e->start = now;
+ e->next = wpa_s->bssid_ignore;
+ wpa_s->bssid_ignore = e;
+ wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR
+ " into ignore list, ignoring for %d seconds",
+ MAC2STR(bssid), e->timeout_secs);
+
+ return e->count;
+}
+
+
+/**
+ * wpa_bssid_ignore_del - Remove an BSSID from the ignore list
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be removed from the ignore list
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_bssid_ignore_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wpa_bssid_ignore *e, *prev = NULL;
+
+ if (wpa_s == NULL || bssid == NULL)
+ return -1;
+
+ e = wpa_s->bssid_ignore;
+ while (e) {
+ if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) {
+ if (prev == NULL) {
+ wpa_s->bssid_ignore = e->next;
+ } else {
+ prev->next = e->next;
+ }
+ wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR
+ " from ignore list", MAC2STR(bssid));
+ os_free(e);
+ return 0;
+ }
+ prev = e;
+ e = e->next;
+ }
+ return -1;
+}
+
+
+/**
+ * wpa_bssid_ignore_is_listed - Check whether a BSSID is ignored temporarily
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be checked
+ * Returns: count if BSS is currently considered to be ignored, 0 otherwise
+ */
+int wpa_bssid_ignore_is_listed(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wpa_bssid_ignore *e;
+ struct os_reltime now;
+
+ e = wpa_bssid_ignore_get(wpa_s, bssid);
+ if (!e)
+ return 0;
+ os_get_reltime(&now);
+ if (os_reltime_expired(&now, &e->start, e->timeout_secs))
+ return 0;
+ return e->count;
+}
+
+
+/**
+ * wpa_bssid_ignore_clear - Clear the ignore list of all entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_bssid_ignore_clear(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bssid_ignore *e, *prev;
+
+ e = wpa_s->bssid_ignore;
+ wpa_s->bssid_ignore = NULL;
+ while (e) {
+ prev = e;
+ e = e->next;
+ wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR
+ " from ignore list (clear)", MAC2STR(prev->bssid));
+ os_free(prev);
+ }
+}
+
+
+/**
+ * wpa_bssid_ignore_update - Update the entries in the ignore list,
+ * deleting entries that have been expired for over an hour.
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_bssid_ignore_update(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bssid_ignore *e, *prev = NULL;
+ struct os_reltime now;
+
+ if (!wpa_s)
+ return;
+
+ e = wpa_s->bssid_ignore;
+ os_get_reltime(&now);
+ while (e) {
+ if (os_reltime_expired(&now, &e->start,
+ e->timeout_secs + 3600)) {
+ struct wpa_bssid_ignore *to_delete = e;
+
+ if (prev) {
+ prev->next = e->next;
+ e = prev->next;
+ } else {
+ wpa_s->bssid_ignore = e->next;
+ e = wpa_s->bssid_ignore;
+ }
+ wpa_printf(MSG_INFO, "Removed BSSID " MACSTR
+ " from ignore list (expired)",
+ MAC2STR(to_delete->bssid));
+ os_free(to_delete);
+ } else {
+ prev = e;
+ e = e->next;
+ }
+ }
+}
diff --git a/wpa_supplicant/bssid_ignore.h b/wpa_supplicant/bssid_ignore.h
new file mode 100644
index 00000000..721b0e12
--- /dev/null
+++ b/wpa_supplicant/bssid_ignore.h
@@ -0,0 +1,33 @@
+/*
+ * wpa_supplicant - List of temporarily ignored BSSIDs
+ * Copyright (c) 2003-2021, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BSSID_IGNORE_H
+#define BSSID_IGNORE_H
+
+struct wpa_bssid_ignore {
+ struct wpa_bssid_ignore *next;
+ u8 bssid[ETH_ALEN];
+ int count;
+ /* Time of the most recent trigger to ignore this BSSID. */
+ struct os_reltime start;
+ /*
+ * Number of seconds after start that the entey will be considered
+ * valid.
+ */
+ int timeout_secs;
+};
+
+struct wpa_bssid_ignore * wpa_bssid_ignore_get(struct wpa_supplicant *wpa_s,
+ const u8 *bssid);
+int wpa_bssid_ignore_add(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpa_bssid_ignore_del(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpa_bssid_ignore_is_listed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+void wpa_bssid_ignore_clear(struct wpa_supplicant *wpa_s);
+void wpa_bssid_ignore_update(struct wpa_supplicant *wpa_s);
+
+#endif /* BSSID_IGNORE_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 173be096..16936317 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -442,47 +442,99 @@ static char * wpa_config_write_bssid_hint(const struct parse_data *data,
#endif /* NO_CONFIG_WRITE */
+static int wpa_config_parse_bssid_ignore(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ return wpa_config_parse_addr_list(data, line, value,
+ &ssid->bssid_ignore,
+ &ssid->num_bssid_ignore,
+ "bssid_ignore", 1, 1);
+}
+
+
+/* deprecated alias for bssid_ignore for backwards compatibility */
static int wpa_config_parse_bssid_blacklist(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
{
return wpa_config_parse_addr_list(data, line, value,
- &ssid->bssid_blacklist,
- &ssid->num_bssid_blacklist,
- "bssid_blacklist", 1, 1);
+ &ssid->bssid_ignore,
+ &ssid->num_bssid_ignore,
+ "bssid_ignore", 1, 1);
}
#ifndef NO_CONFIG_WRITE
+
+static char * wpa_config_write_bssid_ignore(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_addr_list(data, ssid->bssid_ignore,
+ ssid->num_bssid_ignore,
+ "bssid_ignore");
+}
+
+
+/* deprecated alias for bssid_ignore for backwards compatibility */
static char * wpa_config_write_bssid_blacklist(const struct parse_data *data,
struct wpa_ssid *ssid)
{
- return wpa_config_write_addr_list(data, ssid->bssid_blacklist,
- ssid->num_bssid_blacklist,
- "bssid_blacklist");
+ return wpa_config_write_addr_list(data, ssid->bssid_ignore,
+ ssid->num_bssid_ignore,
+ "bssid_ignore");
}
+
#endif /* NO_CONFIG_WRITE */
+static int wpa_config_parse_bssid_accept(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ return wpa_config_parse_addr_list(data, line, value,
+ &ssid->bssid_accept,
+ &ssid->num_bssid_accept,
+ "bssid_accept", 1, 1);
+}
+
+
+/* deprecated alias for bssid_accept for backwards compatibility */
static int wpa_config_parse_bssid_whitelist(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
{
return wpa_config_parse_addr_list(data, line, value,
- &ssid->bssid_whitelist,
- &ssid->num_bssid_whitelist,
- "bssid_whitelist", 1, 1);
+ &ssid->bssid_accept,
+ &ssid->num_bssid_accept,
+ "bssid_accept", 1, 1);
}
#ifndef NO_CONFIG_WRITE
+
+static char * wpa_config_write_bssid_accept(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_addr_list(data, ssid->bssid_accept,
+ ssid->num_bssid_accept,
+ "bssid_accept");
+}
+
+
+/* deprecated alias for bssid_accept for backwards compatibility */
static char * wpa_config_write_bssid_whitelist(const struct parse_data *data,
struct wpa_ssid *ssid)
{
- return wpa_config_write_addr_list(data, ssid->bssid_whitelist,
- ssid->num_bssid_whitelist,
- "bssid_whitelist");
+ return wpa_config_write_addr_list(data, ssid->bssid_accept,
+ ssid->num_bssid_accept,
+ "bssid_accept");
}
+
+#endif /* NO_CONFIG_WRITE */
+
+
+#ifndef NO_CONFIG_WRITE
#endif /* NO_CONFIG_WRITE */
@@ -2362,8 +2414,10 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(scan_ssid, 0, 1) },
{ FUNC(bssid) },
{ FUNC(bssid_hint) },
- { FUNC(bssid_blacklist) },
- { FUNC(bssid_whitelist) },
+ { FUNC(bssid_ignore) },
+ { FUNC(bssid_accept) },
+ { FUNC(bssid_blacklist) }, /* deprecated alias for bssid_ignore */
+ { FUNC(bssid_whitelist) }, /* deprecated alias for bssid_accept */
{ FUNC_KEY(psk) },
{ INT(mem_only_psk) },
{ STR_KEY(sae_password) },
@@ -2573,6 +2627,7 @@ static const struct parse_data ssid_fields[] = {
{ STR_LEN(dpp_netaccesskey) },
{ INT(dpp_netaccesskey_expiry) },
{ STR_LEN(dpp_csign) },
+ { STR_LEN(dpp_pp_key) },
{ INT_RANGE(dpp_pfs, 0, 2) },
#endif /* CONFIG_DPP */
{ INT_RANGE(owe_group, 0, 65535) },
@@ -2582,6 +2637,7 @@ static const struct parse_data ssid_fields[] = {
{ 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
@@ -2761,8 +2817,8 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
os_free(ssid->freq_list);
os_free(ssid->bgscan);
os_free(ssid->p2p_client_list);
- os_free(ssid->bssid_blacklist);
- os_free(ssid->bssid_whitelist);
+ os_free(ssid->bssid_ignore);
+ os_free(ssid->bssid_accept);
#ifdef CONFIG_HT_OVERRIDES
os_free(ssid->ht_mcs);
#endif /* CONFIG_HT_OVERRIDES */
@@ -2775,6 +2831,7 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
os_free(ssid->dpp_connector);
bin_clear_free(ssid->dpp_netaccesskey, ssid->dpp_netaccesskey_len);
os_free(ssid->dpp_csign);
+ os_free(ssid->dpp_pp_key);
while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry,
list))) {
dl_list_del(&psk->list);
@@ -2887,6 +2944,7 @@ void wpa_config_free(struct wpa_config *config)
os_free(config->p2p_no_go_freq.range);
os_free(config->autoscan);
os_free(config->freq_list);
+ os_free(config->initial_freq_list);
wpabuf_free(config->wps_nfc_dh_pubkey);
wpabuf_free(config->wps_nfc_dh_privkey);
wpabuf_free(config->wps_nfc_dev_pw);
@@ -3035,6 +3093,8 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
ssid->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
ssid->ht = 1;
+ ssid->vht = 1;
+ ssid->he = 1;
#ifdef IEEE8021X_EAPOL
ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
@@ -3141,6 +3201,7 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
}
ret = -1;
}
+ ssid->was_recently_reconfigured = true;
return ret;
}
@@ -4254,6 +4315,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 =
@@ -4261,9 +4324,20 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const struct hostapd_wmm_ac_params ac_be =
{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
- { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
+ { aCWmin - 1, aCWmin, 2, 3008 / 32, 0 };
const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
- { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
+ { aCWmin - 2, aCWmin - 1, 2, 1504 / 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)
@@ -4289,10 +4363,15 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->ap_isolate = DEFAULT_AP_ISOLATE;
config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ;
+ config->scan_res_valid_for_connect = DEFAULT_SCAN_RES_VALID_FOR_CONNECT;
config->wmm_ac_params[0] = ac_be;
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;
@@ -4305,8 +4384,8 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->disassoc_imminent_rssi_threshold =
DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD;
config->oce = DEFAULT_OCE_SUPPORT;
- config->btm_offload = DEFAULT_BTM_OFFLOAD;
#endif /* CONFIG_MBO */
+ config->btm_offload = DEFAULT_BTM_OFFLOAD;
if (ctrl_interface)
config->ctrl_interface = os_strdup(ctrl_interface);
@@ -4343,13 +4422,31 @@ void wpa_config_debug_dump_networks(struct wpa_config *config)
#endif /* CONFIG_NO_STDOUT_DEBUG */
+/**
+ * Structure for global configuration parsing. This data is used to implement a
+ * generic parser for the global interface configuration. The table of variables
+ * is defined below in this file (global_fields[]).
+ */
struct global_parse_data {
+ /* Configuration variable name */
char *name;
+
+ /* Parser function for this variable. The parser functions return 0 or 1
+ * to indicate success. Value 0 indicates that the parameter value may
+ * have changed while value 1 means that the value did not change.
+ * Error cases (failure to parse the string) are indicated by returning
+ * -1. */
int (*parser)(const struct global_parse_data *data,
struct wpa_config *config, int line, const char *value);
+
+ /* Getter function to print the variable in text format to buf. */
int (*get)(const char *name, struct wpa_config *config, long offset,
char *buf, size_t buflen, int pretty_print);
+
+ /* Variable specific parameters for the parser. */
void *param1, *param2, *param3;
+
+ /* Indicates which configuration variable has changed. */
unsigned int changed_flag;
};
@@ -4360,6 +4457,7 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data,
{
int val, *dst;
char *end;
+ bool same;
dst = (int *) (((u8 *) config) + (long) data->param1);
val = strtol(pos, &end, 0);
@@ -4368,6 +4466,7 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data,
line, pos);
return -1;
}
+ same = *dst == val;
*dst = val;
wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
@@ -4388,7 +4487,7 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data,
return -1;
}
- return 0;
+ return same;
}
@@ -4396,7 +4495,7 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
struct wpa_config *config, int line,
const char *pos)
{
- size_t len;
+ size_t len, prev_len;
char **dst, *tmp;
len = os_strlen(pos);
@@ -4420,11 +4519,20 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
return -1;
}
+ dst = (char **) (((u8 *) config) + (long) data->param1);
+ if (*dst)
+ prev_len = os_strlen(*dst);
+ else
+ prev_len = 0;
+
+ /* No change to the previously configured value */
+ if (*dst && prev_len == len && os_memcmp(*dst, pos, len) == 0)
+ return 1;
+
tmp = os_strdup(pos);
if (tmp == NULL)
return -1;
- dst = (char **) (((u8 *) config) + (long) data->param1);
os_free(*dst);
*dst = tmp;
wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
@@ -4465,6 +4573,10 @@ static int wpa_global_config_parse_bin(const struct global_parse_data *data,
return -1;
dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
+ if (wpabuf_cmp(*dst, tmp) == 0) {
+ wpabuf_free(tmp);
+ return 1;
+ }
wpabuf_free(*dst);
*dst = tmp;
wpa_printf(MSG_DEBUG, "%s", data->name);
@@ -4492,6 +4604,26 @@ static int wpa_config_process_freq_list(const struct global_parse_data *data,
}
+static int
+wpa_config_process_initial_freq_list(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *value)
+{
+ int *freqs;
+
+ freqs = wpa_config_parse_int_array(value);
+ if (!freqs)
+ return -1;
+ if (freqs[0] == 0) {
+ os_free(freqs);
+ freqs = NULL;
+ }
+ os_free(config->initial_freq_list);
+ config->initial_freq_list = freqs;
+ return 0;
+}
+
+
#ifdef CONFIG_P2P
static int wpa_global_config_parse_ipv4(const struct global_parse_data *data,
struct wpa_config *config, int line,
@@ -4506,6 +4638,8 @@ static int wpa_global_config_parse_ipv4(const struct global_parse_data *data,
return -1;
dst = (u32 *) (((u8 *) config) + (long) data->param1);
+ if (os_memcmp(dst, &addr.u.v4.s_addr, 4) == 0)
+ return 1;
os_memcpy(dst, &addr.u.v4.s_addr, 4);
wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name,
WPA_GET_BE32((u8 *) dst));
@@ -4523,6 +4657,8 @@ static int wpa_config_process_country(const struct global_parse_data *data,
wpa_printf(MSG_DEBUG, "Invalid country set");
return -1;
}
+ if (pos[0] == config->country[0] && pos[1] == config->country[1])
+ return 1;
config->country[0] = pos[0];
config->country[1] = pos[1];
wpa_printf(MSG_DEBUG, "country='%c%c'",
@@ -4906,7 +5042,7 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(eapol_version, 1, 2), 0 },
#endif /* CONFIG_MACSEC */
{ INT(ap_scan), 0 },
- { FUNC(bgscan), 0 },
+ { FUNC(bgscan), CFG_CHANGED_BGSCAN },
#ifdef CONFIG_MESH
{ INT(user_mpm), 0 },
{ INT_RANGE(max_peer_links, 0, 255), 0 },
@@ -4980,6 +5116,7 @@ static const struct global_parse_data global_fields[] = {
{ INT(p2p_device_random_mac_addr), 0 },
{ FUNC(p2p_device_persistent_mac_addr), 0 },
{ INT(p2p_interface_random_mac_addr), 0 },
+ { INT(p2p_6ghz_disable), 0 },
#endif /* CONFIG_P2P */
{ FUNC(country), CFG_CHANGED_COUNTRY },
{ INT(bss_max_count), 0 },
@@ -5021,7 +5158,9 @@ static const struct global_parse_data global_fields[] = {
{ FUNC(ap_vendor_elements), 0 },
{ INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
{ FUNC(freq_list), 0 },
+ { FUNC(initial_freq_list), 0},
{ INT(scan_cur_freq), 0 },
+ { INT(scan_res_valid_for_connect), 0},
{ INT(sched_scan_interval), 0 },
{ INT(sched_scan_start_delay), 0 },
{ INT(tdls_external_control), 0},
@@ -5049,8 +5188,8 @@ static const struct global_parse_data global_fields[] = {
MBO_CELL_CAPA_NOT_SUPPORTED), 0 },
{ INT_RANGE(disassoc_imminent_rssi_threshold, -120, 0), 0 },
{ INT_RANGE(oce, 0, 3), 0 },
- { INT_RANGE(btm_offload, 0, 1), CFG_CHANGED_DISABLE_BTM_NOTIFY },
#endif /* CONFIG_MBO */
+ { INT_RANGE(btm_offload, 0, 1), CFG_CHANGED_DISABLE_BTM_NOTIFY },
{ INT(gas_address3), 0 },
{ INT_RANGE(ftm_responder, 0, 1), 0 },
{ INT_RANGE(ftm_initiator, 0, 1), 0 },
@@ -5068,6 +5207,11 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(extended_key_id, 0, 1), 0 },
#endif /* CONFIG_WNM */
{ INT_RANGE(wowlan_disconnect_on_deinit, 0, 1), 0},
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ { INT_RANGE(force_kdk_derivation, 0, 1), 0 },
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN */
};
#undef FUNC
@@ -5143,6 +5287,19 @@ const char * wpa_config_get_global_field_name(unsigned int i, int *no_var)
}
+/**
+ * wpa_config_process_global - Set a variable in global configuration
+ * @config: Pointer to global configuration data
+ * @pos: Name and value in the format "{name}={value}"
+ * @line: Line number in configuration file or 0 if not used
+ * Returns: 0 on success with a possible change in value, 1 on success with no
+ * change to previously configured value, or -1 on failure
+ *
+ * This function can be used to set global configuration variables based on
+ * both the configuration file and management interface input. The value
+ * parameter must be in the same format as the text-based configuration file is
+ * using. For example, strings are using double quotation marks.
+ */
int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
{
size_t i;
@@ -5155,11 +5312,14 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
pos[flen] != '=')
continue;
- if (field->parser(field, config, line, pos + flen + 1)) {
+ ret = field->parser(field, config, line, pos + flen + 1);
+ if (ret < 0) {
wpa_printf(MSG_ERROR, "Line %d: failed to "
"parse '%s'.", line, pos);
ret = -1;
}
+ if (ret == 1)
+ break;
if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN)
config->wps_nfc_pw_from_config = 1;
config->changed_parameters |= field->changed_flag;
@@ -5167,6 +5327,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 712e8717..914b5d9c 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -46,6 +46,7 @@
#define DEFAULT_OCE_SUPPORT OCE_STA
#define DEFAULT_EXTENDED_KEY_ID 0
#define DEFAULT_BTM_OFFLOAD 0
+#define DEFAULT_SCAN_RES_VALID_FOR_CONNECT 5
#include "config_ssid.h"
#include "wps/wps.h"
@@ -377,7 +378,8 @@ struct wpa_cred {
#define CFG_CHANGED_SCHED_SCAN_PLANS BIT(17)
#define CFG_CHANGED_WOWLAN_TRIGGERS BIT(18)
#define CFG_CHANGED_DISABLE_BTM BIT(19)
-#define CFG_CHANGED_DISABLE_BTM_NOTIFY BIT(20)
+#define CFG_CHANGED_BGSCAN BIT(20)
+#define CFG_CHANGED_DISABLE_BTM_NOTIFY BIT(21)
/**
* struct wpa_config - wpa_supplicant configuration data
@@ -651,7 +653,7 @@ struct wpa_config {
* This variable control whether wpa_supplicant is allow to re-write
* its configuration with wpa_config_write(). If this is zero,
* configuration data is only changed in memory and the external data
- * is not overriden. If this is non-zero, wpa_supplicant will update
+ * is not overridden. If this is non-zero, wpa_supplicant will update
* the configuration data (e.g., a file) whenever configuration is
* changed. This update may replace the old configuration which can
* remove comments from it in case of a text file configuration.
@@ -781,6 +783,8 @@ struct wpa_config {
int p2p_ignore_shared_freq;
int p2p_optimize_listen_chan;
+ int p2p_6ghz_disable;
+
struct wpabuf *wps_vendor_ext_m1;
#define MAX_WPS_VENDOR_EXT 10
@@ -916,6 +920,19 @@ struct wpa_config {
int *freq_list;
/**
+ * initial_freq_list - like freq_list but for initial scan
+ *
+ * This is an optional zero-terminated array of frequencies in
+ * megahertz (MHz) to allow for narrowing scanning range when
+ * the application is started.
+ *
+ * This can be used to speed up initial connection time if the
+ * channel is known ahead of time, without limiting the scanned
+ * frequencies during normal use.
+ */
+ int *initial_freq_list;
+
+ /**
* scan_cur_freq - Whether to scan only the current channel
*
* If true, attempt to scan only the current channel if any other
@@ -924,6 +941,15 @@ struct wpa_config {
int scan_cur_freq;
/**
+ * scan_res_valid_for_connect - Seconds scans are valid for association
+ *
+ * This configures the number of seconds old scan results are considered
+ * valid for association. When scan results are older than this value
+ * a new scan is triggered prior to the association.
+ */
+ int scan_res_valid_for_connect;
+
+ /**
* changed_parameters - Bitmap of changed parameters since last update
*/
unsigned int changed_parameters;
@@ -976,7 +1002,7 @@ struct wpa_config {
int go_venue_type;
/**
- * hessid - Homogenous ESS identifier
+ * hessid - Homogeneous ESS identifier
*
* If this is set (any octet is non-zero), scans will be used to
* request response only from BSSes belonging to the specified
@@ -1060,6 +1086,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
@@ -1449,15 +1476,14 @@ struct wpa_config {
* - Set BIT(1) to enable OCE in STA-CFON mode
*/
unsigned int oce;
-
+#endif /* CONFIG_MBO */
/**
* btm_offload - Set where to perform roaming logic
* - Set to 0 to handle fully roaming logic in supplicant
* - Set to 1 to skip roaming logic in supplicant for firmware roaming
* just parse BTM frame and notify framework
*/
- int btm_offload;
-#endif /* CONFIG_MBO */
+ int btm_offload;
/**
* gas_address3 - GAS Address3 field behavior
@@ -1547,9 +1573,31 @@ struct wpa_config {
/**
* p2p_device_random_mac_addr - P2P Device MAC address policy default
*
- * 0 = use permanent MAC address
+ * 0 = use permanent MAC address (the one set by default by the device
+ * driver). Notice that, if the device driver is configured to
+ * always use random MAC addresses, this flag breaks reinvoking a
+ * persistent group, so flags 1 or 2 should be used instead with
+ * such drivers if persistent groups are used.
* 1 = use random MAC address on creating the interface if there is no
- * persistent groups.
+ * persistent group. Besides, if a persistent group is created,
+ * p2p_device_persistent_mac_addr is set to the MAC address of the
+ * P2P Device interface, so that this address will be subsequently
+ * used to change the MAC address of the P2P Device interface. With
+ * no persistent group, the random MAC address is created by
+ * wpa_supplicant, changing the one set by the device driver.
+ * The device driver shall support SIOCGIFFLAGS/SIOCSIFFLAGS ioctl
+ * interface control operations.
+ * 2 = this flag should be used when the device driver uses random MAC
+ * addresses by default when a P2P Device interface is created.
+ * If p2p_device_persistent_mac_addr is set, use this MAC address
+ * on creating the P2P Device interface. If not set, use the
+ * default method adopted by the device driver (e.g., random MAC
+ * address). Besides, if a persistent group is created,
+ * p2p_device_persistent_mac_addr is set to the MAC address of the
+ * P2P Device interface, so that this address will be subsequently
+ * used in place of the default address set by the device driver.
+ * (This option does not need support of SIOCGIFFLAGS/SIOCSIFFLAGS
+ * ioctl interface control operations and uses NL80211_ATTR_MAC).
*
* By default, permanent MAC address is used.
*/
@@ -1609,6 +1657,16 @@ struct wpa_config {
* 1 = Trigger disconnection
*/
int wowlan_disconnect_on_deinit;
+
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ /*
+ * Normally, KDK should be derived if and only if both sides support
+ * secure LTF. Allow forcing KDK derivation for testing purposes.
+ */
+ int force_kdk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN*/
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 5faed4ee..9fbfbf9f 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -23,105 +23,7 @@
#include "p2p/p2p.h"
#include "eap_peer/eap_methods.h"
#include "eap_peer/eap.h"
-
-
-static int newline_terminated(const char *buf, size_t buflen)
-{
- size_t len = os_strlen(buf);
- if (len == 0)
- return 0;
- if (len == buflen - 1 && buf[buflen - 1] != '\r' &&
- buf[len - 1] != '\n')
- return 0;
- return 1;
-}
-
-
-static void skip_line_end(FILE *stream)
-{
- char buf[100];
- while (fgets(buf, sizeof(buf), stream)) {
- buf[sizeof(buf) - 1] = '\0';
- if (newline_terminated(buf, sizeof(buf)))
- return;
- }
-}
-
-
-/**
- * wpa_config_get_line - Read the next configuration file line
- * @s: Buffer for the line
- * @size: The buffer length
- * @stream: File stream to read from
- * @line: Pointer to a variable storing the file line number
- * @_pos: Buffer for the pointer to the beginning of data on the text line or
- * %NULL if not needed (returned value used instead)
- * Returns: Pointer to the beginning of data on the text line or %NULL if no
- * more text lines are available.
- *
- * This function reads the next non-empty line from the configuration file and
- * removes comments. The returned string is guaranteed to be null-terminated.
- */
-static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
- char **_pos)
-{
- char *pos, *end, *sstart;
-
- while (fgets(s, size, stream)) {
- (*line)++;
- s[size - 1] = '\0';
- if (!newline_terminated(s, size)) {
- /*
- * The line was truncated - skip rest of it to avoid
- * confusing error messages.
- */
- wpa_printf(MSG_INFO, "Long line in configuration file "
- "truncated");
- skip_line_end(stream);
- }
- pos = s;
-
- /* Skip white space from the beginning of line. */
- while (*pos == ' ' || *pos == '\t' || *pos == '\r')
- pos++;
-
- /* Skip comment lines and empty lines */
- if (*pos == '#' || *pos == '\n' || *pos == '\0')
- continue;
-
- /*
- * Remove # comments unless they are within a double quoted
- * string.
- */
- sstart = os_strchr(pos, '"');
- if (sstart)
- sstart = os_strrchr(sstart + 1, '"');
- if (!sstart)
- sstart = pos;
- end = os_strchr(sstart, '#');
- if (end)
- *end-- = '\0';
- else
- end = pos + os_strlen(pos) - 1;
-
- /* Remove trailing white space. */
- while (end > pos &&
- (*end == '\n' || *end == ' ' || *end == '\t' ||
- *end == '\r'))
- *end-- = '\0';
-
- if (*pos == '\0')
- continue;
-
- if (_pos)
- *_pos = pos;
- return pos;
- }
-
- if (_pos)
- *_pos = NULL;
- return NULL;
-}
+#include "utils/config.h"
static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
@@ -767,8 +669,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT(scan_ssid);
write_bssid(f, ssid);
write_bssid_hint(f, ssid);
- write_str(f, "bssid_blacklist", ssid);
- write_str(f, "bssid_whitelist", ssid);
+ write_str(f, "bssid_ignore", ssid);
+ write_str(f, "bssid_accept", ssid);
write_psk(f, ssid);
INT(mem_only_psk);
STR(sae_password);
@@ -876,9 +778,10 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
INT(disabled);
INT(mixed_cell);
- INT(vht);
+ INT_DEF(vht, 1);
INT_DEF(ht, 1);
INT(ht40);
+ INT_DEF(he, 1);
INT_DEF(max_oper_chwidth, DEFAULT_MAX_OPER_CHWIDTH);
INT(vht_center_freq1);
INT(vht_center_freq2);
@@ -928,6 +831,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(dpp_netaccesskey);
INT(dpp_netaccesskey_expiry);
STR(dpp_csign);
+ STR(dpp_pp_key);
INT(dpp_pfs);
#endif /* CONFIG_DPP */
INT(owe_group);
@@ -937,6 +841,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
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);
@@ -1332,6 +1237,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->p2p_go_freq_change_policy != DEFAULT_P2P_GO_FREQ_MOVE)
fprintf(f, "p2p_go_freq_change_policy=%u\n",
config->p2p_go_freq_change_policy);
+
+ if (config->p2p_6ghz_disable)
+ fprintf(f, "p2p_6ghz_disable=%d\n", config->p2p_6ghz_disable);
+
if (WPA_GET_BE32(config->ip_addr_go))
fprintf(f, "ip_addr_go=%u.%u.%u.%u\n",
config->ip_addr_go[0], config->ip_addr_go[1],
@@ -1468,9 +1377,23 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
}
fprintf(f, "\n");
}
+ if (config->initial_freq_list && config->initial_freq_list[0]) {
+ int i;
+ fprintf(f, "initial_freq_list=");
+ for (i = 0; config->initial_freq_list[i]; i++) {
+ fprintf(f, "%s%d", i > 0 ? " " : "",
+ config->initial_freq_list[i]);
+ }
+ fprintf(f, "\n");
+ }
if (config->scan_cur_freq != DEFAULT_SCAN_CUR_FREQ)
fprintf(f, "scan_cur_freq=%d\n", config->scan_cur_freq);
+ if (config->scan_res_valid_for_connect !=
+ DEFAULT_SCAN_RES_VALID_FOR_CONNECT)
+ fprintf(f, "scan_res_valid_for_connect=%d\n",
+ config->scan_res_valid_for_connect);
+
if (config->sched_scan_interval)
fprintf(f, "sched_scan_interval=%u\n",
config->sched_scan_interval);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 6737223f..d1ff5f83 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -61,6 +61,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
*
@@ -146,16 +152,16 @@ struct wpa_ssid {
u8 bssid[ETH_ALEN];
/**
- * bssid_blacklist - List of inacceptable BSSIDs
+ * bssid_ignore - List of inacceptable BSSIDs
*/
- u8 *bssid_blacklist;
- size_t num_bssid_blacklist;
+ u8 *bssid_ignore;
+ size_t num_bssid_ignore;
/**
- * bssid_blacklist - List of acceptable BSSIDs
+ * bssid_accept - List of acceptable BSSIDs
*/
- u8 *bssid_whitelist;
- size_t num_bssid_whitelist;
+ u8 *bssid_accept;
+ size_t num_bssid_accept;
/**
* bssid_set - Whether BSSID is configured for this network
@@ -1017,6 +1023,16 @@ struct wpa_ssid {
size_t dpp_csign_len;
/**
+ * dpp_pp_key - ppKey (Configurator privacy protection public key)
+ */
+ u8 *dpp_pp_key;
+
+ /**
+ * dpp_pp_key_len - ppKey length in octets
+ */
+ size_t dpp_pp_key_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)
@@ -1120,6 +1136,25 @@ struct wpa_ssid {
* 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;
+
+ /**
+ * was_recently_reconfigured - Whether this SSID config has been changed
+ * recently
+ *
+ * This is an internally used variable, i.e., not used in external
+ * configuration.
+ */
+ bool was_recently_reconfigured;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index f2d4d01f..dffcd1be 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -22,6 +22,7 @@
#ifdef CONFIG_DPP
#include "common/dpp.h"
#endif /* CONFIG_DPP */
+#include "common/ptksa_cache.h"
#include "crypto/tls.h"
#include "ap/hostapd.h"
#include "eap_peer/eap.h"
@@ -48,7 +49,7 @@
#include "scan.h"
#include "ctrl_iface.h"
#include "interworking.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
#include "autoscan.h"
#include "wnm_sta.h"
#include "offchannel.h"
@@ -299,20 +300,30 @@ static int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd)
}
-static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band)
+static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *bands)
{
union wpa_event_data event;
+ u32 setband_mask = WPA_SETBAND_AUTO;
- if (os_strcmp(band, "AUTO") == 0)
- wpa_s->setband = WPA_SETBAND_AUTO;
- else if (os_strcmp(band, "5G") == 0)
- wpa_s->setband = WPA_SETBAND_5G;
- else if (os_strcmp(band, "2G") == 0)
- wpa_s->setband = WPA_SETBAND_2G;
- else
- return -1;
+ /*
+ * For example:
+ * SET setband 2G,6G
+ * SET setband 5G
+ * SET setband AUTO
+ */
+ if (!os_strstr(bands, "AUTO")) {
+ if (os_strstr(bands, "5G"))
+ setband_mask |= WPA_SETBAND_5G;
+ if (os_strstr(bands, "6G"))
+ setband_mask |= WPA_SETBAND_6G;
+ if (os_strstr(bands, "2G"))
+ setband_mask |= WPA_SETBAND_2G;
+ if (setband_mask == WPA_SETBAND_AUTO)
+ return -1;
+ }
- if (wpa_drv_setband(wpa_s, wpa_s->setband) == 0) {
+ wpa_s->setband_mask = setband_mask;
+ if (wpa_drv_setband(wpa_s, wpa_s->setband_mask) == 0) {
os_memset(&event, 0, sizeof(event));
event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
@@ -751,6 +762,26 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
}
} 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)
@@ -785,6 +816,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
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);
+ } else if (os_strcasecmp(cmd, "force_hunting_and_pecking_pwe") == 0) {
+ wpa_s->force_hunting_and_pecking_pwe = (atoi(value) != 0) ? 1 : 0;
#ifdef CONFIG_DPP
} else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
os_free(wpa_s->dpp_config_obj_override);
@@ -878,6 +911,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
if (ret == 0)
wpa_supplicant_update_config(wpa_s);
+ else if (ret == 1)
+ ret = 0;
}
return ret;
@@ -2277,8 +2312,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;
@@ -2517,20 +2556,20 @@ static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
}
-static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
- char *cmd, char *buf,
- size_t buflen)
+static int wpa_supplicant_ctrl_iface_bssid_ignore(struct wpa_supplicant *wpa_s,
+ char *cmd, char *buf,
+ size_t buflen)
{
u8 bssid[ETH_ALEN];
- struct wpa_blacklist *e;
+ struct wpa_bssid_ignore *e;
char *pos, *end;
int ret;
- /* cmd: "BLACKLIST [<BSSID>]" */
+ /* cmd: "BSSID_IGNORE [<BSSID>]" */
if (*cmd == '\0') {
pos = buf;
end = buf + buflen;
- e = wpa_s->blacklist;
+ e = wpa_s->bssid_ignore;
while (e) {
ret = os_snprintf(pos, end - pos, MACSTR "\n",
MAC2STR(e->bssid));
@@ -2544,12 +2583,12 @@ static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
cmd++;
if (os_strncmp(cmd, "clear", 5) == 0) {
- wpa_blacklist_clear(wpa_s);
+ wpa_bssid_ignore_clear(wpa_s);
os_memcpy(buf, "OK\n", 3);
return 3;
}
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: BSSID_IGNORE bssid='%s'", cmd);
if (hwaddr_aton(cmd, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
return -1;
@@ -2559,10 +2598,10 @@ static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
* Add the BSSID twice, so its count will be 2, causing it to be
* skipped when processing scan results.
*/
- ret = wpa_blacklist_add(wpa_s, bssid);
+ ret = wpa_bssid_ignore_add(wpa_s, bssid);
if (ret < 0)
return -1;
- ret = wpa_blacklist_add(wpa_s, bssid);
+ ret = wpa_bssid_ignore_add(wpa_s, bssid);
if (ret < 0)
return -1;
os_memcpy(buf, "OK\n", 3);
@@ -2934,7 +2973,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);
@@ -2961,6 +3000,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",
@@ -2989,8 +3043,7 @@ 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)) {
+ if (wpa_bss_get_ie_ext(bss, WLAN_EID_EXT_EDMG_OPERATION)) {
ret = os_snprintf(pos, end - pos, "[EDMG]");
if (os_snprintf_error(end - pos, ret))
return -1;
@@ -3439,38 +3492,12 @@ static int wpa_supplicant_ctrl_iface_remove_network(
struct wpa_supplicant *wpa_s, char *cmd)
{
int id;
- struct wpa_ssid *ssid;
int result;
/* cmd: "<network id>" or "all" */
if (os_strcmp(cmd, "all") == 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
- if (wpa_s->sched_scanning)
- wpa_supplicant_cancel_sched_scan(wpa_s);
-
- eapol_sm_invalidate_cached_session(wpa_s->eapol);
- if (wpa_s->current_ssid) {
-#ifdef CONFIG_SME
- wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
- wpa_sm_set_config(wpa_s->wpa, NULL);
- eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
- if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
- wpa_s->own_disconnect_req = 1;
- wpa_supplicant_deauthenticate(
- wpa_s, WLAN_REASON_DEAUTH_LEAVING);
- }
- ssid = wpa_s->conf->ssid;
- while (ssid) {
- struct wpa_ssid *remove_ssid = ssid;
- id = ssid->id;
- ssid = ssid->next;
- if (wpa_s->last_ssid == remove_ssid)
- wpa_s->last_ssid = NULL;
- wpas_notify_network_removed(wpa_s, remove_ssid);
- wpa_config_remove_network(wpa_s->conf, id);
- }
- return 0;
+ return wpa_supplicant_remove_all_networks(wpa_s);
}
id = atoi(cmd);
@@ -3506,6 +3533,20 @@ static int wpa_supplicant_ctrl_iface_update_network(
if (ret == 1)
return 0; /* No change to the previously configured value */
+#ifdef CONFIG_BGSCAN
+ if (os_strcmp(name, "bgscan") == 0) {
+ /*
+ * Reset the bgscan parameters for the current network and
+ * return. There's no need to flush caches for bgscan parameter
+ * changes.
+ */
+ if (wpa_s->current_ssid == ssid &&
+ wpa_s->wpa_state == WPA_COMPLETED)
+ wpa_supplicant_reset_bgscan(wpa_s);
+ return 0;
+ }
+#endif /* CONFIG_BGSCAN */
+
if (os_strcmp(name, "bssid") != 0 &&
os_strcmp(name, "bssid_hint") != 0 &&
os_strcmp(name, "priority") != 0) {
@@ -4460,6 +4501,15 @@ static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_FILS_SK_PFS */
#endif /* CONFIG_FILS */
+#ifdef CONFIG_PASN
+ ret = os_snprintf(pos, end - pos, "%sPASN",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+#endif /* CONFIG_PASN */
+
return pos - buf;
}
@@ -4771,6 +4821,45 @@ 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 */
+
+#ifdef CONFIG_OCV
+ if (os_strcmp(field, "ocv") == 0) {
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
+ (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OCV))
+ res = os_snprintf(buf, buflen, "supported");
+ else
+ res = os_snprintf(buf, buflen, "not supported");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_OCV */
+
+ if (os_strcmp(field, "beacon_prot") == 0) {
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION) ||
+ (wpa_s->drv_flags2 &
+ WPA_DRIVER_FLAGS2_BEACON_PROTECTION_CLIENT))
+ res = os_snprintf(buf, buflen, "supported");
+ else
+ res = os_snprintf(buf, buflen, "not supported");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -4891,7 +4980,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;
@@ -4980,7 +5069,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
return 0;
pos += ret;
- ie = (const u8 *) (bss + 1);
+ ie = wpa_bss_ie_ptr(bss);
for (i = 0; i < bss->ie_len; i++) {
ret = os_snprintf(pos, end - pos, "%02x", *ie++);
if (os_snprintf_error(end - pos, ret))
@@ -5011,6 +5100,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",
@@ -5132,7 +5236,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
#ifdef CONFIG_WPS
if (mask & WPA_BSS_MASK_WPS_SCAN) {
- ie = (const u8 *) (bss + 1);
+ ie = wpa_bss_ie_ptr(bss);
ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
if (ret >= end - pos)
return 0;
@@ -5143,7 +5247,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
#ifdef CONFIG_P2P
if (mask & WPA_BSS_MASK_P2P_SCAN) {
- ie = (const u8 *) (bss + 1);
+ ie = wpa_bss_ie_ptr(bss);
ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
if (ret >= end - pos)
return 0;
@@ -5155,7 +5259,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
#ifdef CONFIG_WIFI_DISPLAY
if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
struct wpabuf *wfd;
- ie = (const u8 *) (bss + 1);
+
+ ie = wpa_bss_ie_ptr(bss);
wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
WFD_IE_VENDOR_TYPE);
if (wfd) {
@@ -5227,13 +5332,21 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
os_snprintf(title, sizeof(title), "anqp[%u]",
elem->infoid);
pos = anqp_add_hex(pos, end, title, elem->payload);
+ if (elem->protected_response) {
+ ret = os_snprintf(pos, end - pos,
+ "protected-anqp-info[%u]=1\n",
+ elem->infoid);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
}
}
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_MESH
if (mask & WPA_BSS_MASK_MESH_SCAN) {
- ie = (const u8 *) (bss + 1);
+ ie = wpa_bss_ie_ptr(bss);
ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
if (ret >= end - pos)
return 0;
@@ -5280,7 +5393,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
return 0;
pos += ret;
- ie = (const u8 *) (bss + 1);
+ ie = wpa_bss_ie_ptr(bss);
ie += bss->ie_len;
for (i = 0; i < bss->beacon_ie_len; i++) {
ret = os_snprintf(pos, end - pos, "%02x", *ie++);
@@ -7398,7 +7511,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];
@@ -7412,6 +7525,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
@@ -7446,7 +7568,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);
}
@@ -8169,13 +8291,17 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
char *buf, size_t buflen)
{
int ret;
- char *pos;
+ char *pos, *temp = NULL;
u8 *data = NULL;
unsigned int vendor_id, subcmd;
+ enum nested_attr nested_attr_flag = NESTED_ATTR_UNSPECIFIED;
struct wpabuf *reply;
size_t data_len = 0;
- /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
+ /**
+ * cmd: <vendor id> <subcommand id> [<hex formatted data>]
+ * [nested=<0|1>]
+ */
vendor_id = strtoul(cmd, &pos, 16);
if (!isblank((unsigned char) *pos))
return -EINVAL;
@@ -8185,7 +8311,9 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
if (*pos != '\0') {
if (!isblank((unsigned char) *pos++))
return -EINVAL;
- data_len = os_strlen(pos);
+
+ temp = os_strchr(pos, ' ');
+ data_len = temp ? (size_t) (temp - pos) : os_strlen(pos);
}
if (data_len) {
@@ -8202,6 +8330,11 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
}
}
+ pos = os_strstr(cmd, "nested=");
+ if (pos)
+ nested_attr_flag = atoi(pos + 7) ? NESTED_ATTR_USED :
+ NESTED_ATTR_NOT_USED;
+
reply = wpabuf_alloc((buflen - 1) / 2);
if (!reply) {
os_free(data);
@@ -8209,7 +8342,7 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
}
ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len,
- reply);
+ nested_attr_flag, reply);
if (ret == 0)
ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
@@ -8325,15 +8458,17 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->set_sta_uapsd = 0;
wpa_s->sta_uapsd = 0;
+ wpa_s->consecutive_conn_failures = 0;
+
wpa_drv_radio_disable(wpa_s, 0);
- wpa_blacklist_clear(wpa_s);
- wpa_s->extra_blacklist_count = 0;
+ wpa_bssid_ignore_clear(wpa_s);
wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
wpa_config_flush_blobs(wpa_s->conf);
wpa_s->conf->auto_interworking = 0;
wpa_s->conf->okc = 0;
+ ptksa_cache_flush(wpa_s->ptksa, NULL, WPA_CIPHER_NONE);
wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
rsn_preauth_deinit(wpa_s->wpa);
@@ -8381,6 +8516,13 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
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;
@@ -8399,6 +8541,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
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)) {
@@ -8424,6 +8567,15 @@ 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));
+
+#ifdef CONFIG_PASN
+ wpas_pasn_auth_stop(wpa_s);
+#endif /* CONFIG_PASN */
+
+ if (wpa_s->mac_addr_changed && wpa_s->conf->mac_addr == 0)
+ wpas_restore_permanent_mac_addr(wpa_s);
}
@@ -9264,7 +9416,7 @@ static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
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");
+ "test data: RX - ignore unexpected IP header");
return;
}
@@ -9677,8 +9829,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
if (wpa_s->vendor_elem[frame] == NULL) {
wpa_s->vendor_elem[frame] = buf;
- wpas_vendor_elem_update(wpa_s);
- return 0;
+ goto update_ies;
}
if (wpabuf_resize(&wpa_s->vendor_elem[frame], len) < 0) {
@@ -9688,8 +9839,14 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
wpabuf_free(buf);
+
+update_ies:
wpas_vendor_elem_update(wpa_s);
+ if (frame == VENDOR_ELEM_PROBE_REQ ||
+ frame == VENDOR_ELEM_PROBE_REQ_P2P)
+ wpa_supplicant_set_default_scan_ies(wpa_s);
+
return 0;
}
@@ -9996,6 +10153,7 @@ static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s,
static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s)
{
+ ptksa_cache_flush(wpa_s->ptksa, NULL, WPA_CIPHER_NONE);
wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
#ifdef CONFIG_AP
wpas_ap_pmksa_cache_flush(wpa_s);
@@ -10200,7 +10358,7 @@ static int wpas_ctrl_iface_mesh_pmksa_add(struct wpa_supplicant *wpa_s,
char *cmd)
{
/*
- * We do not check mesh interface existance because PMKSA should be
+ * We do not check mesh interface existence because PMKSA should be
* stored before wpa_s->ifmsh creation to suppress commit message
* creation.
*/
@@ -10258,6 +10416,143 @@ 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);
+}
+
+
+#ifdef CONFIG_PASN
+static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *token, *context = NULL;
+ u8 bssid[ETH_ALEN];
+ int akmp = -1, cipher = -1, got_bssid = 0;
+ u16 group = 0xFFFF;
+ int id = 0;
+
+ /*
+ * Entry format: bssid=<BSSID> akmp=<AKMP> cipher=<CIPHER> group=<group>
+ */
+ while ((token = str_token(cmd, " ", &context))) {
+ if (os_strncmp(token, "bssid=", 6) == 0) {
+ if (hwaddr_aton(token + 6, bssid))
+ return -1;
+ got_bssid = 1;
+ } else if (os_strcmp(token, "akmp=PASN") == 0) {
+ akmp = WPA_KEY_MGMT_PASN;
+#ifdef CONFIG_IEEE80211R
+ } else if (os_strcmp(token, "akmp=FT-PSK") == 0) {
+ akmp = WPA_KEY_MGMT_FT_PSK;
+ } else if (os_strcmp(token, "akmp=FT-EAP-SHA384") == 0) {
+ akmp = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+ } else if (os_strcmp(token, "akmp=FT-EAP") == 0) {
+ akmp = WPA_KEY_MGMT_FT_IEEE8021X;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ } else if (os_strcmp(token, "akmp=SAE") == 0) {
+ akmp = WPA_KEY_MGMT_SAE;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ } else if (os_strcmp(token, "akmp=FILS-SHA256") == 0) {
+ akmp = WPA_KEY_MGMT_FILS_SHA256;
+ } else if (os_strcmp(token, "akmp=FILS-SHA384") == 0) {
+ akmp = WPA_KEY_MGMT_FILS_SHA384;
+#endif /* CONFIG_FILS */
+ } else if (os_strcmp(token, "cipher=CCMP-256") == 0) {
+ cipher = WPA_CIPHER_CCMP_256;
+ } else if (os_strcmp(token, "cipher=GCMP-256") == 0) {
+ cipher = WPA_CIPHER_GCMP_256;
+ } else if (os_strcmp(token, "cipher=CCMP") == 0) {
+ cipher = WPA_CIPHER_CCMP;
+ } else if (os_strcmp(token, "cipher=GCMP") == 0) {
+ cipher = WPA_CIPHER_GCMP;
+ } else if (os_strncmp(token, "group=", 6) == 0) {
+ group = atoi(token + 6);
+ } else if (os_strncmp(token, "nid=", 4) == 0) {
+ id = atoi(token + 4);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: PASN Invalid parameter: '%s'",
+ token);
+ return -1;
+ }
+ }
+
+ if (!got_bssid || akmp == -1 || cipher == -1 || group == 0xFFFF) {
+ wpa_printf(MSG_DEBUG,"CTRL: PASN missing parameter");
+ return -1;
+ }
+
+ return wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id);
+}
+#endif /* CONFIG_PASN */
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
@@ -10716,8 +11011,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "BSSID ", 6) == 0) {
if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
reply_len = -1;
+ } else if (os_strncmp(buf, "BSSID_IGNORE", 12) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_bssid_ignore(
+ wpa_s, buf + 12, reply, reply_size);
} else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
- reply_len = wpa_supplicant_ctrl_iface_blacklist(
+ /* deprecated backwards compatibility alias for BSSID_IGNORE */
+ reply_len = wpa_supplicant_ctrl_iface_bssid_ignore(
wpa_s, buf + 9, reply, reply_size);
} else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
reply_len = wpa_supplicant_ctrl_iface_log_level(
@@ -11142,13 +11441,25 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
wpas_dpp_chirp_stop(wpa_s);
} else if (os_strncmp(buf, "DPP_RECONFIG ", 13) == 0) {
- struct wpa_ssid *ssid;
-
- ssid = wpa_config_get_network(wpa_s->conf, atoi(buf + 13));
- if (!ssid || wpas_dpp_reconfig(wpa_s, ssid) < 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;
+#ifdef CONFIG_PASN
+ } else if (os_strncmp(buf, "PASN_START ", 11) == 0) {
+ if (wpas_ctrl_iface_pasn_start(wpa_s, buf + 11) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "PASN_STOP") == 0) {
+ wpas_pasn_auth_stop(wpa_s);
+ } else if (os_strcmp(buf, "PTKSA_CACHE_LIST") == 0) {
+ reply_len = ptksa_cache_list(wpa_s->ptksa, reply, reply_size);
+#endif /* CONFIG_PASN */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/wpa_supplicant/dbus/dbus_common.c b/wpa_supplicant/dbus/dbus_common.c
index efa6c7b2..a727217f 100644
--- a/wpa_supplicant/dbus/dbus_common.c
+++ b/wpa_supplicant/dbus/dbus_common.c
@@ -108,17 +108,18 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data)
flags = dbus_watch_get_flags(watch);
fd = dbus_watch_get_unix_fd(watch);
- eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception,
- priv, watch);
-
- if (flags & DBUS_WATCH_READABLE) {
- eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
- priv, watch);
- }
- if (flags & DBUS_WATCH_WRITABLE) {
- eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
- priv, watch);
- }
+ if (eloop_register_sock(fd, EVENT_TYPE_EXCEPTION,
+ process_watch_exception, priv, watch) < 0)
+ return FALSE;
+
+ if ((flags & DBUS_WATCH_READABLE) &&
+ eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
+ priv, watch) < 0)
+ return FALSE;
+ if ((flags & DBUS_WATCH_WRITABLE) &&
+ eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
+ priv, watch) < 0)
+ return FALSE;
dbus_watch_set_data(watch, priv, NULL);
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 793a881e..2c01943f 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1824,7 +1824,7 @@ void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
* @sa: station addr (p2p i/f) of the peer
* @dialog_token: service discovery request dialog token
* @update_indic: service discovery request update indicator
- * @tlvs: service discovery request genrated byte array of tlvs
+ * @tlvs: service discovery request generated byte array of tlvs
* @tlvs_len: service discovery request tlvs length
*/
void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
@@ -1893,7 +1893,7 @@ void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
* @wpa_s: %wpa_supplicant network interface data
* @sa: station addr (p2p i/f) of the peer
* @update_indic: service discovery request update indicator
- * @tlvs: service discovery request genrated byte array of tlvs
+ * @tlvs: service discovery request generated byte array of tlvs
* @tlvs_len: service discovery request tlvs length
*/
void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
@@ -3212,6 +3212,14 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
END_ARGS
}
},
+ { "Roam", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_roam,
+ {
+ { "addr", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+
#ifndef CONFIG_NO_CONFIG_BLOBS
{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) wpas_dbus_handler_add_blob,
@@ -3613,7 +3621,7 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
},
{ "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_bridge_ifname,
- NULL,
+ wpas_dbus_setter_bridge_ifname,
NULL
},
{ "ConfigFile", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index d1f9607c..7d20f212 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -138,7 +138,10 @@ DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message)
static const char * const dont_quote[] = {
"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
"bssid", "scan_freq", "freq_list", "scan_ssid", "bssid_hint",
- "bssid_blacklist", "bssid_whitelist", "group_mgmt",
+ "bssid_ignore", "bssid_accept", /* deprecated aliases */
+ "bssid_blacklist", "bssid_whitelist",
+ "group_mgmt",
+ "ignore_broadcast_ssid",
#ifdef CONFIG_MESH
"mesh_basic_rates",
#endif /* CONFIG_MESH */
@@ -229,8 +232,6 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
} else if (entry.type == DBUS_TYPE_STRING) {
if (should_quote_opt(entry.key)) {
size = os_strlen(entry.str_value);
- if (size == 0)
- goto error;
size += 3;
value = os_zalloc(size);
@@ -267,8 +268,28 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
} else
goto error;
- if (wpa_config_set(ssid, entry.key, value, 0) < 0)
+ ret = wpa_config_set(ssid, entry.key, value, 0);
+ if (ret < 0)
goto error;
+ if (ret == 1)
+ goto skip_update;
+
+#ifdef CONFIG_BGSCAN
+ if (os_strcmp(entry.key, "bgscan") == 0) {
+ /*
+ * Reset the bgscan parameters for the current network
+ * and continue. There's no need to flush caches for
+ * bgscan parameter changes.
+ */
+ if (wpa_s->current_ssid == ssid &&
+ wpa_s->wpa_state == WPA_COMPLETED)
+ wpa_supplicant_reset_bgscan(wpa_s);
+ os_free(value);
+ value = NULL;
+ wpa_dbus_dict_entry_clear(&entry);
+ continue;
+ }
+#endif /* CONFIG_BGSCAN */
if (os_strcmp(entry.key, "bssid") != 0 &&
os_strcmp(entry.key, "priority") != 0)
@@ -290,6 +311,7 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
else if (os_strcmp(entry.key, "priority") == 0)
wpa_config_update_prio_list(wpa_s->conf);
+ skip_update:
os_free(value);
value = NULL;
wpa_dbus_dict_entry_clear(&entry);
@@ -991,7 +1013,7 @@ 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[12];
+ const char *capabilities[13];
size_t num_items = 0;
struct wpa_global *global = user_data;
struct wpa_supplicant *wpa_s;
@@ -1042,6 +1064,9 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(
#ifdef CONFIG_OWE
capabilities[num_items++] = "owe";
#endif /* CONFIG_OWE */
+#ifdef CONFIG_SUITEB192
+ capabilities[num_items++] = "suiteb192";
+#endif /* CONFIG_SUITEB192 */
if (ext_key_id_supported)
capabilities[num_items++] = "extended_key_id";
@@ -1677,7 +1702,8 @@ DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
* Returns: NULL
*
* Handler function for notifying system there will be a expected disconnect.
- * This will prevent wpa_supplicant from adding blacklists upon next disconnect..
+ * This will prevent wpa_supplicant from adding the BSSID to the ignore list
+ * upon next disconnect.
*/
DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message,
struct wpa_global *global)
@@ -1797,25 +1823,6 @@ out:
}
-static void remove_network(void *arg, struct wpa_ssid *ssid)
-{
- struct wpa_supplicant *wpa_s = arg;
-
- wpas_notify_network_removed(wpa_s, ssid);
-
- if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
- wpa_printf(MSG_ERROR,
- "%s[dbus]: error occurred when removing network %d",
- __func__, ssid->id);
- return;
- }
-
- if (ssid == wpa_s->current_ssid)
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
-}
-
-
/**
* wpas_dbus_handler_remove_all_networks - Remove all configured networks
* @message: Pointer to incoming dbus message
@@ -1827,11 +1834,8 @@ static void remove_network(void *arg, struct wpa_ssid *ssid)
DBusMessage * wpas_dbus_handler_remove_all_networks(
DBusMessage *message, struct wpa_supplicant *wpa_s)
{
- if (wpa_s->sched_scanning)
- wpa_supplicant_cancel_sched_scan(wpa_s);
-
/* NB: could check for failure and return an error */
- wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
+ wpa_supplicant_remove_all_networks(wpa_s);
return NULL;
}
@@ -1956,6 +1960,55 @@ out:
}
+/**
+ * wpas_dbus_handler_roam - Initiate a roam to another BSS within the ESS
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "Roam" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_NO_SCAN_PROCESSING
+ return wpas_dbus_error_unknown_error(message,
+ "scan processing not included");
+#else /* CONFIG_NO_SCAN_PROCESSING */
+ u8 bssid[ETH_ALEN];
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ char *addr;
+
+ if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID))
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ if (hwaddr_aton(addr, bssid))
+ return wpas_dbus_error_invalid_args(
+ message, "Invalid hardware address format");
+
+ wpa_printf(MSG_DEBUG, "dbus: Roam " MACSTR, MAC2STR(bssid));
+
+ if (!ssid)
+ return dbus_message_new_error(
+ message, WPAS_DBUS_ERROR_NOT_CONNECTED,
+ "This interface is not connected");
+
+ bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "dbus: Roam: Target BSS not found");
+ return wpas_dbus_error_invalid_args(
+ message, "Target BSS not found");
+ }
+
+ wpa_s->reassociate = 1;
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+
+ return NULL;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+}
+
#ifndef CONFIG_NO_CONFIG_BLOBS
/**
@@ -2521,7 +2574,7 @@ wpas_dbus_handler_tdls_cancel_channel_switch(DBusMessage *message,
* wpas_dbus_handler_save_config - Save configuration to configuration file
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NULL on Success, Otherwise errror message
+ * Returns: NULL on Success, Otherwise error message
*
* Handler function for "SaveConfig" method call of network interface.
*/
@@ -2822,6 +2875,12 @@ dbus_bool_t wpas_dbus_getter_capabilities(
goto nomem;
#endif /* CONFIG_SAE */
+#ifdef CONFIG_OWE
+ if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) &&
+ !wpa_dbus_dict_string_array_add_element(&iter_array, "owe"))
+ goto nomem;
+#endif /* CONFIG_OWE */
+
if (!wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
@@ -3634,6 +3693,43 @@ dbus_bool_t wpas_dbus_getter_bridge_ifname(
}
+dbus_bool_t wpas_dbus_setter_bridge_ifname(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ const char *bridge_ifname = NULL;
+ const char *msg;
+ int r;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &bridge_ifname))
+ return FALSE;
+
+ r = wpa_supplicant_update_bridge_ifname(wpa_s, bridge_ifname);
+ if (r != 0) {
+ switch (r) {
+ case -EINVAL:
+ msg = "invalid interface name";
+ break;
+ case -EBUSY:
+ msg = "interface is busy";
+ break;
+ case -EIO:
+ msg = "socket error";
+ break;
+ default:
+ msg = "unknown error";
+ break;
+ }
+ dbus_set_error_const(error, DBUS_ERROR_FAILED, msg);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
/**
* wpas_dbus_getter_config_file - Get interface configuration file path
* @iter: Pointer to incoming dbus message iter
@@ -3941,14 +4037,15 @@ dbus_bool_t wpas_dbus_setter_iface_global(
return FALSE;
}
- if (wpa_config_process_global(wpa_s->conf, buf, -1)) {
+ ret = wpa_config_process_global(wpa_s->conf, buf, -1);
+ if (ret < 0) {
dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
"Failed to set interface property %s",
property_desc->dbus_property);
return FALSE;
+ } else if (ret == 0) {
+ wpa_supplicant_update_config(wpa_s);
}
-
- wpa_supplicant_update_config(wpa_s);
return TRUE;
}
@@ -4988,8 +5085,8 @@ dbus_bool_t wpas_dbus_getter_bss_ies(
return FALSE;
return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
- res + 1, res->ie_len,
- error);
+ wpa_bss_ie_ptr(res),
+ res->ie_len, error);
}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index afa26efe..c36383f0 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -117,6 +117,9 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -167,6 +170,7 @@ DECLARE_ACCESSOR(wpas_dbus_setter_scan_interval);
DECLARE_ACCESSOR(wpas_dbus_getter_ifname);
DECLARE_ACCESSOR(wpas_dbus_getter_driver);
DECLARE_ACCESSOR(wpas_dbus_getter_bridge_ifname);
+DECLARE_ACCESSOR(wpas_dbus_setter_bridge_ifname);
DECLARE_ACCESSOR(wpas_dbus_getter_config_file);
DECLARE_ACCESSOR(wpas_dbus_getter_current_bss);
DECLARE_ACCESSOR(wpas_dbus_getter_current_network);
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 7e06fdd3..a6cd9330 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -530,6 +530,8 @@ CONFIG_WIFI_DISPLAY=y
#
# External password backend for testing purposes (developer use)
#CONFIG_EXT_PASSWORD_TEST=y
+# File-based backend to read passwords from an external file.
+#CONFIG_EXT_PASSWORD_FILE=y
# Enable Fast Session Transfer (FST)
#CONFIG_FST=y
@@ -626,3 +628,9 @@ CONFIG_DPP=y
# in the future.
#CONFIG_NO_TKIP=y
+# Pre-Association Security Negotiation (PASN)
+# Experimental implementation based on IEEE P802.11z/D2.6 and the protocol
+# design is still subject to change. As such, this should not yet be enabled in
+# production use.
+#CONFIG_PASN=y
+
diff --git a/wpa_supplicant/doc/docbook/.gitignore b/wpa_supplicant/doc/docbook/.gitignore
index 8c3945c5..dac35c5a 100644
--- a/wpa_supplicant/doc/docbook/.gitignore
+++ b/wpa_supplicant/doc/docbook/.gitignore
@@ -1,5 +1,6 @@
manpage.links
manpage.refs
+manpage.log
*.8
*.5
*.html
diff --git a/wpa_supplicant/doc/docbook/eapol_test.sgml b/wpa_supplicant/doc/docbook/eapol_test.sgml
index e7705abf..4cfa3c1d 100644
--- a/wpa_supplicant/doc/docbook/eapol_test.sgml
+++ b/wpa_supplicant/doc/docbook/eapol_test.sgml
@@ -1,6 +1,10 @@
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
<refmeta>
<refentrytitle>eapol_test</refentrytitle>
<manvolnum>8</manvolnum>
diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/wpa_supplicant/doc/docbook/wpa_background.sgml
index f6a0ca8b..22241ccf 100644
--- a/wpa_supplicant/doc/docbook/wpa_background.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_background.sgml
@@ -1,6 +1,10 @@
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
<refmeta>
<refentrytitle>wpa_background</refentrytitle>
<manvolnum>8</manvolnum>
diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/wpa_supplicant/doc/docbook/wpa_cli.sgml
index dc7fee46..2ba1fe42 100644
--- a/wpa_supplicant/doc/docbook/wpa_cli.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_cli.sgml
@@ -1,6 +1,10 @@
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
<refmeta>
<refentrytitle>wpa_cli</refentrytitle>
<manvolnum>8</manvolnum>
diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml
index 31214e3e..cb0c735e 100644
--- a/wpa_supplicant/doc/docbook/wpa_gui.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml
@@ -1,6 +1,10 @@
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
<refmeta>
<refentrytitle>wpa_gui</refentrytitle>
<manvolnum>8</manvolnum>
diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
index ed9baf1e..07729690 100644
--- a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
@@ -1,6 +1,10 @@
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
<refmeta>
<refentrytitle>wpa_passphrase</refentrytitle>
<manvolnum>8</manvolnum>
diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/wpa_supplicant/doc/docbook/wpa_priv.sgml
index dd445651..0d5c94a9 100644
--- a/wpa_supplicant/doc/docbook/wpa_priv.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_priv.sgml
@@ -1,6 +1,10 @@
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
<refmeta>
<refentrytitle>wpa_priv</refentrytitle>
<manvolnum>8</manvolnum>
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
index 462039d9..8a0314e8 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
@@ -1,5 +1,9 @@
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
<refmeta>
<refentrytitle>wpa_supplicant.conf</refentrytitle>
<manvolnum>5</manvolnum>
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index aaff1500..144654aa 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -1,6 +1,10 @@
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
<refmeta>
<refentrytitle>wpa_supplicant</refentrytitle>
<manvolnum>8</manvolnum>
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 8c2e302c..d9352154 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -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"
@@ -32,6 +33,7 @@
static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
unsigned int freq);
static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
+static void wpas_dpp_auth_conf_wait_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator);
static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst,
@@ -49,6 +51,9 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
#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 };
@@ -89,6 +94,10 @@ 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;
}
@@ -466,6 +475,8 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
"DPP: Terminate authentication exchange due to a request to do so on TX status");
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s,
+ NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
NULL);
#ifdef CONFIG_DPP2
@@ -498,6 +509,17 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
}
}
+ if (auth->waiting_auth_conf &&
+ auth->auth_resp_status == DPP_STATUS_OK) {
+ /* Make sure we do not get stuck waiting for Auth Confirm
+ * indefinitely after successfully transmitted Auth Response to
+ * allow new authentication exchanges to be started. */
+ eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s,
+ NULL);
+ eloop_register_timeout(1, 0, wpas_dpp_auth_conf_wait_timeout,
+ wpa_s, NULL);
+ }
+
if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp &&
result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
/* Allow timeout handling to stop iteration if no response is
@@ -587,6 +609,23 @@ static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
}
+static void wpas_dpp_auth_conf_wait_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->waiting_auth_conf)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Terminate authentication exchange due to Auth Confirm timeout");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL "No Auth Confirm received");
+ offchannel_send_action_done(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+}
+
+
static void wpas_dpp_set_testing_options(struct wpa_supplicant *wpa_s,
struct dpp_authentication *auth)
{
@@ -673,7 +712,9 @@ static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s)
freq = auth->freq[auth->freq_idx++];
auth->curr_freq = freq;
- if (is_zero_ether_addr(auth->peer_bi->mac_addr))
+ if (!is_zero_ether_addr(auth->peer_mac_addr))
+ dst = auth->peer_mac_addr;
+ else if (is_zero_ether_addr(auth->peer_bi->mac_addr))
dst = broadcast;
else
dst = auth->peer_bi->mac_addr;
@@ -804,6 +845,8 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
if (!tcp && wpa_s->dpp_auth) {
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s,
+ NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
NULL);
#ifdef CONFIG_DPP2
@@ -832,7 +875,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;
@@ -1185,6 +1230,15 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
ssid->dpp_csign_len = wpabuf_len(conf->c_sign_key);
}
+ if (conf->pp_key) {
+ ssid->dpp_pp_key = os_malloc(wpabuf_len(conf->pp_key));
+ if (!ssid->dpp_pp_key)
+ goto fail;
+ os_memcpy(ssid->dpp_pp_key, wpabuf_head(conf->pp_key),
+ wpabuf_len(conf->pp_key));
+ ssid->dpp_pp_key_len = wpabuf_len(conf->pp_key);
+ }
+
if (auth->net_access_key) {
ssid->dpp_netaccesskey =
os_malloc(wpabuf_len(auth->net_access_key));
@@ -1220,6 +1274,102 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
}
}
+#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;
@@ -1299,6 +1449,8 @@ static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
struct dpp_config_obj *conf)
{
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_AKM "%s",
+ dpp_akm_str(conf->akm));
if (conf->ssid_len)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
wpa_ssid_txt(conf->ssid, conf->ssid_len));
@@ -1314,6 +1466,21 @@ static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
conf->connector);
}
+ if (conf->passphrase[0]) {
+ char hex[64 * 2 + 1];
+
+ wpa_snprintf_hex(hex, sizeof(hex),
+ (const u8 *) conf->passphrase,
+ os_strlen(conf->passphrase));
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_PASS "%s",
+ hex);
+ } else if (conf->psk_set) {
+ char hex[PMK_LEN * 2 + 1];
+
+ wpa_snprintf_hex(hex, sizeof(hex), conf->psk, PMK_LEN);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s",
+ hex);
+ }
if (conf->c_sign_key) {
char *hex;
size_t hexlen;
@@ -1329,6 +1496,20 @@ static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
os_free(hex);
}
}
+ if (conf->pp_key) {
+ char *hex;
+ size_t hexlen;
+
+ hexlen = 2 * wpabuf_len(conf->pp_key) + 1;
+ hex = os_malloc(hexlen);
+ if (hex) {
+ wpa_snprintf_hex(hex, hexlen,
+ wpabuf_head(conf->pp_key),
+ wpabuf_len(conf->pp_key));
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PP_KEY "%s", hex);
+ os_free(hex);
+ }
+ }
if (auth->net_access_key) {
char *hex;
size_t hexlen;
@@ -1351,6 +1532,32 @@ static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
}
}
+#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);
}
@@ -1366,6 +1573,7 @@ static int wpas_dpp_handle_key_pkg(struct wpa_supplicant *wpa_s,
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);
@@ -1381,6 +1589,31 @@ static int wpas_dpp_handle_key_pkg(struct wpa_supplicant *wpa_s,
}
+#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,
@@ -1425,11 +1658,20 @@ 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;
}
+ 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]);
@@ -1475,6 +1717,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:
@@ -1625,6 +1870,8 @@ static void wpas_dpp_rx_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
return;
}
+ eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s, NULL);
+
if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
wpas_notify_dpp_auth_failure(wpa_s);
@@ -1684,9 +1931,22 @@ static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
MAC2STR(src));
if (!auth || !auth->waiting_conf_result) {
- wpa_printf(MSG_DEBUG,
- "DPP: No DPP Configuration waiting for result - drop");
- return;
+ if (auth &&
+ os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) == 0 &&
+ gas_server_response_sent(wpa_s->gas_server,
+ auth->gas_server_ctx)) {
+ /* This could happen if the TX status event gets delayed
+ * long enough for the Enrollee to have time to send
+ * the next frame before the TX status gets processed
+ * locally. */
+ wpa_printf(MSG_DEBUG,
+ "DPP: GAS response was sent but TX status not yet received - assume it was ACKed since the Enrollee sent the next frame in the sequence");
+ auth->waiting_conf_result = 1;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for result - drop");
+ return;
+ }
}
if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
@@ -1828,6 +2088,8 @@ wpas_dpp_rx_presence_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
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);
+ dpp_notify_chirp_received(wpa_s, peer_bi ? (int) peer_bi->id : -1, src,
+ freq, r_bootstrap);
if (!peer_bi) {
wpa_printf(MSG_DEBUG,
"DPP: No matching bootstrapping information found");
@@ -1846,8 +2108,9 @@ wpas_dpp_rx_presence_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
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);
+ /* The source address of the Presence Announcement frame overrides any
+ * MAC address information from the bootstrapping information. */
+ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
wpa_s->dpp_auth = auth;
if (wpas_dpp_auth_init_next(wpa_s) < 0) {
@@ -1879,11 +2142,12 @@ 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;
- u16 csign_hash_len;
+ 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;
@@ -1913,7 +2177,21 @@ wpas_dpp_rx_reconfig_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
return;
}
- auth = dpp_reconfig_init(wpa_s->dpp, wpa_s, conf, freq);
+ 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);
@@ -1963,17 +2241,29 @@ wpas_dpp_rx_reconfig_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Request from "
MACSTR, MAC2STR(src));
- if (!wpa_s->dpp || wpa_s->dpp_auth ||
- !wpa_s->dpp_reconfig_announcement || !wpa_s->dpp_reconfig_ssid)
+ 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)
+ !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,
@@ -2667,8 +2957,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;
@@ -2699,11 +2989,22 @@ 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);
wpas_notify_dpp_configuration_failure(wpa_s);
}
auth->conf_resp = resp;
+ auth->gas_server_ctx = resp_ctx;
return resp;
}
@@ -2726,13 +3027,23 @@ 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);
+ eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
#ifdef CONFIG_DPP2
if (ok && auth->peer_version >= 2 &&
- auth->conf_resp_status == DPP_STATUS_OK) {
+ auth->conf_resp_status == DPP_STATUS_OK &&
+ !auth->waiting_conf_result) {
wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
wpas_notify_dpp_config_sent_wait_response(wpa_s);
auth->waiting_conf_result = 1;
@@ -3087,10 +3398,8 @@ 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);
@@ -3111,9 +3420,9 @@ 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_auth_conf_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
#ifdef CONFIG_DPP2
@@ -3123,9 +3432,12 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
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);
@@ -3134,6 +3446,7 @@ 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);
}
@@ -3146,6 +3459,10 @@ int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
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) {
@@ -3166,6 +3483,8 @@ int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
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);
@@ -3208,13 +3527,26 @@ static void wpas_dpp_chirp_tx_status(struct wpa_supplicant *wpa_s,
static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
{
- struct wpabuf *msg;
+ struct wpabuf *msg, *announce = NULL;
int type;
msg = wpa_s->dpp_presence_announcement;
type = DPP_PA_PRESENCE_ANNOUNCEMENT;
if (!msg) {
- msg = wpa_s->dpp_reconfig_announcement;
+ 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;
@@ -3228,6 +3560,8 @@ static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
wpabuf_head(msg), wpabuf_len(msg),
2000, wpas_dpp_chirp_tx_status, 0) < 0)
wpas_dpp_chirp_stop(wpa_s);
+
+ wpabuf_free(announce);
}
@@ -3239,8 +3573,9 @@ static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode;
int c;
struct wpa_bss *bss;
+ bool chan6;
- if (!bi && !wpa_s->dpp_reconfig_announcement)
+ if (!bi && !wpa_s->dpp_reconfig_ssid)
return;
wpa_s->dpp_chirp_scan_done = 1;
@@ -3256,10 +3591,25 @@ static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
}
/* 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_IEEE80211G, false);
+ chan6 = mode == NULL;
+ if (mode) {
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
+ chan->freq != 2437)
+ continue;
+ chan6 = true;
+ break;
+ }
+ }
+ if (chan6)
+ 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);
+ HOSTAPD_MODE_IEEE80211A, false);
if (mode) {
int chan44 = 0, chan149 = 0;
@@ -3281,7 +3631,7 @@ static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
}
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
- HOSTAPD_MODE_IEEE80211AD, 0);
+ HOSTAPD_MODE_IEEE80211AD, false);
if (mode) {
for (c = 0; c < mode->num_channels; c++) {
struct hostapd_channel_data *chan = &mode->channels[c];
@@ -3320,6 +3670,17 @@ static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx)
if (wpa_s->dpp_chirp_freq == 0) {
if (wpa_s->dpp_chirp_round % 4 == 0 &&
!wpa_s->dpp_chirp_scan_done) {
+ if (wpas_scan_scheduled(wpa_s)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Deferring chirp scan because another scan is planned already");
+ if (eloop_register_timeout(1, 0,
+ wpas_dpp_chirp_next,
+ wpa_s, NULL) < 0) {
+ wpas_dpp_chirp_stop(wpa_s);
+ return;
+ }
+ return;
+ }
wpa_printf(MSG_DEBUG,
"DPP: Update channel list for chirping");
wpa_s->scan_req = MANUAL_SCAN_REQ;
@@ -3428,15 +3789,13 @@ int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd)
void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
{
if (wpa_s->dpp_presence_announcement ||
- wpa_s->dpp_reconfig_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;
- wpabuf_free(wpa_s->dpp_reconfig_announcement);
- wpa_s->dpp_reconfig_announcement = NULL;
if (wpa_s->dpp_chirp_listen)
wpas_dpp_listen_stop(wpa_s);
wpa_s->dpp_chirp_listen = 0;
@@ -3452,23 +3811,55 @@ void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
}
-int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd)
{
- if (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
- !ssid->dpp_csign)
+ 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,
+ ssid->dpp_pp_key,
+ ssid->dpp_pp_key_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_announcement =
- dpp_build_reconfig_announcement(ssid->dpp_csign,
- ssid->dpp_csign_len);
- if (!wpa_s->dpp_reconfig_announcement)
- return -1;
wpa_s->dpp_reconfig_ssid = ssid;
wpa_s->dpp_reconfig_ssid_id = ssid->id;
- wpa_s->dpp_chirp_iter = 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 = 0;
@@ -3476,4 +3867,111 @@ int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
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 2dc86e09..b0d5fcf1 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -39,6 +39,7 @@ 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, struct wpa_ssid *ssid);
+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 54ae03b5..237f4e08 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -719,12 +719,14 @@ static inline int wpa_drv_wowlan(struct wpa_supplicant *wpa_s,
static inline int wpa_drv_vendor_cmd(struct wpa_supplicant *wpa_s,
int vendor_id, int subcmd, const u8 *data,
- size_t data_len, struct wpabuf *buf)
+ size_t data_len,
+ enum nested_attr nested_attr_flag,
+ struct wpabuf *buf)
{
if (!wpa_s->driver->vendor_cmd)
return -1;
return wpa_s->driver->vendor_cmd(wpa_s->drv_priv, vendor_id, subcmd,
- data, data_len, buf);
+ data, data_len, nested_attr_flag, buf);
}
static inline int wpa_drv_roaming(struct wpa_supplicant *wpa_s, int allowed,
@@ -952,11 +954,11 @@ static inline int wpa_drv_disable_transmit_sa(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_MACSEC */
static inline int wpa_drv_setband(struct wpa_supplicant *wpa_s,
- enum set_band band)
+ u32 band_mask)
{
if (!wpa_s->driver->set_band)
return -1;
- return wpa_s->driver->set_band(wpa_s->drv_priv, band);
+ return wpa_s->driver->set_band(wpa_s->drv_priv, band_mask);
}
static inline int wpa_drv_get_pref_freq_list(struct wpa_supplicant *wpa_s,
@@ -1069,14 +1071,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(
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 096fd02c..01bbde6d 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -30,8 +30,9 @@
#include "common/ieee802_11_common.h"
#include "common/gas_server.h"
#include "common/dpp.h"
+#include "common/ptksa_cache.h"
#include "crypto/random.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
#include "wpas_glue.h"
#include "wps_supplicant.h"
#include "ibss_rsn.h"
@@ -49,6 +50,7 @@
#include "mesh_mpm.h"
#include "wmm_ac.h"
#include "dpp_supplicant.h"
+#include "rsn_supp/wpa_i.h"
#define MAX_OWE_TRANSITION_BSS_SELECT_COUNT 5
@@ -356,6 +358,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;
@@ -1058,7 +1063,7 @@ static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
}
-static int disabled_freq(struct wpa_supplicant *wpa_s, int freq)
+int disabled_freq(struct wpa_supplicant *wpa_s, int freq)
{
int i, j;
@@ -1080,32 +1085,407 @@ static int disabled_freq(struct wpa_supplicant *wpa_s, int freq)
}
+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, int bssid_ignore_count,
+ 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) {
+ int count;
+ 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;
+
+ count = wpa_bssid_ignore_is_listed(wpa_s, bss->bssid);
+ if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
+ bss, count, 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, int bssid_ignore_count,
+ 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) && bssid_ignore_count) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID ignored (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 the list of BSSIDs to ignore */
+ if (ssid->num_bssid_ignore &&
+ addr_in_list(bss->bssid, ssid->bssid_ignore,
+ ssid->num_bssid_ignore)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID configured to be ignored");
+ return false;
+ }
+
+ /* if there is a list of accepted BSSIDs, only accept those APs */
+ if (ssid->num_bssid_accept &&
+ !addr_in_list(bss->bssid, ssid->bssid_accept,
+ ssid->num_bssid_accept)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID not in list of accepted values");
+ 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;
+ int bssid_ignore_count;
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;
@@ -1125,13 +1505,13 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
osen ? " osen=1" : "");
}
- e = wpa_blacklist_get(wpa_s, bss->bssid);
- if (e) {
+ bssid_ignore_count = wpa_bssid_ignore_is_listed(wpa_s, bss->bssid);
+ if (bssid_ignore_count) {
int limit = 1;
if (wpa_supplicant_enabled_networks(wpa_s) == 1) {
/*
* When only a single network is enabled, we can
- * trigger blacklisting on the first failure. This
+ * trigger BSSID ignoring on the first failure. This
* should not be done with multiple enabled networks to
* avoid getting forced to move into a worse ESS on
* single error if there are no other BSSes of the
@@ -1139,11 +1519,11 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
*/
limit = 0;
}
- if (e->count > limit) {
+ if (bssid_ignore_count > limit) {
if (debug_print) {
wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - blacklisted (count=%d limit=%d)",
- e->count, limit);
+ " skip - BSSID ignored (count=%d limit=%d)",
+ bssid_ignore_count, limit);
}
return NULL;
}
@@ -1177,299 +1557,10 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
return NULL;
}
- wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
-
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;
- }
-
-#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");
- continue;
- }
-#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");
- 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, ssid, bss, debug_print)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - rate sets do not match");
- continue;
- }
-
-#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) &&
- (!(ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX)) ||
- ie[1] < 1 ||
- !(ie[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)))) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - SAE H2E required, but not supported by the AP");
- continue;
- }
-#endif /* CONFIG_SAE */
-
-#ifndef CONFIG_IBSS_RSN
- if (ssid->mode == WPAS_MODE_IBSS &&
- !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
- 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, bssid_ignore_count, debug_print))
+ return ssid;
}
/* No matching configuration found */
@@ -1570,12 +1661,12 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
break;
}
- if (selected == NULL && wpa_s->blacklist &&
+ if (selected == NULL && wpa_s->bssid_ignore &&
!wpa_s->countermeasures) {
- wpa_dbg(wpa_s, MSG_DEBUG, "No APs found - clear "
- "blacklist and try again");
- wpa_blacklist_clear(wpa_s);
- wpa_s->blacklist_cleared++;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "No APs found - clear BSSID ignore list and try again");
+ wpa_bssid_ignore_clear(wpa_s);
+ wpa_s->bssid_ignore_cleared = true;
} else if (selected == NULL)
break;
}
@@ -1763,58 +1854,25 @@ 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);
+ const u8 *ies = wpa_bss_ie_ptr(bss);
size_t ie_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr);
}
-#endif /* CONFIG_NO_ROAMING */
-
-static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
- struct wpa_bss *selected,
- struct wpa_ssid *ssid)
+int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *current_bss,
+ struct wpa_bss *selected)
{
- struct wpa_bss *current_bss = NULL;
-#ifndef CONFIG_NO_ROAMING
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;
-#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 */
-
- 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 */
+ 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",
@@ -1933,13 +1991,64 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
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 */
@@ -1984,9 +2093,18 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
return -1;
if (data && data->scan_info.external_scan)
return -1;
- wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try "
- "scanning again");
- wpa_supplicant_req_new_scan(wpa_s, 1, 0);
+ if (wpa_s->scan_res_fail_handler) {
+ void (*handler)(struct wpa_supplicant *wpa_s);
+
+ handler = wpa_s->scan_res_fail_handler;
+ wpa_s->scan_res_fail_handler = NULL;
+ handler(wpa_s);
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Failed to get scan results - try scanning again");
+ wpa_supplicant_req_new_scan(wpa_s, 1, 0);
+ }
+
ret = -1;
goto scan_work_done;
}
@@ -2264,6 +2382,7 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
wpa_msg_ctrl(wpa_s, MSG_INFO,
WPA_EVENT_NETWORK_NOT_FOUND);
+ wpas_notify_network_not_found(wpa_s);
}
}
return 0;
@@ -2332,7 +2451,7 @@ int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
os_get_reltime(&now);
if (os_reltime_expired(&now, &wpa_s->last_scan,
- SCAN_RES_VALID_FOR_CONNECT)) {
+ wpa_s->conf->scan_res_valid_for_connect)) {
wpa_printf(MSG_DEBUG, "Fast associate: Old scan results");
return -1;
}
@@ -2571,11 +2690,11 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
{
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);
@@ -2621,6 +2740,8 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
data->assoc_info.resp_ies_len,
&resp_elems, 0) != ParseFailed) {
wpa_s->connection_set = 1;
+ wpa_s->connection_11b_only = supp_rates_11b_only(&req_elems) ||
+ supp_rates_11b_only(&resp_elems);
wpa_s->connection_ht = req_elems.ht_capabilities &&
resp_elems.ht_capabilities;
/* Do not include subset of VHT on 2.4 GHz vendor
@@ -2716,7 +2837,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)) {
@@ -2751,7 +2872,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,
@@ -2807,11 +2928,20 @@ no_pfs:
p += len;
}
#endif /* CONFIG_SME */
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ if (((wpa_s->key_mgmt == WPA_KEY_MGMT_FT_PSK) ||
+ (wpa_s->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) ||
+ (wpa_s->key_mgmt == WPA_KEY_MGMT_FT_SAE) ||
+ (wpa_s->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X_SHA384)) &&
+ wpa_ft_is_completed(wpa_s->wpa)) {
+ return 0;
+ }
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
/* 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,
@@ -2829,6 +2959,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;
@@ -2941,7 +3076,7 @@ static void wpas_fst_update_mb_assoc(struct wpa_supplicant *wpa_s,
if (!bss)
return;
- ieprb = (const u8 *) (bss + 1);
+ ieprb = wpa_bss_ie_ptr(bss);
iebcn = ieprb + bss->ie_len;
if (!wpas_fst_update_mbie(wpa_s, ieprb, bss->ie_len))
@@ -2961,6 +3096,9 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
#if defined(CONFIG_FILS) || defined(CONFIG_MBO)
struct wpa_bss *bss;
#endif /* CONFIG_FILS || CONFIG_MBO */
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ struct wpa_ie_data ie;
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
@@ -2978,6 +3116,27 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
wpa_s->own_reconnect_req = 0;
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ if (!(wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0)) {
+ struct wpa_ft_ies parse;
+ /* Check for FT reassociation is done by the driver */
+#ifdef CONFIG_IEEE80211R
+ int use_sha384 = wpa_key_mgmt_sha384(wpa_s->wpa->key_mgmt);
+ if (wpa_key_mgmt_ft(wpa_s->key_mgmt) && (wpa_s->key_mgmt == ie.key_mgmt)) {
+ if (wpa_ft_parse_ies(data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len, &parse, use_sha384) < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to parse FT IEs");
+ return;
+ }
+ if (parse.rsn_pmkid != NULL) {
+ wpa_set_ft_completed(wpa_s->wpa);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Assume FT reassoc completed by the driver");
+ }
+ }
+#endif /* CONFIG_IEEE80211R */
+ }
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+
ft_completed = wpa_ft_is_completed(wpa_s->wpa);
if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
return;
@@ -2996,6 +3155,15 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
return;
}
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ /* For driver based roaming, insert PSK during the initial association */
+ if (is_zero_ether_addr(wpa_s->bssid) &&
+ wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+ /* In case the driver wants to handle re-assocs, pass it down the PMK. */
+ wpa_dbg(wpa_s, MSG_DEBUG, "Pass the PMK to the driver");
+ wpa_sm_install_pmk(wpa_s->wpa);
+ }
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
if (os_reltime_initialized(&wpa_s->session_start)) {
@@ -3128,7 +3296,20 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
*/
eapol_sm_notify_portValid(wpa_s->eapol, true);
}
-
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ if (ft_completed && wpa_key_mgmt_ft(wpa_s->key_mgmt)) {
+ if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+ wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID, key_mgmt: 0x%0x",
+ wpa_s->key_mgmt);
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ return;
+ }
+ os_memcpy(wpa_s->bssid, bssid, ETH_ALEN);
+ wpa_s->assoc_freq = data->assoc_info.freq;
+ wpa_sm_notify_brcm_ft_reassoc(wpa_s->wpa, bssid);
+ }
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
wpa_s->last_eapol_matches_bssid = 0;
#ifdef CONFIG_TESTING_OPTIONS
@@ -3385,6 +3566,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
wpas_connection_failed(wpa_s, bssid);
wpa_sm_notify_disassoc(wpa_s->wpa);
+ ptksa_cache_flush(wpa_s->ptksa, wpa_s->bssid, WPA_CIPHER_NONE);
+
if (locally_generated)
wpa_s->disconnect_reason = -reason_code;
else
@@ -3478,7 +3661,7 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
/* initialize countermeasures */
wpa_s->countermeasures = 1;
- wpa_blacklist_add(wpa_s, wpa_s->bssid);
+ wpa_bssid_ignore_add(wpa_s, wpa_s->bssid);
wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
@@ -4162,6 +4345,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)
@@ -4330,6 +4520,31 @@ static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s,
}
+static const char * connect_fail_reason(enum sta_connect_fail_reason_codes code)
+{
+ switch (code) {
+ case STA_CONNECT_FAIL_REASON_UNSPECIFIED:
+ return "";
+ case STA_CONNECT_FAIL_REASON_NO_BSS_FOUND:
+ return "no_bss_found";
+ case STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL:
+ return "auth_tx_fail";
+ case STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED:
+ return "auth_no_ack_received";
+ case STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED:
+ return "auth_no_resp_received";
+ case STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL:
+ return "assoc_req_tx_fail";
+ case STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED:
+ return "assoc_no_ack_received";
+ case STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED:
+ return "assoc_no_resp_received";
+ default:
+ return "unknown_reason";
+ }
+}
+
+
static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
@@ -4349,24 +4564,32 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
if (data->assoc_reject.bssid)
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
- "bssid=" MACSTR " status_code=%u%s%s%s",
+ "bssid=" MACSTR " status_code=%u%s%s%s%s%s",
MAC2STR(data->assoc_reject.bssid),
data->assoc_reject.status_code,
data->assoc_reject.timed_out ? " timeout" : "",
data->assoc_reject.timeout_reason ? "=" : "",
data->assoc_reject.timeout_reason ?
- data->assoc_reject.timeout_reason : "");
+ data->assoc_reject.timeout_reason : "",
+ data->assoc_reject.reason_code !=
+ STA_CONNECT_FAIL_REASON_UNSPECIFIED ?
+ " qca_driver_reason=" : "",
+ connect_fail_reason(data->assoc_reject.reason_code));
else
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
- "status_code=%u%s%s%s",
+ "status_code=%u%s%s%s%s%s",
data->assoc_reject.status_code,
data->assoc_reject.timed_out ? " timeout" : "",
data->assoc_reject.timeout_reason ? "=" : "",
data->assoc_reject.timeout_reason ?
- data->assoc_reject.timeout_reason : "");
+ data->assoc_reject.timeout_reason : "",
+ data->assoc_reject.reason_code !=
+ STA_CONNECT_FAIL_REASON_UNSPECIFIED ?
+ " qca_driver_reason=" : "",
+ connect_fail_reason(data->assoc_reject.reason_code));
wpa_s->assoc_status_code = data->assoc_reject.status_code;
- wpas_notify_assoc_status_code(wpa_s,
- bssid, data->assoc_reject.timed_out);
+ wpas_notify_assoc_status_code(wpa_s, bssid, data->assoc_reject.timed_out,
+ data->assoc_reject.resp_ies, data->assoc_reject.resp_ies_len);
#ifdef CONFIG_OWE
if (data->assoc_reject.status_code ==
@@ -4400,7 +4623,9 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
* 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->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 ||
@@ -4651,7 +4876,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
} else {
wpa_dbg(wpa_s, MSG_DEBUG, "External program started a scan");
- wpa_s->radio->external_scan_running = 1;
+ wpa_s->radio->external_scan_req_interface = wpa_s;
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED);
}
break;
@@ -4659,7 +4884,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_s->scan_res_handler = NULL;
wpa_s->own_scan_running = 0;
- wpa_s->radio->external_scan_running = 0;
+ wpa_s->radio->external_scan_req_interface = NULL;
wpa_s->last_scan_req = NORMAL_SCAN_REQ;
break;
}
@@ -4679,7 +4904,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
if (!(data && data->scan_info.external_scan))
wpa_s->own_scan_running = 0;
if (data && data->scan_info.nl_scan_event)
- wpa_s->radio->external_scan_running = 0;
+ wpa_s->radio->external_scan_req_interface = NULL;
radio_work_check_next(wpa_s);
break;
#endif /* CONFIG_NO_SCAN_PROCESSING */
@@ -4742,6 +4967,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
" type=%d stype=%d",
MAC2STR(data->tx_status.dst),
data->tx_status.type, data->tx_status.stype);
+#ifdef CONFIG_PASN
+ if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
+ data->tx_status.stype == WLAN_FC_STYPE_AUTH &&
+ wpas_pasn_auth_tx_status(wpa_s, data->tx_status.data,
+ data->tx_status.data_len,
+ data->tx_status.ack) == 0)
+ break;
+#endif /* CONFIG_PASN */
#ifdef CONFIG_AP
if (wpa_s->ap_iface == NULL) {
#ifdef CONFIG_OFFCHANNEL
@@ -4837,6 +5070,12 @@ 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;
+ if (wpa_s->current_bss &&
+ wpa_s->current_bss->freq != data->ch_switch.freq) {
+ wpa_s->current_bss->freq = data->ch_switch.freq;
+ notify_bss_changes(wpa_s, WPA_BSS_FREQ_CHANGED_FLAG,
+ wpa_s->current_bss);
+ }
#ifdef CONFIG_SME
switch (data->ch_switch.ch_offset) {
@@ -4868,7 +5107,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;
@@ -4968,6 +5209,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
mesh_mpm_mgmt_rx(wpa_s, &data->rx_mgmt);
break;
}
+#ifdef CONFIG_PASN
+ if (stype == WLAN_FC_STYPE_AUTH &&
+ wpas_pasn_auth_rx(wpa_s, mgmt,
+ data->rx_mgmt.frame_len) != -2)
+ break;
+#endif /* CONFIG_PASN */
#ifdef CONFIG_SAE
if (stype == WLAN_FC_STYPE_AUTH &&
@@ -5150,13 +5397,13 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
wpa_supplicant_mark_disassoc(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;
+ if (age.sec >= wpa_s->conf->scan_res_valid_for_connect) {
+ clear_at.sec = wpa_s->conf->scan_res_valid_for_connect;
clear_at.usec = 0;
} else {
struct os_reltime tmp;
- tmp.sec = SCAN_RES_VALID_FOR_CONNECT;
+ tmp.sec = wpa_s->conf->scan_res_valid_for_connect;
tmp.usec = 0;
os_reltime_sub(&tmp, &age, &clear_at);
}
@@ -5379,8 +5626,6 @@ void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
return;
wpa_s = wpa_supplicant_add_iface(ctx, wpa_i, NULL);
os_free(wpa_i);
- if (wpa_s)
- wpa_s->matched = 1;
}
#endif /* CONFIG_MATCH_IFACE */
diff --git a/wpa_supplicant/examples/dpp-nfc.py b/wpa_supplicant/examples/dpp-nfc.py
index 18835455..8e865f3f 100755
--- a/wpa_supplicant/examples/dpp-nfc.py
+++ b/wpa_supplicant/examples/dpp-nfc.py
@@ -7,6 +7,8 @@
# 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
@@ -29,20 +31,28 @@ init_on_touch = False
in_raw_mode = False
prev_tcgetattr = 0
no_input = False
-srv = None
continue_loop = True
terminate_now = False
summary_file = None
success_file = None
-my_crn_ready = False
-my_crn = None
-peer_crn = None
-hs_sent = False
+netrole = None
+operation_success = False
mutex = threading.Lock()
-def summary(txt):
+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:
- print(txt)
+ if color:
+ print(color + txt + C_NORMAL)
+ else:
+ print(txt)
if summary_file:
with open(summary_file, 'a') as f:
f.write(txt + "\n")
@@ -67,15 +77,18 @@ def wpas_connect():
return None
for ctrl in ifaces:
- if ifname:
- if ifname not in ctrl:
- continue
+ 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):
@@ -84,7 +97,7 @@ def dpp_nfc_uri_process(uri):
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")
+ 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))
@@ -99,7 +112,7 @@ def dpp_nfc_uri_process(uri):
summary("Initiate DPP authentication: " + cmd)
res = wpas.request(cmd)
if "OK" not in res:
- summary("Failed to initiate DPP Authentication")
+ summary("Failed to initiate DPP Authentication", color=C_RED)
return False
summary("DPP Authentication initiated")
return True
@@ -110,20 +123,20 @@ def dpp_hs_tag_read(record):
return False
summary(record)
if len(record.data) < 5:
- summary("Too short DPP HS")
+ summary("Too short DPP HS", color=C_RED)
return False
if record.data[0] != 0:
- summary("Unexpected URI Identifier Code")
+ summary("Unexpected URI Identifier Code", color=C_RED)
return False
uribuf = record.data[1:]
try:
uri = uribuf.decode()
except:
- summary("Invalid URI payload")
+ summary("Invalid URI payload", color=C_RED)
return False
summary("URI: " + uri)
if not uri.startswith("DPP:"):
- summary("Not a DPP URI")
+ summary("Not a DPP URI", color=C_RED)
return False
return dpp_nfc_uri_process(uri)
@@ -179,12 +192,43 @@ def dpp_bootstrap_gen(wpas, type="qrcode", chan=None, mac=None, info=None,
raise Exception("Failed to generate bootstrapping info")
return int(res)
-def wpas_get_nfc_uri(start_listen=True, pick_channel=False):
+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
- chan = 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:
@@ -192,15 +236,18 @@ def wpas_get_nfc_uri(start_listen=True, pick_channel=False):
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:
- wpas.request("DPP_LISTEN 2412 netrole=configurator")
+ 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):
@@ -219,82 +266,180 @@ def wpas_report_handover_sel(uri):
cmd = "DPP_NFC_HANDOVER_SEL own=%d uri=%s" % (own_id, uri)
return wpas.request(cmd)
-def dpp_handover_client(llc):
- uri = wpas_get_nfc_uri(start_listen=False)
+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")
+ 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)
- crn = os.urandom(2)
+ 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))
- global peer_crn
- if peer_crn is not None:
+ if handover.peer_crn is not None and not alt:
summary("NFC handover request from peer was already received - do not send own")
return
- client = nfc.handover.HandoverClient(llc)
- try:
- summary("Trying to initiate NFC connection handover")
- client.connect()
- summary("Connected for handover")
- except nfc.llcp.ConnectRefused:
- summary("Handover connection refused")
- client.close()
- return
- except Exception as e:
- summary("Other exception: " + str(e))
- client.close()
- return
+ 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 peer_crn is not None:
+ if handover.peer_crn is not None and not alt:
summary("NFC handover request from peer was already received - do not send own")
- client.close()
return
summary("Sending handover request")
- global my_crn, my_crn_ready, hs_sent
- my_crn_ready = True
+ handover.my_crn_ready = True
if not client.send_records(message):
- my_crn_ready = False
- summary("Failed to send handover request")
- client.close()
+ handover.my_crn_ready = False
+ summary("Failed to send handover request", color=C_RED)
+ run_client_alt(handover, alt)
return
- my_crn, = struct.unpack('>H', crn)
+ 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 hs_sent:
+ 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))
+ summary("Client receive failed: %s" % str(e), color=C_RED)
message = None
if message is None:
- if hs_sent:
+ 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")
- client.close()
+ 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)
- client.close()
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:
@@ -303,15 +448,19 @@ def dpp_handover_client(llc):
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")
+ 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")
+ summary("DPP handover report rejected", color=C_RED)
break
success_report("DPP handover reported successfully (initiator)")
@@ -331,7 +480,7 @@ def dpp_handover_client(llc):
# TODO: Single Configurator instance
res = wpas.request("DPP_CONFIGURATOR_ADD")
if "FAIL" in res:
- summary("Failed to initiate Configurator")
+ summary("Failed to initiate Configurator", color=C_RED)
break
conf_id = int(res)
extra = " conf=sta-dpp configurator=%d" % conf_id
@@ -341,17 +490,23 @@ def dpp_handover_client(llc):
cmd += extra
res = wpas.request(cmd)
if "FAIL" in res:
- summary("Failed to initiate DPP authentication")
+ summary("Failed to initiate DPP authentication", color=C_RED)
break
- if not dpp_found:
+ 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")
- client.close()
+ 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")
- client.close()
+ handover.close()
summary("Done with handover")
global only_one
if only_one:
@@ -360,22 +515,67 @@ def dpp_handover_client(llc):
continue_loop = False
global no_wait
- if no_wait:
- print("Trying to exit..")
+ 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, llc):
+ def __init__(self, handover, llc):
super(HandoverServer, self).__init__(llc)
self.sent_carrier = None
self.ho_server_processing = False
self.success = False
- self.try_own = 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
@@ -384,33 +584,33 @@ class HandoverServer(nfc.handover.HandoverServer):
print("\n")
summary("HandoverServer - request received: " + str(records))
- global my_crn, peer_crn, my_crn_ready
-
for carrier in records:
if not isinstance(carrier, ndef.HandoverRequestRecord):
continue
if carrier.collision_resolution_number:
- peer_crn = carrier.collision_resolution_number
- summary("peer_crn: %d" % peer_crn)
+ handover.peer_crn = carrier.collision_resolution_number
+ summary("peer_crn: %d" % handover.peer_crn)
- if my_crn is None and my_crn_ready:
+ 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 my_crn is not None:
+ if handover.my_crn is not None:
break
time.sleep(0.01)
- if my_crn is not None:
- summary("my_crn: %d" % my_crn)
+ if handover.my_crn is not None:
+ summary("my_crn: %d" % handover.my_crn)
- if my_crn is not None and peer_crn is not None:
- if my_crn == peer_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 ((my_crn & 1) == (peer_crn & 1) and my_crn > peer_crn) or \
- ((my_crn & 1) != (peer_crn & 1) and my_crn < peer_crn):
+ 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")
- pass
+ handover.i_m_selector = True
else:
summary("Peer is the Handover Selector device")
summary("Ignore the received request.")
@@ -428,61 +628,73 @@ class HandoverServer(nfc.handover.HandoverServer):
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")
+ summary("URI Identifier Code 'None' not seen", color=C_RED)
continue
uri = carrier.data[1:].decode("utf-8")
summary("Received DPP URI: " + uri)
- data = wpas_get_nfc_uri(start_listen=False, pick_channel=True)
+ 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)
- res = wpas_report_handover_req(uri)
+ 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")
+ 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
- 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
+ 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))
- 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 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"
- summary(cmd)
- res = wpas.request(cmd)
- if "OK" not in res:
- summary("Failed to start DPP listen")
- break
+ 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))
@@ -492,11 +704,26 @@ class HandoverServer(nfc.handover.HandoverServer):
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:
- self.try_own = True
- global hs_sent
- hs_sent = True
+ 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():
@@ -553,17 +780,25 @@ def dpp_tag_read(tag):
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")
+ 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
- tag.ndef.records = dpp_tag_data
+ 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("Done - remove tag")
- global only_one
+ 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
@@ -574,7 +809,7 @@ 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")
+ summary("Could not get NFC URI from wpa_supplicant", color=C_RED)
return
global dpp_sel_wait_remove
@@ -583,7 +818,7 @@ def write_nfc_uri(clf, wait_remove=True):
uri = ndef.UriRecord(data)
summary(uri)
- summary("Touch an NFC tag")
+ 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})
@@ -592,7 +827,7 @@ 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")
+ summary("Could not get NFC URI from wpa_supplicant", color=C_RED)
return
global dpp_sel_wait_remove
@@ -606,7 +841,7 @@ def write_nfc_hs(clf, wait_remove=True):
summary(hs)
summary(carrier)
- summary("Touch an NFC tag")
+ 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)
@@ -624,17 +859,24 @@ def rdwr_connected(tag):
global continue_loop
continue_loop = False
else:
- summary("Not an NDEF tag - remove tag")
+ summary("Not an NDEF tag - remove tag", color=C_RED)
return True
return not no_wait
-def llcp_worker(llc):
+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")
- dpp_handover_client(llc)
- summary("Exiting llcp_worker thread (init_in_touch)")
+ summary("Starting handover client (init_on_touch)")
+ dpp_handover_client(handover)
+ summary("Exiting llcp_worker thread (init_on_touch)")
return
global no_input
@@ -642,16 +884,18 @@ def llcp_worker(llc):
summary("Wait for handover to complete")
else:
print("Wait for handover to complete - press 'i' to initiate")
- global srv
- global wait_connection
- while not wait_connection and srv.sent_carrier is None:
- if srv.try_own:
- srv.try_own = False
+ 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")
- dpp_handover_client(llc)
+ 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 srv.ho_server_processing:
+ if handover.srv.ho_server_processing:
time.sleep(0.025)
elif no_input:
time.sleep(0.5)
@@ -661,7 +905,7 @@ def llcp_worker(llc):
continue
clear_raw_mode()
summary("Starting handover client")
- dpp_handover_client(llc)
+ dpp_handover_client(handover)
summary("Exiting llcp_worker thread (manual init)")
return
@@ -672,28 +916,73 @@ def llcp_worker(llc):
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):
- summary("Start LLCP server")
- global srv
- srv = HandoverServer(llc)
+ global handover
+ handover.start_handover_server(llc)
return llc
def llcp_connected(llc):
summary("P2P LLCP connected")
- global wait_connection, my_crn, peer_crn, my_crn_ready, hs_sent
- wait_connection = False
- my_crn_ready = False
- my_crn = None
- peer_crn = None
- hs_sent = False
- global srv
- srv.start()
+ global handover
+ handover.connected = True
+ handover.srv.start()
if init_on_touch or not no_input:
- threading.Thread(target=llcp_worker, args=(llc,)).start()
+ 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():
@@ -737,22 +1026,53 @@ def main():
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
+ 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
@@ -788,19 +1108,22 @@ def main():
no_input = True
clf = nfc.ContactlessFrontend()
- global wait_connection
try:
if not clf.open(args.device):
- summary("Could not open connection with an NFC device")
- raise SystemExit
+ 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
@@ -810,8 +1133,14 @@ def main():
clear_raw_mode()
if was_in_raw_mode:
print("\r")
- summary("Waiting for a tag or peer to be touched")
- wait_connection = True
+ 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}):
@@ -833,9 +1162,18 @@ def main():
summary("clf.connect failed: " + str(e))
break
- global srv
- if only_one and srv and srv.success:
- raise SystemExit
+ 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
diff --git a/wpa_supplicant/examples/p2p-action-udhcp.sh b/wpa_supplicant/examples/p2p-action-udhcp.sh
index d7d0e79b..53d8b777 100755
--- a/wpa_supplicant/examples/p2p-action-udhcp.sh
+++ b/wpa_supplicant/examples/p2p-action-udhcp.sh
@@ -50,7 +50,7 @@ fi
if [ "$CMD" = "P2P-CROSS-CONNECT-ENABLE" ]; then
GIFNAME=$3
UPLINK=$4
- # enable NAT/masquarade $GIFNAME -> $UPLINK
+ # enable NAT/masquerade $GIFNAME -> $UPLINK
iptables -P FORWARD DROP
iptables -t nat -A POSTROUTING -o $UPLINK -j MASQUERADE
iptables -A FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
@@ -61,7 +61,7 @@ fi
if [ "$CMD" = "P2P-CROSS-CONNECT-DISABLE" ]; then
GIFNAME=$3
UPLINK=$4
- # disable NAT/masquarade $GIFNAME -> $UPLINK
+ # disable NAT/masquerade $GIFNAME -> $UPLINK
sysctl net.ipv4.ip_forward=0
iptables -t nat -D POSTROUTING -o $UPLINK -j MASQUERADE
iptables -D FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
diff --git a/wpa_supplicant/examples/p2p-action.sh b/wpa_supplicant/examples/p2p-action.sh
index 797d43a0..6c27b27b 100755
--- a/wpa_supplicant/examples/p2p-action.sh
+++ b/wpa_supplicant/examples/p2p-action.sh
@@ -77,7 +77,7 @@ fi
if [ "$CMD" = "P2P-CROSS-CONNECT-ENABLE" ]; then
GIFNAME=$3
UPLINK=$4
- # enable NAT/masquarade $GIFNAME -> $UPLINK
+ # enable NAT/masquerade $GIFNAME -> $UPLINK
iptables -P FORWARD DROP
iptables -t nat -A POSTROUTING -o $UPLINK -j MASQUERADE
iptables -A FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
@@ -88,7 +88,7 @@ fi
if [ "$CMD" = "P2P-CROSS-CONNECT-DISABLE" ]; then
GIFNAME=$3
UPLINK=$4
- # disable NAT/masquarade $GIFNAME -> $UPLINK
+ # disable NAT/masquerade $GIFNAME -> $UPLINK
sysctl net.ipv4.ip_forward=0
iptables -t nat -D POSTROUTING -o $UPLINK -j MASQUERADE
iptables -D FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
diff --git a/wpa_supplicant/examples/p2p/p2p_connect.py b/wpa_supplicant/examples/p2p/p2p_connect.py
index 2f62e9c9..bfb55334 100644
--- a/wpa_supplicant/examples/p2p/p2p_connect.py
+++ b/wpa_supplicant/examples/p2p/p2p_connect.py
@@ -71,7 +71,7 @@ class P2P_Connect():
global wpas_dbus_interfaces_interface
global wpas_dbus_interfaces_p2pdevice
- # Dictionary of Arguements
+ # Dictionary of Arguments
global p2p_connect_arguements
# Constructor
@@ -146,9 +146,9 @@ class P2P_Connect():
signal_name="WpsFailed")
- #Constructing all the arguements needed to connect
+ #Constructing all the arguments needed to connect
def constructArguements(self):
- # Adding required arguements
+ # Adding required arguments
self.p2p_connect_arguements = {'wps_method':self.wps_method,
'peer':dbus.ObjectPath(self.path+'/Peers/'+self.addr)}
@@ -198,7 +198,7 @@ class P2P_Connect():
usage()
quit()
- # Go_intent is optional for all arguements
+ # Go_intent is optional for all arguments
if (self.go_intent != None):
self.p2p_connect_arguements.update(
{'go_intent':dbus.Int32(self.go_intent)})
@@ -239,7 +239,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
@@ -266,9 +266,9 @@ if __name__ == "__main__":
else:
assert False, "unhandled option"
- # Required Arguements check
+ # Required Arguments check
if (interface_name == None or wps_method == None or addr == None):
- print("Error:\n Required arguements not specified")
+ print("Error:\n Required arguments not specified")
usage()
quit()
@@ -289,7 +289,7 @@ if __name__ == "__main__":
addr,pin,wps_method,go_intent)
except:
- print("Error:\n Invalid Arguements")
+ print("Error:\n Invalid Arguments")
usage()
quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_disconnect.py b/wpa_supplicant/examples/p2p/p2p_disconnect.py
index 85b5a8b3..f04b98e6 100644
--- a/wpa_supplicant/examples/p2p/p2p_disconnect.py
+++ b/wpa_supplicant/examples/p2p/p2p_disconnect.py
@@ -125,7 +125,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
diff --git a/wpa_supplicant/examples/p2p/p2p_find.py b/wpa_supplicant/examples/p2p/p2p_find.py
index e2df5289..412d8120 100644
--- a/wpa_supplicant/examples/p2p/p2p_find.py
+++ b/wpa_supplicant/examples/p2p/p2p_find.py
@@ -136,7 +136,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
diff --git a/wpa_supplicant/examples/p2p/p2p_flush.py b/wpa_supplicant/examples/p2p/p2p_flush.py
index 42fc7a3e..5cc3a0e1 100644
--- a/wpa_supplicant/examples/p2p/p2p_flush.py
+++ b/wpa_supplicant/examples/p2p/p2p_flush.py
@@ -125,7 +125,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
diff --git a/wpa_supplicant/examples/p2p/p2p_group_add.py b/wpa_supplicant/examples/p2p/p2p_group_add.py
index 6d408218..db6d60d8 100644
--- a/wpa_supplicant/examples/p2p/p2p_group_add.py
+++ b/wpa_supplicant/examples/p2p/p2p_group_add.py
@@ -18,7 +18,7 @@ def usage():
print(" [-w <wpas_dbus_interface>]")
print("Options:")
print(" -i = interface name")
- print(" -p = persistant group = 0 (0=false, 1=true)")
+ print(" -p = persistent group = 0 (0=false, 1=true)")
print(" -f = frequency")
print(" -o = persistent group object path")
print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
@@ -57,7 +57,7 @@ class P2P_Group_Add (threading.Thread):
global wpas_dbus_interfaces_interface
global wpas_dbus_interfaces_p2pdevice
- # Arguements
+ # Arguments
global P2PDictionary
# Constructor
@@ -120,7 +120,7 @@ class P2P_Group_Add (threading.Thread):
signal_name="WpsFailed")
# Sets up p2p_group_add dictionary
- def constructArguements(self):
+ def constructArguments(self):
self.P2PDictionary = {'persistent':self.persistent}
if (self.frequency != None):
@@ -141,7 +141,7 @@ class P2P_Group_Add (threading.Thread):
self.p2p_interface.GroupAdd(self.P2PDictionary)
except:
- print("Error:\n Could not preform group add")
+ print("Error:\n Could not perform group add")
usage()
os._exit(0)
@@ -172,7 +172,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
@@ -213,9 +213,9 @@ if __name__ == "__main__":
p2p_group_add_test = P2P_Group_Add(interface_name,wpas_dbus_interface,
persistent,frequency,persistent_group_object)
except:
- print("Error:\n Invalid Arguements")
+ print("Error:\n Invalid Arguments")
- p2p_group_add_test.constructArguements()
+ p2p_group_add_test.constructArguments()
p2p_group_add_test.start()
time.sleep(5)
print("Error:\n Group formation timed out")
diff --git a/wpa_supplicant/examples/p2p/p2p_invite.py b/wpa_supplicant/examples/p2p/p2p_invite.py
index 341dcd0a..8944e11e 100644
--- a/wpa_supplicant/examples/p2p/p2p_invite.py
+++ b/wpa_supplicant/examples/p2p/p2p_invite.py
@@ -25,7 +25,7 @@ def usage():
# Required Signals
def InvitationResult(invite_result):
- print("Inviation Result signal :")
+ print("Invitation Result signal :")
status = invite_result['status']
print("status = ", status)
if invite_result.has_key('BSSID'):
@@ -55,7 +55,7 @@ class P2P_Invite (threading.Thread):
global wpas_dbus_interfaces_interface
global wpas_dbus_interfaces_p2pdevice
- # Arguements
+ # Arguments
global P2PDictionary
# Constructor
@@ -127,7 +127,7 @@ class P2P_Invite (threading.Thread):
self.p2p_interface.Invite(self.P2PDictionary)
except:
- print("Error:\n Invalid Arguements")
+ print("Error:\n Invalid Arguments")
usage()
os._exit(0)
@@ -154,7 +154,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
@@ -190,7 +190,7 @@ if __name__ == "__main__":
P2P_Invite(interface_name,wpas_dbus_interface,
addr,persistent_group_object)
except:
- print("Error:\n Invalid Arguements")
+ print("Error:\n Invalid Arguments")
usage()
os._exit(1)
diff --git a/wpa_supplicant/examples/p2p/p2p_listen.py b/wpa_supplicant/examples/p2p/p2p_listen.py
index b0837d9d..cbeda9ff 100644
--- a/wpa_supplicant/examples/p2p/p2p_listen.py
+++ b/wpa_supplicant/examples/p2p/p2p_listen.py
@@ -126,7 +126,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
diff --git a/wpa_supplicant/examples/p2p/p2p_stop_find.py b/wpa_supplicant/examples/p2p/p2p_stop_find.py
index bdb4c0e3..f3671964 100644
--- a/wpa_supplicant/examples/p2p/p2p_stop_find.py
+++ b/wpa_supplicant/examples/p2p/p2p_stop_find.py
@@ -130,7 +130,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
diff --git a/wpa_supplicant/examples/udhcpd-p2p.conf b/wpa_supplicant/examples/udhcpd-p2p.conf
index df590940..f92cc619 100644
--- a/wpa_supplicant/examples/udhcpd-p2p.conf
+++ b/wpa_supplicant/examples/udhcpd-p2p.conf
@@ -11,8 +11,8 @@ end 192.168.42.254 #default: 192.168.0.254
interface wlan2 #default: eth0
-# The maximim number of leases (includes addressesd reserved
-# by OFFER's, DECLINE's, and ARP conficts
+# The maximum number of leases (includes addresses reserved
+# by OFFER's, DECLINE's, and ARP conflicts)
#max_leases 254 #default: 254
@@ -52,12 +52,12 @@ interface wlan2 #default: eth0
# If a lease to be given is below this value, the full lease time is
# instead used (seconds).
-#min_lease 60 #defult: 60
+#min_lease 60 #default: 60
# The location of the leases file
-#lease_file /var/lib/misc/udhcpd.leases #defualt: /var/lib/misc/udhcpd.leases
+#lease_file /var/lib/misc/udhcpd.leases #default: /var/lib/misc/udhcpd.leases
# The location of the pid file
pidfile /var/run/udhcpd-wlan2.pid #default: /var/run/udhcpd.pid
@@ -77,7 +77,7 @@ pidfile /var/run/udhcpd-wlan2.pid #default: /var/run/udhcpd.pid
#boot_file /var/nfs_root #default: (none)
-# The remainer of options are DHCP options and can be specifed with the
+# The remainder of options are DHCP options and can be specified with the
# keyword 'opt' or 'option'. If an option can take multiple items, such
# as the dns option, they can be listed on the same line, or multiple
# lines. The only option with a default is 'lease'.
@@ -116,5 +116,3 @@ option lease 864000 # 10 days of seconds
# Static leases map
#static_lease 00:60:08:11:CE:4E 192.168.0.54
#static_lease 00:60:08:11:CE:3E 192.168.0.44
-
-
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 4b3fcfcf..e60a8c1f 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -694,13 +694,15 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
return;
}
- if (!query->maintain_addr &&
- 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;
diff --git a/wpa_supplicant/hidl/1.3/android.hardware.wifi.supplicant-service.rc b/wpa_supplicant/hidl/1.4/android.hardware.wifi.supplicant-service.rc
index 3cf2500a..71318d46 100644
--- a/wpa_supplicant/hidl/1.3/android.hardware.wifi.supplicant-service.rc
+++ b/wpa_supplicant/hidl/1.4/android.hardware.wifi.supplicant-service.rc
@@ -9,6 +9,7 @@ service wpa_supplicant /vendor/bin/hw/wpa_supplicant \
interface android.hardware.wifi.supplicant@1.1::ISupplicant default
interface android.hardware.wifi.supplicant@1.2::ISupplicant default
interface android.hardware.wifi.supplicant@1.3::ISupplicant default
+ interface android.hardware.wifi.supplicant@1.4::ISupplicant default
class main
socket wpa_wlan0 dgram 660 wifi wifi
disabled
diff --git a/wpa_supplicant/hidl/1.3/manifest.xml b/wpa_supplicant/hidl/1.4/android.hardware.wifi.supplicant.xml
index 33e4fd4d..772096c1 100644
--- a/wpa_supplicant/hidl/1.3/manifest.xml
+++ b/wpa_supplicant/hidl/1.4/android.hardware.wifi.supplicant.xml
@@ -2,7 +2,7 @@
<hal format="hidl">
<name>android.hardware.wifi.supplicant</name>
<transport>hwbinder</transport>
- <version>1.3</version>
+ <version>1.4</version>
<interface>
<name>ISupplicant</name>
<instance>default</instance>
diff --git a/wpa_supplicant/hidl/1.3/hidl.cpp b/wpa_supplicant/hidl/1.4/hidl.cpp
index 310e56c6..649772ae 100644
--- a/wpa_supplicant/hidl/1.3/hidl.cpp
+++ b/wpa_supplicant/hidl/1.4/hidl.cpp
@@ -28,7 +28,7 @@ using android::hardware::setupTransportPolling;
using android::hardware::wifi::supplicant::V1_3::DppFailureCode;
using android::hardware::wifi::supplicant::V1_3::DppProgressCode;
using android::hardware::wifi::supplicant::V1_3::DppSuccessCode;
-using android::hardware::wifi::supplicant::V1_3::implementation::HidlManager;
+using android::hardware::wifi::supplicant::V1_4::implementation::HidlManager;
static void wpas_hidl_notify_dpp_failure(struct wpa_supplicant *wpa_s, DppFailureCode code);
static void wpas_hidl_notify_dpp_progress(struct wpa_supplicant *wpa_s, DppProgressCode code);
@@ -66,7 +66,9 @@ struct wpas_hidl_priv *wpas_hidl_init(struct wpa_global *global)
hidl_manager = HidlManager::getInstance();
if (!hidl_manager)
goto err;
- hidl_manager->registerHidlService(global);
+ if (hidl_manager->registerHidlService(global)) {
+ goto err;
+ }
// We may not need to store this hidl manager reference in the
// global data strucure because we've made it a singleton class.
priv->hidl_manager = (void *)hidl_manager;
@@ -250,13 +252,13 @@ void wpas_hidl_notify_hs20_rx_subscription_remediation(
void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
{
- if (!wpa_s || !wpa_s->global->hidl || !url)
+ if (!wpa_s || !wpa_s->global->hidl)
return;
wpa_printf(
MSG_DEBUG,
"Notifying HS20 deauth imminent notice rx to hidl control: %s",
- url);
+ url ? url : "<no URL>");
HidlManager *hidl_manager = HidlManager::getInstance();
if (!hidl_manager)
@@ -266,6 +268,23 @@ void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
wpa_s, code, reauth_delay, url);
}
+void wpas_hidl_notify_hs20_rx_terms_and_conditions_acceptance(
+ struct wpa_supplicant *wpa_s, const char *url)
+{
+ if (!wpa_s || !wpa_s->global->hidl || !url)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "Notifying HS20 terms and conditions acceptance rx to hidl control: %s",
+ url);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyHs20RxTermsAndConditionsAcceptance(wpa_s, url);
+}
+
void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
{
if (!wpa_s)
@@ -283,7 +302,7 @@ void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
}
void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s,
- const u8 *bssid, u8 timed_out)
+ const u8 *bssid, u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len)
{
if (!wpa_s)
return;
@@ -296,7 +315,7 @@ void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s,
if (!hidl_manager)
return;
- hidl_manager->notifyAssocReject(wpa_s, bssid, timed_out);
+ hidl_manager->notifyAssocReject(wpa_s, bssid, timed_out, assoc_resp_ie, assoc_resp_ie_len);
}
void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s)
@@ -378,7 +397,8 @@ void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s)
void wpas_hidl_notify_p2p_device_found(
struct wpa_supplicant *wpa_s, const u8 *addr,
const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
- u8 peer_wfd_device_info_len)
+ u8 peer_wfd_device_info_len, const u8 *peer_wfd_r2_device_info,
+ u8 peer_wfd_r2_device_info_len)
{
if (!wpa_s || !addr || !info)
return;
@@ -392,7 +412,9 @@ void wpas_hidl_notify_p2p_device_found(
return;
hidl_manager->notifyP2pDeviceFound(
- wpa_s, addr, info, peer_wfd_device_info, peer_wfd_device_info_len);
+ wpa_s, addr, info, peer_wfd_device_info,
+ peer_wfd_device_info_len, peer_wfd_r2_device_info,
+ peer_wfd_r2_device_info_len);
}
void wpas_hidl_notify_p2p_device_lost(
@@ -876,3 +898,31 @@ void wpas_hidl_notify_bss_tm_status(struct wpa_supplicant *wpa_s)
hidl_manager->notifyBssTmStatus(wpa_s);
}
+
+void wpas_hidl_notify_transition_disable(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ u8 bitmap)
+{
+ if (!wpa_s || !ssid)
+ return;
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyTransitionDisable(wpa_s, ssid, bitmap);
+}
+
+void wpas_hidl_notify_network_not_found(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notify network not found");
+
+ hidl_manager->notifyNetworkNotFound(wpa_s);
+}
diff --git a/wpa_supplicant/hidl/1.3/hidl.h b/wpa_supplicant/hidl/1.4/hidl.h
index bf03bf96..0974048c 100644
--- a/wpa_supplicant/hidl/1.3/hidl.h
+++ b/wpa_supplicant/hidl/1.4/hidl.h
@@ -49,9 +49,11 @@ extern "C"
void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay,
const char *url);
+ void wpas_hidl_notify_hs20_rx_terms_and_conditions_acceptance(
+ struct wpa_supplicant *wpa_s, const char *url);
void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
- void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s,
- const u8 *bssid, u8 timed_out);
+ void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len);
void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s);
void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s);
void wpas_hidl_notify_wps_event_fail(
@@ -63,7 +65,8 @@ extern "C"
void wpas_hidl_notify_p2p_device_found(
struct wpa_supplicant *wpa_s, const u8 *addr,
const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
- u8 peer_wfd_device_info_len);
+ u8 peer_wfd_device_info_len, const u8 *peer_wfd_r2_device_info,
+ u8 peer_wfd_r2_device_info_len);
void wpas_hidl_notify_p2p_device_lost(
struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr);
void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s);
@@ -121,6 +124,9 @@ extern "C"
void wpas_hidl_notify_pmk_cache_added(
struct wpa_supplicant *wpas, struct rsn_pmksa_cache_entry *pmksa_entry);
void wpas_hidl_notify_bss_tm_status(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_transition_disable(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, u8 bitmap);
+ void wpas_hidl_notify_network_not_found(struct wpa_supplicant *wpa_s);
#else // CONFIG_CTRL_IFACE_HIDL
static inline int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
{
@@ -164,9 +170,12 @@ static void wpas_hidl_notify_hs20_rx_subscription_remediation(
static void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
{}
+void wpas_hidl_notify_hs20_rx_terms_and_conditions_acceptance(
+ struct wpa_supplicant *wpa_s, const char *url)
+{}
static void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s,
- const u8 *bssid, u8 timed_out) {}
+static void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len) {}
static void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s) {}
static void wpas_hidl_notify_wps_event_fail(
struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
@@ -263,6 +272,13 @@ static void wpas_hidl_notify_pmk_cache_added(struct wpa_supplicant *wpas,
{}
void wpas_hidl_notify_bss_tm_status(struct wpa_supplicant *wpa_s)
{}
+static void wpas_hidl_notify_transition_disable(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ u8 bitmap)
+{}
+static void wpas_hidl_notify_network_not_found(struct wpa_supplicant *wpa_s)
+{}
+}
#endif // CONFIG_CTRL_IFACE_HIDL
#ifdef _cplusplus
diff --git a/wpa_supplicant/hidl/1.3/hidl_constants.h b/wpa_supplicant/hidl/1.4/hidl_constants.h
index 988a5900..988a5900 100644
--- a/wpa_supplicant/hidl/1.3/hidl_constants.h
+++ b/wpa_supplicant/hidl/1.4/hidl_constants.h
diff --git a/wpa_supplicant/hidl/1.3/hidl_i.h b/wpa_supplicant/hidl/1.4/hidl_i.h
index 9cff40d1..9cff40d1 100644
--- a/wpa_supplicant/hidl/1.3/hidl_i.h
+++ b/wpa_supplicant/hidl/1.4/hidl_i.h
diff --git a/wpa_supplicant/hidl/1.3/hidl_manager.cpp b/wpa_supplicant/hidl/1.4/hidl_manager.cpp
index 2734e98d..0a5fcebc 100644
--- a/wpa_supplicant/hidl/1.3/hidl_manager.cpp
+++ b/wpa_supplicant/hidl/1.4/hidl_manager.cpp
@@ -17,12 +17,14 @@
extern "C" {
#include "scan.h"
#include "src/eap_common/eap_sim_common.h"
+#include "list.h"
}
namespace {
using android::hardware::hidl_array;
constexpr uint8_t kWfdDeviceInfoLen = 6;
+constexpr uint8_t kWfdR2DeviceInfoLen = 2;
// GSM-AUTH:<RAND1>:<RAND2>[:<RAND3>]
constexpr char kGsmAuthRegex2[] = "GSM-AUTH:([0-9a-f]+):([0-9a-f]+)";
constexpr char kGsmAuthRegex3[] =
@@ -33,6 +35,7 @@ constexpr size_t kGsmRandLenBytes = GSM_RAND_LEN;
constexpr size_t kUmtsRandLenBytes = EAP_AKA_RAND_LEN;
constexpr size_t kUmtsAutnLenBytes = EAP_AKA_AUTN_LEN;
constexpr u8 kZeroBssid[6] = {0, 0, 0, 0, 0, 0};
+
/**
* Check if the provided |wpa_supplicant| structure represents a P2P iface or
* not.
@@ -62,32 +65,17 @@ const std::string getNetworkObjectMapKey(
*/
template <class CallbackType>
int registerForDeathAndAddCallbackHidlObjectToList(
+ const android::sp<DeathNotifier> &death_notifier,
const android::sp<CallbackType> &callback,
- const std::function<void(const android::sp<CallbackType> &)>
- &on_hidl_died_fctor,
std::vector<android::sp<CallbackType>> &callback_list)
{
-#if 0 // TODO(b/31632518): HIDL object death notifications.
- auto death_notifier = new CallbackObjectDeathNotifier<CallbackType>(
- callback, on_hidl_died_fctor);
- // Use the |callback.get()| as cookie so that we don't need to
- // store a reference to this |CallbackObjectDeathNotifier| instance
- // to use in |unlinkToDeath| later.
- // NOTE: This may cause an immediate callback if the object is already
- // dead, so add it to the list before we register for callback!
- if (android::hardware::IInterface::asBinder(callback)->linkToDeath(
- death_notifier, callback.get()) != android::OK) {
+ if (!callback->linkToDeath(death_notifier, 0)) {
wpa_printf(
MSG_ERROR,
"Error registering for death notification for "
"supplicant callback object");
- callback_list.erase(
- std::remove(
- callback_list.begin(), callback_list.end(), callback),
- callback_list.end());
return 1;
}
-#endif // TODO(b/31632518): HIDL object death notifications.
callback_list.push_back(callback);
return 0;
}
@@ -122,9 +110,8 @@ int removeHidlObjectFromMap(
template <class CallbackType>
int addIfaceCallbackHidlObjectToMap(
+ const android::sp<DeathNotifier> &death_notifier,
const std::string &ifname, const android::sp<CallbackType> &callback,
- const std::function<void(const android::sp<CallbackType> &)>
- &on_hidl_died_fctor,
std::map<const std::string, std::vector<android::sp<CallbackType>>>
&callbacks_map)
{
@@ -138,15 +125,14 @@ int addIfaceCallbackHidlObjectToMap(
// Register for death notification before we add it to our list.
return registerForDeathAndAddCallbackHidlObjectToList<CallbackType>(
- callback, on_hidl_died_fctor, iface_callback_list);
+ death_notifier, callback, iface_callback_list);
}
template <class CallbackType>
int addNetworkCallbackHidlObjectToMap(
+ const android::sp<DeathNotifier> &death_notifier,
const std::string &ifname, int network_id,
const android::sp<CallbackType> &callback,
- const std::function<void(const android::sp<CallbackType> &)>
- &on_hidl_died_fctor,
std::map<const std::string, std::vector<android::sp<CallbackType>>>
&callbacks_map)
{
@@ -163,11 +149,12 @@ int addNetworkCallbackHidlObjectToMap(
// Register for death notification before we add it to our list.
return registerForDeathAndAddCallbackHidlObjectToList<CallbackType>(
- callback, on_hidl_died_fctor, network_callback_list);
+ death_notifier, callback, network_callback_list);
}
template <class CallbackType>
int removeAllIfaceCallbackHidlObjectsFromMap(
+ const android::sp<DeathNotifier> &death_notifier,
const std::string &ifname,
std::map<const std::string, std::vector<android::sp<CallbackType>>>
&callbacks_map)
@@ -175,25 +162,22 @@ int removeAllIfaceCallbackHidlObjectsFromMap(
auto iface_callback_map_iter = callbacks_map.find(ifname);
if (iface_callback_map_iter == callbacks_map.end())
return 1;
-#if 0 // TODO(b/31632518): HIDL object death notifications.
const auto &iface_callback_list = iface_callback_map_iter->second;
for (const auto &callback : iface_callback_list) {
- if (android::hardware::IInterface::asBinder(callback)
- ->unlinkToDeath(nullptr, callback.get()) !=
- android::OK) {
+ if (!callback->unlinkToDeath(death_notifier)) {
wpa_printf(
MSG_ERROR,
"Error deregistering for death notification for "
"iface callback object");
}
}
-#endif // TODO(b/31632518): HIDL object death notifications.
callbacks_map.erase(iface_callback_map_iter);
return 0;
}
template <class CallbackType>
int removeAllNetworkCallbackHidlObjectsFromMap(
+ const android::sp<DeathNotifier> &death_notifier,
const std::string &network_key,
std::map<const std::string, std::vector<android::sp<CallbackType>>>
&callbacks_map)
@@ -201,12 +185,9 @@ int removeAllNetworkCallbackHidlObjectsFromMap(
auto network_callback_map_iter = callbacks_map.find(network_key);
if (network_callback_map_iter == callbacks_map.end())
return 1;
-#if 0 // TODO(b/31632518): HIDL object death notifications.
const auto &network_callback_list = network_callback_map_iter->second;
for (const auto &callback : network_callback_list) {
- if (android::hardware::IInterface::asBinder(callback)
- ->unlinkToDeath(nullptr, callback.get()) !=
- android::OK) {
+ if (!callback->unlinkToDeath(death_notifier)) {
wpa_printf(
MSG_ERROR,
"Error deregistering for death "
@@ -214,7 +195,6 @@ int removeAllNetworkCallbackHidlObjectsFromMap(
"network callback object");
}
}
-#endif // TODO(b/31632518): HIDL object death notifications.
callbacks_map.erase(network_callback_map_iter);
return 0;
}
@@ -345,6 +325,38 @@ void callWithEachNetworkCallback(
}
}
+template <class CallbackTypeBase, class CallbackTypeDerived>
+void callWithEachNetworkCallbackDerived(
+ const std::string &ifname, int network_id,
+ const std::function<
+ android::hardware::Return<void>(android::sp<CallbackTypeDerived>)> &method,
+ const std::map<
+ const std::string, std::vector<android::sp<CallbackTypeBase>>>
+ &callbacks_map)
+{
+ if (ifname.empty())
+ return;
+
+ // Generate the key to be used to lookup the network.
+ const std::string network_key =
+ getNetworkObjectMapKey(ifname, network_id);
+ auto network_callback_map_iter = callbacks_map.find(network_key);
+ if (network_callback_map_iter == callbacks_map.end())
+ return;
+ const auto &network_callback_list = network_callback_map_iter->second;
+ for (const auto &callback : network_callback_list) {
+ android::sp<CallbackTypeDerived> callback_derived =
+ CallbackTypeDerived::castFrom(callback);
+ if (callback_derived == nullptr)
+ continue;
+ if (!method(callback_derived).isOk()) {
+ wpa_printf(
+ MSG_ERROR,
+ "Failed to invoke HIDL network callback");
+ }
+ }
+}
+
int parseGsmAuthNetworkRequest(
const std::string &params_str,
std::vector<hidl_array<uint8_t, kGsmRandLenBytes>> *out_rands)
@@ -400,9 +412,11 @@ namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
using V1_0::ISupplicantStaIfaceCallback;
+using V1_0::ISupplicantP2pIfaceCallback;
+using ISupplicantP2pIfaceCallbackV1_4 = V1_4::ISupplicantP2pIfaceCallback;
HidlManager *HidlManager::instance_ = NULL;
@@ -424,6 +438,8 @@ int HidlManager::registerHidlService(struct wpa_global *global)
{
// Create the main hidl service object and register it.
supplicant_object_ = new Supplicant(global);
+ wpa_global_ = global;
+ death_notifier_ = sp<DeathNotifier>::make(global);
if (supplicant_object_->registerAsService() != android::NO_ERROR) {
return 1;
}
@@ -518,13 +534,13 @@ int HidlManager::unregisterInterface(struct wpa_supplicant *wpa_s)
!removeHidlObjectFromMap(wpa_s->ifname, p2p_iface_object_map_);
if (success) { // assumed to be P2P
success = !removeAllIfaceCallbackHidlObjectsFromMap(
- wpa_s->ifname, p2p_iface_callbacks_map_);
+ death_notifier_, wpa_s->ifname, p2p_iface_callbacks_map_);
} else { // assumed to be STA
success = !removeHidlObjectFromMap(
wpa_s->ifname, sta_iface_object_map_);
if (success) {
success = !removeAllIfaceCallbackHidlObjectsFromMap(
- wpa_s->ifname, sta_iface_callbacks_map_);
+ death_notifier_, wpa_s->ifname, sta_iface_callbacks_map_);
}
}
if (!success) {
@@ -638,7 +654,7 @@ int HidlManager::unregisterNetwork(
return 1;
}
if (removeAllNetworkCallbackHidlObjectsFromMap(
- network_key, p2p_network_callbacks_map_))
+ death_notifier_, network_key, p2p_network_callbacks_map_))
return 1;
// Invoke the |onNetworkRemoved| method on all registered
@@ -659,7 +675,7 @@ int HidlManager::unregisterNetwork(
return 1;
}
if (removeAllNetworkCallbackHidlObjectsFromMap(
- network_key, sta_network_callbacks_map_))
+ death_notifier_, network_key, sta_network_callbacks_map_))
return 1;
// Invoke the |onNetworkRemoved| method on all registered
@@ -809,23 +825,33 @@ void HidlManager::notifyAnqpQueryDone(
sta_iface_object_map_.end())
return;
- ISupplicantStaIfaceCallback::AnqpData hidl_anqp_data;
+ V1_4::ISupplicantStaIfaceCallback::AnqpData hidl_anqp_data;
ISupplicantStaIfaceCallback::Hs20AnqpData hidl_hs20_anqp_data;
if (std::string(result) == "SUCCESS") {
- hidl_anqp_data.venueName =
+ hidl_anqp_data.V1_0.venueName =
misc_utils::convertWpaBufToVector(anqp->venue_name);
- hidl_anqp_data.roamingConsortium =
+ hidl_anqp_data.V1_0.roamingConsortium =
misc_utils::convertWpaBufToVector(anqp->roaming_consortium);
- hidl_anqp_data.ipAddrTypeAvailability =
+ hidl_anqp_data.V1_0.ipAddrTypeAvailability =
misc_utils::convertWpaBufToVector(
anqp->ip_addr_type_availability);
- hidl_anqp_data.naiRealm =
+ hidl_anqp_data.V1_0.naiRealm =
misc_utils::convertWpaBufToVector(anqp->nai_realm);
- hidl_anqp_data.anqp3gppCellularNetwork =
+ hidl_anqp_data.V1_0.anqp3gppCellularNetwork =
misc_utils::convertWpaBufToVector(anqp->anqp_3gpp);
- hidl_anqp_data.domainName =
+ hidl_anqp_data.V1_0.domainName =
misc_utils::convertWpaBufToVector(anqp->domain_name);
+ struct wpa_bss_anqp_elem *elem;
+ dl_list_for_each(elem, &anqp->anqp_elems, struct wpa_bss_anqp_elem,
+ list) {
+ if (elem->infoid == ANQP_VENUE_URL && elem->protected_response) {
+ hidl_anqp_data.venueUrl =
+ misc_utils::convertWpaBufToVector(elem->payload);
+ break;
+ }
+ }
+
hidl_hs20_anqp_data.operatorFriendlyName =
misc_utils::convertWpaBufToVector(
anqp->hs20_operator_friendly_name);
@@ -839,9 +865,9 @@ void HidlManager::notifyAnqpQueryDone(
anqp->hs20_osu_providers_list);
}
- callWithEachStaIfaceCallback(
+ callWithEachStaIfaceCallback_1_4(
wpa_s->ifname, std::bind(
- &ISupplicantStaIfaceCallback::onAnqpQueryDone,
+ &V1_4::ISupplicantStaIfaceCallback::onAnqpQueryDone_1_4,
std::placeholders::_1, bssid, hidl_anqp_data,
hidl_hs20_anqp_data));
}
@@ -908,18 +934,18 @@ void HidlManager::notifyHs20RxSubscriptionRemediation(
}
/**
- * Notify all listeners about the reception of HS20 immient deauth
+ * Notify all listeners about the reception of HS20 imminent deauth
* notification from the server.
*
* @param wpa_s |wpa_supplicant| struct corresponding to the interface.
* @param code Deauth reason code sent from server.
* @param reauth_delay Reauthentication delay in seconds sent from server.
- * @param url URL of the server.
+ * @param url URL of the server containing the reason text.
*/
void HidlManager::notifyHs20RxDeauthImminentNotice(
struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
{
- if (!wpa_s || !url)
+ if (!wpa_s)
return;
if (sta_iface_object_map_.find(wpa_s->ifname) ==
@@ -934,6 +960,30 @@ void HidlManager::notifyHs20RxDeauthImminentNotice(
}
/**
+ * Notify all listeners about the reception of HS20 terms and conditions
+ * acceptance notification from the server.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
+ * @param url URL of the T&C server.
+ */
+void HidlManager::notifyHs20RxTermsAndConditionsAcceptance(
+ struct wpa_supplicant *wpa_s, const char *url)
+{
+ if (!wpa_s || !url)
+ return;
+
+ if (sta_iface_object_map_.find(wpa_s->ifname)
+ == sta_iface_object_map_.end())
+ return;
+
+ callWithEachStaIfaceCallback_1_4(wpa_s->ifname,
+ std::bind(
+ &V1_4::ISupplicantStaIfaceCallback
+ ::onHs20TermsAndConditionsAcceptanceRequestedNotification,
+ std::placeholders::_1, wpa_s->bssid, url));
+}
+
+/**
* Notify all listeners about the reason code for disconnection from the
* currently connected network.
*
@@ -972,24 +1022,91 @@ void HidlManager::notifyDisconnectReason(struct wpa_supplicant *wpa_s)
* @param bssid bssid of AP that rejected the association.
* @param timed_out flag to indicate failure is due to timeout
* (auth, assoc, ...) rather than explicit rejection response from the AP.
+ * @param assoc_resp_ie Association response IE.
+ * @param assoc_resp_ie_len Association response IE length.
*/
void HidlManager::notifyAssocReject(struct wpa_supplicant *wpa_s,
- const u8 *bssid, u8 timed_out)
+ const u8 *bssid, u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len)
{
+ std::string hidl_ifname = wpa_s->ifname;
+#ifdef CONFIG_MBO
+ struct wpa_bss *reject_bss;
+#endif /* CONFIG_MBO */
+ V1_4::ISupplicantStaIfaceCallback::AssociationRejectionData hidl_assoc_reject_data = {};
+
if (!wpa_s)
return;
if (sta_iface_object_map_.find(wpa_s->ifname) ==
sta_iface_object_map_.end())
return;
+ if (wpa_s->current_ssid) {
+ std::vector < uint8_t > hidl_ssid;
+ hidl_ssid.assign(
+ wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid + wpa_s->current_ssid->ssid_len);
+ hidl_assoc_reject_data.ssid = hidl_ssid;
+ }
+ hidl_assoc_reject_data.bssid = bssid;
+ hidl_assoc_reject_data.statusCode = static_cast<ISupplicantStaIfaceCallback::StatusCode>(
+ wpa_s->assoc_status_code);
+ if (timed_out) {
+ hidl_assoc_reject_data.timedOut = true;
+ }
+#ifdef CONFIG_MBO
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+ reject_bss = wpa_s->current_bss;
+ } else {
+ reject_bss = wpa_bss_get_bssid(wpa_s, bssid);
+ }
+ if (reject_bss && assoc_resp_ie && assoc_resp_ie_len > 0) {
+ if (wpa_s->assoc_status_code ==
+ WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS) {
+ const u8 *rssi_rej;
+ rssi_rej = mbo_get_attr_from_ies(
+ assoc_resp_ie,
+ assoc_resp_ie_len,
+ OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT);
+ if (rssi_rej && rssi_rej[1] == 2) {
+ wpa_printf(MSG_INFO,
+ "OCE: RSSI-based association rejection from "
+ MACSTR " Delta RSSI: %u, Retry Delay: %u bss rssi: %d",
+ MAC2STR(reject_bss->bssid),
+ rssi_rej[2], rssi_rej[3], reject_bss->level);
+ hidl_assoc_reject_data.isOceRssiBasedAssocRejectAttrPresent = true;
+ hidl_assoc_reject_data.oceRssiBasedAssocRejectData.deltaRssi
+ = rssi_rej[2];
+ hidl_assoc_reject_data.oceRssiBasedAssocRejectData.retryDelayS
+ = rssi_rej[3];
+ }
+ } else if (wpa_s->assoc_status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY
+ || wpa_s->assoc_status_code == WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA) {
+ const u8 *assoc_disallowed;
+ assoc_disallowed = mbo_get_attr_from_ies(
+ assoc_resp_ie,
+ assoc_resp_ie_len,
+ MBO_ATTR_ID_ASSOC_DISALLOW);
+ if (assoc_disallowed && assoc_disallowed[1] == 1) {
+ wpa_printf(MSG_INFO,
+ "MBO: association disallowed indication from "
+ MACSTR " Reason: %d",
+ MAC2STR(reject_bss->bssid),
+ assoc_disallowed[2]);
+ hidl_assoc_reject_data.isMboAssocDisallowedReasonCodePresent = true;
+ hidl_assoc_reject_data.mboAssocDisallowedReason
+ = static_cast<V1_4::ISupplicantStaIfaceCallback
+ ::MboAssocDisallowedReasonCode>(assoc_disallowed[2]);
+ }
+ }
+ }
+#endif /* CONFIG_MBO */
- callWithEachStaIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantStaIfaceCallback::onAssociationRejected,
- std::placeholders::_1, bssid,
- static_cast<ISupplicantStaIfaceCallback::StatusCode>(
- wpa_s->assoc_status_code), timed_out == 1));
+ const std::function<
+ Return<void>(android::sp<V1_4::ISupplicantStaIfaceCallback>)>
+ func = std::bind(
+ &V1_4::ISupplicantStaIfaceCallback::onAssociationRejected_1_4,
+ std::placeholders::_1, hidl_assoc_reject_data);
+ callWithEachStaIfaceCallbackDerived(hidl_ifname, func);
}
void HidlManager::notifyAuthTimeout(struct wpa_supplicant *wpa_s)
@@ -1110,7 +1227,8 @@ void HidlManager::notifyWpsEventPbcOverlap(struct wpa_supplicant *wpa_s)
void HidlManager::notifyP2pDeviceFound(
struct wpa_supplicant *wpa_s, const u8 *addr,
const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
- u8 peer_wfd_device_info_len)
+ u8 peer_wfd_device_info_len, const u8 *peer_wfd_r2_device_info,
+ u8 peer_wfd_r2_device_info_len)
{
if (!wpa_s || !addr || !info)
return;
@@ -1132,13 +1250,39 @@ void HidlManager::notifyP2pDeviceFound(
}
}
- callWithEachP2pIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantP2pIfaceCallback::onDeviceFound,
- std::placeholders::_1, addr, info->p2p_device_addr,
- info->pri_dev_type, info->device_name, info->config_methods,
- info->dev_capab, info->group_capab, hidl_peer_wfd_device_info));
+ std::array<uint8_t, kWfdR2DeviceInfoLen> hidl_peer_wfd_r2_device_info{};
+ if (peer_wfd_r2_device_info) {
+ if (peer_wfd_r2_device_info_len != kWfdR2DeviceInfoLen) {
+ wpa_printf(
+ MSG_ERROR, "Unexpected WFD R2 device info len: %d",
+ peer_wfd_r2_device_info_len);
+ return;
+ } else {
+ os_memcpy(
+ hidl_peer_wfd_r2_device_info.data(),
+ peer_wfd_r2_device_info, kWfdR2DeviceInfoLen);
+ }
+ }
+
+ if (peer_wfd_r2_device_info_len == kWfdR2DeviceInfoLen) {
+ const std::function<
+ Return<void>(android::sp<V1_4::ISupplicantP2pIfaceCallback>)>
+ func = std::bind(
+ &ISupplicantP2pIfaceCallbackV1_4::onR2DeviceFound,
+ std::placeholders::_1, addr, info->p2p_device_addr,
+ info->pri_dev_type, info->device_name, info->config_methods,
+ info->dev_capab, info->group_capab, hidl_peer_wfd_device_info,
+ hidl_peer_wfd_r2_device_info);
+ callWithEachP2pIfaceCallbackDerived(wpa_s->ifname, func);
+ } else {
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onDeviceFound,
+ std::placeholders::_1, addr, info->p2p_device_addr,
+ info->pri_dev_type, info->device_name, info->config_methods,
+ info->dev_capab, info->group_capab, hidl_peer_wfd_device_info));
+ }
}
void HidlManager::notifyP2pDeviceLost(
@@ -1236,9 +1380,8 @@ void HidlManager::notifyP2pGroupStarted(
return;
// For group notifications, need to use the parent iface for callbacks.
- struct wpa_supplicant *wpa_s = wpa_group_s->parent;
- if (p2p_iface_object_map_.find(wpa_s->ifname) ==
- p2p_iface_object_map_.end())
+ struct wpa_supplicant *wpa_s = getTargetP2pIfaceForGroup(wpa_group_s);
+ if (!wpa_s)
return;
uint32_t hidl_freq = wpa_group_s->current_bss
@@ -1279,9 +1422,8 @@ void HidlManager::notifyP2pGroupRemoved(
return;
// For group notifications, need to use the parent iface for callbacks.
- struct wpa_supplicant *wpa_s = wpa_group_s->parent;
- if (p2p_iface_object_map_.find(wpa_s->ifname) ==
- p2p_iface_object_map_.end())
+ struct wpa_supplicant *wpa_s = getTargetP2pIfaceForGroup(wpa_group_s);
+ if (!wpa_s)
return;
bool hidl_is_go = (std::string(role) == "GO");
@@ -1386,15 +1528,15 @@ void HidlManager::notifyP2pSdResponse(
}
void HidlManager::notifyApStaAuthorized(
- struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+ struct wpa_supplicant *wpa_group_s, const u8 *sta, const u8 *p2p_dev_addr)
{
- if (!wpa_s || !wpa_s->parent || !sta)
+ if (!wpa_group_s || !wpa_group_s->parent || !sta)
return;
- if (p2p_iface_object_map_.find(wpa_s->parent->ifname) ==
- p2p_iface_object_map_.end())
+ wpa_supplicant *wpa_s = getTargetP2pIfaceForGroup(wpa_group_s);
+ if (!wpa_s)
return;
callWithEachP2pIfaceCallback(
- wpa_s->parent->ifname,
+ wpa_s->ifname,
std::bind(
&ISupplicantP2pIfaceCallback::onStaAuthorized,
std::placeholders::_1, sta,
@@ -1402,16 +1544,16 @@ void HidlManager::notifyApStaAuthorized(
}
void HidlManager::notifyApStaDeauthorized(
- struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+ struct wpa_supplicant *wpa_group_s, const u8 *sta, const u8 *p2p_dev_addr)
{
- if (!wpa_s || !wpa_s->parent || !sta)
+ if (!wpa_group_s || !wpa_group_s->parent || !sta)
return;
- if (p2p_iface_object_map_.find(wpa_s->parent->ifname) ==
- p2p_iface_object_map_.end())
+ wpa_supplicant *wpa_s = getTargetP2pIfaceForGroup(wpa_group_s);
+ if (!wpa_s)
return;
callWithEachP2pIfaceCallback(
- wpa_s->parent->ifname,
+ wpa_s->ifname,
std::bind(
&ISupplicantP2pIfaceCallback::onStaDeauthorized,
std::placeholders::_1, sta,
@@ -1572,7 +1714,7 @@ void HidlManager::notifyDppProgress(struct wpa_supplicant *wpa_s,
* @param ifname Interface name
* @param code Status code
*/
-void HidlManager::notifyDppSuccess(struct wpa_supplicant *wpa_s, DppSuccessCode code)
+void HidlManager::notifyDppSuccess(struct wpa_supplicant *wpa_s, V1_3::DppSuccessCode code)
{
std::string hidl_ifname = wpa_s->ifname;
@@ -1703,7 +1845,7 @@ uint32_t getBssTmDataAssocRetryDelayMs(struct wpa_supplicant *wpa_s)
//wnm_bss_termination_duration contains 12 bytes of BSS
//termination duration subelement. Format of IE is
// Sub eid | Length | BSS termination TSF | Duration
- // 1 1 8 2
+ // 1 1 8 2
// Duration indicates number of minutes for which BSS is not
// present.
duration_ms = WPA_GET_LE16(wpa_s->wnm_bss_termination_duration + 10);
@@ -1759,6 +1901,76 @@ void HidlManager::notifyBssTmStatus(struct wpa_supplicant *wpa_s)
#endif
}
+uint32_t setTransitionDisableFlagsMask(u8 bitmap)
+{
+ uint32_t flags = 0;
+
+ if (bitmap & TRANSITION_DISABLE_WPA3_PERSONAL) {
+ flags |= V1_4::ISupplicantStaNetworkCallback::
+ TransitionDisableIndication::
+ USE_WPA3_PERSONAL;
+ bitmap &= ~TRANSITION_DISABLE_WPA3_PERSONAL;
+ }
+ if (bitmap & TRANSITION_DISABLE_SAE_PK) {
+ flags |= V1_4::ISupplicantStaNetworkCallback::
+ TransitionDisableIndication::
+ USE_SAE_PK;
+ bitmap &= ~TRANSITION_DISABLE_SAE_PK;
+ }
+ if (bitmap & TRANSITION_DISABLE_WPA3_ENTERPRISE) {
+ flags |= V1_4::ISupplicantStaNetworkCallback::
+ TransitionDisableIndication::
+ USE_WPA3_ENTERPRISE;
+ bitmap &= ~TRANSITION_DISABLE_WPA3_ENTERPRISE;
+ }
+ if (bitmap & TRANSITION_DISABLE_ENHANCED_OPEN) {
+ flags |= V1_4::ISupplicantStaNetworkCallback::
+ TransitionDisableIndication::
+ USE_ENHANCED_OPEN;
+ bitmap &= ~TRANSITION_DISABLE_ENHANCED_OPEN;
+ }
+
+ if (bitmap != 0) {
+ wpa_printf(MSG_WARNING, "Unhandled transition disable bit: 0x%x", bitmap);
+ }
+
+ return flags;
+}
+
+void HidlManager::notifyTransitionDisable(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, u8 bitmap)
+{
+ uint32_t flag = setTransitionDisableFlagsMask(bitmap);
+ const std::function<
+ Return<void>(android::sp<V1_4::ISupplicantStaNetworkCallback>)>
+ func = std::bind(
+ &V1_4::ISupplicantStaNetworkCallback::onTransitionDisable,
+ std::placeholders::_1, flag);
+
+ callWithEachStaNetworkCallbackDerived(wpa_s->ifname, ssid->id, func);
+}
+
+void HidlManager::notifyNetworkNotFound(struct wpa_supplicant *wpa_s)
+{
+ std::vector<uint8_t> hidl_ssid;
+
+ if (!wpa_s->current_ssid) {
+ wpa_printf(MSG_ERROR, "Current network NULL. Drop WPA_EVENT_NETWORK_NOT_FOUND!");
+ return;
+ }
+
+ hidl_ssid.assign(
+ wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid + wpa_s->current_ssid->ssid_len);
+
+ const std::function<
+ Return<void>(android::sp<V1_4::ISupplicantStaIfaceCallback>)>
+ func = std::bind(
+ &V1_4::ISupplicantStaIfaceCallback::onNetworkNotFound,
+ std::placeholders::_1, hidl_ssid);
+ callWithEachStaIfaceCallbackDerived(wpa_s->ifname, func);
+}
+
/**
* Retrieve the |ISupplicantP2pIface| hidl object reference using the provided
* ifname.
@@ -1846,7 +2058,7 @@ int HidlManager::getP2pNetworkHidlObjectByIfnameAndNetworkId(
*/
int HidlManager::getStaNetworkHidlObjectByIfnameAndNetworkId(
const std::string &ifname, int network_id,
- android::sp<ISupplicantStaNetwork> *network_object)
+ android::sp<V1_3::ISupplicantStaNetwork> *network_object)
{
if (ifname.empty() || network_id < 0 || !network_object)
return 1;
@@ -1874,13 +2086,9 @@ int HidlManager::getStaNetworkHidlObjectByIfnameAndNetworkId(
int HidlManager::addSupplicantCallbackHidlObject(
const android::sp<ISupplicantCallback> &callback)
{
- // Register for death notification before we add it to our list.
- auto on_hidl_died_fctor = std::bind(
- &HidlManager::removeSupplicantCallbackHidlObject, this,
- std::placeholders::_1);
return registerForDeathAndAddCallbackHidlObjectToList<
ISupplicantCallback>(
- callback, on_hidl_died_fctor, supplicant_callbacks_);
+ death_notifier_, callback, supplicant_callbacks_);
}
/**
@@ -1896,13 +2104,8 @@ int HidlManager::addP2pIfaceCallbackHidlObject(
const std::string &ifname,
const android::sp<ISupplicantP2pIfaceCallback> &callback)
{
- const std::function<void(
- const android::sp<ISupplicantP2pIfaceCallback> &)>
- on_hidl_died_fctor = std::bind(
- &HidlManager::removeP2pIfaceCallbackHidlObject, this, ifname,
- std::placeholders::_1);
return addIfaceCallbackHidlObjectToMap(
- ifname, callback, on_hidl_died_fctor, p2p_iface_callbacks_map_);
+ death_notifier_, ifname, callback, p2p_iface_callbacks_map_);
}
/**
@@ -1918,13 +2121,8 @@ int HidlManager::addStaIfaceCallbackHidlObject(
const std::string &ifname,
const android::sp<ISupplicantStaIfaceCallback> &callback)
{
- const std::function<void(
- const android::sp<ISupplicantStaIfaceCallback> &)>
- on_hidl_died_fctor = std::bind(
- &HidlManager::removeStaIfaceCallbackHidlObject, this, ifname,
- std::placeholders::_1);
return addIfaceCallbackHidlObjectToMap(
- ifname, callback, on_hidl_died_fctor, sta_iface_callbacks_map_);
+ death_notifier_, ifname, callback, sta_iface_callbacks_map_);
}
/**
@@ -1941,13 +2139,8 @@ int HidlManager::addP2pNetworkCallbackHidlObject(
const std::string &ifname, int network_id,
const android::sp<ISupplicantP2pNetworkCallback> &callback)
{
- const std::function<void(
- const android::sp<ISupplicantP2pNetworkCallback> &)>
- on_hidl_died_fctor = std::bind(
- &HidlManager::removeP2pNetworkCallbackHidlObject, this, ifname,
- network_id, std::placeholders::_1);
return addNetworkCallbackHidlObjectToMap(
- ifname, network_id, callback, on_hidl_died_fctor,
+ death_notifier_, ifname, network_id, callback,
p2p_network_callbacks_map_);
}
@@ -1965,17 +2158,49 @@ int HidlManager::addStaNetworkCallbackHidlObject(
const std::string &ifname, int network_id,
const android::sp<ISupplicantStaNetworkCallback> &callback)
{
- const std::function<void(
- const android::sp<ISupplicantStaNetworkCallback> &)>
- on_hidl_died_fctor = std::bind(
- &HidlManager::removeStaNetworkCallbackHidlObject, this, ifname,
- network_id, std::placeholders::_1);
return addNetworkCallbackHidlObjectToMap(
- ifname, network_id, callback, on_hidl_died_fctor,
+ death_notifier_, ifname, network_id, callback,
sta_network_callbacks_map_);
}
/**
+ * Finds the correct |wpa_supplicant| object for P2P notifications
+ *
+ * @param wpa_s the |wpa_supplicant| that triggered the P2P event.
+ * @return appropriate |wpa_supplicant| object or NULL if not found.
+ */
+struct wpa_supplicant *HidlManager::getTargetP2pIfaceForGroup(
+ struct wpa_supplicant *wpa_group_s)
+{
+ if (!wpa_group_s || !wpa_group_s->parent)
+ return NULL;
+
+ struct wpa_supplicant *target_wpa_s = wpa_group_s->parent;
+
+ // check wpa_supplicant object is a p2p device interface
+ if ((wpa_group_s == wpa_group_s->p2pdev) && wpa_group_s->p2p_mgmt) {
+ if (p2p_iface_object_map_.find(wpa_group_s->ifname) !=
+ p2p_iface_object_map_.end())
+ return wpa_group_s;
+ }
+
+ if (p2p_iface_object_map_.find(target_wpa_s->ifname) !=
+ p2p_iface_object_map_.end())
+ return target_wpa_s;
+
+ // try P2P device if available
+ if (!target_wpa_s->p2pdev || !target_wpa_s->p2pdev->p2p_mgmt)
+ return NULL;
+
+ target_wpa_s = target_wpa_s->p2pdev;
+ if (p2p_iface_object_map_.find(target_wpa_s->ifname) !=
+ p2p_iface_object_map_.end())
+ return target_wpa_s;
+
+ return NULL;
+}
+
+/**
* Removes the provided |ISupplicantCallback| hidl object reference
* from our global callback list.
*
@@ -2089,6 +2314,24 @@ void HidlManager::callWithEachP2pIfaceCallback(
/**
* Helper function to invoke the provided callback method on all the
+ * registered derived interface callback hidl objects for the specified
+ * |ifname|.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param method Pointer to the required hidl method from
+ * derived |V1_x::ISupplicantIfaceCallback|.
+ */
+template <class CallbackTypeDerived>
+void HidlManager::callWithEachP2pIfaceCallbackDerived(
+ const std::string &ifname,
+ const std::function<
+ Return<void>(android::sp<CallbackTypeDerived>)> &method)
+{
+ callWithEachIfaceCallbackDerived(ifname, method, p2p_iface_callbacks_map_);
+}
+
+/**
+ * Helper function to invoke the provided callback method on all the
* registered V1.1 interface callback hidl objects for the specified
* |ifname|.
*
@@ -2140,6 +2383,23 @@ void HidlManager::callWithEachStaIfaceCallback_1_3(
/**
* Helper function to invoke the provided callback method on all the
+ * registered V1.4 interface callback hidl objects for the specified
+ * |ifname|.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param method Pointer to the required hidl method from
+ * |V1_4::ISupplicantIfaceCallback|.
+ */
+void HidlManager::callWithEachStaIfaceCallback_1_4(
+ const std::string &ifname,
+ const std::function<
+ Return<void>(android::sp<V1_4::ISupplicantStaIfaceCallback>)> &method)
+{
+ callWithEachIfaceCallbackDerived(ifname, method, sta_iface_callbacks_map_);
+}
+
+/**
+ * Helper function to invoke the provided callback method on all the
* registered derived interface callback hidl objects for the specified
* |ifname|.
*
@@ -2210,8 +2470,26 @@ void HidlManager::callWithEachStaNetworkCallback(
callWithEachNetworkCallback(
ifname, network_id, method, sta_network_callbacks_map_);
}
+
+/**
+ * Helper function to invoke the provided callback method on all the
+ * registered derived interface callback hidl objects for the specified
+ * |ifname|.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param method Pointer to the required hidl method from
+ * derived |V1_x::ISupplicantIfaceCallback|.
+ */
+template <class CallbackTypeDerived>
+void HidlManager::callWithEachStaNetworkCallbackDerived(
+ const std::string &ifname, int network_id,
+ const std::function<
+ Return<void>(android::sp<CallbackTypeDerived>)> &method)
+{
+ callWithEachNetworkCallbackDerived(ifname, network_id, method, sta_network_callbacks_map_);
+}
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/hidl_manager.h b/wpa_supplicant/hidl/1.4/hidl_manager.h
index b40d303d..ccde11c4 100644
--- a/wpa_supplicant/hidl/1.3/hidl_manager.h
+++ b/wpa_supplicant/hidl/1.4/hidl_manager.h
@@ -16,8 +16,9 @@
#include <android/hardware/wifi/supplicant/1.0/ISupplicantCallback.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIfaceCallback.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetworkCallback.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaNetworkCallback.h>
#include "p2p_iface.h"
#include "p2p_network.h"
@@ -34,11 +35,31 @@ extern "C"
#include "driver_i.h"
}
+class DeathNotifier : public android::hardware::hidl_death_recipient
+{
+public:
+ DeathNotifier(struct wpa_global *wpa_global)
+ : wpa_global_(wpa_global)
+ {}
+
+ void serviceDied(
+ uint64_t /*cookie*/,
+ const android::wp<android::hidl::base::V1_0::IBase>
+ & /* who */) override
+ {
+ wpa_printf(MSG_ERROR, "Client died. Terminating...");
+ wpa_supplicant_terminate_proc(wpa_global_);
+ }
+
+private:
+ struct wpa_global *wpa_global_;
+};
+
namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
using V1_0::ISupplicant;
using V1_0::ISupplicantP2pIface;
@@ -81,10 +102,12 @@ public:
struct wpa_supplicant *wpa_s, const char *url, u8 osu_method);
void notifyHs20RxDeauthImminentNotice(
struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay,
- const char *url);
+ const char *url);
+ void notifyHs20RxTermsAndConditionsAcceptance(
+ struct wpa_supplicant *wpa_s, const char *url);
void notifyDisconnectReason(struct wpa_supplicant *wpa_s);
- void notifyAssocReject(struct wpa_supplicant *wpa_s,
- const u8 *bssid, u8 timed_out);
+ void notifyAssocReject(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len);
void notifyAuthTimeout(struct wpa_supplicant *wpa_s);
void notifyBssidChanged(struct wpa_supplicant *wpa_s);
void notifyWpsEventFail(
@@ -95,7 +118,8 @@ public:
void notifyP2pDeviceFound(
struct wpa_supplicant *wpa_s, const u8 *addr,
const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
- u8 peer_wfd_device_info_len);
+ u8 peer_wfd_device_info_len, const u8 *peer_wfd_r2_device_info,
+ u8 peer_wfd_r2_device_info_len);
void notifyP2pDeviceLost(
struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr);
void notifyP2pFindStopped(struct wpa_supplicant *wpa_s);
@@ -134,7 +158,7 @@ public:
void notifyDppConfigReceived(struct wpa_supplicant *wpa_s,
struct wpa_ssid *config);
void notifyDppConfigSent(struct wpa_supplicant *wpa_s);
- void notifyDppSuccess(struct wpa_supplicant *wpa_s, DppSuccessCode code);
+ void notifyDppSuccess(struct wpa_supplicant *wpa_s, V1_3::DppSuccessCode code);
void notifyDppFailure(struct wpa_supplicant *wpa_s,
android::hardware::wifi::supplicant::V1_3::DppFailureCode code);
void notifyDppFailure(struct wpa_supplicant *wpa_s,
@@ -146,6 +170,10 @@ public:
void notifyPmkCacheAdded(struct wpa_supplicant *wpa_s,
struct rsn_pmksa_cache_entry *pmksa_entry);
void notifyBssTmStatus(struct wpa_supplicant *wpa_s);
+ void notifyTransitionDisable(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ u8 bitmap);
+ void notifyNetworkNotFound(struct wpa_supplicant *wpa_s);
// Methods called from hidl objects.
void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
@@ -163,7 +191,7 @@ public:
android::sp<ISupplicantP2pNetwork> *network_object);
int getStaNetworkHidlObjectByIfnameAndNetworkId(
const std::string &ifname, int network_id,
- android::sp<ISupplicantStaNetwork> *network_object);
+ android::sp<V1_3::ISupplicantStaNetwork> *network_object);
int addSupplicantCallbackHidlObject(
const android::sp<ISupplicantCallback> &callback);
int addP2pIfaceCallbackHidlObject(
@@ -185,6 +213,8 @@ private:
HidlManager(const HidlManager &) = default;
HidlManager &operator=(const HidlManager &) = default;
+ struct wpa_supplicant *getTargetP2pIfaceForGroup(
+ struct wpa_supplicant *wpa_s);
void removeSupplicantCallbackHidlObject(
const android::sp<ISupplicantCallback> &callback);
void removeP2pIfaceCallbackHidlObject(
@@ -207,6 +237,11 @@ private:
const std::string &ifname,
const std::function<android::hardware::Return<void>(
android::sp<ISupplicantP2pIfaceCallback>)> &method);
+ template <class CallbackTypeDerived>
+ void callWithEachP2pIfaceCallbackDerived(
+ const std::string &ifname,
+ const std::function<
+ Return<void>(android::sp<CallbackTypeDerived>)> &method);
void callWithEachStaIfaceCallback(
const std::string &ifname,
const std::function<android::hardware::Return<void>(
@@ -223,6 +258,10 @@ private:
const std::string &ifname,
const std::function<android::hardware::Return<void>(
android::sp<V1_3::ISupplicantStaIfaceCallback>)> &method);
+ void callWithEachStaIfaceCallback_1_4(
+ const std::string &ifname,
+ const std::function<android::hardware::Return<void>(
+ android::sp<V1_4::ISupplicantStaIfaceCallback>)> &method);
template <class CallbackTypeDerived>
void callWithEachStaIfaceCallbackDerived(
const std::string &ifname,
@@ -236,9 +275,18 @@ private:
const std::string &ifname, int network_id,
const std::function<android::hardware::Return<void>(
android::sp<ISupplicantStaNetworkCallback>)> &method);
+ template <class CallbackTypeDerived>
+ void callWithEachStaNetworkCallbackDerived(
+ const std::string &ifname, int network_id,
+ const std::function<
+ Return<void>(android::sp<CallbackTypeDerived>)> &method);
// Singleton instance of this class.
static HidlManager *instance_;
+ // Raw pointer to the global structure maintained by the core.
+ struct wpa_global *wpa_global_;
+ // Death notifier.
+ android::sp<DeathNotifier> death_notifier_;
// The main hidl service object.
android::sp<Supplicant> supplicant_object_;
// Map of all the P2P interface specific hidl objects controlled by
@@ -292,40 +340,6 @@ private:
const std::string,
std::vector<android::sp<ISupplicantStaNetworkCallback>>>
sta_network_callbacks_map_;
-
-#if 0 // TODO(b/31632518): HIDL object death notifications.
- /**
- * Helper class used to deregister the callback object reference from
- * our callback list on the death of the hidl object.
- * This class stores a reference of the callback hidl object and a
- * function to be called to indicate the death of the hidl object.
- */
- template <class CallbackType>
- class CallbackObjectDeathNotifier
- : public android::hardware::IBinder::DeathRecipient
- {
- public:
- CallbackObjectDeathNotifier(
- const android::sp<CallbackType> &callback,
- const std::function<void(const android::sp<CallbackType> &)>
- &on_hidl_died)
- : callback_(callback), on_hidl_died_(on_hidl_died)
- {
- }
- void binderDied(const android::wp<android::hardware::IBinder>
- & /* who */) override
- {
- on_hidl_died_(callback_);
- }
-
- private:
- // The callback hidl object reference.
- const android::sp<CallbackType> callback_;
- // Callback function to be called when the hidl dies.
- const std::function<void(const android::sp<CallbackType> &)>
- on_hidl_died_;
- };
-#endif
};
// The hidl interface uses some values which are the same as internal ones to
@@ -339,51 +353,51 @@ static_assert(
"Debug level value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::NONE) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::KeyMgmtMask::NONE) ==
WPA_KEY_MGMT_NONE,
"KeyMgmt value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK) ==
WPA_KEY_MGMT_PSK,
"KeyMgmt value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP) ==
WPA_KEY_MGMT_IEEE8021X,
"KeyMgmt value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X) ==
WPA_KEY_MGMT_IEEE8021X_NO_WPA,
"KeyMgmt value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_EAP) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::KeyMgmtMask::FT_EAP) ==
WPA_KEY_MGMT_FT_IEEE8021X,
"KeyMgmt value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_PSK) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::KeyMgmtMask::FT_PSK) ==
WPA_KEY_MGMT_FT_PSK,
"KeyMgmt value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OSEN) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::KeyMgmtMask::OSEN) ==
WPA_KEY_MGMT_OSEN,
"KeyMgmt value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::SAE) ==
+ static_cast<uint32_t>(V1_2::ISupplicantStaNetwork::KeyMgmtMask::SAE) ==
WPA_KEY_MGMT_SAE,
"KeyMgmt value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::SUITE_B_192) ==
+ static_cast<uint32_t>(V1_2::ISupplicantStaNetwork::KeyMgmtMask::SUITE_B_192) ==
WPA_KEY_MGMT_IEEE8021X_SUITE_B_192,
"KeyMgmt value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OWE) ==
+ static_cast<uint32_t>(V1_2::ISupplicantStaNetwork::KeyMgmtMask::OWE) ==
WPA_KEY_MGMT_OWE,
"KeyMgmt value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK_SHA256) ==
+ static_cast<uint32_t>(V1_2::ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK_SHA256) ==
WPA_KEY_MGMT_PSK_SHA256,
"KeyMgmt value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP_SHA256) ==
+ static_cast<uint32_t>(V1_2::ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP_SHA256) ==
WPA_KEY_MGMT_IEEE8021X_SHA256,
"KeyMgmt value mismatch");
static_assert(
@@ -395,15 +409,15 @@ static_assert(
WPA_KEY_MGMT_WAPI_CERT,
"KeyMgmt value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::WPA) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::ProtoMask::WPA) ==
WPA_PROTO_WPA,
"Proto value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::RSN) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::ProtoMask::RSN) ==
WPA_PROTO_RSN,
"Proto value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::OSEN) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::ProtoMask::OSEN) ==
WPA_PROTO_OSEN,
"Proto value mismatch");
static_assert(
@@ -411,35 +425,35 @@ static_assert(
WPA_PROTO_WAPI,
"Proto value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::OPEN) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::AuthAlgMask::OPEN) ==
WPA_AUTH_ALG_OPEN,
"AuthAlg value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::SHARED) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::AuthAlgMask::SHARED) ==
WPA_AUTH_ALG_SHARED,
"AuthAlg value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::LEAP) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::AuthAlgMask::LEAP) ==
WPA_AUTH_ALG_LEAP,
"AuthAlg value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP40) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::GroupCipherMask::WEP40) ==
WPA_CIPHER_WEP40,
"GroupCipher value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP104) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::GroupCipherMask::WEP104) ==
WPA_CIPHER_WEP104,
"GroupCipher value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::TKIP) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::GroupCipherMask::TKIP) ==
WPA_CIPHER_TKIP,
"GroupCipher value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::CCMP) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::GroupCipherMask::CCMP) ==
WPA_CIPHER_CCMP,
"GroupCipher value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::GCMP_256) ==
+ static_cast<uint32_t>(V1_2::ISupplicantStaNetwork::GroupCipherMask::GCMP_256) ==
WPA_CIPHER_GCMP_256,
"GroupCipher value mismatch");
static_assert(
@@ -448,24 +462,24 @@ static_assert(
"GroupCipher value mismatch");
static_assert(
static_cast<uint32_t>(
- ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) ==
+ V1_0::ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) ==
WPA_CIPHER_GTK_NOT_USED,
"GroupCipher value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::NONE) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::PairwiseCipherMask::NONE) ==
WPA_CIPHER_NONE,
"PairwiseCipher value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::TKIP) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::PairwiseCipherMask::TKIP) ==
WPA_CIPHER_TKIP,
"PairwiseCipher value mismatch");
static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::CCMP) ==
+ static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::PairwiseCipherMask::CCMP) ==
WPA_CIPHER_CCMP,
"PairwiseCipher value mismatch");
static_assert(
static_cast<uint32_t>(
- ISupplicantStaNetwork::PairwiseCipherMask::GCMP_256) ==
+ V1_2::ISupplicantStaNetwork::PairwiseCipherMask::GCMP_256) ==
WPA_CIPHER_GCMP_256,
"PairwiseCipher value mismatch");
static_assert(
@@ -761,7 +775,7 @@ static_assert(
P2P_PROV_DISC_INFO_UNAVAILABLE,
"P2P status code value mismatch");
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/hidl_return_util.h b/wpa_supplicant/hidl/1.4/hidl_return_util.h
index 4c1f919a..217f2153 100644
--- a/wpa_supplicant/hidl/1.3/hidl_return_util.h
+++ b/wpa_supplicant/hidl/1.4/hidl_return_util.h
@@ -14,10 +14,9 @@ namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
namespace hidl_return_util {
-using V1_0::SupplicantStatusCode;
/**
* These utility functions are used to invoke a method on the provided
@@ -30,10 +29,11 @@ using V1_0::SupplicantStatusCode;
* provided error status and default values.
*/
// Use for HIDL methods which return only an instance of SupplicantStatus.
-template <typename ObjT, typename WorkFuncT, typename... Args>
+template <typename ObjT, typename SupplicantStatusCodeT, typename WorkFuncT,
+ typename SupplicantStatusT, typename... Args>
Return<void> validateAndCall(
- ObjT* obj, SupplicantStatusCode status_code_if_invalid, WorkFuncT&& work,
- const std::function<void(const SupplicantStatus&)>& hidl_cb, Args&&... args)
+ ObjT* obj, SupplicantStatusCodeT status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const SupplicantStatusT&)>& hidl_cb, Args&&... args)
{
if (obj->isValid()) {
hidl_cb((obj->*work)(std::forward<Args>(args)...));
@@ -45,16 +45,17 @@ Return<void> validateAndCall(
// Use for HIDL methods which return instance of SupplicantStatus and a single
// return value.
-template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
+template <typename ObjT, typename SupplicantStatusCodeT, typename WorkFuncT,
+ typename SupplicantStatusT, typename ReturnT, typename... Args>
Return<void> validateAndCall(
- ObjT* obj, SupplicantStatusCode status_code_if_invalid, WorkFuncT&& work,
- const std::function<void(const SupplicantStatus&, ReturnT)>& hidl_cb,
+ ObjT* obj, SupplicantStatusCodeT status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const SupplicantStatusT&, ReturnT)>& hidl_cb,
Args&&... args)
{
if (obj->isValid()) {
const auto& ret_pair =
(obj->*work)(std::forward<Args>(args)...);
- const SupplicantStatus& status = std::get<0>(ret_pair);
+ const SupplicantStatusT& status = std::get<0>(ret_pair);
const auto& ret_value = std::get<1>(ret_pair);
hidl_cb(status, ret_value);
} else {
@@ -68,18 +69,18 @@ Return<void> validateAndCall(
// Use for HIDL methods which return instance of SupplicantStatus and 2 return
// values.
template <
- typename ObjT, typename WorkFuncT, typename ReturnT1, typename ReturnT2,
- typename... Args>
+ typename ObjT, typename SupplicantStatusCodeT, typename WorkFuncT,
+ typename SupplicantStatusT, typename ReturnT1, typename ReturnT2, typename... Args>
Return<void> validateAndCall(
- ObjT* obj, SupplicantStatusCode status_code_if_invalid, WorkFuncT&& work,
- const std::function<void(const SupplicantStatus&, ReturnT1, ReturnT2)>&
+ ObjT* obj, SupplicantStatusCodeT status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const SupplicantStatusT&, ReturnT1, ReturnT2)>&
hidl_cb,
Args&&... args)
{
if (obj->isValid()) {
const auto& ret_tuple =
(obj->*work)(std::forward<Args>(args)...);
- const SupplicantStatus& status = std::get<0>(ret_tuple);
+ const SupplicantStatusT& status = std::get<0>(ret_tuple);
const auto& ret_value1 = std::get<1>(ret_tuple);
const auto& ret_value2 = std::get<2>(ret_tuple);
hidl_cb(status, ret_value1, ret_value2);
@@ -94,7 +95,7 @@ Return<void> validateAndCall(
} // namespace hidl_return_util
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/iface_config_utils.cpp b/wpa_supplicant/hidl/1.4/iface_config_utils.cpp
index 31370a6c..9af3ea9a 100644
--- a/wpa_supplicant/hidl/1.3/iface_config_utils.cpp
+++ b/wpa_supplicant/hidl/1.4/iface_config_utils.cpp
@@ -81,9 +81,11 @@ namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
namespace iface_config_utils {
+using V1_0::SupplicantStatusCode;
+
SupplicantStatus setWpsDeviceName(
struct wpa_supplicant* wpa_s, const std::string& name)
{
@@ -176,7 +178,7 @@ SupplicantStatus setExternalSim(
}
} // namespace iface_config_utils
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/iface_config_utils.h b/wpa_supplicant/hidl/1.4/iface_config_utils.h
index 822d7ac5..a94feb59 100644
--- a/wpa_supplicant/hidl/1.3/iface_config_utils.h
+++ b/wpa_supplicant/hidl/1.4/iface_config_utils.h
@@ -30,7 +30,7 @@ namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
namespace iface_config_utils {
SupplicantStatus setWpsDeviceName(
@@ -51,7 +51,7 @@ SupplicantStatus setExternalSim(
struct wpa_supplicant* wpa_s, bool useExternalSim);
} // namespace iface_config_utils
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/misc_utils.h b/wpa_supplicant/hidl/1.4/misc_utils.h
index b95b1eeb..6e69d4c0 100644
--- a/wpa_supplicant/hidl/1.3/misc_utils.h
+++ b/wpa_supplicant/hidl/1.4/misc_utils.h
@@ -27,7 +27,7 @@ namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
namespace misc_utils {
using wpabuf_unique_ptr = std::unique_ptr<wpabuf, void (*)(wpabuf *)>;
@@ -103,7 +103,7 @@ inline std::stringstream& deserializePmkCacheEntry(
}
} // namespace misc_utils
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/p2p_iface.cpp b/wpa_supplicant/hidl/1.4/p2p_iface.cpp
index ffa9b6a6..cabcccb6 100644
--- a/wpa_supplicant/hidl/1.3/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/1.4/p2p_iface.cpp
@@ -25,7 +25,13 @@ extern "C"
#include "driver_i.h"
}
-#define P2P_MAX_JOIN_SCAN_ATTEMPTS 10
+#define P2P_MAX_JOIN_SCAN_ATTEMPTS 3
+// Wait time before triggering the single channel scan to discover Auto GO.
+// Use a shorter wait time when the given frequency is GO operating frequency.
+// The idea is to quickly finish scans and return the status to application.
+#define P2P_JOIN_SINGLE_CHANNEL_SCAN_INTERVAL_USECS 200000
+// Wait time before triggering the multiple channel scan to discover Auto GO.
+#define P2P_JOIN_MULTIPLE_CHANNEL_SCAN_INTERVAL_USECS 1000000
namespace {
const char kConfigMethodStrPbc[] = "pbc";
@@ -33,6 +39,7 @@ const char kConfigMethodStrDisplay[] = "display";
const char kConfigMethodStrKeypad[] = "keypad";
constexpr char kSetMiracastMode[] = "MIRACAST ";
constexpr uint8_t kWfdDeviceInfoSubelemId = 0;
+constexpr uint8_t kWfdR2DeviceInfoSubelemId = 11;
constexpr char kWfdDeviceInfoSubelemLenHexStr[] = "0006";
std::function<void()> pending_join_scan_callback = NULL;
@@ -91,30 +98,106 @@ int isPskPassphraseValid(const std::string &psk)
return 1;
}
-void setBandScanFreqsList(
+static int setBandScanFreqsList(
struct wpa_supplicant *wpa_s,
- enum hostapd_hw_mode band,
+ enum hostapd_hw_mode hw_mode,
+ bool exclude_dfs,
struct wpa_driver_scan_params *params)
{
- /* 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, 0);
- if (mode == NULL) {
- /* No channels supported in this band. */
- return;
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode, 0);
+ if (mode == NULL || !mode->num_channels) {
+ wpa_printf(MSG_ERROR,
+ "P2P: No channels supported in this hw_mode: %d", hw_mode);
+ return -1;
}
+ /*
+ * Allocate memory for frequency array, allocate one extra
+ * slot for the zero-terminator.
+ */
params->freqs = (int *) os_calloc(mode->num_channels + 1, sizeof(int));
- if (params->freqs == NULL)
- return;
+ if (params->freqs == NULL) {
+ return -ENOMEM;
+ }
for (count = 0, i = 0; i < mode->num_channels; i++) {
- if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
+ if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED) {
+ continue;
+ }
+ if (exclude_dfs && (mode->channels[i].flag & HOSTAPD_CHAN_RADAR)) {
continue;
+ }
params->freqs[count++] = mode->channels[i].freq;
}
+ if (!count && params->freqs) {
+ wpa_printf(MSG_ERROR,
+ "P2P: All channels(exclude_dfs: %d) are disabled in this hw_mode: %d",
+ exclude_dfs, hw_mode);
+ os_free(params->freqs);
+ return -1;
+ }
+ return 0;
}
+
+static int setP2pCliOptimizedScanFreqsList(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params, int freq)
+{
+ if (freq == 2 || freq == 5) {
+ enum hostapd_hw_mode mode;
+ int ret;
+ if (wpa_s->hw.modes == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Unknown what %dG channels the driver supports.", freq);
+ return 0;
+ }
+ mode = freq == 5 ? HOSTAPD_MODE_IEEE80211A : HOSTAPD_MODE_IEEE80211G;
+ if (wpa_s->p2p_join_scan_count < 2) {
+ // scan all non DFS channels in the first two attempts
+ ret = setBandScanFreqsList(wpa_s, mode, true, params);
+ if (ret < 0 && (-ENOMEM != ret)) {
+ // try to scan all channels before returning error
+ ret = setBandScanFreqsList(wpa_s, mode, false, params);
+ }
+ } else {
+ // scan all channels
+ ret = setBandScanFreqsList(wpa_s, mode, false, params);
+ }
+ return ret;
+ } else {
+ if (disabled_freq(wpa_s, freq)) {
+ wpa_printf(MSG_ERROR,
+ "P2P: freq %d is not supported for a client.", freq);
+ return -1;
+ }
+ /*
+ * Allocate memory for frequency array, allocate one extra
+ * slot for the zero-terminator.
+ */
+ params->freqs = (int *) os_calloc(2, sizeof(int));
+ if (params->freqs) {
+ params->freqs[0] = freq;
+ } else {
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+/**
+ * getP2pJoinScanInterval - Get the delay in triggering the scan to discover
+ * Auto GO.
+ */
+static int getP2pJoinScanIntervalUsecs(int freq)
+{
+ if (freq == 5 || freq == 2 || freq == 0) {
+ return P2P_JOIN_MULTIPLE_CHANNEL_SCAN_INTERVAL_USECS;
+ } else {
+ return P2P_JOIN_SINGLE_CHANNEL_SCAN_INTERVAL_USECS;
+ }
+}
+
/*
* isAnyEtherAddr - match any ether address
*
@@ -248,47 +331,13 @@ int joinScanReq(
wpa_printf(MSG_DEBUG, "Scan SSID %s for join with frequency %d (reinvoke)",
wpa_ssid_txt(params.ssids[0].ssid, params.ssids[0].ssid_len), freq);
+ /* Construct an optimized p2p scan channel list */
if (freq > 0) {
- if (freq == 2 || freq == 5) {
- if (wpa_s->hw.modes != NULL) {
- switch (freq) {
- case 2:
- setBandScanFreqsList(wpa_s,
- HOSTAPD_MODE_IEEE80211G, &params);
- break;
- case 5:
- setBandScanFreqsList(wpa_s,
- HOSTAPD_MODE_IEEE80211A, &params);
- break;
- }
- if (!params.freqs) {
- wpa_printf(MSG_ERROR,
- "P2P: No supported channels in %dG band.", freq);
- return -1;
- }
- } else {
- wpa_printf(MSG_DEBUG,
- "P2P: Unknown what %dG channels the driver supports.", freq);
- }
- } else {
- if (0 == p2p_supported_freq_cli(wpa_s->global->p2p, freq)) {
- wpa_printf(MSG_ERROR,
- "P2P: freq %d is not supported for a client.", freq);
- return -1;
- }
-
- /*
- * Allocate memory for frequency array, allocate one extra
- * slot for the zero-terminator.
- */
- params.freqs = (int *) os_calloc(2, sizeof(int));
- if (params.freqs) {
- params.freqs[0] = freq;
- } else {
- wpa_printf(MSG_ERROR,
- "P2P: Cannot allocate memory for scan params.");
- return -1;
- }
+ ret = setP2pCliOptimizedScanFreqsList(wpa_s, &params, freq);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ "Failed to set frequency in p2p scan params, error = %d", ret);
+ return -1;
}
}
@@ -319,6 +368,7 @@ int joinScanReq(
if (wpa_s->scan_res_handler) {
wpa_printf(MSG_DEBUG, "Replace current running scan result handler");
}
+ wpa_s->p2p_join_scan_count++;
wpa_s->scan_res_handler = scanResJoinWrapper;
wpa_s->own_scan_requested = 1;
wpa_s->clear_driver_scan_cache = 0;
@@ -406,7 +456,7 @@ namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
using hidl_return_util::validateAndCall;
using V1_0::SupplicantStatusCode;
@@ -881,6 +931,37 @@ Return<void> P2pIface::setMacRandomization(bool enable, setMacRandomization_cb _
&P2pIface::setMacRandomizationInternal, _hidl_cb, enable);
}
+Return<void> P2pIface::setEdmg(bool enable, setEdmg_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &P2pIface::setEdmgInternal, _hidl_cb, enable);
+}
+
+Return<void> P2pIface::getEdmg(getEdmg_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &P2pIface::getEdmgInternal, _hidl_cb);
+}
+
+Return<void> P2pIface::registerCallback_1_4(
+ const sp<V1_4::ISupplicantP2pIfaceCallback>& callback,
+ registerCallback_1_4_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::registerCallback_1_4Internal, _hidl_cb, callback);
+}
+
+Return<void> P2pIface::setWfdR2DeviceInfo(
+ const hidl_array<uint8_t, 4>& info, setWfdR2DeviceInfo_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setWfdR2DeviceInfoInternal, _hidl_cb, info);
+}
+
std::pair<SupplicantStatus, std::string> P2pIface::getNameInternal()
{
return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
@@ -1083,8 +1164,9 @@ std::pair<SupplicantStatus, std::string> P2pIface::connectInternal(
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
const char* pin =
pre_selected_pin.length() > 0 ? pre_selected_pin.data() : nullptr;
+ bool auto_join = !join_existing_group;
int new_pin = wpas_p2p_connect(
- wpa_s, peer_address.data(), pin, wps_method, persistent, false,
+ wpa_s, peer_address.data(), pin, wps_method, persistent, auto_join,
join_existing_group, false, go_intent_signed, 0, 0, -1, false, ht40,
vht, CHANWIDTH_USE_HT, he, 0, nullptr, 0);
if (new_pin < 0) {
@@ -1175,6 +1257,7 @@ SupplicantStatus P2pIface::removeGroupInternal(const std::string& group_ifname)
if (!wpa_group_s) {
return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
}
+ wpa_group_s->global->p2p_go_found_external_scan = 0;
if (wpas_p2p_group_remove(wpa_group_s, group_ifname.c_str())) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -1722,7 +1805,6 @@ SupplicantStatus P2pIface::addGroup_1_2Internal(
if (-EBUSY == ret) {
// re-schedule this join scan and don't consume retry count.
if (pending_scan_res_join_callback) {
- wpa_s->p2p_join_scan_count--;
pending_scan_res_join_callback();
}
} else if (0 != ret) {
@@ -1731,7 +1813,7 @@ SupplicantStatus P2pIface::addGroup_1_2Internal(
}
};
- pending_scan_res_join_callback = [wpa_s, ssid, passphrase, peer_address, this]() {
+ pending_scan_res_join_callback = [wpa_s, ssid, passphrase, peer_address, freq, this]() {
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) {
return;
}
@@ -1741,8 +1823,10 @@ SupplicantStatus P2pIface::addGroup_1_2Internal(
struct wpa_bss *bss = findBssBySsid(
wpa_s, peer_address.data(), ssid.data(), ssid.size());
if (bss) {
+ wpa_s->global->p2p_go_found_external_scan = 1;
if (0 != joinGroup(wpa_s, bss->bssid, ssid, passphrase)) {
wpa_printf(MSG_ERROR, "P2P: Failed to join a group.");
+ wpa_s->global->p2p_go_found_external_scan = 0;
}
// no need to notify group join failure here,
// it will be handled by wpas_p2p_group_add_persistent
@@ -1750,13 +1834,12 @@ SupplicantStatus P2pIface::addGroup_1_2Internal(
pending_scan_res_join_callback = NULL;
return;
}
-
- wpa_s->p2p_join_scan_count++;
- wpa_printf(MSG_DEBUG, "P2P: Join scan attempt %d.", wpa_s->p2p_join_scan_count);
+ wpa_printf(MSG_DEBUG, "P2P: Join scan count %d.", wpa_s->p2p_join_scan_count);
eloop_cancel_timeout(joinScanWrapper, wpa_s, NULL);
- if (wpa_s->p2p_join_scan_count <= P2P_MAX_JOIN_SCAN_ATTEMPTS) {
+ if (wpa_s->p2p_join_scan_count < P2P_MAX_JOIN_SCAN_ATTEMPTS) {
wpa_printf(MSG_DEBUG, "P2P: Try join again later.");
- eloop_register_timeout(1, 0, joinScanWrapper, wpa_s, this);
+ eloop_register_timeout(0, getP2pJoinScanIntervalUsecs(freq),
+ joinScanWrapper, wpa_s, this);
return;
}
@@ -1781,14 +1864,6 @@ SupplicantStatus P2pIface::setMacRandomizationInternal(bool enable)
bool currentEnabledState = !!wpa_s->conf->p2p_device_random_mac_addr;
u8 *addr = NULL;
- // A dedicated p2p device is not managed by supplicant,
- // supplicant could not change its MAC address.
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) {
- wpa_printf(MSG_ERROR,
- "Dedicated P2P device don't support MAC randomization");
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, "NotSupported"};
- }
-
// The same state, no change is needed.
if (currentEnabledState == enable) {
wpa_printf(MSG_DEBUG, "The random MAC is %s already.",
@@ -1832,6 +1907,56 @@ SupplicantStatus P2pIface::setMacRandomizationInternal(bool enable)
return {SupplicantStatusCode::SUCCESS, ""};
}
+V1_4::SupplicantStatus P2pIface::setEdmgInternal(bool enable)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ wpa_printf(MSG_DEBUG, "set p2p_go_edmg to %d", enable);
+ wpa_s->conf->p2p_go_edmg = enable ? 1 : 0;
+ wpa_s->p2p_go_edmg = enable ? 1 : 0;
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<V1_4::SupplicantStatus, bool> P2pIface::getEdmgInternal()
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ return {{V1_4::SupplicantStatusCode::SUCCESS, ""},
+ (wpa_s->p2p_go_edmg == 1)};
+}
+
+V1_4::SupplicantStatus P2pIface::registerCallback_1_4Internal(
+ const sp<V1_4::ISupplicantP2pIfaceCallback>& callback)
+{
+ HidlManager* hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager ||
+ hidl_manager->addP2pIfaceCallbackHidlObject(ifname_, callback)) {
+ return {V1_4::SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
+}
+
+V1_4::SupplicantStatus P2pIface::setWfdR2DeviceInfoInternal(
+ const std::array<uint8_t, 4>& info)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ uint32_t wfd_r2_device_info_hex_len = info.size() * 2 + 1;
+ std::vector<char> wfd_r2_device_info_hex(wfd_r2_device_info_hex_len);
+ wpa_snprintf_hex(
+ wfd_r2_device_info_hex.data(), wfd_r2_device_info_hex.size(),
+ info.data(),info.size());
+ std::string wfd_r2_device_info_set_cmd_str =
+ std::to_string(kWfdR2DeviceInfoSubelemId) + " " +
+ wfd_r2_device_info_hex.data();
+ std::vector<char> wfd_r2_device_info_set_cmd(
+ wfd_r2_device_info_set_cmd_str.c_str(),
+ wfd_r2_device_info_set_cmd_str.c_str() +
+ wfd_r2_device_info_set_cmd_str.size() + 1);
+ if (wifi_display_subelem_set(
+ wpa_s->global, wfd_r2_device_info_set_cmd.data())) {
+ return {V1_4::SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
+}
+
/**
* Retrieve the underlying |wpa_supplicant| struct
* pointer for this iface.
@@ -1853,7 +1978,7 @@ wpa_supplicant* P2pIface::retrieveGroupIfacePtr(const std::string& group_ifname)
}
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/p2p_iface.h b/wpa_supplicant/hidl/1.4/p2p_iface.h
index 608dbd4b..c8ddc01a 100644
--- a/wpa_supplicant/hidl/1.3/p2p_iface.h
+++ b/wpa_supplicant/hidl/1.4/p2p_iface.h
@@ -15,7 +15,7 @@
#include <android-base/macros.h>
-#include <android/hardware/wifi/supplicant/1.2/ISupplicantP2pIface.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantP2pIface.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIfaceCallback.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetwork.h>
@@ -30,11 +30,13 @@ extern "C"
#include "config.h"
}
+#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
+
namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
using V1_0::SupplicantNetworkId;
using V1_0::SupplicantStatus;
@@ -47,7 +49,7 @@ using V1_0::ISupplicantP2pNetwork;
* object is used for control operations on a specific interface
* controlled by wpa_supplicant.
*/
-class P2pIface : public V1_2::ISupplicantP2pIface
+class P2pIface : public V1_4::ISupplicantP2pIface
{
public:
P2pIface(struct wpa_global* wpa_global, const char ifname[]);
@@ -196,6 +198,14 @@ public:
bool joinExistingGroup, addGroup_1_2_cb _hidl_cb) override;
Return<void> setMacRandomization(
bool enable, setMacRandomization_cb _hidl_cb) override;
+ Return<void> setEdmg(bool enable, setEdmg_cb _hidl_cb) override;
+ Return<void> getEdmg(getEdmg_cb _hidl_cb) override;
+ Return<void> registerCallback_1_4(
+ const sp<V1_4::ISupplicantP2pIfaceCallback>& callback,
+ registerCallback_1_4_cb _hidl_cb) override;
+ Return<void> setWfdR2DeviceInfo(
+ const hidl_array<uint8_t, 4>& info,
+ setWfdR2DeviceInfo_cb _hidl_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
@@ -305,6 +315,12 @@ private:
bool persistent, uint32_t freq, const std::array<uint8_t, 6>& peer_address,
bool joinExistingGroup);
SupplicantStatus setMacRandomizationInternal(bool enable);
+ V1_4::SupplicantStatus setEdmgInternal(bool enable);
+ std::pair<V1_4::SupplicantStatus, bool> getEdmgInternal();
+ V1_4::SupplicantStatus registerCallback_1_4Internal(
+ const sp<V1_4::ISupplicantP2pIfaceCallback>& callback);
+ V1_4::SupplicantStatus setWfdR2DeviceInfoInternal(
+ const std::array<uint8_t, 4>& info);
struct wpa_supplicant* retrieveIfacePtr();
struct wpa_supplicant* retrieveGroupIfacePtr(
@@ -321,7 +337,7 @@ private:
};
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/p2p_network.cpp b/wpa_supplicant/hidl/1.4/p2p_network.cpp
index c87e4c0e..cba2fdd2 100644
--- a/wpa_supplicant/hidl/1.3/p2p_network.cpp
+++ b/wpa_supplicant/hidl/1.4/p2p_network.cpp
@@ -20,7 +20,7 @@ namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
using hidl_return_util::validateAndCall;
using V1_0::SupplicantStatusCode;
@@ -250,7 +250,7 @@ struct wpa_supplicant *P2pNetwork::retrieveIfacePtr()
(struct wpa_global *)wpa_global_, ifname_.c_str());
}
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/p2p_network.h b/wpa_supplicant/hidl/1.4/p2p_network.h
index 8c134b06..94e37635 100644
--- a/wpa_supplicant/hidl/1.3/p2p_network.h
+++ b/wpa_supplicant/hidl/1.4/p2p_network.h
@@ -26,7 +26,7 @@ namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
using V1_0::ISupplicantP2pNetwork;
using V1_0::ISupplicantP2pNetworkCallback;
@@ -96,7 +96,7 @@ private:
};
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/sta_iface.cpp b/wpa_supplicant/hidl/1.4/sta_iface.cpp
index b738ff7d..1bf279e4 100644
--- a/wpa_supplicant/hidl/1.3/sta_iface.cpp
+++ b/wpa_supplicant/hidl/1.4/sta_iface.cpp
@@ -35,10 +35,13 @@ using android::hardware::wifi::V1_0::WifiChannelWidthInMhz;
using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
using android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
-using android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface;
-using android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities;
using android::hardware::wifi::supplicant::V1_3::WifiTechnology;
-using android::hardware::wifi::supplicant::V1_3::implementation::HidlManager;
+using android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface;
+using android::hardware::wifi::supplicant::V1_4::ConnectionCapabilities;
+using android::hardware::wifi::supplicant::V1_4::LegacyMode;
+using android::hardware::wifi::supplicant::V1_4::implementation::HidlManager;
+using android::hardware::wifi::supplicant::V1_4::DppResponderBootstrapInfo;
+using android::hardware::wifi::supplicant::V1_4::DppCurve;
constexpr uint32_t kMaxAnqpElems = 100;
constexpr char kGetMacAddress[] = "MACADDR";
@@ -217,16 +220,76 @@ uint32_t convertWpaKeyMgmtCapabilitiesToHidl (
return mask;
}
+const std::string getDppListenChannel(struct wpa_supplicant *wpa_s, int32_t *listen_channel)
+{
+ struct hostapd_hw_modes *mode;
+ int chan44 = 0, chan149 = 0;
+ *listen_channel = 0;
+
+ /* Check if device support 2.4GHz band*/
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211G, 0);
+ if (mode) {
+ *listen_channel = 6;
+ return "81/6";
+ }
+ /* Check if device support 5GHz band */
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211A, 0);
+ if (mode) {
+ for (int i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *chan = &mode->channels[i];
+
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR))
+ continue;
+ if (chan->freq == 5220)
+ chan44 = 1;
+ if (chan->freq == 5745)
+ chan149 = 1;
+ }
+ if (chan149) {
+ *listen_channel = 149;
+ return "124/149";
+ } else if (chan44) {
+ *listen_channel = 44;
+ return "115/44";
+ }
+ }
+
+ return "";
+}
+
+const std::string convertCurveTypeToName(DppCurve curve)
+{
+ switch (curve) {
+ case DppCurve::PRIME256V1:
+ return "prime256v1";
+ case DppCurve::SECP384R1:
+ return "secp384r1";
+ case DppCurve::SECP521R1:
+ return "secp521r1";
+ case DppCurve::BRAINPOOLP256R1:
+ return "brainpoolP256r1";
+ case DppCurve::BRAINPOOLP384R1:
+ return "brainpoolP384r1";
+ case DppCurve::BRAINPOOLP512R1:
+ return "brainpoolP512r1";
+ }
+ WPA_ASSERT(false);
+}
+
} // namespace
namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
using hidl_return_util::validateAndCall;
using V1_0::ISupplicantStaIfaceCallback;
+using V1_0::SupplicantStatusCode;
StaIface::StaIface(struct wpa_global *wpa_global, const char ifname[])
: wpa_global_(wpa_global), ifname_(ifname), is_valid_(true)
@@ -337,6 +400,16 @@ Return<void> StaIface::registerCallback_1_3(
&StaIface::registerCallbackInternal, _hidl_cb, callback_1_3);
}
+Return<void> StaIface::registerCallback_1_4(
+ const sp<V1_4::ISupplicantStaIfaceCallback> &callback,
+ registerCallback_1_4_cb _hidl_cb)
+{
+ sp<V1_4::ISupplicantStaIfaceCallback> callback_1_4 = callback;
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::registerCallbackInternal_1_4, _hidl_cb, callback_1_4);
+}
+
Return<void> StaIface::reassociate(reassociate_cb _hidl_cb)
{
return validateAndCall(
@@ -390,7 +463,7 @@ Return<void> StaIface::initiateTdlsTeardown(
}
Return<void> StaIface::initiateAnqpQuery(
const hidl_array<uint8_t, 6> &mac_address,
- const hidl_vec<ISupplicantStaIface::AnqpInfoId> &info_elements,
+ const hidl_vec<V1_0::ISupplicantStaIface::AnqpInfoId> &info_elements,
const hidl_vec<ISupplicantStaIface::Hs20AnqpSubtypes> &sub_types,
initiateAnqpQuery_cb _hidl_cb)
{
@@ -400,6 +473,15 @@ Return<void> StaIface::initiateAnqpQuery(
info_elements, sub_types);
}
+Return<void> StaIface::initiateVenueUrlAnqpQuery(
+ const hidl_array<uint8_t, 6> &mac_address,
+ initiateVenueUrlAnqpQuery_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::initiateVenueUrlAnqpQueryInternal, _hidl_cb, mac_address);
+}
+
Return<void> StaIface::initiateHs20IconQuery(
const hidl_array<uint8_t, 6> &mac_address, const hidl_string &file_name,
initiateHs20IconQuery_cb _hidl_cb)
@@ -663,6 +745,31 @@ Return<void> StaIface::stopDppInitiator(stopDppInitiator_cb _hidl_cb)
&StaIface::stopDppInitiatorInternal, _hidl_cb);
}
+Return<void> StaIface::generateDppBootstrapInfoForResponder(
+ const hidl_array<uint8_t, 6> &mac_address, const hidl_string& device_info,
+ DppCurve curve, generateDppBootstrapInfoForResponder_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::generateDppBootstrapInfoForResponderInternal, _hidl_cb, mac_address,
+ device_info, curve);
+}
+
+Return<void> StaIface::startDppEnrolleeResponder(
+ uint32_t listen_channel, startDppEnrolleeResponder_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::startDppEnrolleeResponderInternal, _hidl_cb, listen_channel);
+}
+
+Return<void> StaIface::stopDppResponder(uint32_t own_bootstrap_id, stopDppResponder_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::stopDppResponderInternal, _hidl_cb, own_bootstrap_id);
+}
+
Return<void> StaIface::getWpaDriverCapabilities(
getWpaDriverCapabilities_cb _hidl_cb)
{
@@ -671,6 +778,14 @@ Return<void> StaIface::getWpaDriverCapabilities(
&StaIface::getWpaDriverCapabilitiesInternal, _hidl_cb);
}
+Return<void> StaIface::getWpaDriverCapabilities_1_4(
+ getWpaDriverCapabilities_1_4_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_UNKNOWN,
+ &StaIface::getWpaDriverCapabilitiesInternal_1_4, _hidl_cb);
+}
+
Return<void> StaIface::setMboCellularDataStatus(bool available,
setMboCellularDataStatus_cb _hidl_cb)
{
@@ -742,7 +857,7 @@ SupplicantStatus StaIface::filsHlpAddRequestInternal(
std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
StaIface::addNetworkInternal()
{
- android::sp<ISupplicantStaNetwork> network;
+ android::sp<V1_3::ISupplicantStaNetwork> network;
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct wpa_ssid *ssid = wpa_supplicant_add_network(wpa_s);
if (!ssid) {
@@ -765,6 +880,14 @@ Return<void> StaIface::getConnectionCapabilities(
&StaIface::getConnectionCapabilitiesInternal, _hidl_cb);
}
+Return<void> StaIface::getConnectionCapabilities_1_4(
+ getConnectionCapabilities_1_4_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_UNKNOWN,
+ &StaIface::getConnectionCapabilitiesInternal_1_4, _hidl_cb);
+}
+
SupplicantStatus StaIface::removeNetworkInternal(SupplicantNetworkId id)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
@@ -781,7 +904,7 @@ SupplicantStatus StaIface::removeNetworkInternal(SupplicantNetworkId id)
std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
StaIface::getNetworkInternal(SupplicantNetworkId id)
{
- android::sp<ISupplicantStaNetwork> network;
+ android::sp<V1_3::ISupplicantStaNetwork> network;
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct wpa_ssid *ssid = wpa_config_get_network(wpa_s->conf, id);
if (!ssid) {
@@ -812,12 +935,18 @@ StaIface::listNetworksInternal()
SupplicantStatus StaIface::registerCallbackInternal(
const sp<ISupplicantStaIfaceCallback> &callback)
{
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"};
+}
+
+V1_4::SupplicantStatus StaIface::registerCallbackInternal_1_4(
+ const sp<V1_4::ISupplicantStaIfaceCallback> &callback)
+{
HidlManager *hidl_manager = HidlManager::getInstance();
if (!hidl_manager ||
hidl_manager->addStaIfaceCallbackHidlObject(ifname_, callback)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ return {V1_4::SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
- return {SupplicantStatusCode::SUCCESS, ""};
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
}
SupplicantStatus StaIface::reassociateInternal()
@@ -943,14 +1072,28 @@ SupplicantStatus StaIface::initiateAnqpQueryInternal(
static_cast<std::underlying_type<
ISupplicantStaIface::Hs20AnqpSubtypes>::type>(type));
}
+
if (anqp_send_req(
- wpa_s, mac_address.data(), info_elems_buf, num_info_elems,
- sub_types_bitmask, false)) {
+ wpa_s, mac_address.data(), 0, info_elems_buf, num_info_elems,
+ sub_types_bitmask, 0)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
}
+V1_4::SupplicantStatus StaIface::initiateVenueUrlAnqpQueryInternal(
+ const std::array<uint8_t, 6> &mac_address)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ uint16_t info_elems_buf[1] = {ANQP_VENUE_URL};
+
+ if (anqp_send_req(
+ wpa_s, mac_address.data(), 0, info_elems_buf, 1, 0, 0)) {
+ return {V1_4::SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
+}
+
SupplicantStatus StaIface::initiateHs20IconQueryInternal(
const std::array<uint8_t, 6> &mac_address, const std::string &file_name)
{
@@ -1421,56 +1564,182 @@ SupplicantStatus StaIface::stopDppInitiatorInternal()
#endif
}
-std::pair<SupplicantStatus, ConnectionCapabilities>
+std::pair<V1_4::SupplicantStatus, DppResponderBootstrapInfo>
+StaIface::generateDppBootstrapInfoForResponderInternal(const std::array<uint8_t, 6> &mac_address,
+ const std::string& device_info, DppCurve curve)
+{
+#ifdef CONFIG_DPP
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ std::string cmd = "type=qrcode";
+ int32_t id;
+ int32_t listen_channel = 0;
+ struct DppResponderBootstrapInfo bootstrap_info;
+ const char *uri;
+ std::string listen_channel_str;
+ std::string mac_addr_str;
+ char buf[3] = {0};
+
+ cmd += (device_info.empty()) ? "" : " info=" + device_info;
+
+ listen_channel_str = getDppListenChannel(wpa_s, &listen_channel);
+ if (listen_channel == 0) {
+ wpa_printf(MSG_ERROR, "StaIface: Failed to derive DPP listen channel");
+ return {{V1_4::SupplicantStatusCode::FAILURE_UNKNOWN, ""}, bootstrap_info};
+ }
+ cmd += " chan=" + listen_channel_str;
+
+ cmd += " mac=";
+ for (int i = 0;i < 6;i++) {
+ snprintf(buf, sizeof(buf), "%02x", mac_address[i]);
+ mac_addr_str.append(buf);
+ }
+ cmd += mac_addr_str;
+
+ cmd += " curve=" + convertCurveTypeToName(curve);
+
+ id = dpp_bootstrap_gen(wpa_s->dpp, cmd.c_str());
+ wpa_printf(MSG_DEBUG,
+ "DPP generate bootstrap QR code command: %s id: %d", cmd.c_str(), id);
+ if (id > 0) {
+ uri = dpp_bootstrap_get_uri(wpa_s->dpp, id);
+ if (uri) {
+ wpa_printf(MSG_DEBUG, "DPP Bootstrap info: id: %d "
+ "listen_channel: %d uri: %s", id, listen_channel, uri);
+ bootstrap_info.bootstrapId = id;
+ bootstrap_info.listenChannel = listen_channel;
+ bootstrap_info.uri = uri;
+ return {{V1_4::SupplicantStatusCode::SUCCESS, ""}, bootstrap_info};
+ }
+ }
+ return {{V1_4::SupplicantStatusCode::FAILURE_UNKNOWN, ""}, bootstrap_info};
+#else
+ return {{V1_4::SupplicantStatusCode::FAILURE_UNSUPPORTED, ""}, bootstrap_info};
+#endif
+}
+
+V1_4::SupplicantStatus StaIface::startDppEnrolleeResponderInternal(uint32_t listen_channel)
+{
+#ifdef CONFIG_DPP
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ std::string cmd = "";
+ uint32_t freq = (listen_channel <= 14 ? 2407 : 5000) + listen_channel * 5;
+
+ /* Report received configuration to HIDL and create an internal profile */
+ wpa_s->conf->dpp_config_processing = 1;
+
+ cmd += std::to_string(freq);
+ cmd += " role=enrollee netrole=sta";
+
+ wpa_printf(MSG_DEBUG,
+ "DPP Enrollee Responder command: %s", cmd.c_str());
+
+ if (wpas_dpp_listen(wpa_s, cmd.c_str()) == 0) {
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
+ }
+ return {V1_4::SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+#else
+ return {V1_4::SupplicantStatusCode::FAILURE_UNSUPPORTED, ""};
+#endif
+}
+
+V1_4::SupplicantStatus StaIface::stopDppResponderInternal(uint32_t own_bootstrap_id)
+{
+#ifdef CONFIG_DPP
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ std::string bootstrap_id_str;
+
+ if (own_bootstrap_id == 0) {
+ bootstrap_id_str = "*";
+ }
+ else {
+ bootstrap_id_str = std::to_string(own_bootstrap_id);
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP Stop DPP Responder id: %d ", own_bootstrap_id);
+ wpas_dpp_stop(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+
+ if (dpp_bootstrap_remove(wpa_s->dpp, bootstrap_id_str.c_str()) < 0) {
+ wpa_printf(MSG_ERROR, "StaIface: dpp_bootstrap_remove failed");
+ }
+
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
+#else
+ return {V1_4::SupplicantStatusCode::FAILURE_UNSUPPORTED, ""};
+#endif
+}
+
+std::pair<SupplicantStatus, android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities>
StaIface::getConnectionCapabilitiesInternal()
{
+ struct android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities capa;
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"}, capa};
+}
+
+std::pair<V1_4::SupplicantStatus, ConnectionCapabilities>
+StaIface::getConnectionCapabilitiesInternal_1_4()
+{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct ConnectionCapabilities capa;
if (wpa_s->connection_set) {
+ capa.legacyMode = LegacyMode::UNKNOWN;
if (wpa_s->connection_he) {
- capa.technology = WifiTechnology::HE;
+ capa.V1_3.technology = WifiTechnology::HE;
} else if (wpa_s->connection_vht) {
- capa.technology = WifiTechnology::VHT;
+ capa.V1_3.technology = WifiTechnology::VHT;
} else if (wpa_s->connection_ht) {
- capa.technology = WifiTechnology::HT;
+ capa.V1_3.technology = WifiTechnology::HT;
} else {
- capa.technology = WifiTechnology::LEGACY;
+ capa.V1_3.technology = WifiTechnology::LEGACY;
+ if (wpas_freq_to_band(wpa_s->assoc_freq) == BAND_2_4_GHZ) {
+ capa.legacyMode = (wpa_s->connection_11b_only) ? LegacyMode::B_MODE
+ : LegacyMode::G_MODE;
+ } else {
+ capa.legacyMode = LegacyMode::A_MODE;
+ }
}
switch (wpa_s->connection_channel_bandwidth) {
case CHAN_WIDTH_20:
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
+ capa.V1_3.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
break;
case CHAN_WIDTH_40:
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_40;
+ capa.V1_3.channelBandwidth = WifiChannelWidthInMhz::WIDTH_40;
break;
case CHAN_WIDTH_80:
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80;
+ capa.V1_3.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80;
break;
case CHAN_WIDTH_160:
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_160;
+ capa.V1_3.channelBandwidth = WifiChannelWidthInMhz::WIDTH_160;
break;
case CHAN_WIDTH_80P80:
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80P80;
+ capa.V1_3.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80P80;
break;
default:
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
+ capa.V1_3.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
break;
}
- capa.maxNumberRxSpatialStreams = wpa_s->connection_max_nss_rx;
- capa.maxNumberTxSpatialStreams = wpa_s->connection_max_nss_tx;
+ capa.V1_3.maxNumberRxSpatialStreams = wpa_s->connection_max_nss_rx;
+ capa.V1_3.maxNumberTxSpatialStreams = wpa_s->connection_max_nss_tx;
} else {
- capa.technology = WifiTechnology::UNKNOWN;
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
- capa.maxNumberTxSpatialStreams = 1;
- capa.maxNumberRxSpatialStreams = 1;
+ capa.V1_3.technology = WifiTechnology::UNKNOWN;
+ capa.V1_3.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
+ capa.V1_3.maxNumberTxSpatialStreams = 1;
+ capa.V1_3.maxNumberRxSpatialStreams = 1;
+ capa.legacyMode = LegacyMode::UNKNOWN;
}
- return {{SupplicantStatusCode::SUCCESS, ""}, capa};
+ return {{V1_4::SupplicantStatusCode::SUCCESS, ""}, capa};
}
std::pair<SupplicantStatus, uint32_t>
StaIface::getWpaDriverCapabilitiesInternal()
{
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"}, 0};
+}
+
+std::pair<V1_4::SupplicantStatus, uint32_t>
+StaIface::getWpaDriverCapabilitiesInternal_1_4()
+{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
uint32_t mask = 0;
@@ -1479,15 +1748,19 @@ StaIface::getWpaDriverCapabilitiesInternal()
* transition + Cellular steering. 11v is a default feature in
* supplicant. And cellular steering is handled in framework.
*/
- mask |= WpaDriverCapabilitiesMask::MBO;
+ mask |= V1_3::WpaDriverCapabilitiesMask::MBO;
if (wpa_s->enable_oce & OCE_STA) {
- mask |= WpaDriverCapabilitiesMask::OCE;
+ mask |= V1_3::WpaDriverCapabilitiesMask::OCE;
}
#endif
+#ifdef CONFIG_SAE_PK
+ mask |= V1_4::WpaDriverCapabilitiesMask::SAE_PK;
+#endif
+ mask |= V1_4::WpaDriverCapabilitiesMask::WFD_R2;
wpa_printf(MSG_DEBUG, "Driver capability mask: 0x%x", mask);
- return {{SupplicantStatusCode::SUCCESS, ""}, mask};
+ return {{V1_4::SupplicantStatusCode::SUCCESS, ""}, mask};
}
SupplicantStatus StaIface::setMboCellularDataStatusInternal(bool available)
@@ -1501,7 +1774,19 @@ SupplicantStatus StaIface::setMboCellularDataStatusInternal(bool available)
} else {
mbo_cell_capa = MBO_CELL_CAPA_NOT_AVAILABLE;
}
+
+#ifdef ENABLE_PRIV_CMD_UPDATE_MBO_CELL_STATUS
+ char mbo_cmd[32];
+ char buf[32];
+
+ os_snprintf(mbo_cmd, sizeof(mbo_cmd), "%s %d", "MBO CELL_DATA_CAP", mbo_cell_capa);
+ if (wpa_drv_driver_cmd(wpa_s, mbo_cmd, buf, sizeof(buf)) < 0) {
+ wpa_printf(MSG_ERROR, "MBO CELL_DATA_CAP cmd failed CAP:%d", mbo_cell_capa);
+ }
+#else
wpas_mbo_update_cell_capa(wpa_s, mbo_cell_capa);
+#endif
+
return {SupplicantStatusCode::SUCCESS, ""};
#else
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
@@ -1535,7 +1820,7 @@ wpa_supplicant *StaIface::retrieveIfacePtr()
return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
}
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/sta_iface.h b/wpa_supplicant/hidl/1.4/sta_iface.h
index ba06e5a5..d49e4694 100644
--- a/wpa_supplicant/hidl/1.3/sta_iface.h
+++ b/wpa_supplicant/hidl/1.4/sta_iface.h
@@ -15,8 +15,8 @@
#include <android-base/macros.h>
-#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
-#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.h>
#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
extern "C"
@@ -33,7 +33,7 @@ namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
using V1_0::ISupplicantNetwork;
using android::hardware::wifi::supplicant::V1_2::DppAkm;
@@ -44,7 +44,7 @@ using android::hardware::wifi::supplicant::V1_2::DppNetRole;
* object is used for control operations on a specific interface
* controlled by wpa_supplicant.
*/
-class StaIface : public V1_3::ISupplicantStaIface
+class StaIface : public V1_4::ISupplicantStaIface
{
public:
StaIface(struct wpa_global* wpa_global, const char ifname[]);
@@ -90,6 +90,9 @@ public:
Return<void> registerCallback_1_3(
const sp<V1_3::ISupplicantStaIfaceCallback>& callback,
registerCallback_cb _hidl_cb) override;
+ Return<void> registerCallback_1_4(
+ const sp<V1_4::ISupplicantStaIfaceCallback> &callback,
+ registerCallback_1_4_cb _hidl_cb) override;
Return<void> reassociate(reassociate_cb _hidl_cb) override;
Return<void> reconnect(reconnect_cb _hidl_cb) override;
Return<void> disconnect(disconnect_cb _hidl_cb) override;
@@ -106,9 +109,12 @@ public:
initiateTdlsTeardown_cb _hidl_cb) override;
Return<void> initiateAnqpQuery(
const hidl_array<uint8_t, 6>& mac_address,
- const hidl_vec<ISupplicantStaIface::AnqpInfoId>& info_elements,
+ const hidl_vec<V1_0::ISupplicantStaIface::AnqpInfoId>& info_elements,
const hidl_vec<ISupplicantStaIface::Hs20AnqpSubtypes>& sub_types,
initiateAnqpQuery_cb _hidl_cb) override;
+ Return<void> initiateVenueUrlAnqpQuery(
+ const hidl_array<uint8_t, 6>& mac_address,
+ initiateVenueUrlAnqpQuery_cb _hidl_cb) override;
Return<void> initiateHs20IconQuery(
const hidl_array<uint8_t, 6>& mac_address,
const hidl_string& file_name,
@@ -189,12 +195,23 @@ public:
Return<void> stopDppInitiator(stopDppInitiator_cb _hidl_cb) override;
Return<void> getConnectionCapabilities(
getConnectionCapabilities_cb _hidl_cb) override;
+ Return<void> getConnectionCapabilities_1_4(
+ getConnectionCapabilities_1_4_cb _hidl_cb) override;
Return<void> getWpaDriverCapabilities(
getWpaDriverCapabilities_cb _hidl_cb) override;
Return<void> setMboCellularDataStatus(bool available,
setMboCellularDataStatus_cb _hidl_cb) override;
Return<void> getKeyMgmtCapabilities_1_3(
getKeyMgmtCapabilities_1_3_cb _hidl_cb) override;
+ Return<void> getWpaDriverCapabilities_1_4(
+ getWpaDriverCapabilities_1_4_cb _hidl_cb) override;
+ Return<void> generateDppBootstrapInfoForResponder(const hidl_array<uint8_t, 6> &mac_address,
+ const hidl_string& device_info, DppCurve curve,
+ generateDppBootstrapInfoForResponder_cb _hidl_cb) override;
+ Return<void> startDppEnrolleeResponder(uint32_t listen_channel,
+ startDppEnrolleeResponder_cb _hidl_cb) override;
+ Return<void> stopDppResponder(uint32_t own_bootstrap_id,
+ stopDppResponder_cb _hidl_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
@@ -215,6 +232,8 @@ private:
const sp<V1_0::ISupplicantStaIfaceCallback>& callback);
SupplicantStatus registerCallbackInternal_1_1(
const sp<V1_1::ISupplicantStaIfaceCallback>& callback);
+ V1_4::SupplicantStatus registerCallbackInternal_1_4(
+ const sp<V1_4::ISupplicantStaIfaceCallback>& callback);
SupplicantStatus reassociateInternal();
SupplicantStatus reconnectInternal();
SupplicantStatus disconnectInternal();
@@ -230,6 +249,8 @@ private:
const std::vector<ISupplicantStaIface::AnqpInfoId>& info_elements,
const std::vector<ISupplicantStaIface::Hs20AnqpSubtypes>&
sub_types);
+ V1_4::SupplicantStatus initiateVenueUrlAnqpQueryInternal(
+ const std::array<uint8_t, 6>& mac_address);
SupplicantStatus initiateHs20IconQueryInternal(
const std::array<uint8_t, 6>& mac_address,
const std::string& file_name);
@@ -282,10 +303,19 @@ private:
SupplicantStatus startDppEnrolleeInitiatorInternal(uint32_t peer_bootstrap_id,
uint32_t own_bootstrap_id);
SupplicantStatus stopDppInitiatorInternal();
- std::pair<SupplicantStatus, ConnectionCapabilities> getConnectionCapabilitiesInternal();
+ std::pair<SupplicantStatus, V1_3::ConnectionCapabilities> getConnectionCapabilitiesInternal();
+ std::pair<V1_4::SupplicantStatus, V1_4::ConnectionCapabilities>
+ getConnectionCapabilitiesInternal_1_4();
std::pair<SupplicantStatus, uint32_t> getWpaDriverCapabilitiesInternal();
SupplicantStatus setMboCellularDataStatusInternal(bool available);
std::pair<SupplicantStatus, uint32_t> getKeyMgmtCapabilitiesInternal_1_3();
+ std::pair<V1_4::SupplicantStatus, uint32_t> getWpaDriverCapabilitiesInternal_1_4();
+ std::pair<V1_4::SupplicantStatus, V1_4::DppResponderBootstrapInfo>
+ generateDppBootstrapInfoForResponderInternal(
+ const std::array<uint8_t, 6>& mac_address, const std::string& device_info,
+ DppCurve curve);
+ V1_4::SupplicantStatus startDppEnrolleeResponderInternal(uint32_t listen_channel);
+ V1_4::SupplicantStatus stopDppResponderInternal(uint32_t own_bootstrap_id);
struct wpa_supplicant* retrieveIfacePtr();
@@ -300,7 +330,7 @@ private:
};
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/sta_network.cpp b/wpa_supplicant/hidl/1.4/sta_network.cpp
index 9716b6ee..ee132ac0 100644
--- a/wpa_supplicant/hidl/1.3/sta_network.cpp
+++ b/wpa_supplicant/hidl/1.4/sta_network.cpp
@@ -22,6 +22,7 @@ using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
using android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
using ISupplicantStaNetworkV1_2 = android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork;
using ISupplicantStaNetworkV1_3 = android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
+using ISupplicantStaNetworkV1_4 = android::hardware::wifi::supplicant::V1_4::ISupplicantStaNetwork;
constexpr uint8_t kZeroBssid[6] = {0, 0, 0, 0, 0, 0};
@@ -60,7 +61,8 @@ constexpr uint32_t kAllowedGroupCipherMask =
static_cast<uint32_t>(
ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) |
static_cast<uint32_t>(ISupplicantStaNetworkV1_2::GroupCipherMask::GCMP_256) |
- static_cast<uint32_t>(ISupplicantStaNetworkV1_3::GroupCipherMask::SMS4));
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_3::GroupCipherMask::SMS4) |
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_4::GroupCipherMask::GCMP_128));
constexpr uint32_t kAllowedPairwisewCipherMask =
(static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::NONE) |
static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::TKIP) |
@@ -68,7 +70,8 @@ constexpr uint32_t kAllowedPairwisewCipherMask =
static_cast<uint32_t>(
ISupplicantStaNetworkV1_2::PairwiseCipherMask::GCMP_256) |
static_cast<uint32_t>(
- ISupplicantStaNetworkV1_3::PairwiseCipherMask::SMS4));
+ ISupplicantStaNetworkV1_3::PairwiseCipherMask::SMS4) |
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_4::PairwiseCipherMask::GCMP_128));
constexpr uint32_t kAllowedGroupMgmtCipherMask =
(static_cast<uint32_t>(
ISupplicantStaNetworkV1_2::GroupMgmtCipherMask::BIP_GMAC_128) |
@@ -104,9 +107,10 @@ namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
using hidl_return_util::validateAndCall;
+using V1_0::SupplicantStatus;
using V1_0::SupplicantStatusCode;
StaNetwork::StaNetwork(
@@ -153,6 +157,15 @@ Return<void> StaNetwork::registerCallback(
&StaNetwork::registerCallbackInternal, _hidl_cb, callback);
}
+Return<void> StaNetwork::registerCallback_1_4(
+ const sp<V1_4::ISupplicantStaNetworkCallback> &callback,
+ registerCallback_1_4_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::registerCallback_1_4Internal, _hidl_cb, callback);
+}
+
Return<void> StaNetwork::setSsid(
const hidl_vec<uint8_t> &ssid, setSsid_cb _hidl_cb)
{
@@ -409,6 +422,13 @@ Return<void> StaNetwork::setWapiCertSuite(
&StaNetwork::setWapiCertSuiteInternal, _hidl_cb, suite);
}
+Return<void> StaNetwork::setEdmg(bool enable, setEdmg_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEdmgInternal, _hidl_cb, enable);
+}
+
Return<void> StaNetwork::getSsid(getSsid_cb _hidl_cb)
{
return validateAndCall(
@@ -637,6 +657,13 @@ Return<void> StaNetwork::getWapiCertSuite(getWapiCertSuite_cb _hidl_cb)
&StaNetwork::getWapiCertSuiteInternal, _hidl_cb);
}
+Return<void> StaNetwork::getEdmg(getEdmg_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEdmgInternal, _hidl_cb);
+}
+
Return<void> StaNetwork::enable(bool no_connect, enable_cb _hidl_cb)
{
return validateAndCall(
@@ -822,7 +849,7 @@ Return<void> StaNetwork::setSaePasswordId(
}
Return<void> StaNetwork::setOcsp(
- OcspType ocspType, setOcsp_cb _hidl_cb) {
+ V1_3::OcspType ocspType, setOcsp_cb _hidl_cb) {
return validateAndCall(
this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&StaNetwork::setOcspInternal, _hidl_cb, ocspType);
@@ -928,6 +955,53 @@ Return<void> StaNetwork::setEapErp(bool enable, setEapErp_cb _hidl_cb)
&StaNetwork::setEapErpInternal, _hidl_cb, enable);
}
+Return<void> StaNetwork::setGroupCipher_1_4(
+ uint32_t group_cipher_mask, setGroupCipher_1_4_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setGroupCipher_1_4Internal, _hidl_cb, group_cipher_mask);
+}
+
+Return<void> StaNetwork::getGroupCipher_1_4(getGroupCipher_1_4_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getGroupCipher_1_4Internal, _hidl_cb);
+}
+
+Return<void> StaNetwork::setPairwiseCipher_1_4(
+ uint32_t pairwise_cipher_mask, setPairwiseCipher_1_4_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setPairwiseCipher_1_4Internal, _hidl_cb,
+ pairwise_cipher_mask);
+}
+
+Return<void> StaNetwork::getPairwiseCipher_1_4(
+ getPairwiseCipher_1_4_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getPairwiseCipher_1_4Internal, _hidl_cb);
+}
+
+Return<void> StaNetwork::setSaeH2eMode(
+ ISupplicantStaNetworkV1_4::SaeH2eMode mode, setSaeH2eMode_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setSaeH2eModeInternal, _hidl_cb, mode);
+}
+
+Return<void> StaNetwork::enableSaePkOnlyMode(bool enable, enableSaePkOnlyMode_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::enableSaePkOnlyModeInternal, _hidl_cb, enable);
+}
+
std::pair<SupplicantStatus, uint32_t> StaNetwork::getIdInternal()
{
return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
@@ -946,12 +1020,18 @@ std::pair<SupplicantStatus, IfaceType> StaNetwork::getTypeInternal()
SupplicantStatus StaNetwork::registerCallbackInternal(
const sp<ISupplicantStaNetworkCallback> &callback)
{
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"};
+}
+
+V1_4::SupplicantStatus StaNetwork::registerCallback_1_4Internal(
+ const sp<V1_4::ISupplicantStaNetworkCallback> &callback)
+{
HidlManager *hidl_manager = HidlManager::getInstance();
if (!hidl_manager || hidl_manager->addStaNetworkCallbackHidlObject(
ifname_, network_id_, callback)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ return {V1_4::SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
- return {SupplicantStatusCode::SUCCESS, ""};
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
}
SupplicantStatus StaNetwork::setSsidInternal(const std::vector<uint8_t> &ssid)
@@ -1028,6 +1108,14 @@ SupplicantStatus StaNetwork::setAuthAlgInternal(uint32_t auth_alg_mask)
return {SupplicantStatusCode::SUCCESS, ""};
}
+V1_4::SupplicantStatus StaNetwork::setEdmgInternal(bool enable)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ wpa_ssid->enable_edmg = enable ? 1 : 0;
+ resetInternalStateAfterParamsUpdate();
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
+}
+
SupplicantStatus StaNetwork::setGroupCipherInternal(uint32_t group_cipher_mask)
{
return {SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"};
@@ -1794,6 +1882,13 @@ std::pair<SupplicantStatus, std::string> StaNetwork::getIdStrInternal()
return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->id_str}};
}
+std::pair<V1_4::SupplicantStatus, bool> StaNetwork::getEdmgInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{V1_4::SupplicantStatusCode::SUCCESS, ""},
+ (wpa_ssid->enable_edmg == 1)};
+}
+
std::pair<SupplicantStatus, std::vector<uint8_t>>
StaNetwork::getWpsNfcConfigurationTokenInternal()
{
@@ -2130,9 +2225,9 @@ std::pair<SupplicantStatus, uint32_t> StaNetwork::getGroupMgmtCipherInternal()
wpa_ssid->group_mgmt_cipher & kAllowedGroupMgmtCipherMask};
}
-SupplicantStatus StaNetwork::setOcspInternal(OcspType ocspType) {
+SupplicantStatus StaNetwork::setOcspInternal(V1_3::OcspType ocspType) {
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (ocspType < OcspType::NONE || ocspType > OcspType::REQUIRE_ALL_CERTS_STATUS) {
+ if (ocspType < V1_3::OcspType::NONE || ocspType > V1_3::OcspType::REQUIRE_ALL_CERTS_STATUS) {
return{ SupplicantStatusCode::FAILURE_ARGS_INVALID, "" };
}
wpa_ssid->eap.cert.ocsp = (int) ocspType;
@@ -2142,11 +2237,11 @@ SupplicantStatus StaNetwork::setOcspInternal(OcspType ocspType) {
return {SupplicantStatusCode::SUCCESS, ""};
}
-std::pair<SupplicantStatus, OcspType> StaNetwork::getOcspInternal()
+std::pair<SupplicantStatus, V1_3::OcspType> StaNetwork::getOcspInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
return {{SupplicantStatusCode::SUCCESS, ""},
- (OcspType) wpa_ssid->eap.cert.ocsp};
+ (V1_3::OcspType) wpa_ssid->eap.cert.ocsp};
}
SupplicantStatus StaNetwork::setPmkCacheInternal(const std::vector<uint8_t>& serializedEntry) {
@@ -2217,41 +2312,62 @@ std::pair<SupplicantStatus, uint32_t> StaNetwork::getProto_1_3Internal()
SupplicantStatus StaNetwork::setGroupCipher_1_3Internal(uint32_t group_cipher_mask)
{
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getGroupCipher_1_3Internal()
+{
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"}, 0};
+}
+
+SupplicantStatus StaNetwork::setPairwiseCipher_1_3Internal(
+ uint32_t pairwise_cipher_mask)
+{
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getPairwiseCipher_1_3Internal()
+{
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"}, 0};
+}
+
+V1_4::SupplicantStatus StaNetwork::setGroupCipher_1_4Internal(uint32_t group_cipher_mask)
+{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (group_cipher_mask & ~kAllowedGroupCipherMask) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ return {V1_4::SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
}
wpa_ssid->group_cipher = group_cipher_mask;
wpa_printf(MSG_MSGDUMP, "group_cipher: 0x%x", wpa_ssid->group_cipher);
resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
}
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getGroupCipher_1_3Internal()
+std::pair<V1_4::SupplicantStatus, uint32_t> StaNetwork::getGroupCipher_1_4Internal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
+ return {{V1_4::SupplicantStatusCode::SUCCESS, ""},
wpa_ssid->group_cipher & kAllowedGroupCipherMask};
}
-SupplicantStatus StaNetwork::setPairwiseCipher_1_3Internal(
+V1_4::SupplicantStatus StaNetwork::setPairwiseCipher_1_4Internal(
uint32_t pairwise_cipher_mask)
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (pairwise_cipher_mask & ~kAllowedPairwisewCipherMask) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ return {V1_4::SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
}
wpa_ssid->pairwise_cipher = pairwise_cipher_mask;
wpa_printf(
MSG_MSGDUMP, "pairwise_cipher: 0x%x", wpa_ssid->pairwise_cipher);
resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
}
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getPairwiseCipher_1_3Internal()
+std::pair<V1_4::SupplicantStatus, uint32_t> StaNetwork::getPairwiseCipher_1_4Internal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
+ return {{V1_4::SupplicantStatusCode::SUCCESS, ""},
wpa_ssid->pairwise_cipher & kAllowedPairwisewCipherMask};
}
@@ -2502,8 +2618,39 @@ SupplicantStatus StaNetwork::setEapErpInternal(bool enable)
#endif /* CONFIG_FILS */
}
+V1_4::SupplicantStatus StaNetwork::setSaeH2eModeInternal(
+ ISupplicantStaNetworkV1_4::SaeH2eMode mode)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ switch (mode) {
+ case ISupplicantStaNetworkV1_4::SaeH2eMode::DISABLED:
+ wpa_s->conf->sae_pwe = 0;
+ break;
+ case ISupplicantStaNetworkV1_4::SaeH2eMode::H2E_MANDATORY:
+ wpa_s->conf->sae_pwe = 1;
+ break;
+ case ISupplicantStaNetworkV1_4::SaeH2eMode::H2E_OPTIONAL:
+ wpa_s->conf->sae_pwe = 2;
+ break;
+ }
+ resetInternalStateAfterParamsUpdate();
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
+}
+
+V1_4::SupplicantStatus StaNetwork::enableSaePkOnlyModeInternal(bool enable)
+{
+#ifdef CONFIG_SAE_PK
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ wpa_ssid->sae_pk = enable ? SAE_PK_MODE_ONLY : SAE_PK_MODE_AUTOMATIC;
+ resetInternalStateAfterParamsUpdate();
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
+#else
+ return {V1_4::SupplicantStatusCode::FAILURE_UNSUPPORTED, ""};
+#endif
+}
+
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/sta_network.h b/wpa_supplicant/hidl/1.4/sta_network.h
index 0057596b..152f00f8 100644
--- a/wpa_supplicant/hidl/1.3/sta_network.h
+++ b/wpa_supplicant/hidl/1.4/sta_network.h
@@ -15,7 +15,7 @@
#include <android-base/macros.h>
-#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaNetwork.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
extern "C"
@@ -34,7 +34,7 @@ namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
using V1_0::ISupplicantStaNetworkCallback;
using V1_2::DppFailureCode;
@@ -45,7 +45,7 @@ using V1_2::DppProgressCode;
* object is used for control operations on a specific network
* controlled by wpa_supplicant.
*/
-class StaNetwork : public V1_3::ISupplicantStaNetwork
+class StaNetwork : public V1_4::ISupplicantStaNetwork
{
public:
StaNetwork(
@@ -62,6 +62,9 @@ public:
Return<void> registerCallback(
const sp<ISupplicantStaNetworkCallback>& callback,
registerCallback_cb _hidl_cb) override;
+ Return<void> registerCallback_1_4(
+ const sp<V1_4::ISupplicantStaNetworkCallback>& callback,
+ registerCallback_1_4_cb _hidl_cb) override;
Return<void> setSsid(
const hidl_vec<uint8_t>& ssid, setSsid_cb _hidl_cb) override;
Return<void> setBssid(
@@ -133,6 +136,7 @@ public:
const hidl_string& id_str, setIdStr_cb _hidl_cb) override;
Return<void> setUpdateIdentifier(
uint32_t id, setUpdateIdentifier_cb _hidl_cb) override;
+ Return<void> setEdmg(bool enable, setEdmg_cb _hidl_cb) override;
Return<void> getSsid(getSsid_cb _hidl_cb) override;
Return<void> getBssid(getBssid_cb _hidl_cb) override;
Return<void> getScanSsid(getScanSsid_cb _hidl_cb) override;
@@ -172,6 +176,7 @@ public:
Return<void> getIdStr(getIdStr_cb _hidl_cb) override;
Return<void> getWpsNfcConfigurationToken(
getWpsNfcConfigurationToken_cb _hidl_cb) override;
+ Return<void> getEdmg(getEdmg_cb _hidl_cb) override;
Return<void> enable(bool no_connect, enable_cb _hidl_cb) override;
Return<void> disable(disable_cb _hidl_cb) override;
Return<void> select(select_cb _hidl_cb) override;
@@ -227,7 +232,7 @@ public:
const hidl_string& sae_password_id,
setSaePasswordId_cb _hidl_cb) override;
Return<void> setOcsp(
- OcspType ocspType, setOcsp_cb _hidl_cb) override;
+ V1_3::OcspType ocspType, setOcsp_cb _hidl_cb) override;
Return<void> getOcsp(
getOcsp_cb _hidl_cb) override;
Return<void> setPmkCache(const hidl_vec<uint8_t>& serializedEntry,
@@ -256,6 +261,19 @@ public:
std::function<void(const SupplicantStatus &status)> _hidl_cb)
override;
Return<void> setEapErp(bool enable, setEapErp_cb _hidl_cb) override;
+ Return<void> setPairwiseCipher_1_4(
+ uint32_t pairwise_cipher_mask,
+ setPairwiseCipher_1_4_cb _hidl_cb) override;
+ Return<void> getPairwiseCipher_1_4(
+ getPairwiseCipher_1_4_cb _hidl_cb) override;
+ Return<void> setGroupCipher_1_4(
+ uint32_t group_cipher_mask,
+ setGroupCipher_1_4_cb _hidl_cb) override;
+ Return<void> getGroupCipher_1_4(
+ getGroupCipher_1_4_cb _hidl_cb) override;
+ Return<void> setSaeH2eMode(V1_4::ISupplicantStaNetwork::SaeH2eMode mode,
+ setSaeH2eMode_cb _hidl_cb) override;
+ Return<void> enableSaePkOnlyMode(bool enable, enableSaePkOnlyMode_cb _hidl_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
@@ -264,6 +282,8 @@ private:
std::pair<SupplicantStatus, IfaceType> getTypeInternal();
SupplicantStatus registerCallbackInternal(
const sp<ISupplicantStaNetworkCallback>& callback);
+ V1_4::SupplicantStatus registerCallback_1_4Internal(
+ const sp<V1_4::ISupplicantStaNetworkCallback>& callback);
SupplicantStatus setSsidInternal(const std::vector<uint8_t>& ssid);
SupplicantStatus setBssidInternal(const std::array<uint8_t, 6>& bssid);
SupplicantStatus setScanSsidInternal(bool enable);
@@ -305,6 +325,7 @@ private:
SupplicantStatus setProactiveKeyCachingInternal(bool enable);
SupplicantStatus setIdStrInternal(const std::string& id_str);
SupplicantStatus setUpdateIdentifierInternal(uint32_t id);
+ V1_4::SupplicantStatus setEdmgInternal(bool enable);
std::pair<SupplicantStatus, std::vector<uint8_t>> getSsidInternal();
std::pair<SupplicantStatus, std::array<uint8_t, 6>> getBssidInternal();
std::pair<SupplicantStatus, bool> getScanSsidInternal();
@@ -345,6 +366,7 @@ private:
std::pair<SupplicantStatus, std::string> getIdStrInternal();
std::pair<SupplicantStatus, std::vector<uint8_t>>
getWpsNfcConfigurationTokenInternal();
+ std::pair<V1_4::SupplicantStatus, bool> getEdmgInternal();
SupplicantStatus enableInternal(bool no_connect);
SupplicantStatus disableInternal();
SupplicantStatus selectInternal();
@@ -372,8 +394,8 @@ private:
const std::string& sae_password_id);
SupplicantStatus setGroupMgmtCipherInternal(uint32_t group_mgmt_cipher_mask);
std::pair<SupplicantStatus, uint32_t> getGroupMgmtCipherInternal();
- SupplicantStatus setOcspInternal(OcspType ocspType);
- std::pair<SupplicantStatus, OcspType> getOcspInternal();
+ SupplicantStatus setOcspInternal(V1_3::OcspType ocspType);
+ std::pair<SupplicantStatus, V1_3::OcspType> getOcspInternal();
SupplicantStatus setPmkCacheInternal(const std::vector<uint8_t>& serialziedEntry);
SupplicantStatus setWapiCertSuiteInternal(const std::string& suite);
std::pair<SupplicantStatus, std::string> getWapiCertSuiteInternal();
@@ -388,6 +410,13 @@ private:
uint32_t pairwise_cipher_mask);
SupplicantStatus setWapiPskInternal(const std::vector<uint8_t>& psk);
std::pair<SupplicantStatus, std::vector<uint8_t>> getWapiPskInternal();
+ std::pair<V1_4::SupplicantStatus, uint32_t> getGroupCipher_1_4Internal();
+ V1_4::SupplicantStatus setGroupCipher_1_4Internal(uint32_t group_cipher_mask);
+ std::pair<V1_4::SupplicantStatus, uint32_t> getPairwiseCipher_1_4Internal();
+ V1_4::SupplicantStatus setPairwiseCipher_1_4Internal(
+ uint32_t pairwise_cipher_mask);
+ V1_4::SupplicantStatus setSaeH2eModeInternal(V1_4::ISupplicantStaNetwork::SaeH2eMode mode);
+ V1_4::SupplicantStatus enableSaePkOnlyModeInternal(bool enable);
struct wpa_ssid* retrieveNetworkPtr();
struct wpa_supplicant* retrieveIfacePtr();
@@ -427,7 +456,7 @@ private:
};
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/supplicant.cpp b/wpa_supplicant/hidl/1.4/supplicant.cpp
index 50d23436..6f4cde69 100644
--- a/wpa_supplicant/hidl/1.3/supplicant.cpp
+++ b/wpa_supplicant/hidl/1.4/supplicant.cpp
@@ -10,6 +10,7 @@
#include "hidl_manager.h"
#include "hidl_return_util.h"
#include "supplicant.h"
+#include "p2p_iface.h"
#include <android-base/file.h>
#include <fcntl.h>
@@ -156,7 +157,7 @@ namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
using hidl_return_util::validateAndCall;
using V1_0::SupplicantStatusCode;
@@ -254,6 +255,39 @@ Return<void> Supplicant::terminate()
}
std::pair<SupplicantStatus, sp<ISupplicantIface>>
+Supplicant::addP2pDevInterface(struct wpa_interface iface_params)
+{
+ char primary_ifname[IFNAMSIZ];
+ u32 primary_ifname_len =
+ strlen(iface_params.ifname) - strlen(P2P_MGMT_DEVICE_PREFIX);
+
+ if(primary_ifname_len > IFNAMSIZ) {
+ wpa_printf(MSG_DEBUG, "%s, Invalid primary iface name ", __FUNCTION__);
+ return {{SupplicantStatusCode::FAILURE_ARGS_INVALID, ""}, {}};
+ }
+
+ strncpy(primary_ifname, iface_params.ifname +
+ strlen(P2P_MGMT_DEVICE_PREFIX), primary_ifname_len);
+ wpa_printf(MSG_DEBUG, "%s, Initialize p2p-dev-wlan0 iface with"
+ "primary_iface = %s", __FUNCTION__, primary_ifname);
+ struct wpa_supplicant* wpa_s =
+ wpa_supplicant_get_iface(wpa_global_, primary_ifname);
+ if (!wpa_s) {
+ wpa_printf(MSG_DEBUG, "%s,NULL wpa_s for wlan0", __FUNCTION__);
+ return {{SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""},
+ nullptr};
+ }
+ if (wpas_p2p_add_p2pdev_interface(
+ wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
+ wpa_printf(MSG_INFO,
+ "Failed to enable P2P Device");
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN,
+ "Enable P2P Device failed"}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS,""}, {}};
+}
+
+std::pair<SupplicantStatus, sp<ISupplicantIface>>
Supplicant::addInterfaceInternal(const IfaceInfo& iface_info)
{
android::sp<ISupplicantIface> iface;
@@ -305,10 +339,19 @@ Supplicant::addInterfaceInternal(const IfaceInfo& iface_info)
}
}
iface_params.ifname = iface_info.name.c_str();
- struct wpa_supplicant* wpa_s =
- wpa_supplicant_add_iface(wpa_global_, &iface_params, NULL);
- if (!wpa_s) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ if (strncmp(iface_params.ifname, P2P_MGMT_DEVICE_PREFIX,
+ strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
+ std::tie(status, iface) = addP2pDevInterface(iface_params);
+ if (status.code != SupplicantStatusCode::SUCCESS) {
+ return {{status.code,
+ status.debugMessage.c_str()}, iface};
+ }
+ } else {
+ struct wpa_supplicant* wpa_s =
+ wpa_supplicant_add_iface(wpa_global_, &iface_params, NULL);
+ if (!wpa_s) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
}
// The supplicant core creates a corresponding hidl object via
// HidlManager when |wpa_supplicant_add_iface| is called.
@@ -417,7 +460,7 @@ SupplicantStatus Supplicant::setConcurrencyPriorityInternal(IfaceType type)
return SupplicantStatus{SupplicantStatusCode::SUCCESS, ""};
}
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/supplicant.h b/wpa_supplicant/hidl/1.4/supplicant.h
index 0c0ac726..2944c50b 100644
--- a/wpa_supplicant/hidl/1.3/supplicant.h
+++ b/wpa_supplicant/hidl/1.4/supplicant.h
@@ -13,7 +13,7 @@
#include <android/hardware/wifi/supplicant/1.0/ISupplicantCallback.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantIface.h>
#include <android/hardware/wifi/supplicant/1.0/types.h>
-#include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicant.h>
#include <android-base/macros.h>
#include <hidl/Status.h>
@@ -29,7 +29,7 @@ namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
using V1_0::ISupplicantCallback;
using V1_0::ISupplicantIface;
@@ -39,7 +39,7 @@ using V1_0::ISupplicantIface;
* object is used core for global control operations on
* wpa_supplicant.
*/
-class Supplicant : public V1_3::ISupplicant
+class Supplicant : public V1_4::ISupplicant
{
public:
Supplicant(struct wpa_global* global);
@@ -81,6 +81,8 @@ private:
SupplicantStatus setDebugParamsInternal(
ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys);
SupplicantStatus setConcurrencyPriorityInternal(IfaceType type);
+ std::pair<SupplicantStatus, sp<ISupplicantIface>> addP2pDevInterface(
+ struct wpa_interface iface_params);
// Raw pointer to the global structure maintained by the core.
struct wpa_global* wpa_global_;
@@ -93,7 +95,7 @@ private:
};
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index ce5608e0..eaf0803d 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -22,7 +22,7 @@
#include "scan.h"
#include "notify.h"
#include "bss.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
#include "gas_query.h"
#include "interworking.h"
#include "hs20_supplicant.h"
@@ -73,7 +73,12 @@ void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s)
const u8 *ext_capa;
u32 filter = 0;
- if (!bss || !is_hs20_network(wpa_s, wpa_s->current_ssid, bss)) {
+ if (!bss || !is_hs20_network(wpa_s, wpa_s->current_ssid, bss)
+#ifndef ANDROID
+ // HS 2.0 Configuration is not used in AOSP
+ || !is_hs20_config(wpa_s)
+#endif
+ ) {
wpa_printf(MSG_DEBUG,
"Not configuring frame filtering - BSS " MACSTR
" is not a Hotspot 2.0 network", MAC2STR(bssid));
@@ -158,11 +163,15 @@ int get_hs20_version(struct wpa_bss *bss)
return ((ie[6] >> 4) & 0x0f) + 1;
}
+int is_hs20_config(struct wpa_supplicant *wpa_s)
+{
+ return wpa_s->conf->hs20;
+}
int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss)
{
- if (!wpa_s->conf->hs20 || !ssid)
+ if (!ssid)
return 0;
if (ssid->parent_cred)
@@ -906,14 +915,25 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
/* OSU Friendly Name Duples */
while (pos - pos2 >= 4 && prov->friendly_name_count < OSU_MAX_ITEMS) {
struct osu_lang_string *f;
- if (1 + pos2[0] > pos - pos2 || pos2[0] < 3) {
+ u8 slen;
+
+ slen = pos2[0];
+ if (1 + slen > pos - pos2) {
wpa_printf(MSG_DEBUG, "Invalid OSU Friendly Name");
break;
}
+ if (slen < 3) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid OSU Friendly Name (no room for language)");
+ break;
+ }
f = &prov->friendly_name[prov->friendly_name_count++];
- os_memcpy(f->lang, pos2 + 1, 3);
- os_memcpy(f->text, pos2 + 1 + 3, pos2[0] - 3);
- pos2 += 1 + pos2[0];
+ pos2++;
+ os_memcpy(f->lang, pos2, 3);
+ pos2 += 3;
+ slen -= 3;
+ os_memcpy(f->text, pos2, slen);
+ pos2 += slen;
}
/* OSU Server URI */
@@ -1295,8 +1315,8 @@ void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
wpas_notify_hs20_rx_deauth_imminent_notice(wpa_s, code, reauth_delay, url);
if (code == HS20_DEAUTH_REASON_CODE_BSS) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Add BSS to blacklist");
- wpa_blacklist_add(wpa_s, wpa_s->bssid);
+ wpa_printf(MSG_DEBUG, "HS 2.0: Add BSS to ignore list");
+ wpa_bssid_ignore_add(wpa_s, wpa_s->bssid);
/* TODO: For now, disable full ESS since some drivers may not
* support disabling per BSS. */
if (wpa_s->current_ssid) {
@@ -1335,6 +1355,7 @@ void hs20_rx_t_c_acceptance(struct wpa_supplicant *wpa_s, const char *url)
}
wpa_msg(wpa_s, MSG_INFO, HS20_T_C_ACCEPTANCE "%s", url);
+ wpas_notify_hs20_rx_terms_and_conditions_acceptance(wpa_s, url);
}
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
index e43414bc..2d478f4f 100644
--- a/wpa_supplicant/hs20_supplicant.h
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -22,6 +22,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, const u8 *sa,
const u8 *data, size_t slen, u8 dialog_token);
int get_hs20_version(struct wpa_bss *bss);
+int is_hs20_config(struct wpa_supplicant *wpa_s);
int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss);
int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index b60f80d7..b93f2a33 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -959,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;
@@ -2480,7 +2482,7 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
bss_load = cred_over_max_bss_load(wpa_s, cred, bss);
conn_capab = cred_conn_capab_missing(wpa_s, cred, bss);
wpa_msg(wpa_s, MSG_INFO, "%s" MACSTR " type=%s%s%s%s id=%d priority=%d sp_priority=%d",
- excluded ? INTERWORKING_BLACKLISTED : INTERWORKING_AP,
+ excluded ? INTERWORKING_EXCLUDED : INTERWORKING_AP,
MAC2STR(bss->bssid), type,
bh ? " below_min_backhaul=1" : "",
bss_load ? " over_max_bss_load=1" : "",
@@ -2530,7 +2532,7 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
(selected_cred == NULL ||
cred_prio_cmp(selected_home_cred, selected_cred) >= 0)) {
/* Prefer network operated by the Home SP */
- wpa_printf(MSG_DEBUG, "Interworking: Overrided selected with selected_home");
+ wpa_printf(MSG_DEBUG, "Interworking: Overrode selected with selected_home");
selected = selected_home;
selected_cred = selected_home_cred;
}
@@ -2748,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)",
@@ -2787,6 +2789,14 @@ 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));
+ wpabuf_free(extra_buf);
+ return -1;
+ }
+
mbo = mbo_build_anqp_buf(wpa_s, bss, mbo_subtypes);
if (mbo) {
if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) {
@@ -2822,7 +2832,7 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
static void anqp_add_extra(struct wpa_supplicant *wpa_s,
struct wpa_bss_anqp *anqp, u16 info_id,
- const u8 *data, size_t slen)
+ const u8 *data, size_t slen, bool protected_response)
{
struct wpa_bss_anqp_elem *tmp, *elem = NULL;
@@ -2847,6 +2857,7 @@ static void anqp_add_extra(struct wpa_supplicant *wpa_s,
wpabuf_free(elem->payload);
}
+ elem->protected_response = protected_response;
elem->payload = wpabuf_alloc_copy(data, slen);
if (!elem->payload) {
dl_list_del(&elem->list);
@@ -2889,6 +2900,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
const u8 *pos = data;
struct wpa_bss_anqp *anqp = NULL;
u8 type;
+ bool protected_response;
if (bss)
anqp = bss->anqp;
@@ -2989,9 +3001,11 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
case ANQP_VENUE_URL:
wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Venue URL",
MAC2STR(sa));
- anqp_add_extra(wpa_s, anqp, info_id, pos, slen);
+ protected_response = pmf_in_use(wpa_s, sa);
+ anqp_add_extra(wpa_s, anqp, info_id, pos, slen,
+ protected_response);
- if (!pmf_in_use(wpa_s, sa)) {
+ if (!protected_response) {
wpa_printf(MSG_DEBUG,
"ANQP: Ignore Venue URL since PMF was not enabled");
break;
@@ -3043,7 +3057,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
default:
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Unsupported ANQP Info ID %u", info_id);
- anqp_add_extra(wpa_s, anqp, info_id, data, slen);
+ anqp_add_extra(wpa_s, anqp, info_id, data, slen,
+ pmf_in_use(wpa_s, sa));
break;
}
}
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index 37ee2e90..77b2c91b 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 c085466b..901b49b4 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -13,6 +13,7 @@
#include "utils/uuid.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "common/hw_features_common.h"
#include "ap/sta_info.h"
#include "ap/hostapd.h"
#include "ap/ieee802_11.h"
@@ -27,22 +28,30 @@
#include "mesh.h"
-static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s)
+static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s,
+ bool also_clear_hostapd)
{
- wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
- wpa_s->ifmsh = NULL;
- wpa_s->current_ssid = NULL;
+ wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh,
+ also_clear_hostapd);
+
+ if (also_clear_hostapd) {
+ wpa_s->ifmsh = NULL;
+ wpa_s->current_ssid = NULL;
+ os_free(wpa_s->mesh_params);
+ wpa_s->mesh_params = NULL;
+ }
+
os_free(wpa_s->mesh_rsn);
wpa_s->mesh_rsn = NULL;
- os_free(wpa_s->mesh_params);
- wpa_s->mesh_params = NULL;
- /* TODO: leave mesh (stop beacon). This will happen on link down
- * anyway, so it's not urgent */
+
+ if (!also_clear_hostapd)
+ wpa_supplicant_leave_mesh(wpa_s, false);
}
void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
- struct hostapd_iface *ifmsh)
+ struct hostapd_iface *ifmsh,
+ bool also_clear_hostapd)
{
if (!ifmsh)
return;
@@ -63,8 +72,10 @@ void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
}
/* take care of shared data */
- hostapd_interface_deinit(ifmsh);
- hostapd_interface_free(ifmsh);
+ if (also_clear_hostapd) {
+ hostapd_interface_deinit(ifmsh);
+ hostapd_interface_free(ifmsh);
+ }
}
@@ -194,6 +205,40 @@ static int wpas_mesh_init_rsn(struct wpa_supplicant *wpa_s)
}
+static int wpas_mesh_update_freq_params(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_driver_mesh_join_params *params = wpa_s->mesh_params;
+ struct hostapd_iface *ifmsh = wpa_s->ifmsh;
+ struct he_capabilities *he_capab = NULL;
+
+ if (ifmsh->current_mode)
+ he_capab = &ifmsh->current_mode->he_capab[IEEE80211_MODE_MESH];
+
+ if (hostapd_set_freq_params(
+ &params->freq,
+ ifmsh->conf->hw_mode,
+ ifmsh->freq,
+ ifmsh->conf->channel,
+ ifmsh->conf->enable_edmg,
+ ifmsh->conf->edmg_channel,
+ ifmsh->conf->ieee80211n,
+ ifmsh->conf->ieee80211ac,
+ ifmsh->conf->ieee80211ax,
+ ifmsh->conf->secondary_channel,
+ hostapd_get_oper_chwidth(ifmsh->conf),
+ hostapd_get_oper_centr_freq_seg0_idx(ifmsh->conf),
+ hostapd_get_oper_centr_freq_seg1_idx(ifmsh->conf),
+ ifmsh->conf->vht_capab,
+ he_capab)) {
+ wpa_printf(MSG_ERROR, "Error updating mesh frequency params");
+ wpa_supplicant_mesh_deinit(wpa_s, true);
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int wpas_mesh_complete(struct wpa_supplicant *wpa_s)
{
struct hostapd_iface *ifmsh = wpa_s->ifmsh;
@@ -207,12 +252,22 @@ static int wpas_mesh_complete(struct wpa_supplicant *wpa_s)
return -1;
}
+ /*
+ * Update channel configuration if the channel has changed since the
+ * initial setting, i.e., due to DFS radar detection during CAC.
+ */
+ if (ifmsh->freq > 0 && ifmsh->freq != params->freq.freq) {
+ wpa_s->assoc_freq = ifmsh->freq;
+ ssid->frequency = ifmsh->freq;
+ if (wpas_mesh_update_freq_params(wpa_s) < 0)
+ return -1;
+ }
+
if (ifmsh->mconf->security != MESH_CONF_SEC_NONE &&
wpas_mesh_init_rsn(wpa_s)) {
wpa_printf(MSG_ERROR,
"mesh: RSN initialization failed - deinit mesh");
- wpa_supplicant_mesh_deinit(wpa_s);
- wpa_drv_leave_mesh(wpa_s);
+ wpa_supplicant_mesh_deinit(wpa_s, false);
return -1;
}
@@ -237,13 +292,90 @@ static int wpas_mesh_complete(struct wpa_supplicant *wpa_s)
/* hostapd sets the interface down until we associate */
wpa_drv_set_operstate(wpa_s, 1);
- if (!ret)
+ if (!ret) {
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+ wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+ ssid->id);
+ wpas_notify_mesh_group_started(wpa_s, ssid);
+ }
+
return ret;
}
+static void wpas_mesh_complete_cb(void *arg)
+{
+ struct wpa_supplicant *wpa_s = arg;
+
+ wpas_mesh_complete(wpa_s);
+}
+
+
+static int wpa_supplicant_mesh_enable_iface_cb(struct hostapd_iface *ifmsh)
+{
+ struct wpa_supplicant *wpa_s = ifmsh->owner;
+ struct hostapd_data *bss;
+
+ ifmsh->mconf = mesh_config_create(wpa_s, wpa_s->current_ssid);
+
+ bss = ifmsh->bss[0];
+ bss->msg_ctx = wpa_s;
+ os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
+ bss->driver = wpa_s->driver;
+ bss->drv_priv = wpa_s->drv_priv;
+ bss->iface = ifmsh;
+ bss->mesh_sta_free_cb = mesh_mpm_free_sta;
+ bss->setup_complete_cb = wpas_mesh_complete_cb;
+ bss->setup_complete_cb_ctx = wpa_s;
+
+ bss->conf->start_disabled = 1;
+ bss->conf->mesh = MESH_ENABLED;
+ bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
+
+ if (wpa_drv_init_mesh(wpa_s)) {
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
+ return -1;
+ }
+
+ if (hostapd_setup_interface(ifmsh)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize hostapd interface for mesh");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_supplicant_mesh_disable_iface_cb(struct hostapd_iface *ifmsh)
+{
+ struct wpa_supplicant *wpa_s = ifmsh->owner;
+ size_t j;
+
+ wpa_supplicant_mesh_deinit(wpa_s, false);
+
+#ifdef NEED_AP_MLME
+ for (j = 0; j < ifmsh->num_bss; j++)
+ hostapd_cleanup_cs_params(ifmsh->bss[j]);
+#endif /* NEED_AP_MLME */
+
+ /* Same as hostapd_interface_deinit() without deinitializing control
+ * interface */
+ for (j = 0; j < ifmsh->num_bss; j++) {
+ struct hostapd_data *hapd = ifmsh->bss[j];
+
+ hostapd_bss_deinit_no_free(hapd);
+ hostapd_free_hapd_data(hapd);
+ }
+
+ hostapd_cleanup_iface_partial(ifmsh);
+
+ return 0;
+}
+
+
static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct hostapd_freq_params *freq)
@@ -267,9 +399,12 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
if (!ifmsh)
return -ENOMEM;
+ ifmsh->owner = wpa_s;
ifmsh->drv_flags = wpa_s->drv_flags;
ifmsh->drv_flags2 = wpa_s->drv_flags2;
ifmsh->num_bss = 1;
+ ifmsh->enable_iface_cb = wpa_supplicant_mesh_enable_iface_cb;
+ ifmsh->disable_iface_cb = wpa_supplicant_mesh_disable_iface_cb;
ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
sizeof(struct hostapd_data *));
if (!ifmsh->bss)
@@ -285,11 +420,14 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
bss->drv_priv = wpa_s->drv_priv;
bss->iface = ifmsh;
bss->mesh_sta_free_cb = mesh_mpm_free_sta;
+ bss->setup_complete_cb = wpas_mesh_complete_cb;
+ bss->setup_complete_cb_ctx = wpa_s;
frequency = ssid->frequency;
if (frequency != freq->freq &&
frequency == freq->freq + freq->sec_channel_offset * 20) {
wpa_printf(MSG_DEBUG, "mesh: pri/sec channels switched");
frequency = freq->freq;
+ ssid->frequency = frequency;
}
wpa_s->assoc_freq = frequency;
wpa_s->current_ssid = ssid;
@@ -311,6 +449,7 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
conf->country[0] = wpa_s->conf->country[0];
conf->country[1] = wpa_s->conf->country[1];
conf->country[2] = ' ';
+ wpa_s->mesh_params->handle_dfs = true;
}
bss->iconf = conf;
@@ -333,30 +472,6 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
frequency);
goto out_free;
}
- if (ssid->ht40)
- conf->secondary_channel = ssid->ht40;
- if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && ssid->vht) {
- if (ssid->max_oper_chwidth != DEFAULT_MAX_OPER_CHWIDTH)
- conf->vht_oper_chwidth = ssid->max_oper_chwidth;
- switch (conf->vht_oper_chwidth) {
- case CHANWIDTH_80MHZ:
- case CHANWIDTH_80P80MHZ:
- ieee80211_freq_to_chan(
- frequency,
- &conf->vht_oper_centr_freq_seg0_idx);
- conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
- break;
- case CHANWIDTH_160MHZ:
- ieee80211_freq_to_chan(
- frequency,
- &conf->vht_oper_centr_freq_seg0_idx);
- conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
- conf->vht_oper_centr_freq_seg0_idx += 40 / 5;
- break;
- }
- ieee80211_freq_to_chan(ssid->vht_center_freq2,
- &conf->vht_oper_centr_freq_seg1_idx);
- }
if (ssid->mesh_basic_rates == NULL) {
/*
@@ -387,6 +502,31 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
conf->basic_rates[rate_len] = -1;
}
+ /* While it can enhance performance to switch the primary channel, which
+ * is also the secondary channel of another network at the same time),
+ * to the other primary channel, problems exist with this in mesh
+ * networks.
+ *
+ * Example with problems:
+ * - 3 mesh nodes M1-M3, freq (5200, 5180)
+ * - other node O1, e.g. AP mode, freq (5180, 5200),
+ * Locations: O1 M1 M2 M3
+ *
+ * M3 can only send frames to M1 over M2, no direct connection is
+ * possible
+ * Start O1, M1 and M3 first, M1 or O1 will switch channels to align
+ * with* each other. M3 does not swap, because M1 or O1 cannot be
+ * reached. M2 is started afterwards and can either connect to M3 or M1
+ * because of this primary secondary channel switch.
+ *
+ * Solutions: (1) central coordination -> not always possible
+ * (2) disable pri/sec channel switch in mesh networks
+ *
+ * In AP mode, when all nodes can work independently, this poses of
+ * course no problem, therefore disable it only in mesh mode. */
+ conf->no_pri_sec_switch = 1;
+ wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+
if (wpa_drv_init_mesh(wpa_s)) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
return -1;
@@ -398,11 +538,9 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
return -1;
}
- wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
-
return 0;
out_free:
- wpa_supplicant_mesh_deinit(wpa_s);
+ wpa_supplicant_mesh_deinit(wpa_s, true);
return -ENOMEM;
}
@@ -450,7 +588,7 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
goto out;
}
- wpa_supplicant_mesh_deinit(wpa_s);
+ wpa_supplicant_mesh_deinit(wpa_s, true);
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
wpa_s->group_cipher = WPA_CIPHER_NONE;
@@ -521,25 +659,25 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
wpa_s->mesh_params = params;
if (wpa_supplicant_mesh_init(wpa_s, ssid, &params->freq)) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
- wpa_drv_leave_mesh(wpa_s);
+ wpa_supplicant_leave_mesh(wpa_s, true);
ret = -1;
goto out;
}
- ret = wpas_mesh_complete(wpa_s);
out:
return ret;
}
-int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s)
+int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s, bool need_deinit)
{
int ret = 0;
wpa_msg(wpa_s, MSG_INFO, "leaving mesh");
/* Need to send peering close messages first */
- wpa_supplicant_mesh_deinit(wpa_s);
+ if (need_deinit)
+ wpa_supplicant_mesh_deinit(wpa_s, true);
ret = wpa_drv_leave_mesh(wpa_s);
if (ret)
diff --git a/wpa_supplicant/mesh.h b/wpa_supplicant/mesh.h
index 7317083c..a429e5e2 100644
--- a/wpa_supplicant/mesh.h
+++ b/wpa_supplicant/mesh.h
@@ -11,9 +11,11 @@
int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
-int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s,
+ bool need_deinit);
void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
- struct hostapd_iface *ifmsh);
+ struct hostapd_iface *ifmsh,
+ bool also_clear_hostapd);
int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
char *end);
int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 12aafcb9..b6a5e885 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -533,11 +533,14 @@ 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,
MAC2STR(sta->addr));
eloop_cancel_timeout(plink_timer, wpa_s, sta);
+ eloop_cancel_timeout(mesh_auth_timer, wpa_s, sta);
return 0;
}
@@ -1290,8 +1293,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 f19bfbfc..834c7a1c 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -195,7 +195,8 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX IGTK",
rsn->igtk, rsn->igtk_len);
wpa_drv_set_key(rsn->wpa_s,
- wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL,
+ wpa_cipher_to_alg(rsn->mgmt_group_cipher),
+ broadcast_ether_addr,
rsn->igtk_key_id, 1,
seq, sizeof(seq), rsn->igtk, rsn->igtk_len,
KEY_FLAG_GROUP_TX_DEFAULT);
@@ -204,7 +205,8 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
/* group privacy / data frames */
wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK",
rsn->mgtk, rsn->mgtk_len);
- wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL,
+ wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher),
+ broadcast_ether_addr,
rsn->mgtk_key_id, 1, seq, sizeof(seq),
rsn->mgtk, rsn->mgtk_len, KEY_FLAG_GROUP_TX_DEFAULT);
diff --git a/wpa_supplicant/nmake.mak b/wpa_supplicant/nmake.mak
index 80e0ac88..617df036 100644
--- a/wpa_supplicant/nmake.mak
+++ b/wpa_supplicant/nmake.mak
@@ -114,7 +114,7 @@ OBJS = \
$(OBJDIR)\driver_ndis_.obj \
$(OBJDIR)\scan_helpers.obj \
$(OBJDIR)\events.obj \
- $(OBJDIR)\blacklist.obj \
+ $(OBJDIR)\bssid_ignore.obj \
$(OBJDIR)\scan.obj \
$(OBJDIR)\wpas_glue.obj \
$(OBJDIR)\eap_register.obj \
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 16e747f4..5508f168 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -149,14 +149,15 @@ void wpas_notify_auth_status_code(struct wpa_supplicant *wpa_s)
void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s,
- const u8 *bssid, u8 timed_out)
+ const u8 *bssid, u8 timed_out,
+ const u8 *assoc_resp_ie, size_t assoc_resp_ie_len)
{
if (wpa_s->p2p_mgmt)
return;
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ASSOC_STATUS_CODE);
- wpas_hidl_notify_assoc_reject(wpa_s, bssid, timed_out);
+ wpas_hidl_notify_assoc_reject(wpa_s, bssid, timed_out, assoc_resp_ie, assoc_resp_ie_len);
}
void wpas_notify_auth_timeout(struct wpa_supplicant *wpa_s) {
@@ -427,6 +428,11 @@ void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
wpas_notify_persistent_group_removed(wpa_s, ssid);
wpas_p2p_network_removed(wpa_s, ssid);
+
+#ifdef CONFIG_PASN
+ if (wpa_s->pasn.ssid == ssid)
+ wpa_s->pasn.ssid = NULL;
+#endif /* CONFIG_PASN */
}
@@ -641,6 +647,7 @@ void wpas_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s)
void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
const u8 *addr, const struct p2p_peer_info *info,
const u8* peer_wfd_device_info, u8 peer_wfd_device_info_len,
+ const u8* peer_wfd_r2_device_info, u8 peer_wfd_r2_device_info_len,
int new_device)
{
if (new_device) {
@@ -653,7 +660,9 @@ void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
wpas_hidl_notify_p2p_device_found(wpa_s, addr, info,
peer_wfd_device_info,
- peer_wfd_device_info_len);
+ peer_wfd_device_info_len,
+ peer_wfd_r2_device_info,
+ peer_wfd_r2_device_info_len);
}
@@ -1007,14 +1016,23 @@ void wpas_notify_hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s,
const char *url)
{
#ifdef CONFIG_HS20
- if (!wpa_s || !url)
+ if (!wpa_s)
return;
wpas_hidl_notify_hs20_rx_deauth_imminent_notice(wpa_s, code, reauth_delay,
- url);
+ url);
#endif /* CONFIG_HS20 */
}
+void wpas_notify_hs20_rx_terms_and_conditions_acceptance(
+ struct wpa_supplicant *wpa_s, const char *url) {
+#ifdef CONFIG_HS20
+ if (!wpa_s || !url)
+ return;
+
+ wpas_hidl_notify_hs20_rx_terms_and_conditions_acceptance(wpa_s, url);
+#endif /* CONFIG_HS20 */
+}
#ifdef CONFIG_MESH
@@ -1208,3 +1226,24 @@ void wpas_notify_pmk_cache_added(struct wpa_supplicant *wpa_s,
wpas_hidl_notify_pmk_cache_added(wpa_s, entry);
}
+
+void wpas_notify_transition_disable(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ u8 bitmap)
+{
+ if (!wpa_s)
+ return;
+
+ if (!ssid)
+ return;
+
+ wpas_hidl_notify_transition_disable(wpa_s, ssid, bitmap);
+}
+
+void wpas_notify_network_not_found(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_network_not_found(wpa_s);
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 0e7991bd..706573c9 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -28,8 +28,8 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
enum wpa_states old_state);
void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
void wpas_notify_auth_status_code(struct wpa_supplicant *wpa_s);
-void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s,
- const u8 *bssid, u8 timed_out);
+void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s, const u8 *bssid, u8 timed_out,
+ const u8 *assoc_resp_ie, size_t assoc_resp_ie_len);
void wpas_notify_auth_timeout(struct wpa_supplicant *wpa_s);
void wpas_notify_roam_time(struct wpa_supplicant *wpa_s);
void wpas_notify_roam_complete(struct wpa_supplicant *wpa_s);
@@ -101,6 +101,7 @@ void wpas_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s);
void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
const u8 *addr, const struct p2p_peer_info *info,
const u8* peer_wfd_device_info, u8 peer_wfd_device_info_len,
+ const u8* peer_wfd_r2_device_info, u8 peer_wfd_r2_device_info_len,
int new_device);
void wpas_notify_p2p_device_lost(struct wpa_supplicant *wpa_s,
const u8 *dev_addr);
@@ -175,6 +176,8 @@ void wpas_notify_hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s,
void wpas_notify_hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s,
u8 code, u16 reauth_delay,
const char *url);
+void wpas_notify_hs20_rx_terms_and_conditions_acceptance(
+ struct wpa_supplicant *wpa_s, const char *url);
void wpas_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_notify_dpp_config_sent(struct wpa_supplicant *wpa_s);
@@ -194,5 +197,9 @@ void wpas_notify_dpp_config_accepted(struct wpa_supplicant *wpa_s);
void wpas_notify_dpp_config_rejected(struct wpa_supplicant *wpa_s);
void wpas_notify_pmk_cache_added(struct wpa_supplicant *wpa_s,
struct rsn_pmksa_cache_entry *entry);
+void wpas_notify_transition_disable(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ u8 bitmap);
+void wpas_notify_network_not_found(struct wpa_supplicant *wpa_s);
#endif /* NOTIFY_H */
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index bd97fee5..a0ad0c2f 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -22,10 +22,10 @@ static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode,
unsigned int *flags)
{
int i;
- int is_6ghz = op_class >= 131 && op_class <= 136;
+ bool is_6ghz = op_class >= 131 && op_class <= 136;
for (i = 0; i < mode->num_channels; i++) {
- int chan_is_6ghz;
+ bool chan_is_6ghz;
chan_is_6ghz = mode->channels[i].freq >= 5935 &&
mode->channels[i].freq <= 7115;
@@ -47,15 +47,15 @@ static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode,
}
-static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel,
+ const u8 *center_channels, size_t num_chan)
{
- u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
size_t i;
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
- for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
+ for (i = 0; i < num_chan; i++) {
/*
* In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
* so the center channel is 6 channels away from the start/end.
@@ -75,8 +75,22 @@ static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode,
u8 center_chan;
unsigned int i;
unsigned int no_ir = 0;
+ const u8 *center_channels;
+ size_t num_chan;
+ const u8 center_channels_5ghz[] = { 42, 58, 106, 122, 138, 155, 171 };
+ const u8 center_channels_6ghz[] = { 7, 23, 39, 55, 71, 87, 103, 119,
+ 135, 151, 167, 183, 199, 215 };
+
+ if (is_6ghz_op_class(op_class)) {
+ center_channels = center_channels_6ghz;
+ num_chan = ARRAY_SIZE(center_channels_6ghz);
+ } else {
+ center_channels = center_channels_5ghz;
+ num_chan = ARRAY_SIZE(center_channels_5ghz);
+ }
- center_chan = get_center_80mhz(mode, channel);
+ center_chan = get_center_80mhz(mode, channel, center_channels,
+ num_chan);
if (!center_chan)
return NOT_ALLOWED;
@@ -106,15 +120,15 @@ static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode,
}
-static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
+static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel,
+ const u8 *center_channels, size_t num_chan)
{
- u8 center_channels[] = { 50, 114 };
unsigned int i;
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
- for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
+ for (i = 0; i < num_chan; i++) {
/*
* In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
* so the center channel is 14 channels away from the start/end.
@@ -134,8 +148,21 @@ static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
u8 center_chan;
unsigned int i;
unsigned int no_ir = 0;
+ const u8 *center_channels;
+ size_t num_chan;
+ const u8 center_channels_5ghz[] = { 50, 114, 163 };
+ const u8 center_channels_6ghz[] = { 15, 47, 79, 111, 143, 175, 207 };
+
+ if (is_6ghz_op_class(op_class)) {
+ center_channels = center_channels_6ghz;
+ num_chan = ARRAY_SIZE(center_channels_6ghz);
+ } else {
+ center_channels = center_channels_5ghz;
+ num_chan = ARRAY_SIZE(center_channels_5ghz);
+ }
- center_chan = get_center_160mhz(mode, channel);
+ center_chan = get_center_160mhz(mode, channel, center_channels,
+ num_chan);
if (!center_chan)
return NOT_ALLOWED;
@@ -176,11 +203,12 @@ enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
enum chan_allowed res, res2;
res2 = res = allow_channel(mode, op_class, channel, &flag);
- if (bw == BW40MINUS) {
+ if (bw == BW40MINUS || (bw == BW40 && (((channel - 1) / 4) % 2))) {
if (!(flag & HOSTAPD_CHAN_HT40MINUS))
return NOT_ALLOWED;
res2 = allow_channel(mode, op_class, channel - 4, NULL);
- } else if (bw == BW40PLUS) {
+ } else if (bw == BW40PLUS ||
+ (bw == BW40 && !(((channel - 1) / 4) % 2))) {
if (!(flag & HOSTAPD_CHAN_HT40PLUS))
return NOT_ALLOWED;
res2 = allow_channel(mode, op_class, channel + 4, NULL);
@@ -292,7 +320,7 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_VHT_OVERRIDES */
if (op_class->op_class == 128) {
- u8 channels[] = { 42, 58, 106, 122, 138, 155 };
+ u8 channels[] = { 42, 58, 106, 122, 138, 155, 171 };
for (i = 0; i < ARRAY_SIZE(channels); i++) {
if (verify_channel(mode, op_class->op_class,
@@ -309,6 +337,8 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
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 ||
+ verify_channel(mode, op_class->op_class, 163,
op_class->bw) != NOT_ALLOWED;
}
@@ -326,6 +356,10 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
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 ||
+ verify_channel(mode, op_class->op_class, 155,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 171,
op_class->bw) != NOT_ALLOWED)
found++;
if (verify_channel(mode, op_class->op_class, 106,
@@ -333,7 +367,14 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
verify_channel(mode, op_class->op_class, 138,
op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, op_class->op_class, 155,
+ if (verify_channel(mode, op_class->op_class, 122,
+ op_class->bw) != NOT_ALLOWED &&
+ verify_channel(mode, op_class->op_class, 155,
+ op_class->bw) != NOT_ALLOWED)
+ found++;
+ if (verify_channel(mode, op_class->op_class, 138,
+ op_class->bw) != NOT_ALLOWED &&
+ verify_channel(mode, op_class->op_class, 171,
op_class->bw) != NOT_ALLOWED)
found++;
@@ -343,6 +384,41 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
return 0;
}
+ if (op_class->op_class == 135) {
+ /* Need at least two 80 MHz segments which do not fall under the
+ * same 160 MHz segment to support 80+80 in 6 GHz.
+ */
+ int first_seg = 0;
+ int curr_seg = 0;
+
+ for (chan = op_class->min_chan; chan <= op_class->max_chan;
+ chan += op_class->inc) {
+ curr_seg++;
+ if (verify_channel(mode, op_class->op_class, chan,
+ op_class->bw) != NOT_ALLOWED) {
+ if (!first_seg) {
+ first_seg = curr_seg;
+ continue;
+ }
+
+ /* Supported if at least two non-consecutive 80
+ * MHz segments allowed.
+ */
+ if ((curr_seg - first_seg) > 1)
+ return 1;
+
+ /* Supported even if the 80 MHz segments are
+ * consecutive when they do not fall under the
+ * same 160 MHz segment.
+ */
+ if ((first_seg % 2) == 0)
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
found = 0;
for (chan = op_class->min_chan; chan <= op_class->max_chan;
chan += op_class->inc) {
@@ -361,12 +437,13 @@ static int wpas_sta_secondary_channel_offset(struct wpa_bss *bss, u8 *current,
u8 *channel)
{
- u8 *ies, phy_type;
+ const u8 *ies;
+ u8 phy_type;
size_t ies_len;
if (!bss)
return -1;
- ies = (u8 *) (bss + 1);
+ ies = wpa_bss_ie_ptr(bss);
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);
@@ -412,9 +489,13 @@ size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
}
*ie_len = wpabuf_len(buf) - 2;
- if (*ie_len < 2 || wpabuf_len(buf) > len) {
+ if (*ie_len < 2) {
+ wpa_printf(MSG_DEBUG,
+ "No supported operating classes IE to add");
+ res = 0;
+ } else if (wpabuf_len(buf) > len) {
wpa_printf(MSG_ERROR,
- "Failed to add supported operating classes IE");
+ "Supported operating classes IE exceeds maximum buffer length");
res = 0;
} else {
os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 2f4682e0..a7e7587b 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -242,6 +242,22 @@ static void wpas_p2p_set_own_freq_preference(struct wpa_supplicant *wpa_s,
}
+static void wpas_p2p_scan_res_handled(struct wpa_supplicant *wpa_s)
+{
+ unsigned int delay = wpas_p2p_search_delay(wpa_s);
+
+ /* In case of concurrent P2P and external scans, delay P2P search. */
+ if (external_scan_running(wpa_s->radio)) {
+ delay = wpa_s->conf->p2p_search_delay;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Delay next P2P search by %d ms to let externally triggered scan complete",
+ delay);
+ }
+
+ p2p_scan_res_handled(wpa_s->global->p2p, delay);
+}
+
+
static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res)
{
@@ -287,7 +303,25 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
break;
}
- p2p_scan_res_handled(wpa_s->global->p2p);
+ wpas_p2p_scan_res_handled(wpa_s);
+}
+
+
+static void wpas_p2p_scan_res_fail_handler(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_scan_work) {
+ struct wpa_radio_work *work = wpa_s->p2p_scan_work;
+
+ wpa_s->p2p_scan_work = NULL;
+ radio_work_done(work);
+ }
+
+ if (wpa_s->global->p2p_disabled || !wpa_s->global->p2p)
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to get scan results - try to continue");
+ wpas_p2p_scan_res_handled(wpa_s);
}
@@ -312,6 +346,15 @@ static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
"Request driver to clear scan cache due to local BSS flush");
params->only_new_results = 1;
}
+
+ if (wpa_s->conf->p2p_6ghz_disable && !params->freqs) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: 6 GHz disabled - update the scan frequency list");
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params,
+ 0);
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
+ 0);
+ }
ret = wpa_drv_scan(wpa_s, params);
if (ret == 0)
wpa_s->curr_scan_cookie = params->scan_cookie;
@@ -326,6 +369,7 @@ static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
p2p_notify_scan_trigger_status(wpa_s->global->p2p, ret);
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
+ wpa_s->scan_res_fail_handler = wpas_p2p_scan_res_fail_handler;
wpa_s->own_scan_requested = 1;
wpa_s->clear_driver_scan_cache = 0;
wpa_s->p2p_scan_work = work;
@@ -522,7 +566,7 @@ static int wpas_p2p_disconnect_safely(struct wpa_supplicant *wpa_s,
/*
* The calling wpa_s instance is going to be removed. Do that
* from an eloop callback to keep the instance available until
- * the caller has returned. This my be needed, e.g., to provide
+ * the caller has returned. This may be needed, e.g., to provide
* control interface responses on the per-interface socket.
*/
if (eloop_register_timeout(0, 0, run_wpas_p2p_disconnect,
@@ -1063,9 +1107,9 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
"group is persistent - BSS " MACSTR
" did not include P2P IE", MAC2STR(bssid));
wpa_hexdump(MSG_DEBUG, "P2P: Probe Response IEs",
- (u8 *) (bss + 1), bss->ie_len);
+ wpa_bss_ie_ptr(bss), bss->ie_len);
wpa_hexdump(MSG_DEBUG, "P2P: Beacon IEs",
- ((u8 *) bss + 1) + bss->ie_len,
+ wpa_bss_ie_ptr(bss) + bss->ie_len,
bss->beacon_ie_len);
return 0;
}
@@ -1912,7 +1956,7 @@ static int wpas_p2p_freq_to_edmg_channel(struct wpa_supplicant *wpa_s,
return -1;
hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
- HOSTAPD_MODE_IEEE80211AD, 0);
+ HOSTAPD_MODE_IEEE80211AD, false);
if (!hwmode) {
wpa_printf(MSG_ERROR,
"Unsupported AP mode: HOSTAPD_MODE_IEEE80211AD");
@@ -2117,6 +2161,7 @@ do { \
d->go_internet = s->go_internet;
d->go_venue_group = s->go_venue_group;
d->go_venue_type = s->go_venue_type;
+ d->p2p_add_cli_chan = s->p2p_add_cli_chan;
}
@@ -2450,10 +2495,13 @@ static void wpas_dev_found(void *ctx, const u8 *addr,
{
u8 *wfd_dev_info = NULL;
u8 wfd_dev_info_len = 0;
+ u8 *wfd_r2_dev_info = NULL;
+ u8 wfd_r2_dev_info_len = 0;
#ifndef CONFIG_NO_STDOUT_DEBUG
struct wpa_supplicant *wpa_s = ctx;
char devtype[WPS_DEV_TYPE_BUFSIZE];
char *wfd_dev_info_hex = NULL;
+ char *wfd_r2_dev_info_hex = NULL;
#ifdef CONFIG_WIFI_DISPLAY
wfd_dev_info_hex = wifi_display_subelem_hex(info->wfd_subelems,
@@ -2464,6 +2512,15 @@ static void wpas_dev_found(void *ctx, const u8 *addr,
// Only used for notification, so not handling error.
hexstr2bin(wfd_dev_info_hex, wfd_dev_info, wfd_dev_info_len);
}
+
+ wfd_r2_dev_info_hex = wifi_display_subelem_hex(info->wfd_subelems,
+ WFD_SUBELEM_R2_DEVICE_INFO);
+ if (wfd_r2_dev_info_hex) {
+ wfd_r2_dev_info_len = strlen(wfd_r2_dev_info_hex) / 2;
+ wfd_r2_dev_info = os_zalloc(wfd_r2_dev_info_len);
+ // Only used for notification, so not handling error.
+ hexstr2bin(wfd_r2_dev_info_hex, wfd_r2_dev_info, wfd_r2_dev_info_len);
+ }
#endif /* CONFIG_WIFI_DISPLAY */
if (info->p2ps_instance) {
@@ -2515,7 +2572,7 @@ static void wpas_dev_found(void *ctx, const u8 *addr,
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
" p2p_dev_addr=" MACSTR
" pri_dev_type=%s name='%s' config_methods=0x%x "
- "dev_capab=0x%x group_capab=0x%x%s%s%s new=%d",
+ "dev_capab=0x%x group_capab=0x%x%s%s%s%s%s new=%d",
MAC2STR(addr), MAC2STR(info->p2p_device_addr),
wps_dev_type_bin2str(info->pri_dev_type, devtype,
sizeof(devtype)),
@@ -2523,15 +2580,19 @@ static void wpas_dev_found(void *ctx, const u8 *addr,
info->dev_capab, info->group_capab,
wfd_dev_info_hex ? " wfd_dev_info=0x" : "",
wfd_dev_info_hex ? wfd_dev_info_hex : "",
+ wfd_r2_dev_info_hex ? " wfd_r2_dev_info=0x" : "",
+ wfd_r2_dev_info_hex ? wfd_r2_dev_info_hex : "",
info->vendor_elems ? " vendor_elems=1" : "",
new_device);
done:
os_free(wfd_dev_info_hex);
+ os_free(wfd_r2_dev_info_hex);
#endif /* CONFIG_NO_STDOUT_DEBUG */
wpas_notify_p2p_device_found(ctx, addr, info, wfd_dev_info,
- wfd_dev_info_len, new_device);
+ wfd_dev_info_len, wfd_r2_dev_info,
+ wfd_r2_dev_info_len, new_device);
os_free(wfd_dev_info);
}
@@ -3543,7 +3604,7 @@ static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode,
u8 channel)
{
- u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
+ u8 center_channels[] = { 42, 58, 106, 122, 138, 155, 171 };
size_t i;
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
@@ -3604,7 +3665,7 @@ static int wpas_p2p_get_center_160mhz(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode,
u8 channel)
{
- u8 center_channels[] = { 50, 114 };
+ u8 center_channels[] = { 50, 114, 163 };
unsigned int i;
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
@@ -3717,7 +3778,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
struct p2p_channels *chan,
- struct p2p_channels *cli_chan)
+ struct p2p_channels *cli_chan,
+ bool p2p_disable_6ghz)
{
struct hostapd_hw_modes *mode;
int cla, op, cli_cla;
@@ -3736,7 +3798,8 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
u8 ch;
struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
- if (o->p2p == NO_P2P_SUPP)
+ if (o->p2p == NO_P2P_SUPP ||
+ (is_6ghz_op_class(o->op_class) && p2p_disable_6ghz))
continue;
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode,
@@ -3747,6 +3810,13 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
wpa_s->global->p2p_24ghz_social_channels = 1;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
enum chan_allowed res;
+
+ /* Check for non-continuous jump in channel index
+ * incrementation */
+ if ((o->op_class >= 128 && o->op_class <= 130) &&
+ ch < 149 && ch + o->inc > 149)
+ ch = 149;
+
res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
if (res == ALLOWED) {
if (reg == NULL) {
@@ -3807,7 +3877,9 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
const struct oper_class_map *o = &global_op_class[op];
u8 ch;
- if (o->p2p == NO_P2P_SUPP)
+ if (o->p2p == NO_P2P_SUPP ||
+ (is_6ghz_op_class(o->op_class) &&
+ wpa_s->conf->p2p_6ghz_disable))
continue;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
@@ -3934,14 +4006,24 @@ int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
char ifname[100];
char force_name[100];
int ret;
+ const u8 *if_addr = NULL;
ret = os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
wpa_s->ifname);
if (os_snprintf_error(sizeof(ifname), ret))
return -1;
+ /* Cut length at the maximum size. Note that we don't need to ensure
+ * collision free names here as the created interface is not a netdev.
+ */
+ ifname[IFNAMSIZ - 1] = '\0';
force_name[0] = '\0';
wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE;
- ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, NULL, NULL,
+
+ if (wpa_s->conf->p2p_device_random_mac_addr == 2 &&
+ !is_zero_ether_addr(wpa_s->conf->p2p_device_persistent_mac_addr))
+ if_addr = wpa_s->conf->p2p_device_persistent_mac_addr;
+
+ ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, if_addr, NULL,
force_name, wpa_s->pending_interface_addr, NULL);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to create P2P Device interface");
@@ -4517,7 +4599,17 @@ int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s)
if (wpa_s->conf->p2p_device_random_mac_addr == 0)
return 0;
- if (wpa_s->conf->ssid == NULL) {
+ if (wpa_s->conf->p2p_device_random_mac_addr == 2) {
+ if (is_zero_ether_addr(
+ wpa_s->conf->p2p_device_persistent_mac_addr) &&
+ !is_zero_ether_addr(wpa_s->own_addr)) {
+ os_memcpy(wpa_s->conf->p2p_device_persistent_mac_addr,
+ wpa_s->own_addr, ETH_ALEN);
+ }
+ return 0;
+ }
+
+ if (!wpa_s->conf->ssid) {
if (random_mac_addr(addr) < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Failed to generate random MAC address");
@@ -4617,6 +4709,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.prov_disc_resp_cb = wpas_prov_disc_resp_cb;
p2p.p2ps_group_capability = p2ps_group_capability;
p2p.get_pref_freq_list = wpas_p2p_get_pref_freq_list;
+ p2p.p2p_6ghz_disable = wpa_s->conf->p2p_6ghz_disable;
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
@@ -4630,7 +4723,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.config_methods = wpa_s->wps->config_methods;
}
- if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {
+ if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels,
+ p2p.p2p_6ghz_disable)) {
wpa_printf(MSG_ERROR,
"P2P: Failed to configure supported channel list");
return -1;
@@ -4777,6 +4871,7 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
wpas_p2p_remove_pending_group_interface(wpa_s);
eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_p2p_reconsider_moving_go, wpa_s, NULL);
wpas_p2p_listen_work_done(wpa_s);
if (wpa_s->p2p_send_action_work) {
os_free(wpa_s->p2p_send_action_work->ctx);
@@ -4925,6 +5020,15 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
MAC2STR(wpa_s->pending_join_dev_addr));
return;
}
+ if (wpa_s->p2p_fallback_to_go_neg) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Join operating "
+ "failed - fall back to GO Negotiation");
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
+ P2P_EVENT_FALLBACK_TO_GO_NEG
+ "reason=join-failed");
+ wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+ return;
+ }
wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
wpas_notify_p2p_group_formation_failure(wpa_s, "");
@@ -5136,7 +5240,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
"from BSS table: %d MHz (SSID %s)", freq,
wpa_ssid_txt(bss->ssid, bss->ssid_len));
- if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
+ if (p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len,
dev_addr) == 0 &&
os_memcmp(wpa_s->pending_join_dev_addr,
wpa_s->pending_join_iface_addr, ETH_ALEN) == 0 &&
@@ -5275,6 +5379,13 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
if (freq > 0) {
freqs[0] = freq;
params.freqs = freqs;
+ } else if (wpa_s->conf->p2p_6ghz_disable) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: 6 GHz disabled - update the scan frequency list");
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, &params,
+ 0);
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, &params,
+ 0);
}
ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
@@ -5305,6 +5416,8 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
* the new scan results become available.
*/
ret = wpa_drv_scan(wpa_s, &params);
+ if (wpa_s->conf->p2p_6ghz_disable && params.freqs != freqs)
+ os_free(params.freqs);
if (!ret) {
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
@@ -5645,6 +5758,9 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
return -1;
}
+ if (is_6ghz_freq(freq) && wpa_s->conf->p2p_6ghz_disable)
+ return -2;
+
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
@@ -5871,6 +5987,8 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
if (os_strcmp(ifname, "*") == 0) {
struct wpa_supplicant *prev;
+ bool calling_wpa_s_group_removed = false;
+
wpa_s = global->ifaces;
while (wpa_s) {
prev = wpa_s;
@@ -5878,9 +5996,23 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
if (prev->p2p_group_interface !=
NOT_P2P_GROUP_INTERFACE ||
(prev->current_ssid &&
- prev->current_ssid->p2p_group))
+ prev->current_ssid->p2p_group)) {
wpas_p2p_disconnect_safely(prev, calling_wpa_s);
+ if (prev == calling_wpa_s)
+ calling_wpa_s_group_removed = true;
+ }
+ }
+
+ if (!calling_wpa_s_group_removed &&
+ (calling_wpa_s->p2p_group_interface !=
+ NOT_P2P_GROUP_INTERFACE ||
+ (calling_wpa_s->current_ssid &&
+ calling_wpa_s->current_ssid->p2p_group))) {
+ wpa_printf(MSG_DEBUG, "Remove calling_wpa_s P2P group");
+ wpas_p2p_disconnect_safely(calling_wpa_s,
+ calling_wpa_s);
}
+
return 0;
}
@@ -7036,7 +7168,7 @@ static void wpas_p2p_scan_res_ignore_search(struct wpa_supplicant *wpa_s,
* Indicate that results have been processed so that the P2P module can
* continue pending tasks.
*/
- p2p_scan_res_handled(wpa_s->global->p2p);
+ wpas_p2p_scan_res_handled(wpa_s);
}
@@ -7951,7 +8083,8 @@ void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s,
os_memset(&chan, 0, sizeof(chan));
os_memset(&cli_chan, 0, sizeof(cli_chan));
- if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan)) {
+ if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan,
+ is_p2p_6ghz_disabled(wpa_s->global->p2p))) {
wpa_printf(MSG_ERROR, "P2P: Failed to update supported "
"channel list");
return;
@@ -9397,6 +9530,8 @@ static void wpas_p2p_move_go_no_csa(struct wpa_supplicant *wpa_s)
{
struct p2p_go_neg_results params;
struct wpa_ssid *current_ssid = wpa_s->current_ssid;
+ void (*ap_configured_cb)(void *ctx, void *data);
+ void *ap_configured_cb_ctx, *ap_configured_cb_data;
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_REMOVE_AND_REFORM_GROUP);
@@ -9406,6 +9541,13 @@ static void wpas_p2p_move_go_no_csa(struct wpa_supplicant *wpa_s)
/* Stop the AP functionality */
/* TODO: Should do this in a way that does not indicated to possible
* P2P Clients in the group that the group is terminated. */
+ /* If this action occurs before a group is started, the callback should
+ * be preserved, or GROUP-STARTED event would be lost. If this action
+ * occurs after a group is started, these pointers are all NULL and
+ * harmless. */
+ ap_configured_cb = wpa_s->ap_configured_cb;
+ ap_configured_cb_ctx = wpa_s->ap_configured_cb_ctx;
+ ap_configured_cb_data = wpa_s->ap_configured_cb_data;
wpa_supplicant_ap_deinit(wpa_s);
/* Reselect the GO frequency */
@@ -9429,6 +9571,11 @@ static void wpas_p2p_move_go_no_csa(struct wpa_supplicant *wpa_s)
return;
}
+ /* Restore preserved callback parameters */
+ wpa_s->ap_configured_cb = ap_configured_cb;
+ wpa_s->ap_configured_cb_ctx = ap_configured_cb_ctx;
+ wpa_s->ap_configured_cb_data = ap_configured_cb_data;
+
/* Update the frequency */
current_ssid->frequency = params.freq;
wpa_s->connect_without_scan = current_ssid;
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
new file mode 100644
index 00000000..4f5ac589
--- /dev/null
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -0,0 +1,1509 @@
+/*
+ * wpa_supplicant - PASN processing
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/dragonfly.h"
+#include "common/ptksa_cache.h"
+#include "utils/eloop.h"
+#include "drivers/driver.h"
+#include "crypto/crypto.h"
+#include "crypto/random.h"
+#include "eap_common/eap_defs.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+#include "config.h"
+
+static const int dot11RSNAConfigPMKLifetime = 43200;
+
+struct wpa_pasn_auth_work {
+ u8 bssid[ETH_ALEN];
+ int akmp;
+ int cipher;
+ u16 group;
+ int network_id;
+};
+
+
+static void wpas_pasn_auth_work_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "PASN: Auth work timeout - stopping auth");
+
+ wpas_pasn_auth_stop(wpa_s);
+}
+
+
+static void wpas_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "PASN: Cancel pasn-start-auth work");
+
+ /* Remove pending/started work */
+ radio_remove_works(wpa_s, "pasn-start-auth", 0);
+}
+
+
+static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ int akmp, int cipher, u8 status)
+{
+ wpa_msg(wpa_s, MSG_INFO,
+ PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u",
+ MAC2STR(bssid), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
+ status);
+}
+
+
+#ifdef CONFIG_SAE
+
+static struct wpabuf * wpas_pasn_wd_sae_commit(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct wpabuf *buf = NULL;
+ const char *password = NULL;
+ int ret;
+
+ if (pasn->ssid) {
+ password = pasn->ssid->sae_password;
+ if (!password)
+ password = pasn->ssid->passphrase;
+ }
+
+ if (!password) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE without a password");
+ return NULL;
+ }
+
+ ret = sae_set_group(&pasn->sae, pasn->group);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group");
+ return NULL;
+ }
+
+ /* TODO: SAE H2E */
+ ret = sae_prepare_commit(wpa_s->own_addr, pasn->bssid,
+ (const u8 *) password, os_strlen(password), 0,
+ &pasn->sae);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit");
+ return NULL;
+ }
+
+ /* Need to add the entire Authentication frame body */
+ buf = wpabuf_alloc(6 + SAE_COMMIT_MAX_LEN);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
+ return NULL;
+ }
+
+ wpabuf_put_le16(buf, WLAN_AUTH_SAE);
+ wpabuf_put_le16(buf, 1);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ sae_write_commit(&pasn->sae, buf, NULL, 0);
+ pasn->sae.state = SAE_COMMITTED;
+
+ return buf;
+}
+
+
+static int wpas_pasn_wd_sae_rx(struct wpa_supplicant *wpa_s, struct wpabuf *wd)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ const u8 *data;
+ size_t buf_len;
+ u16 len, res, alg, seq, status;
+ int groups[] = { pasn->group, 0 };
+ int ret;
+
+ if (!wd)
+ return -1;
+
+ data = wpabuf_head_u8(wd);
+ buf_len = wpabuf_len(wd);
+
+ /* first handle the commit message */
+ if (buf_len < 2) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short (commit)");
+ return -1;
+ }
+
+ len = WPA_GET_LE16(data);
+ if (len < 6 || buf_len - 2 < len) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short for commit");
+ return -1;
+ }
+
+ buf_len -= 2;
+ data += 2;
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: SAE: commit: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ /* TODO: SAE H2E */
+ if (alg != WLAN_AUTH_SAE || seq != 1 || status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE: dropping peer commit");
+ return -1;
+ }
+
+ res = sae_parse_commit(&pasn->sae, data + 6, len - 6, NULL, 0, groups,
+ 0);
+ if (res != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE failed parsing commit");
+ return -1;
+ }
+
+ /* Process the commit message and derive the PMK */
+ ret = sae_process_commit(&pasn->sae);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
+ return -1;
+ }
+
+ buf_len -= len;
+ data += len;
+
+ /* Handle the confirm message */
+ if (buf_len < 2) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short (confirm)");
+ return -1;
+ }
+
+ len = WPA_GET_LE16(data);
+ if (len < 6 || buf_len - 2 < len) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short for confirm");
+ return -1;
+ }
+
+ buf_len -= 2;
+ data += 2;
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: SAE confirm: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ if (alg != WLAN_AUTH_SAE || seq != 2 || status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE confirm");
+ return -1;
+ }
+
+ res = sae_check_confirm(&pasn->sae, data + 6, len - 6);
+ if (res != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: SAE completed successfully");
+ pasn->sae.state = SAE_ACCEPTED;
+
+ return 0;
+}
+
+
+static struct wpabuf * wpas_pasn_wd_sae_confirm(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct wpabuf *buf = NULL;
+
+ /* Need to add the entire authentication frame body */
+ buf = wpabuf_alloc(6 + SAE_CONFIRM_MAX_LEN);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
+ return NULL;
+ }
+
+ wpabuf_put_le16(buf, WLAN_AUTH_SAE);
+ wpabuf_put_le16(buf, 2);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ sae_write_confirm(&pasn->sae, buf);
+ pasn->sae.state = SAE_CONFIRMED;
+
+ return buf;
+}
+
+#endif /* CONFIG_SAE */
+
+
+#ifdef CONFIG_FILS
+
+static struct wpabuf * wpas_pasn_fils_build_auth(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct wpabuf *buf = NULL;
+ struct wpabuf *erp_msg;
+ int ret;
+
+ erp_msg = eapol_sm_build_erp_reauth_start(wpa_s->eapol);
+ if (!erp_msg) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: ERP EAP-Initiate/Re-auth unavailable");
+ return NULL;
+ }
+
+ if (random_get_bytes(pasn->fils.nonce, FILS_NONCE_LEN) < 0 ||
+ random_get_bytes(pasn->fils.session, FILS_SESSION_LEN) < 0)
+ goto fail;
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", pasn->fils.nonce,
+ FILS_NONCE_LEN);
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", pasn->fils.session,
+ FILS_SESSION_LEN);
+
+ buf = wpabuf_alloc(1500);
+ if (!buf)
+ goto fail;
+
+ /* Add the authentication algorithm */
+ wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK);
+
+ /* Authentication Transaction seq# */
+ wpabuf_put_le16(buf, 1);
+
+ /* Status Code */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ /* Own RSNE */
+ wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
+
+ /* FILS Nonce */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
+ wpabuf_put_data(buf, pasn->fils.nonce, FILS_NONCE_LEN);
+
+ /* FILS Session */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
+ wpabuf_put_data(buf, pasn->fils.session, FILS_SESSION_LEN);
+
+ /* Wrapped Data (ERP) */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
+ wpabuf_put_buf(buf, erp_msg);
+
+ /*
+ * Calculate pending PMKID here so that we do not need to maintain a
+ * copy of the EAP-Initiate/Reauth message.
+ */
+ ret = fils_pmkid_erp(pasn->akmp, wpabuf_head(erp_msg),
+ wpabuf_len(erp_msg),
+ pasn->fils.erp_pmkid);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ERP PMKID");
+ goto fail;
+ }
+
+ wpabuf_free(erp_msg);
+ erp_msg = NULL;
+
+ wpa_hexdump_buf(MSG_DEBUG, "PASN: FILS: Authentication frame", buf);
+ return buf;
+fail:
+ wpabuf_free(erp_msg);
+ wpabuf_free(buf);
+ return NULL;
+}
+
+
+static void wpas_pasn_initiate_eapol(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct eapol_config eapol_conf;
+ struct wpa_ssid *ssid = pasn->ssid;
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Initiating EAPOL");
+
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
+ eapol_sm_notify_eap_fail(wpa_s->eapol, false);
+ eapol_sm_notify_portControl(wpa_s->eapol, Auto);
+
+ os_memset(&eapol_conf, 0, sizeof(eapol_conf));
+ eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
+ eapol_conf.workaround = ssid->eap_workaround;
+
+ eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
+}
+
+
+static struct wpabuf * wpas_pasn_wd_fils_auth(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct wpa_bss *bss;
+ const u8 *indic;
+ u16 fils_info;
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: wrapped data - completed=%u",
+ pasn->fils.completed);
+
+ /* Nothing to add as we are done */
+ if (pasn->fils.completed)
+ return NULL;
+
+ if (!pasn->ssid) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: No network block");
+ return NULL;
+ }
+
+ bss = wpa_bss_get_bssid(wpa_s, pasn->bssid);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: BSS not found");
+ return NULL;
+ }
+
+ indic = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
+ if (!indic || indic[1] < 2) {
+ wpa_printf(MSG_DEBUG, "PASN: Missing FILS Indication IE");
+ return NULL;
+ }
+
+ fils_info = WPA_GET_LE16(indic + 2);
+ if (!(fils_info & BIT(9))) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS auth without PFS not supported");
+ return NULL;
+ }
+
+ wpas_pasn_initiate_eapol(wpa_s);
+
+ return wpas_pasn_fils_build_auth(wpa_s);
+}
+
+
+static int wpas_pasn_wd_fils_rx(struct wpa_supplicant *wpa_s, struct wpabuf *wd)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct ieee802_11_elems elems;
+ struct wpa_ie_data rsne_data;
+ u8 rmsk[ERP_MAX_KEY_LEN];
+ size_t rmsk_len;
+ u8 anonce[FILS_NONCE_LEN];
+ const u8 *data;
+ size_t buf_len;
+ struct wpabuf *fils_wd = NULL;
+ u16 alg, seq, status;
+ int ret;
+
+ if (!wd)
+ return -1;
+
+ data = wpabuf_head(wd);
+ buf_len = wpabuf_len(wd);
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: Authentication frame len=%zu",
+ data, buf_len);
+
+ /* first handle the header */
+ if (buf_len < 6) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short");
+ return -1;
+ }
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: commit: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ if (alg != WLAN_AUTH_FILS_SK || seq != 2 ||
+ status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Dropping peer authentication");
+ return -1;
+ }
+
+ data += 6;
+ buf_len -= 6;
+
+ if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
+ return -1;
+ }
+
+ if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
+ !elems.wrapped_data) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
+ return -1;
+ }
+
+ ret = wpa_parse_wpa_ie(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RNSE");
+ return -1;
+ }
+
+ ret = wpa_pasn_validate_rsne(&rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
+ return -1;
+ }
+
+ if (rsne_data.num_pmkid) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Not expecting PMKID in RSNE");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: ANonce", elems.fils_nonce,
+ FILS_NONCE_LEN);
+ os_memcpy(anonce, elems.fils_nonce, FILS_NONCE_LEN);
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: FILS Session", elems.fils_session,
+ FILS_SESSION_LEN);
+
+ if (os_memcmp(pasn->fils.session, elems.fils_session,
+ FILS_SESSION_LEN)) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Session mismatch");
+ return -1;
+ }
+
+ fils_wd = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
+ WLAN_EID_EXT_WRAPPED_DATA);
+
+ if (!fils_wd) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Failed getting wrapped data");
+ return -1;
+ }
+
+ eapol_sm_process_erp_finish(wpa_s->eapol, wpabuf_head(fils_wd),
+ wpabuf_len(fils_wd));
+
+ wpabuf_free(fils_wd);
+ fils_wd = NULL;
+
+ if (eapol_sm_failed(wpa_s->eapol)) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: ERP finish failed");
+ return -1;
+ }
+
+ rmsk_len = ERP_MAX_KEY_LEN;
+ ret = eapol_sm_get_key(wpa_s->eapol, rmsk, rmsk_len);
+
+ if (ret == PMK_LEN) {
+ rmsk_len = PMK_LEN;
+ ret = eapol_sm_get_key(wpa_s->eapol, rmsk, rmsk_len);
+ }
+
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed getting RMSK");
+ return -1;
+ }
+
+ ret = fils_rmsk_to_pmk(pasn->akmp, rmsk, rmsk_len,
+ pasn->fils.nonce, anonce, NULL, 0,
+ pasn->pmk, &pasn->pmk_len);
+
+ forced_memzero(rmsk, sizeof(rmsk));
+
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PMK");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: PMKID", pasn->fils.erp_pmkid,
+ PMKID_LEN);
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: ERP processing succeeded");
+
+ wpa_pasn_pmksa_cache_add(wpa_s->wpa, pasn->pmk,
+ pasn->pmk_len, pasn->fils.erp_pmkid,
+ pasn->bssid, pasn->akmp);
+
+ pasn->fils.completed = true;
+ return 0;
+}
+
+#endif /* CONFIG_FILS */
+
+
+static struct wpabuf * wpas_pasn_get_wrapped_data(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+
+ if (pasn->using_pmksa)
+ return NULL;
+
+ switch (pasn->akmp) {
+ case WPA_KEY_MGMT_PASN:
+ /* no wrapped data */
+ return NULL;
+ case WPA_KEY_MGMT_SAE:
+#ifdef CONFIG_SAE
+ if (pasn->trans_seq == 0)
+ return wpas_pasn_wd_sae_commit(wpa_s);
+ if (pasn->trans_seq == 2)
+ return wpas_pasn_wd_sae_confirm(wpa_s);
+#endif /* CONFIG_SAE */
+ wpa_printf(MSG_ERROR,
+ "PASN: SAE: Cannot derive wrapped data");
+ return NULL;
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+#ifdef CONFIG_FILS
+ return wpas_pasn_wd_fils_auth(wpa_s);
+#endif /* CONFIG_FILS */
+ case WPA_KEY_MGMT_FT_PSK:
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ /*
+ * Wrapped data with these AKMs is optional and is only needed
+ * for further validation of FT security parameters. For now do
+ * not use them.
+ */
+ return NULL;
+ default:
+ wpa_printf(MSG_ERROR,
+ "PASN: TODO: Wrapped data for akmp=0x%x",
+ pasn->akmp);
+ return NULL;
+ }
+}
+
+
+static u8 wpas_pasn_get_wrapped_data_format(struct wpas_pasn *pasn)
+{
+ if (pasn->using_pmksa)
+ return WPA_PASN_WRAPPED_DATA_NO;
+
+ /* Note: Valid AKMP is expected to already be validated */
+ switch (pasn->akmp) {
+ case WPA_KEY_MGMT_SAE:
+ return WPA_PASN_WRAPPED_DATA_SAE;
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+ return WPA_PASN_WRAPPED_DATA_FILS_SK;
+ case WPA_KEY_MGMT_FT_PSK:
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ /*
+ * Wrapped data with these AKMs is optional and is only needed
+ * for further validation of FT security parameters. For now do
+ * not use them.
+ */
+ return WPA_PASN_WRAPPED_DATA_NO;
+ case WPA_KEY_MGMT_PASN:
+ default:
+ return WPA_PASN_WRAPPED_DATA_NO;
+ }
+}
+
+
+static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
+ const u8 *pmkid;
+ u8 wrapped_data;
+ int ret;
+ u16 capab;
+
+ wpa_printf(MSG_DEBUG, "PASN: Building frame 1");
+
+ if (pasn->trans_seq)
+ return NULL;
+
+ buf = wpabuf_alloc(1500);
+ if (!buf)
+ goto fail;
+
+ /* Get public key */
+ pubkey = crypto_ecdh_get_pubkey(pasn->ecdh, 0);
+ pubkey = wpabuf_zeropad(pubkey, crypto_ecdh_prime_len(pasn->ecdh));
+ if (!pubkey) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to get pubkey");
+ goto fail;
+ }
+
+ wrapped_data = wpas_pasn_get_wrapped_data_format(pasn);
+
+ wpa_pasn_build_auth_header(buf, pasn->bssid,
+ wpa_s->own_addr, pasn->bssid,
+ pasn->trans_seq + 1, WLAN_STATUS_SUCCESS);
+
+ pmkid = NULL;
+ if (wpa_key_mgmt_ft(pasn->akmp)) {
+ ret = wpa_pasn_ft_derive_pmk_r1(wpa_s->wpa, pasn->akmp,
+ pasn->bssid,
+ pasn->pmk_r1,
+ &pasn->pmk_r1_len,
+ pasn->pmk_r1_name);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FT: Failed to derive keys");
+ goto fail;
+ }
+
+ pmkid = pasn->pmk_r1_name;
+ } else if (wrapped_data != WPA_PASN_WRAPPED_DATA_NO) {
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = wpa_sm_pmksa_cache_get(wpa_s->wpa, pasn->bssid,
+ NULL, NULL, pasn->akmp);
+ if (pmksa)
+ pmkid = pmksa->pmkid;
+
+ /*
+ * Note: Even when PMKSA is available, also add wrapped data as
+ * it is possible that the PMKID is no longer valid at the AP.
+ */
+ wrapped_data_buf = wpas_pasn_get_wrapped_data(wpa_s);
+ }
+
+ if (wpa_pasn_add_rsne(buf, pmkid, pasn->akmp, pasn->cipher) < 0)
+ goto fail;
+
+ if (!wrapped_data_buf)
+ wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
+
+ wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
+ pubkey, NULL, -1);
+
+ if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
+ goto fail;
+
+ /* Add own RNSXE */
+ /* TODO: How to handle protected TWT and SAE H2E? */
+ capab = 0;
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG)
+ capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
+ wpa_pasn_add_rsnxe(buf, capab);
+
+ ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher,
+ wpabuf_head_u8(buf) + IEEE80211_HDRLEN,
+ wpabuf_len(buf) - IEEE80211_HDRLEN,
+ pasn->hash);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
+ goto fail;
+ }
+
+ pasn->trans_seq++;
+
+ wpabuf_free(wrapped_data_buf);
+ wpabuf_free(pubkey);
+
+ wpa_printf(MSG_DEBUG, "PASN: Frame 1: Success");
+ return buf;
+fail:
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpabuf_free(wrapped_data_buf);
+ wpabuf_free(pubkey);
+ wpabuf_free(buf);
+ return NULL;
+}
+
+
+static struct wpabuf * wpas_pasn_build_auth_3(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct wpabuf *buf, *wrapped_data_buf = NULL;
+ u8 mic[WPA_PASN_MAX_MIC_LEN];
+ u8 mic_len, data_len;
+ const u8 *data;
+ u8 *ptr;
+ u8 wrapped_data;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "PASN: Building frame 3");
+
+ if (pasn->trans_seq != 2)
+ return NULL;
+
+ buf = wpabuf_alloc(1500);
+ if (!buf)
+ goto fail;
+
+ wrapped_data = wpas_pasn_get_wrapped_data_format(pasn);
+
+ wpa_pasn_build_auth_header(buf, pasn->bssid,
+ wpa_s->own_addr, pasn->bssid,
+ pasn->trans_seq + 1, WLAN_STATUS_SUCCESS);
+
+ wrapped_data_buf = wpas_pasn_get_wrapped_data(wpa_s);
+
+ if (!wrapped_data_buf)
+ wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
+
+ wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
+ NULL, NULL, -1);
+
+ if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
+ goto fail;
+ wpabuf_free(wrapped_data_buf);
+ wrapped_data_buf = NULL;
+
+ /* Add the MIC */
+ mic_len = pasn_mic_len(pasn->akmp, pasn->cipher);
+ wpabuf_put_u8(buf, WLAN_EID_MIC);
+ wpabuf_put_u8(buf, mic_len);
+ ptr = wpabuf_put(buf, mic_len);
+
+ os_memset(ptr, 0, mic_len);
+
+ data = wpabuf_head_u8(buf) + IEEE80211_HDRLEN;
+ data_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
+
+ ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
+ wpa_s->own_addr, pasn->bssid,
+ pasn->hash, mic_len * 2, data, data_len, mic);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: frame 3: Failed MIC calculation");
+ goto fail;
+ }
+
+ os_memcpy(ptr, mic, mic_len);
+
+ pasn->trans_seq++;
+
+ wpa_printf(MSG_DEBUG, "PASN: frame 3: Success");
+ return buf;
+fail:
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpabuf_free(wrapped_data_buf);
+ wpabuf_free(buf);
+ return NULL;
+}
+
+
+static void wpas_pasn_reset(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+
+ wpa_printf(MSG_DEBUG, "PASN: Reset");
+
+ crypto_ecdh_deinit(pasn->ecdh);
+ pasn->ecdh = NULL;
+
+ wpas_pasn_cancel_auth_work(wpa_s);
+ wpa_s->pasn_auth_work = NULL;
+
+ eloop_cancel_timeout(wpas_pasn_auth_work_timeout, wpa_s, NULL);
+
+ pasn->akmp = 0;
+ pasn->cipher = 0;
+ pasn->group = 0;
+ pasn->trans_seq = 0;
+ pasn->pmk_len = 0;
+ pasn->using_pmksa = false;
+
+ forced_memzero(pasn->pmk, sizeof(pasn->pmk));
+ forced_memzero(&pasn->ptk, sizeof(pasn->ptk));
+ forced_memzero(&pasn->hash, sizeof(pasn->hash));
+
+ wpabuf_free(pasn->beacon_rsne_rsnxe);
+ pasn->beacon_rsne_rsnxe = NULL;
+
+#ifdef CONFIG_SAE
+ sae_clear_data(&pasn->sae);
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_FILS
+ os_memset(&pasn->fils, 0, sizeof(pasn->fils));
+#endif /* CONFIG_FILS*/
+
+#ifdef CONFIG_IEEE80211R
+ forced_memzero(pasn->pmk_r1, sizeof(pasn->pmk_r1));
+ pasn->pmk_r1_len = 0;
+ os_memset(pasn->pmk_r1_name, 0, sizeof(pasn->pmk_r1_name));
+#endif /* CONFIG_IEEE80211R */
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+}
+
+
+static int wpas_pasn_set_pmk(struct wpa_supplicant *wpa_s,
+ struct wpa_ie_data *rsn_data,
+ struct wpa_pasn_params_data *pasn_data,
+ struct wpabuf *wrapped_data)
+{
+ static const u8 pasn_default_pmk[] = {'P', 'M', 'K', 'z'};
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+
+ os_memset(pasn->pmk, 0, sizeof(pasn->pmk));
+ pasn->pmk_len = 0;
+
+ if (pasn->akmp == WPA_KEY_MGMT_PASN) {
+ wpa_printf(MSG_DEBUG, "PASN: Using default PMK");
+
+ pasn->pmk_len = WPA_PASN_PMK_LEN;
+ os_memcpy(pasn->pmk, pasn_default_pmk,
+ sizeof(pasn_default_pmk));
+ return 0;
+ }
+
+ if (wpa_key_mgmt_ft(pasn->akmp)) {
+#ifdef CONFIG_IEEE80211R
+ wpa_printf(MSG_DEBUG, "PASN: FT: Using PMK-R1");
+ pasn->pmk_len = pasn->pmk_r1_len;
+ os_memcpy(pasn->pmk, pasn->pmk_r1, pasn->pmk_r1_len);
+ pasn->using_pmksa = true;
+ return 0;
+#else /* CONFIG_IEEE80211R */
+ wpa_printf(MSG_DEBUG, "PASN: FT: Not supported");
+ return -1;
+#endif /* CONFIG_IEEE80211R */
+ }
+
+ if (rsn_data->num_pmkid) {
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = wpa_sm_pmksa_cache_get(wpa_s->wpa, pasn->bssid,
+ rsn_data->pmkid, NULL,
+ pasn->akmp);
+ if (pmksa) {
+ wpa_printf(MSG_DEBUG, "PASN: Using PMKSA");
+
+ pasn->pmk_len = pmksa->pmk_len;
+ os_memcpy(pasn->pmk, pmksa->pmk, pmksa->pmk_len);
+ pasn->using_pmksa = true;
+
+ return 0;
+ }
+ }
+
+#ifdef CONFIG_SAE
+ if (pasn->akmp == WPA_KEY_MGMT_SAE) {
+ int ret;
+
+ ret = wpas_pasn_wd_sae_rx(wpa_s, wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed processing SAE wrapped data");
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: Success deriving PMK with SAE");
+ pasn->pmk_len = PMK_LEN;
+ os_memcpy(pasn->pmk, pasn->sae.pmk, PMK_LEN);
+
+ wpa_pasn_pmksa_cache_add(wpa_s->wpa, pasn->pmk,
+ pasn->pmk_len, pasn->sae.pmkid,
+ pasn->bssid, pasn->akmp);
+ return 0;
+ }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_FILS
+ if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+ pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+ int ret;
+
+ ret = wpas_pasn_wd_fils_rx(wpa_s, wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed processing FILS wrapped data");
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ return -1;
+ }
+
+ return 0;
+ }
+#endif /* CONFIG_FILS */
+
+ /* TODO: Derive PMK based on wrapped data */
+ wpa_printf(MSG_DEBUG, "PASN: Missing implementation to derive PMK");
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ return -1;
+}
+
+
+static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ int akmp, int cipher, u16 group, int freq,
+ const u8 *beacon_rsne, u8 beacon_rsne_len,
+ const u8 *beacon_rsnxe, u8 beacon_rsnxe_len,
+ int network_id)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct wpa_ssid *ssid = NULL;
+ struct wpabuf *frame;
+ int ret;
+
+ /* TODO: Currently support only ECC groups */
+ if (!dragonfly_suitable_group(group, 1)) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Reject unsuitable group %u", group);
+ return -1;
+ }
+
+ ssid = wpa_config_get_network(wpa_s->conf, network_id);
+
+ switch (akmp) {
+ case WPA_KEY_MGMT_PASN:
+ break;
+#ifdef CONFIG_SAE
+ case WPA_KEY_MGMT_SAE:
+ if (!ssid) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: No network profile found for SAE");
+ return -1;
+ }
+ pasn->sae.state = SAE_NOTHING;
+ pasn->sae.send_confirm = 0;
+ pasn->ssid = ssid;
+ break;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+ pasn->ssid = ssid;
+ break;
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ case WPA_KEY_MGMT_FT_PSK:
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ break;
+#endif /* CONFIG_IEEE80211R */
+ default:
+ wpa_printf(MSG_ERROR, "PASN: Unsupported AKMP=0x%x", akmp);
+ return -1;
+ }
+
+ pasn->ecdh = crypto_ecdh_init(group);
+ if (!pasn->ecdh) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
+ goto fail;
+ }
+
+ pasn->beacon_rsne_rsnxe = wpabuf_alloc(beacon_rsne_len +
+ beacon_rsnxe_len);
+ if (!pasn->beacon_rsne_rsnxe) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed storing beacon RSNE/RSNXE");
+ goto fail;
+ }
+
+ wpabuf_put_data(pasn->beacon_rsne_rsnxe, beacon_rsne, beacon_rsne_len);
+ if (beacon_rsnxe && beacon_rsnxe_len)
+ wpabuf_put_data(pasn->beacon_rsne_rsnxe, beacon_rsnxe,
+ beacon_rsnxe_len);
+
+ pasn->akmp = akmp;
+ pasn->cipher = cipher;
+ pasn->group = group;
+ pasn->freq = freq;
+ os_memcpy(pasn->bssid, bssid, ETH_ALEN);
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: Init: " MACSTR " akmp=0x%x, cipher=0x%x, group=%u",
+ MAC2STR(pasn->bssid), pasn->akmp, pasn->cipher,
+ pasn->group);
+
+ frame = wpas_pasn_build_auth_1(wpa_s);
+ if (!frame) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame");
+ goto fail;
+ }
+
+ ret = wpa_drv_send_mlme(wpa_s, wpabuf_head(frame), wpabuf_len(frame), 0,
+ pasn->freq, 1000);
+
+ wpabuf_free(frame);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed sending 1st auth frame");
+ goto fail;
+ }
+
+ eloop_register_timeout(2, 0, wpas_pasn_auth_work_timeout, wpa_s, NULL);
+ return 0;
+
+fail:
+ return -1;
+}
+
+
+static struct wpa_bss * wpas_pasn_allowed(struct wpa_supplicant *wpa_s,
+ const u8 *bssid, int akmp, int cipher)
+{
+ struct wpa_bss *bss;
+ const u8 *rsne;
+ struct wpa_ie_data rsne_data;
+ int ret;
+
+ if (os_memcmp(wpa_s->bssid, bssid, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Not doing authentication with current BSS");
+ return NULL;
+ }
+
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "PASN: BSS not found");
+ return NULL;
+ }
+
+ rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (!rsne) {
+ wpa_printf(MSG_DEBUG, "PASN: BSS without RSNE");
+ return NULL;
+ }
+
+ ret = wpa_parse_wpa_ie(rsne, *(rsne + 1) + 2, &rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE data");
+ return NULL;
+ }
+
+ if (!(rsne_data.key_mgmt & akmp) ||
+ !(rsne_data.pairwise_cipher & cipher)) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: AP does not support requested AKMP or cipher");
+ return NULL;
+ }
+
+ return bss;
+}
+
+
+static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct wpa_pasn_auth_work *awork = work->ctx;
+ struct wpa_bss *bss;
+ const u8 *rsne, *rsnxe;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "PASN: auth_start_cb: deinit=%d", deinit);
+
+ if (deinit) {
+ if (work->started) {
+ eloop_cancel_timeout(wpas_pasn_auth_work_timeout,
+ wpa_s, NULL);
+ wpa_s->pasn_auth_work = NULL;
+ }
+ os_free(awork);
+ return;
+ }
+
+ /*
+ * It is possible that by the time the callback is called, the PASN
+ * authentication is not allowed, e.g., a connection with the AP was
+ * established.
+ */
+ bss = wpas_pasn_allowed(wpa_s, awork->bssid, awork->akmp,
+ awork->cipher);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "PASN: auth_start_cb: Not allowed");
+ goto fail;
+ }
+
+ rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (!rsne) {
+ wpa_printf(MSG_DEBUG, "PASN: BSS without RSNE");
+ goto fail;
+ }
+
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+
+ ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher,
+ awork->group, bss->freq, rsne, *(rsne + 1) + 2,
+ rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0,
+ awork->network_id);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed to start PASN authentication");
+ goto fail;
+ }
+
+ wpa_s->pasn_auth_work = work;
+ return;
+fail:
+ os_free(awork);
+ work->ctx = NULL;
+ radio_work_done(work);
+}
+
+
+int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ int akmp, int cipher, u16 group, int network_id)
+{
+ struct wpa_pasn_auth_work *awork;
+ struct wpa_bss *bss;
+
+ wpa_printf(MSG_DEBUG, "PASN: Start: " MACSTR " akmp=0x%x, cipher=0x%x",
+ MAC2STR(bssid), akmp, cipher);
+
+ /*
+ * TODO: Consider modifying the offchannel logic to handle additional
+ * Management frames other then Action frames. For now allow PASN only
+ * with drivers that support off-channel TX.
+ */
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX)) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Driver does not support offchannel TX");
+ return -1;
+ }
+
+ if (radio_work_pending(wpa_s, "pasn-start-auth")) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: send_auth: Work is already pending");
+ return -1;
+ }
+
+ if (wpa_s->pasn_auth_work) {
+ wpa_printf(MSG_DEBUG, "PASN: send_auth: Already in progress");
+ return -1;
+ }
+
+ bss = wpas_pasn_allowed(wpa_s, bssid, akmp, cipher);
+ if (!bss)
+ return -1;
+
+ wpas_pasn_reset(wpa_s);
+
+ awork = os_zalloc(sizeof(*awork));
+ if (!awork)
+ return -1;
+
+ os_memcpy(awork->bssid, bssid, ETH_ALEN);
+ awork->akmp = akmp;
+ awork->cipher = cipher;
+ awork->group = group;
+ awork->network_id = network_id;
+
+ if (radio_add_work(wpa_s, bss->freq, "pasn-start-auth", 1,
+ wpas_pasn_auth_start_cb, awork) < 0) {
+ os_free(awork);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: Auth work successfully added");
+ return 0;
+}
+
+
+void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+
+ if (!wpa_s->pasn.ecdh)
+ return;
+
+ wpa_printf(MSG_DEBUG, "PASN: Stopping authentication");
+
+ wpas_pasn_auth_status(wpa_s, pasn->bssid, pasn->akmp, pasn->cipher,
+ pasn->status);
+
+ wpas_pasn_reset(wpa_s);
+}
+
+
+int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct ieee802_11_elems elems;
+ struct wpa_ie_data rsn_data;
+ struct wpa_pasn_params_data pasn_params;
+ struct wpabuf *wrapped_data = NULL, *secret = NULL, *frame = NULL;
+ u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
+ u8 mic_len;
+ u16 status;
+ int ret;
+ u16 fc = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_AUTH << 4));
+
+ if (!wpa_s->pasn_auth_work || !mgmt ||
+ len < offsetof(struct ieee80211_mgmt, u.auth.variable))
+ return -2;
+
+ /* Not an Authentication frame; do nothing */
+ if ((mgmt->frame_control & fc) != fc)
+ return -2;
+
+ /* Not our frame; do nothing */
+ if (os_memcmp(mgmt->da, wpa_s->own_addr, ETH_ALEN) != 0 ||
+ os_memcmp(mgmt->sa, pasn->bssid, ETH_ALEN) != 0 ||
+ os_memcmp(mgmt->bssid, pasn->bssid, ETH_ALEN) != 0)
+ return -2;
+
+ /* Not PASN; do nothing */
+ if (mgmt->u.auth.auth_alg != host_to_le16(WLAN_AUTH_PASN))
+ return -2;
+
+ if (mgmt->u.auth.auth_transaction !=
+ host_to_le16(pasn->trans_seq + 1)) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: RX: Invalid transaction sequence: (%u != %u)",
+ le_to_host16(mgmt->u.auth.auth_transaction),
+ pasn->trans_seq + 1);
+ return -1;
+ }
+
+ status = le_to_host16(mgmt->u.auth.status_code);
+
+ if (status != WLAN_STATUS_SUCCESS &&
+ status != WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Authentication rejected - status=%u", status);
+ pasn->status = status;
+ wpas_pasn_auth_stop(wpa_s);
+ return -1;
+ }
+
+ if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable),
+ &elems, 0) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed parsing Authentication frame");
+ goto fail;
+ }
+
+ /* Check that the MIC IE exists. Save it and zero out the memory */
+ mic_len = pasn_mic_len(pasn->akmp, pasn->cipher);
+ if (status == WLAN_STATUS_SUCCESS) {
+ if (!elems.mic || elems.mic_len != mic_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid MIC. Expecting len=%u",
+ mic_len);
+ goto fail;
+ } else {
+ os_memcpy(mic, elems.mic, mic_len);
+ /* TODO: Clean this up.. Should not be modifying the
+ * received message buffer. */
+ os_memset((u8 *) elems.mic, 0, mic_len);
+ }
+ }
+
+ if (!elems.pasn_params || !elems.pasn_params_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Missing PASN Parameters IE");
+ goto fail;
+ }
+
+ ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
+ elems.pasn_params_len + 3,
+ true, &pasn_params);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed validation PASN of Parameters IE");
+ goto fail;
+ }
+
+ /* TODO: handle comeback flow */
+ if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Authentication temporarily rejected");
+ goto fail;
+ }
+
+ ret = wpa_parse_wpa_ie(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsn_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed parsing RNSE");
+ goto fail;
+ }
+
+ ret = wpa_pasn_validate_rsne(&rsn_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE");
+ goto fail;
+ }
+
+ if (pasn->akmp != rsn_data.key_mgmt ||
+ pasn->cipher != rsn_data.pairwise_cipher) {
+ wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
+ goto fail;
+ }
+
+ if (pasn->group != pasn_params.group) {
+ wpa_printf(MSG_DEBUG, "PASN: Mismatch in group");
+ goto fail;
+ }
+
+ if (!pasn_params.pubkey || !pasn_params.pubkey_len) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid public key");
+ goto fail;
+ }
+
+ secret = crypto_ecdh_set_peerkey(pasn->ecdh, 0,
+ pasn_params.pubkey,
+ pasn_params.pubkey_len);
+
+ if (!secret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
+ goto fail;
+ }
+
+ if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
+ wrapped_data = ieee802_11_defrag(&elems,
+ WLAN_EID_EXTENSION,
+ WLAN_EID_EXT_WRAPPED_DATA);
+
+ if (!wrapped_data) {
+ wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
+ goto fail;
+ }
+ }
+
+ ret = wpas_pasn_set_pmk(wpa_s, &rsn_data, &pasn_params, wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to set PMK");
+ goto fail;
+ }
+
+ ret = pasn_pmk_to_ptk(pasn->pmk, pasn->pmk_len,
+ wpa_s->own_addr, pasn->bssid,
+ wpabuf_head(secret), wpabuf_len(secret),
+ &pasn->ptk, pasn->akmp, pasn->cipher,
+ WPA_KDK_MAX_LEN);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
+ goto fail;
+ }
+
+ wpabuf_free(wrapped_data);
+ wrapped_data = NULL;
+ wpabuf_free(secret);
+ secret = NULL;
+
+ /* Verify the MIC */
+ ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
+ pasn->bssid, wpa_s->own_addr,
+ wpabuf_head(pasn->beacon_rsne_rsnxe),
+ wpabuf_len(pasn->beacon_rsne_rsnxe),
+ (u8 *) &mgmt->u.auth,
+ len - offsetof(struct ieee80211_mgmt, u.auth),
+ out_mic);
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: Frame MIC", mic, mic_len);
+ if (ret || os_memcmp(mic, out_mic, mic_len) != 0) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed MIC verification");
+ goto fail;
+ }
+
+ pasn->trans_seq++;
+
+ wpa_printf(MSG_DEBUG, "PASN: Success verifying Authentication frame");
+
+ frame = wpas_pasn_build_auth_3(wpa_s);
+ if (!frame) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed building 3rd auth frame");
+ goto fail;
+ }
+
+ ret = wpa_drv_send_mlme(wpa_s, wpabuf_head(frame), wpabuf_len(frame), 0,
+ pasn->freq, 100);
+ wpabuf_free(frame);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed sending 3st auth frame");
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: Success sending last frame. Store PTK");
+
+ ptksa_cache_add(wpa_s->ptksa, pasn->bssid, pasn->cipher,
+ dot11RSNAConfigPMKLifetime, &pasn->ptk);
+
+ forced_memzero(&pasn->ptk, sizeof(pasn->ptk));
+
+ pasn->status = WLAN_STATUS_SUCCESS;
+ return 0;
+fail:
+ wpa_printf(MSG_DEBUG, "PASN: Failed RX processing - terminating");
+ wpabuf_free(wrapped_data);
+ wpabuf_free(secret);
+
+ /*
+ * TODO: In case of an error the standard allows to silently drop
+ * the frame and terminate the authentication exchange. However, better
+ * reply to the AP with an error status.
+ */
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpas_pasn_auth_stop(wpa_s);
+ return -1;
+}
+
+
+int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
+ const u8 *data, size_t data_len, u8 acked)
+
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ const struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) data;
+ u16 fc = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_AUTH << 4));
+
+ wpa_printf(MSG_DEBUG, "PASN: auth_tx_status: acked=%u", acked);
+
+ if (!wpa_s->pasn_auth_work) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: auth_tx_status: no work in progress");
+ return -1;
+ }
+
+ if (!mgmt ||
+ data_len < offsetof(struct ieee80211_mgmt, u.auth.variable))
+ return -1;
+
+ /* Not an authentication frame; do nothing */
+ if ((mgmt->frame_control & fc) != fc)
+ return -1;
+
+ /* Not our frame; do nothing */
+ if (os_memcmp(mgmt->da, pasn->bssid, ETH_ALEN) ||
+ os_memcmp(mgmt->sa, wpa_s->own_addr, ETH_ALEN) ||
+ os_memcmp(mgmt->bssid, pasn->bssid, ETH_ALEN))
+ return -1;
+
+ /* Not PASN; do nothing */
+ if (mgmt->u.auth.auth_alg != host_to_le16(WLAN_AUTH_PASN))
+ return -1;
+
+ if (mgmt->u.auth.auth_transaction != host_to_le16(pasn->trans_seq)) {
+ wpa_printf(MSG_ERROR,
+ "PASN: Invalid transaction sequence: (%u != %u)",
+ pasn->trans_seq,
+ le_to_host16(mgmt->u.auth.auth_transaction));
+ return 0;
+ }
+
+ wpa_printf(MSG_ERROR,
+ "PASN: auth with trans_seq=%u, acked=%u", pasn->trans_seq,
+ acked);
+
+ /*
+ * Even if the frame was not acked, do not treat this is an error, and
+ * try to complete the flow, relying on the PASN timeout callback to
+ * clean up.
+ */
+ if (pasn->trans_seq == 3) {
+ wpa_printf(MSG_DEBUG, "PASN: auth complete with: " MACSTR,
+ MAC2STR(pasn->bssid));
+ /*
+ * Either frame was not ACKed or it was ACKed but the trans_seq
+ * != 1, i.e., not expecting an RX frame, so we are done.
+ */
+ wpas_pasn_auth_stop(wpa_s);
+ }
+
+ return 0;
+}
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index dc955b8f..97c16fb8 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -154,7 +154,8 @@ 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,
- u32 pmk_lifetime, u8 pmk_reauth_threshold)
+ u32 pmk_lifetime, u8 pmk_reauth_threshold,
+ int akmp)
{
printf("%s - not implemented\n", __func__);
return -1;
diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c
new file mode 100644
index 00000000..f6da56ee
--- /dev/null
+++ b/wpa_supplicant/robust_av.c
@@ -0,0 +1,155 @@
+/*
+ * 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;
+ size_t buf_len;
+ int ret;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
+ return 0;
+
+ if (!wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_MSCS)) {
+ 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] <= 8)
+ return;
+
+ /* Subelements start after (ie_id(1) + ie_len(1) + ext_id(1) +
+ * request type(1) + upc(2) + stream timeout(4) =) 10.
+ */
+ mscs_status = get_ie(&mscs_desc_ie[10], mscs_desc_ie[1] - 8,
+ 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 afc11727..cf107eba 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -556,23 +556,32 @@ static int * wpas_add_channels(const struct oper_class_map *op,
static int * wpas_op_class_freqs(const struct oper_class_map *op,
struct hostapd_hw_modes *mode, int active)
{
- u8 channels_80mhz[] = { 42, 58, 106, 122, 138, 155 };
- u8 channels_160mhz[] = { 50, 114 };
+ u8 channels_80mhz_5ghz[] = { 42, 58, 106, 122, 138, 155, 171 };
+ u8 channels_160mhz_5ghz[] = { 50, 114, 163 };
+ u8 channels_80mhz_6ghz[] = { 7, 23, 39, 55, 71, 87, 103, 119, 135, 151,
+ 167, 183, 199, 215 };
+ u8 channels_160mhz_6ghz[] = { 15, 47, 79, 111, 143, 175, 207 };
+ const u8 *channels = NULL;
+ size_t num_chan = 0;
+ bool is_6ghz = is_6ghz_op_class(op->op_class);
/*
* When adding all channels in the operating class, 80 + 80 MHz
* operating classes are like 80 MHz channels because we add all valid
* channels anyway.
*/
- if (op->bw == BW80 || op->bw == BW80P80)
- return wpas_add_channels(op, mode, active, channels_80mhz,
- ARRAY_SIZE(channels_80mhz));
-
- if (op->bw == BW160)
- return wpas_add_channels(op, mode, active, channels_160mhz,
- ARRAY_SIZE(channels_160mhz));
+ if (op->bw == BW80 || op->bw == BW80P80) {
+ channels = is_6ghz ? channels_80mhz_6ghz : channels_80mhz_5ghz;
+ num_chan = is_6ghz ? ARRAY_SIZE(channels_80mhz_6ghz) :
+ ARRAY_SIZE(channels_80mhz_5ghz);
+ } else if (op->bw == BW160) {
+ channels = is_6ghz ? channels_160mhz_6ghz :
+ channels_160mhz_5ghz;
+ num_chan = is_6ghz ? ARRAY_SIZE(channels_160mhz_6ghz) :
+ ARRAY_SIZE(channels_160mhz_5ghz);
+ }
- return wpas_add_channels(op, mode, active, NULL, 0);
+ return wpas_add_channels(op, mode, active, channels, num_chan);
}
@@ -766,10 +775,10 @@ int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
static int wpas_beacon_rep_add_frame_body(struct bitfield *eids,
enum beacon_report_detail detail,
struct wpa_bss *bss, u8 *buf,
- size_t buf_len, u8 **ies_buf,
+ size_t buf_len, const u8 **ies_buf,
size_t *ie_len, int add_fixed)
{
- u8 *ies = *ies_buf;
+ const u8 *ies = *ies_buf;
size_t ies_len = *ie_len;
u8 *pos = buf;
int rem_len;
@@ -851,7 +860,7 @@ static int wpas_add_beacon_rep_elem(struct beacon_rep_data *data,
struct wpa_bss *bss,
struct wpabuf **wpa_buf,
struct rrm_measurement_beacon_report *rep,
- u8 **ie, size_t *ie_len, u8 idx)
+ const u8 **ie, size_t *ie_len, u8 idx)
{
int ret;
u8 *buf, *pos;
@@ -918,8 +927,8 @@ static int wpas_add_beacon_rep(struct wpa_supplicant *wpa_s,
u64 start, u64 parent_tsf)
{
struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
- u8 *ies = (u8 *) (bss + 1);
- u8 *pos = ies;
+ const u8 *ies = wpa_bss_ie_ptr(bss);
+ const u8 *pos = ies;
size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
struct rrm_measurement_beacon_report rep;
u8 idx = 0;
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index b4757309..24d06c00 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -237,6 +237,10 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
if (wpa_s->disconnected)
retry = 0;
+ /* do not retry if operation is not supported */
+ if (ret == -EOPNOTSUPP)
+ retry = 0;
+
wpa_supplicant_notify_scanning(wpa_s, 0);
wpas_notify_scan_done(wpa_s, 0);
if (wpa_s->wpa_state == WPA_SCANNING)
@@ -517,7 +521,7 @@ void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s)
{
struct wpabuf *default_ies = NULL;
u8 ext_capab[18];
- int ext_capab_len;
+ int ext_capab_len, frame_id;
enum wpa_driver_if_type type = WPA_IF_STATION;
#ifdef CONFIG_P2P
@@ -541,6 +545,20 @@ void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s)
wpas_mbo_scan_ie(wpa_s, default_ies);
#endif /* CONFIG_MBO */
+ if (type == WPA_IF_P2P_CLIENT)
+ frame_id = VENDOR_ELEM_PROBE_REQ_P2P;
+ else
+ frame_id = VENDOR_ELEM_PROBE_REQ;
+
+ if (wpa_s->vendor_elem[frame_id]) {
+ size_t len;
+
+ len = wpabuf_len(wpa_s->vendor_elem[frame_id]);
+ if (len > 0 && wpabuf_resize(&default_ies, len) == 0)
+ wpabuf_put_buf(default_ies,
+ wpa_s->vendor_elem[frame_id]);
+ }
+
if (default_ies)
wpa_drv_set_default_scan_ies(wpa_s, wpabuf_head(default_ies),
wpabuf_len(default_ies));
@@ -666,30 +684,38 @@ static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_P2P */
-static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
- enum hostapd_hw_mode band,
- struct wpa_driver_scan_params *params,
- int is_6ghz)
+int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s,
+ enum hostapd_hw_mode band,
+ struct wpa_driver_scan_params *params, bool is_6ghz)
{
/* Include only supported channels for the specified band */
struct hostapd_hw_modes *mode;
- int count, i;
+ int num_chans = 0;
+ int *freqs, i;
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));
- return;
+ if (!mode)
+ return -1;
+
+ if (params->freqs) {
+ while (params->freqs[num_chans])
+ num_chans++;
}
- params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
- if (params->freqs == NULL)
- return;
- for (count = 0, i = 0; i < mode->num_channels; i++) {
+ freqs = os_realloc(params->freqs,
+ (num_chans + mode->num_channels + 1) * sizeof(int));
+ if (!freqs)
+ return -1;
+
+ params->freqs = freqs;
+ for (i = 0; i < mode->num_channels; i++) {
if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
continue;
- params->freqs[count++] = mode->channels[i].freq;
+ params->freqs[num_chans++] = mode->channels[i].freq;
}
+ params->freqs[num_chans] = 0;
+
+ return 0;
}
@@ -700,12 +726,16 @@ static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s,
return; /* unknown what channels the driver supports */
if (params->freqs)
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, 0);
- else if (wpa_s->setband == WPA_SETBAND_2G)
- wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
- params, 0);
+
+ if (wpa_s->setband_mask & WPA_SETBAND_5G)
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
+ 0);
+ if (wpa_s->setband_mask & WPA_SETBAND_2G)
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params,
+ 0);
+ if (wpa_s->setband_mask & WPA_SETBAND_6G)
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
+ 1);
}
@@ -983,6 +1013,19 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
}
#ifdef CONFIG_P2P
+#ifdef ANDROID
+ if (wpa_s->global->p2p_go_found_external_scan &&
+ (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT) &&
+ (wpa_s->global->p2p_group_formation == wpa_s)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Try to fast associate since GO is found in external scan");
+ wpa_s->global->p2p_go_found_external_scan = 0;
+ if (wpa_supplicant_fast_associate(wpa_s) >= 0) {
+ return;
+ }
+ }
+#endif
+
if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
wpa_s->go_params && !wpa_s->conf->passive_scan) {
wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)",
@@ -1197,7 +1240,12 @@ ssid_list_set:
wpa_setband_scan_freqs(wpa_s, &params);
/* See if user specified frequencies. If so, scan only those. */
- if (wpa_s->conf->freq_list && !params.freqs) {
+ if (wpa_s->last_scan_req == INITIAL_SCAN_REQ &&
+ wpa_s->conf->initial_freq_list && !params.freqs) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Optimize scan based on conf->initial_freq_list");
+ int_array_concat(&params.freqs, wpa_s->conf->initial_freq_list);
+ } else if (wpa_s->conf->freq_list && !params.freqs) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Optimize scan based on conf->freq_list");
int_array_concat(&params.freqs, wpa_s->conf->freq_list);
@@ -1865,18 +1913,15 @@ const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
u32 vendor_type)
{
- const u8 *end, *pos;
+ const u8 *ies;
+ const struct element *elem;
- pos = (const u8 *) (res + 1);
- end = pos + res->ie_len;
+ ies = (const u8 *) (res + 1);
- while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
- break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- return pos;
- pos += 2 + pos[1];
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, res->ie_len) {
+ if (elem->datalen >= 4 &&
+ vendor_type == WPA_GET_BE32(elem->data))
+ return &elem->id;
}
return NULL;
@@ -1898,22 +1943,20 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
u32 vendor_type)
{
- const u8 *end, *pos;
+ const u8 *ies;
+ const struct element *elem;
if (res->beacon_ie_len == 0)
return NULL;
- pos = (const u8 *) (res + 1);
- pos += res->ie_len;
- end = pos + res->beacon_ie_len;
+ ies = (const u8 *) (res + 1);
+ ies += res->ie_len;
- while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
- break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- return pos;
- pos += 2 + pos[1];
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies,
+ res->beacon_ie_len) {
+ if (elem->datalen >= 4 &&
+ vendor_type == WPA_GET_BE32(elem->data))
+ return &elem->id;
}
return NULL;
@@ -1944,12 +1987,17 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
end = pos + res->ie_len;
while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
+ u8 ie, len;
+
+ ie = pos[0];
+ len = pos[1];
+ if (len > end - pos - 2)
break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
- pos += 2 + pos[1];
+ pos += 2;
+ if (ie == WLAN_EID_VENDOR_SPECIFIC && len >= 4 &&
+ vendor_type == WPA_GET_BE32(pos))
+ wpabuf_put_data(buf, pos + 4, len - 4);
+ pos += len;
}
if (wpabuf_len(buf) == 0) {
@@ -2187,6 +2235,60 @@ void scan_snr(struct wpa_scan_res *res)
}
+/* 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)
{
@@ -2194,68 +2296,42 @@ static unsigned int interpolate_rate(int snr, int snr0, int snr1,
}
-#define INTERPOLATE_RATE(snr0, snr1, rate0, rate1) \
- if (snr < (snr1)) \
- return interpolate_rate(snr, (snr0), (snr1), (rate0), (rate1))
+static unsigned int max_rate(const struct minsnr_bitrate_entry table[],
+ int snr, bool vht)
+{
+ 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_ht20_rate(int snr, int vht)
+
+static unsigned int max_ht20_rate(int snr, bool vht)
{
- if (snr < 0)
- return 0;
- INTERPOLATE_RATE(0, 2, 0, 6500); /* HT20 MCS0 */
- INTERPOLATE_RATE(2, 5, 6500, 13000); /* HT20 MCS1 */
- INTERPOLATE_RATE(5, 9, 13000, 19500); /* HT20 MCS2 */
- INTERPOLATE_RATE(9, 11, 19500, 26000); /* HT20 MCS3 */
- INTERPOLATE_RATE(11, 15, 26000, 39000); /* HT20 MCS4 */
- INTERPOLATE_RATE(15, 18, 39000, 52000); /* HT20 MCS5 */
- INTERPOLATE_RATE(18, 20, 52000, 58500); /* HT20 MCS6 */
- INTERPOLATE_RATE(20, 25, 58500, 65000); /* HT20 MCS7 */
- if (!vht)
- return 65000;
- INTERPOLATE_RATE(25, 29, 65000, 78000); /* VHT20 MCS8 */
- return 78000;
+ return max_rate(vht20_table, snr, vht);
}
-static unsigned int max_ht40_rate(int snr, int vht)
+static unsigned int max_ht40_rate(int snr, bool vht)
{
- if (snr < 0)
- return 0;
- INTERPOLATE_RATE(0, 5, 0, 13500); /* HT40 MCS0 */
- INTERPOLATE_RATE(5, 8, 13500, 27000); /* HT40 MCS1 */
- INTERPOLATE_RATE(8, 12, 27000, 40500); /* HT40 MCS2 */
- INTERPOLATE_RATE(12, 14, 40500, 54000); /* HT40 MCS3 */
- INTERPOLATE_RATE(14, 18, 54000, 81000); /* HT40 MCS4 */
- INTERPOLATE_RATE(18, 21, 81000, 108000); /* HT40 MCS5 */
- INTERPOLATE_RATE(21, 23, 108000, 121500); /* HT40 MCS6 */
- INTERPOLATE_RATE(23, 28, 121500, 135000); /* HT40 MCS7 */
- if (!vht)
- return 135000;
- INTERPOLATE_RATE(28, 32, 135000, 162000); /* VHT40 MCS8 */
- INTERPOLATE_RATE(32, 34, 162000, 180000); /* VHT40 MCS9 */
- return 180000;
+ return max_rate(vht40_table, snr, vht);
}
static unsigned int max_vht80_rate(int snr)
{
- if (snr < 0)
- return 0;
- INTERPOLATE_RATE(0, 8, 0, 29300); /* VHT80 MCS0 */
- INTERPOLATE_RATE(8, 11, 29300, 58500); /* VHT80 MCS1 */
- INTERPOLATE_RATE(11, 15, 58500, 87800); /* VHT80 MCS2 */
- INTERPOLATE_RATE(15, 17, 87800, 117000); /* VHT80 MCS3 */
- INTERPOLATE_RATE(17, 21, 117000, 175500); /* VHT80 MCS4 */
- INTERPOLATE_RATE(21, 24, 175500, 234000); /* VHT80 MCS5 */
- INTERPOLATE_RATE(24, 26, 234000, 263300); /* VHT80 MCS6 */
- INTERPOLATE_RATE(26, 31, 263300, 292500); /* VHT80 MCS7 */
- INTERPOLATE_RATE(31, 35, 292500, 351000); /* VHT80 MCS8 */
- INTERPOLATE_RATE(35, 37, 351000, 390000); /* VHT80 MCS9 */
- return 390000;
+ return max_rate(vht80_table, snr, 1);
}
-#undef INTERPOLATE_RATE
-
unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
const u8 *ies, size_t ies_len, int rate,
@@ -2309,7 +2385,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
if (capab == CAPAB_HT || capab == CAPAB_HT40 || capab == CAPAB_VHT) {
ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP);
if (ie) {
- tmp = max_ht20_rate(snr, 0);
+ tmp = max_ht20_rate(snr, false);
if (tmp > est)
est = tmp;
}
@@ -2319,7 +2395,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
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, 0);
+ tmp = max_ht40_rate(snr, false);
if (tmp > est)
est = tmp;
}
@@ -2329,7 +2405,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
/* Use +1 to assume VHT is always faster than HT */
ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP);
if (ie) {
- tmp = max_ht20_rate(snr, 1) + 1;
+ tmp = max_ht20_rate(snr, true) + 1;
if (tmp > est)
est = tmp;
@@ -2337,7 +2413,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
if (ie && ie[1] >= 2 &&
(ie[3] &
HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
- tmp = max_ht40_rate(snr, 1) + 1;
+ tmp = max_ht40_rate(snr, true) + 1;
if (tmp > est)
est = tmp;
}
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index c9ce2cec..8eb5c73e 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -86,5 +86,9 @@ 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);
+int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s,
+ enum hostapd_hw_mode band,
+ struct wpa_driver_scan_params *params,
+ bool is_6ghz);
#endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index d06f6e29..36f4d3c4 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -85,16 +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 *ret_use_pt)
+ 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) {
@@ -123,7 +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.tmp->h2e;
+ 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) {
@@ -131,19 +137,37 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
return NULL;
}
+ 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 (use_pt || wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) {
- bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
- if (bss) {
- const u8 *rsnxe;
+ 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 */
- rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
- if (rsnxe && rsnxe[1] >= 1)
- use_pt = !!(rsnxe[2] &
- BIT(WLAN_RSNX_CAPAB_SAE_H2E));
- }
+ if (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 &&
@@ -157,7 +181,7 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
if (use_pt &&
sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt,
wpa_s->own_addr, bssid,
- wpa_s->sme.sae_rejected_groups) < 0)
+ wpa_s->sme.sae_rejected_groups, NULL) < 0)
return NULL;
if (!use_pt &&
sae_prepare_commit(wpa_s->own_addr, bssid,
@@ -167,8 +191,17 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
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 ? 3 + wpabuf_len(wpa_s->sme.sae_token) : 0;
@@ -179,8 +212,12 @@ reuse_data:
return NULL;
if (!external) {
wpabuf_put_le16(buf, 1); /* Transaction seq# */
- wpabuf_put_le16(buf, use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT :
- 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) {
@@ -189,6 +226,8 @@ reuse_data:
}
if (ret_use_pt)
*ret_use_pt = use_pt;
+ if (ret_use_pk)
+ *ret_use_pk = use_pk;
return buf;
}
@@ -261,7 +300,7 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
*pos++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
*pos++ = rrm_ie_len;
- /* Set supported capabilites flags */
+ /* Set supported capabilities flags */
if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)
*pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
@@ -624,7 +663,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
}
#ifdef CONFIG_HS20
- if (is_hs20_network(wpa_s, ssid, bss)) {
+ if (is_hs20_config(wpa_s) && is_hs20_network(wpa_s, ssid, bss)) {
struct wpabuf *hs20;
hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN);
@@ -716,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, NULL);
+ start == 2, NULL,
+ NULL);
else
resp = sme_auth_build_sae_confirm(wpa_s, 0);
if (resp == NULL) {
@@ -1008,8 +1048,11 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
{
struct wpabuf *resp, *buf;
int use_pt;
+ bool use_pk;
+ u16 status;
- resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0, &use_pt);
+ 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;
@@ -1023,10 +1066,14 @@ 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,
- use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT :
- WLAN_STATUS_SUCCESS);
+ 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);
@@ -1223,8 +1270,7 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
wpabuf_free(wpa_s->sme.sae_token);
token_pos = data + sizeof(le16);
token_len = len - sizeof(le16);
- if (wpa_s->sme.sae.tmp)
- h2e = wpa_s->sme.sae.tmp->h2e;
+ h2e = wpa_s->sme.sae.h2e;
if (h2e) {
if (token_len < 3) {
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1287,7 +1333,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
}
if (status_code != WLAN_STATUS_SUCCESS &&
- status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+ status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT &&
+ status_code != WLAN_STATUS_SAE_PK)
return -1;
if (auth_transaction == 1) {
@@ -1304,24 +1351,30 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
"SAE: Ignore commit message while waiting for confirm");
return 0;
}
- if (wpa_s->sme.sae.tmp && wpa_s->sme.sae.tmp->h2e &&
- status_code == WLAN_STATUS_SUCCESS) {
+ 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.tmp && !wpa_s->sme.sae.tmp->h2e &&
+ 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, status_code ==
- WLAN_STATUS_SAE_HASH_TO_ELEMENT);
+ 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");
@@ -1827,6 +1880,40 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
pfs_fail:
#endif /* CONFIG_DPP2 */
+ wpa_s->mscs_setup_done = false;
+ if (wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_MSCS) &&
+ wpa_s->robust_av.valid_config) {
+ struct wpabuf *mscs_ie;
+ size_t mscs_ie_len, buf_len, *wpa_ie_len, max_ie_len;
+
+ 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;
@@ -2373,7 +2460,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, 0);
+ HOSTAPD_MODE_IEEE80211G, false);
if (mode == NULL) {
/* No channels supported in this band - use empty list */
params->freqs = os_zalloc(sizeof(int));
@@ -2573,6 +2660,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;
@@ -2727,6 +2824,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;
@@ -2806,8 +2913,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/wmm_ac.c b/wpa_supplicant/wmm_ac.c
index 38800cc7..d0fdd55d 100644
--- a/wpa_supplicant/wmm_ac.c
+++ b/wpa_supplicant/wmm_ac.c
@@ -400,7 +400,7 @@ static int wmm_ac_ts_req_is_valid(struct wpa_supplicant *wpa_s,
req_ac = up_to_ac[params->user_priority];
- /* Requested accesss category must have acm */
+ /* Requested access category must have acm */
if (!wpa_s->wmm_ac_assoc_info->ac_params[req_ac].acm) {
wpa_printf(MSG_DEBUG, "WMM AC: AC %d is not ACM", req_ac);
return 0;
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index ac04383d..155e8f47 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);
@@ -374,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;
}
}
@@ -542,7 +552,7 @@ static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
freq = 2407 + chan * 5;
else if (chan == 14)
freq = 2484;
- else if (chan >= 36 && chan <= 169)
+ else if (chan >= 36 && chan <= 177)
freq = 5000 + chan * 5;
}
return freq;
@@ -1455,17 +1465,15 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC);
if (vendor) {
wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]);
- if (wpa_s->conf->btm_offload) {
- wpa_msg(wpa_s, MSG_INFO,
- "WNM: Notify BSS Transition Management Request frame status");
- wpa_s->bss_tm_status = WNM_BSS_TM_ACCEPT;
- wpas_notify_bss_tm_status(wpa_s);
- /* since it could be referenced in the scan result logic, initialize it */
- wpa_s->wnm_mbo_trans_reason_present = 0;
- return;
- }
}
#endif /* CONFIG_MBO */
+ if (wpa_s->conf->btm_offload) {
+ wpa_printf(MSG_INFO,
+ "WNM: BTM offload enabled. Notify status and return");
+ wpa_s->bss_tm_status = WNM_BSS_TM_ACCEPT;
+ wpas_notify_bss_tm_status(wpa_s);
+ return;
+ }
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 6a2d2c3d..b98a833d 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -493,7 +493,8 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
"sae_groups", "dtim_period", "beacon_int",
"ap_vendor_elements", "ignore_old_scan_res", "freq_list",
- "scan_cur_freq", "sched_scan_interval",
+ "scan_cur_freq", "scan_res_valid_for_connect",
+ "sched_scan_interval",
"tdls_external_control", "osu_dir", "wowlan_triggers",
"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
@@ -589,7 +590,8 @@ static char ** wpa_cli_complete_get(const char *str, int pos)
"wps_nfc_dev_pw_id", "ext_password_backend",
"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
"dtim_period", "beacon_int", "ignore_old_scan_res",
- "scan_cur_freq", "sched_scan_interval",
+ "scan_cur_freq", "scan_res_valid_for_connect",
+ "sched_scan_interval",
"sched_scan_start_delay",
"tdls_external_control", "osu_dir", "wowlan_triggers",
"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
@@ -1288,9 +1290,10 @@ static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
-static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_bssid_ignore(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
- return wpa_cli_cmd(ctrl, "BLACKLIST", 0, argc, argv);
+ return wpa_cli_cmd(ctrl, "BSSID_IGNORE", 0, argc, argv);
}
@@ -1406,8 +1409,8 @@ static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
static const char *network_fields[] = {
- "ssid", "scan_ssid", "bssid", "bssid_blacklist",
- "bssid_whitelist", "psk", "proto", "key_mgmt",
+ "ssid", "scan_ssid", "bssid", "bssid_ignore",
+ "bssid_accept", "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", "edmg",
@@ -2994,6 +2997,13 @@ static int wpa_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_SET", 1, argc, argv);
+}
+
+
static int wpa_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -3056,9 +3066,139 @@ static int wpa_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
return wpa_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
}
+
+#ifdef CONFIG_DPP2
+
+static int wpa_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_CONTROLLER_START", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_controller_stop(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_CONTROLLER_STOP");
+}
+
+
+static int wpa_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_CHIRP", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_STOP_CHIRP");
+}
+
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
+static int wpa_ctrl_command_bss(struct wpa_ctrl *ctrl, const char *cmd)
+{
+ char buf[512], *pos, *bssid = NULL, *freq = NULL, *level = NULL,
+ *flags = NULL, *ssid = NULL;
+ 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 ? bssid : "N/A",
+ freq ? freq : "N/A", level ? level : "N/A",
+ flags ? flags : "N/A", ssid ? ssid : "N/A");
+ 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;
+}
+
+
+#ifdef CONFIG_PASN
+
+static int wpa_cli_cmd_pasn_auth_start(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "PASN_AUTH_START", 4, argc, argv);
+}
+
+
+static int wpa_cli_cmd_pasn_auth_stop(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "PASN_AUTH_STOP", 0, argc, argv);
+}
+
+static int wpa_cli_cmd_ptksa_cache_list(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "PTKSA_CACHE_LIST", 0, argc, argv);
+}
+
+#endif /* CONFIG_PASN */
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -3185,11 +3325,15 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "bssid", wpa_cli_cmd_bssid, wpa_cli_complete_network_id,
cli_cmd_flag_none,
"<network id> <BSSID> = set preferred BSSID for an SSID" },
- { "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss,
+ { "bssid_ignore", wpa_cli_cmd_bssid_ignore, wpa_cli_complete_bss,
+ cli_cmd_flag_none,
+ "<BSSID> = add a BSSID to the list of temporarily ignored BSSs\n"
+ "bssid_ignore clear = clear the list of temporarily ignored BSSIDs\n"
+ "bssid_ignore = display the list of temporarily ignored BSSIDs" },
+ { "blacklist", /* deprecated alias for bssid_ignore */
+ wpa_cli_cmd_bssid_ignore, wpa_cli_complete_bss,
cli_cmd_flag_none,
- "<BSSID> = add a BSSID to the blacklist\n"
- "blacklist clear = clear the blacklist\n"
- "blacklist = display the blacklist" },
+ "= deprecated alias for bssid_ignore" },
{ "log_level", wpa_cli_cmd_log_level, NULL,
cli_cmd_flag_none,
"<level> [<timestamp>] = update the log level/timestamp\n"
@@ -3692,6 +3836,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "dpp_bootstrap_info", wpa_cli_cmd_dpp_bootstrap_info, NULL,
cli_cmd_flag_none,
"<id> = show DPP bootstrap information" },
+ { "dpp_bootstrap_set", wpa_cli_cmd_dpp_bootstrap_set, NULL,
+ cli_cmd_flag_none,
+ "<id> [conf=..] [ssid=<SSID>] [ssid_charset=#] [psk=<PSK>] [pass=<passphrase>] [configurator=<id>] [conn_status=#] [akm_use_selector=<0|1>] [group_id=..] [expiry=#] [csrattrs=..] = set DPP configurator parameters" },
{ "dpp_auth_init", wpa_cli_cmd_dpp_auth_init, NULL, cli_cmd_flag_none,
"peer=<id> [own=<id>] = initiate DPP bootstrapping" },
{ "dpp_listen", wpa_cli_cmd_dpp_listen, NULL, cli_cmd_flag_none,
@@ -3717,7 +3864,34 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "dpp_pkex_remove", wpa_cli_cmd_dpp_pkex_remove, NULL,
cli_cmd_flag_none,
"*|<id> = remove DPP pkex information" },
+#ifdef CONFIG_DPP2
+ { "dpp_controller_start", wpa_cli_cmd_dpp_controller_start, NULL,
+ cli_cmd_flag_none,
+ "[tcp_port=<port>] [role=..] = start DPP controller" },
+ { "dpp_controller_stop", wpa_cli_cmd_dpp_controller_stop, NULL,
+ cli_cmd_flag_none,
+ "= stop DPP controller" },
+ { "dpp_chirp", wpa_cli_cmd_dpp_chirp, NULL,
+ cli_cmd_flag_none,
+ "own=<BI ID> iter=<count> = start DPP chirp" },
+ { "dpp_stop_chirp", wpa_cli_cmd_dpp_stop_chirp, NULL,
+ cli_cmd_flag_none,
+ "= stop DPP chirp" },
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
+ { "all_bss", wpa_cli_cmd_all_bss, NULL, cli_cmd_flag_none,
+ "= list all BSS entries (scan results)" },
+#ifdef CONFIG_PASN
+ { "pasn_auth_start", wpa_cli_cmd_pasn_auth_start, NULL,
+ cli_cmd_flag_none,
+ "bssid=<BSSID> akmp=<WPA key mgmt> cipher=<WPA cipher> group=<group> nid=<network id> = Start PASN authentication" },
+ { "pasn_auth_stop", wpa_cli_cmd_pasn_auth_stop, NULL,
+ cli_cmd_flag_none,
+ "= Stop PASN authentication" },
+ { "ptksa_cache_list", wpa_cli_cmd_ptksa_cache_list, NULL,
+ cli_cmd_flag_none,
+ "= Get the PTKSA Cache" },
+#endif /* CONFIG_PASN */
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
@@ -4040,6 +4214,8 @@ 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_OVERLAP)) {
+ 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)) {
diff --git a/wpa_supplicant/wpa_gui-qt4/icons/.gitignore b/wpa_supplicant/wpa_gui-qt4/icons/.gitignore
new file mode 100644
index 00000000..8d772cc9
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/icons/.gitignore
@@ -0,0 +1,2 @@
+hicolor
+pixmaps
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index f928fdb8..ff3a9646 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -41,9 +41,10 @@
#include "common/hw_features_common.h"
#include "common/gas_server.h"
#include "common/dpp.h"
+#include "common/ptksa_cache.h"
#include "p2p/p2p.h"
#include "fst/fst.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
#include "wpas_glue.h"
#include "wps_supplicant.h"
#include "ibss_rsn.h"
@@ -222,7 +223,7 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
bssid = wpa_s->pending_bssid;
wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
MAC2STR(bssid));
- wpa_blacklist_add(wpa_s, bssid);
+ wpa_bssid_ignore_add(wpa_s, bssid);
wpas_notify_auth_timeout(wpa_s);
wpa_sm_notify_disassoc(wpa_s->wpa);
wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
@@ -291,7 +292,7 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
{
wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
- wpa_blacklist_del(wpa_s, wpa_s->bssid);
+ wpa_bssid_ignore_del(wpa_s, wpa_s->bssid);
os_free(wpa_s->last_con_fail_realm);
wpa_s->last_con_fail_realm = NULL;
wpa_s->last_con_fail_realm_len = 0;
@@ -574,9 +575,15 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wmm_ac_clear_saved_tspecs(wpa_s);
pmksa_candidate_free(wpa_s->wpa);
+ ptksa_cache_deinit(wpa_s->ptksa);
+ wpa_s->ptksa = NULL;
wpa_sm_deinit(wpa_s->wpa);
wpa_s->wpa = NULL;
- wpa_blacklist_clear(wpa_s);
+ wpa_bssid_ignore_clear(wpa_s);
+
+#ifdef CONFIG_PASN
+ wpas_pasn_auth_stop(wpa_s);
+#endif /* CONFIG_PASN */
wpa_bss_deinit(wpa_s);
@@ -727,6 +734,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
dpp_global_deinit(wpa_s->dpp);
wpa_s->dpp = NULL;
#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_PASN
+ wpas_pasn_auth_stop(wpa_s);
+#endif /* CONFIG_PASN */
}
@@ -804,7 +815,22 @@ const char * wpa_supplicant_state_txt(enum wpa_states state)
#ifdef CONFIG_BGSCAN
-static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
+static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->bgscan_ssid) {
+ bgscan_deinit(wpa_s);
+ wpa_s->bgscan_ssid = NULL;
+ }
+}
+
+
+/**
+ * wpa_supplicant_reset_bgscan - Reset the bgscan for the current SSID.
+ * @wpa_s: Pointer to the wpa_supplicant data
+ *
+ * Stop, start, or reconfigure the scan parameters depending on the method.
+ */
+void wpa_supplicant_reset_bgscan(struct wpa_supplicant *wpa_s)
{
const char *name;
@@ -812,12 +838,12 @@ static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
name = wpa_s->current_ssid->bgscan;
else
name = wpa_s->conf->bgscan;
- if (name == NULL || name[0] == '\0')
+ if (!name || name[0] == '\0') {
+ wpa_supplicant_stop_bgscan(wpa_s);
return;
+ }
if (wpas_driver_bss_selection(wpa_s))
return;
- if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
- return;
#ifdef CONFIG_P2P
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
return;
@@ -847,15 +873,6 @@ static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
wpa_s->bgscan_ssid = NULL;
}
-
-static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
-{
- if (wpa_s->bgscan_ssid != NULL) {
- bgscan_deinit(wpa_s);
- wpa_s->bgscan_ssid = NULL;
- }
-}
-
#endif /* CONFIG_BGSCAN */
@@ -979,8 +996,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
fils_hlp_sent ? " FILS_HLP_SENT" : "");
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
wpas_clear_temp_disabled(wpa_s, ssid, 1);
- wpa_blacklist_clear(wpa_s);
- wpa_s->extra_blacklist_count = 0;
+ wpa_s->consecutive_conn_failures = 0;
wpa_s->new_connection = 0;
wpa_drv_set_operstate(wpa_s, 1);
#ifndef IEEE8021X_EAPOL
@@ -1000,6 +1016,9 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE))
wpas_update_owe_connect_params(wpa_s);
#endif /* CONFIG_OWE */
+#ifdef CONFIG_HS20
+ hs20_configure_frame_filters(wpa_s);
+#endif
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
state == WPA_ASSOCIATED) {
wpa_s->new_connection = 1;
@@ -1012,8 +1031,8 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
wpa_s->wpa_state = state;
#ifdef CONFIG_BGSCAN
- if (state == WPA_COMPLETED)
- wpa_supplicant_start_bgscan(wpa_s);
+ if (state == WPA_COMPLETED && wpa_s->current_ssid != wpa_s->bgscan_ssid)
+ wpa_supplicant_reset_bgscan(wpa_s);
else if (state < WPA_ASSOCIATED)
wpa_supplicant_stop_bgscan(wpa_s);
#endif /* CONFIG_BGSCAN */
@@ -1084,13 +1103,19 @@ static void wpa_supplicant_terminate(int sig, void *signal_ctx)
void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
{
enum wpa_states old_state = wpa_s->wpa_state;
+ enum wpa_states new_state;
+
+ if (old_state == WPA_SCANNING)
+ new_state = WPA_SCANNING;
+ else
+ new_state = WPA_DISCONNECTED;
wpa_s->pairwise_cipher = 0;
wpa_s->group_cipher = 0;
wpa_s->mgmt_group_cipher = 0;
wpa_s->key_mgmt = 0;
if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
- wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+ wpa_supplicant_set_state(wpa_s, new_state);
if (wpa_s->wpa_state != old_state)
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
@@ -1185,6 +1210,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
+ wpa_bssid_ignore_clear(wpa_s);
wpa_dbg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
return 0;
}
@@ -1634,15 +1660,44 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
wpas_get_ssid_pmf(wpa_s, ssid));
#ifdef CONFIG_OCV
- wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
+ (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_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;
+ if (bss && is_6ghz_freq(bss->freq)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: force hash-to-element mode for 6GHz BSS.");
+ sae_pwe = 1;
+ }
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->force_hunting_and_pecking_pwe) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: force hunting and pecking mode.");
+ sae_pwe = 0;
+ }
+#endif
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 */
@@ -1883,6 +1938,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;
}
}
@@ -1890,7 +1948,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;
@@ -2060,7 +2118,9 @@ static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid)
if (!password)
password = ssid->passphrase;
- if ((conf->sae_pwe == 0 && !ssid->sae_password_id) || !password ||
+ 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);
@@ -2099,6 +2159,24 @@ static void wpa_s_clear_sae_rejected(struct wpa_supplicant *wpa_s)
}
+int wpas_restore_permanent_mac_addr(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not restore permanent MAC address");
+ return -1;
+ }
+ wpa_s->mac_addr_changed = 0;
+ if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not update MAC address information");
+ return -1;
+ }
+ wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
+ return 0;
+}
+
+
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
/**
@@ -2159,18 +2237,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
} else if (rand_style == 0 && wpa_s->mac_addr_changed) {
- if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
- wpa_msg(wpa_s, MSG_INFO,
- "Could not restore permanent MAC address");
+ if (wpas_restore_permanent_mac_addr(wpa_s) < 0)
return;
- }
- wpa_s->mac_addr_changed = 0;
- if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
- wpa_msg(wpa_s, MSG_INFO,
- "Could not update MAC address information");
- return;
- }
- wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
}
wpa_s->last_ssid = ssid;
@@ -2222,10 +2290,6 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
}
wpa_s->current_bss = bss;
- wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d",
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
- ssid->id);
- wpas_notify_mesh_group_started(wpa_s, ssid);
#else /* CONFIG_MESH */
wpa_msg(wpa_s, MSG_ERROR,
"mesh mode support not included in the build");
@@ -2249,8 +2313,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_TDLS
if (bss)
- wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
- bss->ie_len);
+ wpa_tdls_ap_ies(wpa_s->wpa, wpa_bss_ie_ptr(bss), bss->ie_len);
#endif /* CONFIG_TDLS */
#ifdef CONFIG_MBO
@@ -2397,6 +2460,8 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
if (!mode)
return;
+ freq->channel = channel;
+
is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
hw_mode == HOSTAPD_MODE_IEEE80211B;
@@ -2981,7 +3046,7 @@ static u8 * wpas_populate_assoc_ies(
}
#ifdef CONFIG_HS20
- if (is_hs20_network(wpa_s, ssid, bss)) {
+ if (is_hs20_config(wpa_s) && is_hs20_network(wpa_s, ssid, bss)) {
struct wpabuf *hs20;
hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN);
@@ -2999,10 +3064,9 @@ static u8 * wpas_populate_assoc_ies(
wpa_ie_len += wpabuf_len(hs20);
}
wpabuf_free(hs20);
-
- hs20_configure_frame_filters(wpa_s);
}
}
+ hs20_configure_frame_filters(wpa_s);
#endif /* CONFIG_HS20 */
if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
@@ -3171,6 +3235,37 @@ pfs_fail:
wpa_ie_len += wpa_s->rsnxe_len;
}
+ if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_MSCS) &&
+ wpa_s->robust_av.valid_config) {
+ struct wpabuf *mscs_ie;
+ size_t mscs_ie_len, buf_len;
+
+ 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;
@@ -3340,7 +3435,7 @@ get_supported_edmg(struct wpa_supplicant *wpa_s,
if (hw_mode == NUM_HOSTAPD_MODES)
goto fail;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode, 0);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode, false);
if (!mode)
goto fail;
@@ -3432,6 +3527,20 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
os_memset(&params, 0, sizeof(params));
wpa_s->reassociate = 0;
wpa_s->eap_expected_failure = 0;
+
+ /* 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) {
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+
if (bss &&
(!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
#ifdef CONFIG_IEEE80211R
@@ -3480,18 +3589,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_supplicant_cancel_scan(wpa_s);
- /* Starting new association, so clear the possibly used WPA IE from the
- * previous association. */
- wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
- wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
- wpa_s->rsnxe_len = 0;
-
- wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
- if (!wpa_ie) {
- wpas_connect_work_done(wpa_s);
- return;
- }
-
wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
use_crypt = 1;
cipher_pairwise = wpa_s->pairwise_cipher;
@@ -3579,8 +3676,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
}
if (bss && ssid->enable_edmg)
- edmg_ie_oper = get_ie_ext((const u8 *) (bss + 1), bss->ie_len,
- WLAN_EID_EXT_EDMG_OPERATION);
+ edmg_ie_oper = wpa_bss_get_ie_ext(bss,
+ WLAN_EID_EXT_EDMG_OPERATION);
else
edmg_ie_oper = NULL;
@@ -3770,6 +3867,10 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_s->current_ssid)
params.prev_bssid = prev_bssid;
+#ifdef CONFIG_SAE
+ params.sae_pwe = wpa_s->conf->sae_pwe;
+#endif /* CONFIG_SAE */
+
ret = wpa_drv_associate(wpa_s, &params);
os_free(wpa_ie);
if (ret < 0) {
@@ -3782,6 +3883,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
* succeed.
*/
wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+ wpa_s->assoc_status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpas_notify_assoc_status_code(wpa_s, wpa_s->pending_bssid, 0, NULL, 0);
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
return;
@@ -3926,7 +4029,7 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
wpa_s->ifname);
wpas_notify_mesh_group_removed(wpa_s, mconf->meshid,
mconf->meshid_len, reason_code);
- wpa_supplicant_leave_mesh(wpa_s);
+ wpa_supplicant_leave_mesh(wpa_s, true);
}
#endif /* CONFIG_MESH */
@@ -4062,6 +4165,52 @@ int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
/**
+ * wpa_supplicant_remove_all_networks - Remove all configured networks
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: 0 on success (errors are currently ignored)
+ *
+ * This function performs the following operations:
+ * 1. Remove all networks.
+ * 2. Send network removal notifications.
+ * 3. Update internal state machines.
+ * 4. Stop any running sched scans.
+ */
+int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid;
+
+ if (wpa_s->sched_scanning)
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ if (wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ struct wpa_ssid *remove_ssid = ssid;
+ int id;
+
+ id = ssid->id;
+ ssid = ssid->next;
+ if (wpa_s->last_ssid == remove_ssid)
+ wpa_s->last_ssid = NULL;
+ wpas_notify_network_removed(wpa_s, remove_ssid);
+ wpa_config_remove_network(wpa_s->conf, id);
+ }
+ return 0;
+}
+
+
+/**
* wpa_supplicant_enable_network - Mark a configured network as enabled
* @wpa_s: wpa_supplicant structure for a network interface
* @ssid: wpa_ssid structure for a configured network or %NULL
@@ -4851,6 +5000,65 @@ static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
}
+int wpa_supplicant_update_bridge_ifname(struct wpa_supplicant *wpa_s,
+ const char *bridge_ifname)
+{
+ if (wpa_s->wpa_state > WPA_SCANNING)
+ return -EBUSY;
+
+ if (bridge_ifname &&
+ os_strlen(bridge_ifname) >= sizeof(wpa_s->bridge_ifname))
+ return -EINVAL;
+
+ if (!bridge_ifname)
+ bridge_ifname = "";
+
+ if (os_strcmp(wpa_s->bridge_ifname, bridge_ifname) == 0)
+ return 0;
+
+ if (wpa_s->l2_br) {
+ l2_packet_deinit(wpa_s->l2_br);
+ wpa_s->l2_br = NULL;
+ }
+
+ os_strlcpy(wpa_s->bridge_ifname, bridge_ifname,
+ sizeof(wpa_s->bridge_ifname));
+
+ if (wpa_s->bridge_ifname[0]) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Receiving packets from bridge interface '%s'",
+ wpa_s->bridge_ifname);
+ wpa_s->l2_br = l2_packet_init_bridge(
+ wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
+ ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
+ if (!wpa_s->l2_br) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to open l2_packet connection for the bridge interface '%s'",
+ wpa_s->bridge_ifname);
+ goto fail;
+ }
+ }
+
+#ifdef CONFIG_TDLS
+ if (!wpa_s->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
+ goto fail;
+#endif /* CONFIG_TDLS */
+
+ return 0;
+fail:
+ wpa_s->bridge_ifname[0] = 0;
+ if (wpa_s->l2_br) {
+ l2_packet_deinit(wpa_s->l2_br);
+ wpa_s->l2_br = NULL;
+ }
+#ifdef CONFIG_TDLS
+ if (!wpa_s->p2p_mgmt)
+ wpa_tdls_init(wpa_s->wpa);
+#endif /* CONFIG_TDLS */
+ return -EIO;
+}
+
+
/**
* wpa_supplicant_driver_init - Initialize driver interface parameters
* @wpa_s: Pointer to wpa_supplicant data
@@ -4946,6 +5154,7 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
wpa_s->parent = parent ? parent : wpa_s;
wpa_s->p2pdev = wpa_s->parent;
wpa_s->sched_scanning = 0;
+ wpa_s->setband_mask = WPA_SETBAND_AUTO;
dl_list_init(&wpa_s->bss_tmp_disallowed);
dl_list_init(&wpa_s->fils_hlp_req);
@@ -5690,7 +5899,7 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
dl_list_for_each(tmp, &radio->work, struct wpa_radio_work,
list) {
if (os_strcmp(tmp->type, "scan") == 0 &&
- radio->external_scan_running &&
+ external_scan_running(radio) &&
(((struct wpa_driver_scan_params *)
tmp->ctx)->only_new_results ||
tmp->wpa_s->clear_driver_scan_cache))
@@ -5746,7 +5955,7 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
* rejected by kernel.
*/
if (os_strcmp(tmp->type, "scan") == 0 &&
- radio->external_scan_running &&
+ external_scan_running(radio) &&
(((struct wpa_driver_scan_params *)
tmp->ctx)->only_new_results ||
tmp->wpa_s->clear_driver_scan_cache))
@@ -5785,7 +5994,7 @@ static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
if (work->started)
return; /* already started and still in progress */
- if (wpa_s && wpa_s->radio->external_scan_running) {
+ if (wpa_s && external_scan_running(wpa_s->radio)) {
wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
return;
}
@@ -5881,6 +6090,10 @@ static void radio_remove_interface(struct wpa_supplicant *wpa_s)
wpa_s->ifname, radio->name);
dl_list_del(&wpa_s->radio_list);
radio_remove_works(wpa_s, NULL, 0);
+ /* If the interface that triggered the external scan was removed, the
+ * external scan is no longer running. */
+ if (wpa_s == radio->external_scan_req_interface)
+ radio->external_scan_req_interface = NULL;
wpa_s->radio = NULL;
if (!dl_list_empty(&radio->ifaces))
return; /* Interfaces remain for this radio */
@@ -6034,6 +6247,8 @@ next_driver:
wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
if (wpa_s->drv_priv == NULL) {
const char *pos;
+ int level = MSG_ERROR;
+
pos = driver ? os_strchr(driver, ',') : NULL;
if (pos) {
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
@@ -6041,8 +6256,12 @@ next_driver:
driver = pos + 1;
goto next_driver;
}
- wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
- "interface");
+
+#ifdef CONFIG_MATCH_IFACE
+ if (wpa_s->matched == WPA_IFACE_MATCHED_NULL)
+ level = MSG_DEBUG;
+#endif /* CONFIG_MATCH_IFACE */
+ wpa_msg(wpa_s, level, "Failed to initialize driver interface");
return -1;
}
if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
@@ -6187,6 +6406,9 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
return -1;
}
os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
+#ifdef CONFIG_MATCH_IFACE
+ wpa_s->matched = iface->matched;
+#endif /* CONFIG_MATCH_IFACE */
if (iface->bridge_ifname) {
if (os_strlen(iface->bridge_ifname) >=
@@ -6494,7 +6716,7 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
wpa_s->disconnected = 1;
if (wpa_s->drv_priv) {
/*
- * Don't deauthenticate if WoWLAN is enabled and not explicitly
+ * Don't deauthenticate if WoWLAN is enable and not explicitly
* been configured to disconnect.
*/
if (!wpa_drv_get_wowlan(wpa_s) ||
@@ -6541,7 +6763,7 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_MESH
if (wpa_s->ifmsh) {
- wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
+ wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh, true);
wpa_s->ifmsh = NULL;
}
#endif /* CONFIG_MESH */
@@ -6580,6 +6802,10 @@ struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
if (!iface)
return NULL;
*iface = *miface;
+ if (!miface->ifname)
+ iface->matched = WPA_IFACE_MATCHED_NULL;
+ else
+ iface->matched = WPA_IFACE_MATCHED;
iface->ifname = ifname;
return iface;
}
@@ -6612,10 +6838,8 @@ static int wpa_supplicant_match_existing(struct wpa_global *global)
continue;
iface = wpa_supplicant_match_iface(global, ifi->if_name);
if (iface) {
- wpa_s = wpa_supplicant_add_iface(global, iface, NULL);
+ wpa_supplicant_add_iface(global, iface, NULL);
os_free(iface);
- if (wpa_s)
- wpa_s->matched = 1;
}
}
@@ -7145,6 +7369,18 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
if (wpa_s->conf->changed_parameters & CFG_CHANGED_DISABLE_BTM)
wpa_supplicant_set_default_scan_ies(wpa_s);
+#ifdef CONFIG_BGSCAN
+ /*
+ * We default to global bgscan parameters only when per-network bgscan
+ * parameters aren't set. Only bother resetting bgscan parameters if
+ * this is the case.
+ */
+ if ((wpa_s->conf->changed_parameters & CFG_CHANGED_BGSCAN) &&
+ wpa_s->current_ssid && !wpa_s->current_ssid->bgscan &&
+ wpa_s->wpa_state == WPA_COMPLETED)
+ wpa_supplicant_reset_bgscan(wpa_s);
+#endif /* CONFIG_BGSCAN */
+
#ifdef CONFIG_WPS
wpas_wps_update_config(wpa_s);
#endif /* CONFIG_WPS */
@@ -7185,7 +7421,7 @@ static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
continue;
if (bss->ssid_len == cbss->ssid_len &&
os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
- wpa_blacklist_get(wpa_s, bss->bssid) == NULL) {
+ !wpa_bssid_ignore_is_listed(wpa_s, bss->bssid)) {
add_freq(freqs, &num_freqs, bss->freq);
if (num_freqs == max_freqs)
break;
@@ -7215,7 +7451,7 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
/*
- * There is no point in blacklisting the AP if this event is
+ * There is no point in ignoring the AP temporarily if this event is
* generated based on local request to disconnect.
*/
if (wpa_s->own_disconnect_req || wpa_s->own_reconnect_req) {
@@ -7237,17 +7473,13 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
/*
- * Add the failed BSSID into the blacklist and speed up next scan
+ * Add the failed BSSID into the ignore list and speed up next scan
* attempt if there could be other APs that could accept association.
- * The current blacklist count indicates how many times we have tried
- * connecting to this AP and multiple attempts mean that other APs are
- * either not available or has already been tried, so that we can start
- * increasing the delay here to avoid constant scanning.
*/
- count = wpa_blacklist_add(wpa_s, bssid);
+ count = wpa_bssid_ignore_add(wpa_s, bssid);
if (count == 1 && wpa_s->current_bss) {
/*
- * This BSS was not in the blacklist before. If there is
+ * This BSS was not in the ignore list before. If there is
* another BSS available for the same ESS, we should try that
* next. Otherwise, we may as well try this one once more
* before allowing other, likely worse, ESSes to be considered.
@@ -7256,7 +7488,7 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
if (freqs) {
wpa_dbg(wpa_s, MSG_DEBUG, "Another BSS in this ESS "
"has been seen; try it next");
- wpa_blacklist_add(wpa_s, bssid);
+ wpa_bssid_ignore_add(wpa_s, bssid);
/*
* On the next scan, go through only the known channels
* used in this ESS based on previous scans to speed up
@@ -7267,19 +7499,19 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
}
- /*
- * Add previous failure count in case the temporary blacklist was
- * cleared due to no other BSSes being available.
- */
- count += wpa_s->extra_blacklist_count;
+ wpa_s->consecutive_conn_failures++;
- if (count > 3 && wpa_s->current_ssid) {
+ if (wpa_s->consecutive_conn_failures > 3 && wpa_s->current_ssid) {
wpa_printf(MSG_DEBUG, "Continuous association failures - "
"consider temporary network disabling");
wpas_auth_failed(wpa_s, "CONN_FAILED");
}
-
- switch (count) {
+ /*
+ * Multiple consecutive connection failures mean that other APs are
+ * either not available or have already been tried, so we can start
+ * increasing the delay here to avoid constant scanning.
+ */
+ switch (wpa_s->consecutive_conn_failures) {
case 1:
timeout = 100;
break;
@@ -7297,8 +7529,9 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
break;
}
- wpa_dbg(wpa_s, MSG_DEBUG, "Blacklist count %d --> request scan in %d "
- "ms", count, timeout);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Consecutive connection failures: %d --> request scan in %d ms",
+ wpa_s->consecutive_conn_failures, timeout);
/*
* TODO: if more than one possible AP is available in scan results,
@@ -7697,7 +7930,6 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s)
wpa_s->normal_scans = 0;
wpa_s->scan_req = NORMAL_SCAN_REQ;
wpa_supplicant_reinit_autoscan(wpa_s);
- wpa_s->extra_blacklist_count = 0;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_s->last_owe_group = 0;
@@ -7914,7 +8146,7 @@ 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,
- int is_6ghz)
+ bool is_6ghz)
{
u16 i;
@@ -7963,7 +8195,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;
}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index f5194bec..11d18854 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -366,7 +366,14 @@ fast_reauth=1
# Password (and passphrase, etc.) backend for external storage
# format: <backend name>[:<optional backend parameters>]
+# Test backend which stores passwords in memory. Should only be used for
+# development purposes.
#ext_password_backend=test:pw1=password|pw2=testing
+# File-based backend which reads passwords from a file. The parameter
+# identifies the file to read passwords from. The password file follows the
+# format of wpa_supplicant.conf and accepts simple `key=passphrase` formatted
+# passwords.
+#ext_password_backend=file:/path/to/passwords.conf
# Disable P2P functionality
@@ -458,6 +465,9 @@ fast_reauth=1
# 1: Scan current operating frequency if another VIF on the same radio
# is already associated.
+# Seconds to consider old scan results valid for association (default: 5)
+#scan_res_valid_for_connect=5
+
# MAC address policy default
# 0 = use permanent MAC address
# 1 = use random MAC address for each ESS connection
@@ -526,7 +536,7 @@ fast_reauth=1
#go_venue_group=7
#go_venue_type=1
-# Homogenous ESS identifier
+# Homogeneous ESS identifier
# If this is set, scans will be used to request response only from BSSes
# belonging to the specified Homogeneous ESS. This is used only if interworking
# is enabled.
@@ -843,6 +853,16 @@ fast_reauth=1
# bssid: BSSID (optional); if set, this network block is used only when
# associating with the AP using the configured BSSID
#
+# ignore_broadcast_ssid: SSID broadcast behavior
+# Send empty SSID in beacons and ignore probe request frames that do not
+# specify full SSID, i.e., require stations to know SSID.
+# default: disabled (0)
+# 1 = send empty (length=0) SSID in beacon and ignore probe request for
+# broadcast SSID
+# 2 = clear SSID (ASCII 0), but keep the original length (this may be required
+# with some clients that do not support empty SSID) and ignore probe
+# requests for broadcast SSID
+#
# priority: priority group (integer)
# By default, all networks will get same priority group (0). If some of the
# networks are more desirable, this field can be used to change the order in
@@ -971,7 +991,8 @@ fast_reauth=1
# This is a countermeasure against multi-channel man-in-the-middle attacks.
# Enabling this automatically also enables ieee80211w, if not yet enabled.
# 0 = disabled (default)
-# 1 = enabled
+# 1 = enabled if wpa_supplicant's SME in use. Otherwise enabled only when the
+# driver indicates support for operating channel validation.
#ocv=1
#
# auth_alg: list of allowed IEEE 802.11 authentication algorithms
@@ -1472,6 +1493,61 @@ fast_reauth=1
# 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 and
+# beacon protection support indication from the driver.
+# 0 = disabled (default)
+# 1 = 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
@@ -1950,12 +2026,12 @@ network={
key_mgmt=NONE
}
-# Example configuration blacklisting two APs - these will be ignored
+# Example configuration ignoring two APs - these will be ignored
# for this network.
network={
ssid="example"
psk="very secret passphrase"
- bssid_blacklist=02:11:22:33:44:55 02:22:aa:44:55:66
+ bssid_ignore=02:11:22:33:44:55 02:22:aa:44:55:66
}
# Example configuration limiting AP selection to a specific set of APs;
@@ -1963,7 +2039,7 @@ network={
network={
ssid="example"
psk="very secret passphrase"
- bssid_whitelist=02:55:ae:bc:00:00/ff:ff:ff:ff:00:00 00:00:77:66:55:44/00:00:ff:ff:ff:ff
+ bssid_accept=02:55:ae:bc:00:00/ff:ff:ff:ff:00:00 00:00:77:66:55:44/00:00:ff:ff:ff:ff
}
# Example config file that will only scan on channel 36.
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 98b317ec..9ce32339 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -14,6 +14,8 @@
#include "common/defs.h"
#include "common/sae.h"
#include "common/wpa_ctrl.h"
+#include "crypto/sha384.h"
+#include "eapol_supp/eapol_supp_sm.h"
#include "wps/wps_defs.h"
#include "config_ssid.h"
#include "wmm_ac.h"
@@ -47,9 +49,6 @@ struct ctrl_iface_global_priv;
struct wpas_dbus_priv;
struct wpas_hidl_priv;
-/* How many seconds to consider old scan results valid for association. */
-#define SCAN_RES_VALID_FOR_CONNECT 5
-
/**
* struct wpa_interface - Parameters for wpa_supplicant_add_iface()
*/
@@ -121,6 +120,18 @@ struct wpa_interface {
* interface that is not a network interface.
*/
int p2p_mgmt;
+
+#ifdef CONFIG_MATCH_IFACE
+ /**
+ * matched - Interface was matched rather than specified
+ *
+ */
+ enum {
+ WPA_IFACE_NOT_MATCHED,
+ WPA_IFACE_MATCHED_NULL,
+ WPA_IFACE_MATCHED
+ } matched;
+#endif /* CONFIG_MATCH_IFACE */
};
/**
@@ -296,6 +307,7 @@ struct wpa_global {
unsigned int p2p_24ghz_social_channels:1;
unsigned int pending_p2ps_group:1;
unsigned int pending_group_iface_for_p2ps:1;
+ unsigned int p2p_go_found_external_scan:1;
unsigned int pending_p2ps_group_freq;
#ifdef CONFIG_WIFI_DISPLAY
@@ -318,12 +330,23 @@ struct wpa_global {
struct wpa_radio {
char name[16]; /* from driver_ops get_radio_name() or empty if not
* available */
- unsigned int external_scan_running:1;
+ /** NULL if no external scan running. */
+ struct wpa_supplicant *external_scan_req_interface;
unsigned int num_active_works;
struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */
struct dl_list work; /* struct wpa_radio_work::list entries */
};
+/**
+ * Checks whether an external scan is running on a given radio.
+ * @radio: Pointer to radio struct
+ * Returns: true if an external scan is running, false otherwise.
+ */
+static inline bool external_scan_running(struct wpa_radio *radio)
+{
+ return radio && radio->external_scan_req_interface;
+}
+
#define MAX_ACTIVE_WORKS 2
@@ -491,6 +514,65 @@ struct driver_signal_override {
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;
+};
+
+#ifdef CONFIG_PASN
+
+struct pasn_fils {
+ u8 nonce[FILS_NONCE_LEN];
+ u8 anonce[FILS_NONCE_LEN];
+ u8 session[FILS_SESSION_LEN];
+ u8 erp_pmkid[PMKID_LEN];
+ bool completed;
+};
+
+struct wpas_pasn {
+ int akmp;
+ int cipher;
+ u16 group;
+ int freq;
+
+ u8 trans_seq;
+ u8 status;
+
+ u8 bssid[ETH_ALEN];
+ size_t pmk_len;
+ u8 pmk[PMK_LEN_MAX];
+ bool using_pmksa;
+
+ u8 hash[SHA384_MAC_LEN];
+
+ struct wpabuf *beacon_rsne_rsnxe;
+ struct wpa_ptk ptk;
+ struct crypto_ecdh *ecdh;
+
+#ifdef CONFIG_SAE
+ struct sae_data sae;
+#endif /* CONFIG_SAE */
+
+ struct wpa_ssid *ssid;
+
+#ifdef CONFIG_FILS
+ struct pasn_fils fils;
+#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_IEEE80211R
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t pmk_r1_len;
+ u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+#endif /* CONFIG_IEEE80211R */
+};
+#endif /* CONFIG_PASN */
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -571,7 +653,7 @@ struct wpa_supplicant {
struct wpa_ssid_value *disallow_aps_ssid;
size_t disallow_aps_ssid_count;
- enum set_band setband;
+ u32 setband_mask;
/* Preferred network for the next connection attempt */
struct wpa_ssid *next_ssid;
@@ -596,6 +678,7 @@ struct wpa_supplicant {
void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
+ void (*scan_res_fail_handler)(struct wpa_supplicant *wpa_s);
struct dl_list bss; /* struct wpa_bss::list */
struct dl_list bss_id; /* struct wpa_bss::list_id */
size_t num_bss;
@@ -615,6 +698,8 @@ struct wpa_supplicant {
int interface_removed; /* whether the network interface has been
* removed */
struct wpa_sm *wpa;
+ struct ptksa_cache *ptksa;
+
struct eapol_sm *eapol;
struct ctrl_iface_priv *ctrl_iface;
@@ -641,19 +726,10 @@ struct wpa_supplicant {
unsigned int keys_cleared; /* bitfield of key indexes that the driver is
* known not to be configured with a key */
- struct wpa_blacklist *blacklist;
+ struct wpa_bssid_ignore *bssid_ignore;
- /**
- * extra_blacklist_count - Sum of blacklist counts after last connection
- *
- * This variable is used to maintain a count of temporary blacklisting
- * failures (maximum number for any BSS) over blacklist clear
- * operations. This is needed for figuring out whether there has been
- * failures prior to the last blacklist clear operation which happens
- * whenever no other not-blacklisted BSS candidates are available. This
- * gets cleared whenever a connection has been established successfully.
- */
- int extra_blacklist_count;
+ /* Number of connection failures since last successful connection */
+ unsigned int consecutive_conn_failures;
/**
* scan_req - Type of the scan request
@@ -758,7 +834,7 @@ struct wpa_supplicant {
struct wps_er *wps_er;
unsigned int wps_run;
struct os_reltime wps_pin_start_time;
- int blacklist_cleared;
+ bool bssid_ignore_cleared;
struct wpabuf *pending_eapol_rx;
struct os_reltime pending_eapol_rx_time;
@@ -779,6 +855,7 @@ struct wpa_supplicant {
unsigned int connection_max_nss_tx:4;
unsigned int connection_channel_bandwidth:5;
unsigned int disable_mbo_oce:1;
+ unsigned int connection_11b_only:1;
struct os_reltime last_mac_addr_change;
int last_mac_addr_style;
@@ -1156,6 +1233,14 @@ struct wpa_supplicant {
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;
+ int force_hunting_and_pecking_pwe;
#endif /* CONFIG_TESTING_OPTIONS */
struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -1281,10 +1366,10 @@ 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_reconfig_announcement;
struct wpabuf *dpp_presence_announcement;
struct dpp_bootstrap_info *dpp_chirp_bi;
int dpp_chirp_freq;
@@ -1295,6 +1380,7 @@ struct wpa_supplicant {
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;
@@ -1314,6 +1400,13 @@ struct wpa_supplicant {
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;
+
+#ifdef CONFIG_PASN
+ struct wpas_pasn pasn;
+ struct wpa_radio_work *pasn_auth_work;
+#endif /* CONFIG_PASN */
};
@@ -1337,9 +1430,12 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
const char * wpa_supplicant_state_txt(enum wpa_states state);
int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s);
int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_update_bridge_ifname(struct wpa_supplicant *wpa_s,
+ const char *bridge_ifname);
int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
u8 *wpa_ie, size_t *wpa_ie_len);
+int wpas_restore_permanent_mac_addr(struct wpa_supplicant *wpa_s);
void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss,
struct wpa_ssid *ssid);
@@ -1362,6 +1458,7 @@ 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);
+int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s);
void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
@@ -1449,6 +1546,7 @@ int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s,
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);
+void wpa_supplicant_reset_bgscan(struct wpa_supplicant *wpa_s);
/* MBO functions */
@@ -1541,6 +1639,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);
@@ -1609,7 +1710,7 @@ 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,
- int is_6ghz);
+ bool is_6ghz);
void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
unsigned int sec, int rssi_threshold);
@@ -1632,4 +1733,23 @@ 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);
+
+int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
+ const u8 *bssid, int akmp, int cipher,
+ u16 group, int network_id);
+void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s);
+int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
+ const u8 *data, size_t data_len, u8 acked);
+int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len);
+int disabled_freq(struct wpa_supplicant *wpa_s, int freq);
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
index 552477db..7a558f33 100644
--- a/wpa_supplicant/wpa_supplicant_template.conf
+++ b/wpa_supplicant/wpa_supplicant_template.conf
@@ -6,4 +6,4 @@ fast_reauth=1
pmf=1
p2p_add_cli_chan=1
oce=1
-wowlan_disconnect_on_deinit=1
+sae_pwe=2
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 6bd271e1..95dad95b 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -16,6 +16,7 @@
#include "config.h"
#include "l2_packet/l2_packet.h"
#include "common/wpa_common.h"
+#include "common/ptksa_cache.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "rsn_supp/pmksa_cache.h"
@@ -307,9 +308,19 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol,
ieee802_1x_notify_create_actor(wpa_s, wpa_s->last_eapol_src);
}
- if (result != EAPOL_SUPP_RESULT_SUCCESS ||
- !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ if (result != EAPOL_SUPP_RESULT_SUCCESS)
+#else
+ if (result != EAPOL_SUPP_RESULT_SUCCESS ||
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+ return;
+
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ if (wpa_ft_is_ft_protocol(wpa_s->wpa)) {
return;
+ }
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt))
return;
@@ -575,7 +586,8 @@ 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,
- u32 pmk_lifetime, u8 pmk_reauth_threshold)
+ u32 pmk_lifetime, u8 pmk_reauth_threshold,
+ int akmp)
{
struct wpa_supplicant *wpa_s = _wpa_s;
struct wpa_ssid *ssid;
@@ -583,9 +595,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;
@@ -1268,6 +1293,7 @@ static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap)
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)) &&
@@ -1279,6 +1305,24 @@ static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap)
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 |
@@ -1298,6 +1342,8 @@ static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap)
changed = 1;
}
+ wpas_notify_transition_disable(wpa_s, ssid, bitmap);
+
if (!changed)
return;
@@ -1308,6 +1354,15 @@ static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap)
#endif /* CONFIG_NO_CONFIG_WRITE */
}
+
+static void wpa_supplicant_store_ptk(void *ctx, u8 *addr, int cipher,
+ u32 life_time, const struct wpa_ptk *ptk)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ ptksa_cache_add(wpa_s->ptksa, addr, cipher, life_time, ptk);
+}
+
#endif /* CONFIG_NO_WPA */
@@ -1315,9 +1370,20 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
{
#ifndef CONFIG_NO_WPA
struct wpa_sm_ctx *ctx;
+
+ wpa_s->ptksa = ptksa_cache_init();
+ if (!wpa_s->ptksa) {
+ wpa_printf(MSG_ERROR, "Failed to allocate PTKSA");
+ return -1;
+ }
+
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate WPA context.");
+
+ ptksa_cache_deinit(wpa_s->ptksa);
+ wpa_s->ptksa = NULL;
+
return -1;
}
@@ -1361,12 +1427,15 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
ctx->fils_hlp_rx = wpa_supplicant_fils_hlp_rx;
ctx->channel_info = wpa_supplicant_channel_info;
ctx->transition_disable = wpa_supplicant_transition_disable;
+ ctx->store_ptk = wpa_supplicant_store_ptk;
wpa_s->wpa = wpa_sm_init(ctx);
if (wpa_s->wpa == NULL) {
- wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
- "machine");
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize WPA state machine");
os_free(ctx);
+ ptksa_cache_deinit(wpa_s->ptksa);
+ wpa_s->ptksa = NULL;
return -1;
}
#endif /* CONFIG_NO_WPA */
@@ -1416,7 +1485,16 @@ 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;
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION) ||
+ (wpa_s->drv_flags2 &
+ WPA_DRIVER_FLAGS2_BEACON_PROTECTION_CLIENT))
+ conf.beacon_prot = ssid->beacon_prot;
+
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ conf.force_kdk_derivation = wpa_s->conf->force_kdk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN */
}
wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
}
diff --git a/wpa_supplicant/wpas_module_tests.c b/wpa_supplicant/wpas_module_tests.c
index 4e37591b..ce5398cb 100644
--- a/wpa_supplicant/wpas_module_tests.c
+++ b/wpa_supplicant/wpas_module_tests.c
@@ -11,60 +11,77 @@
#include "utils/common.h"
#include "utils/module_tests.h"
#include "wpa_supplicant_i.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
-static int wpas_blacklist_module_tests(void)
+static int wpas_bssid_ignore_module_tests(void)
{
struct wpa_supplicant wpa_s;
int ret = -1;
os_memset(&wpa_s, 0, sizeof(wpa_s));
- wpa_blacklist_clear(&wpa_s);
+ wpa_bssid_ignore_clear(&wpa_s);
- if (wpa_blacklist_get(NULL, NULL) != NULL ||
- wpa_blacklist_get(NULL, (u8 *) "123456") != NULL ||
- wpa_blacklist_get(&wpa_s, NULL) != NULL ||
- wpa_blacklist_get(&wpa_s, (u8 *) "123456") != NULL)
+ if (wpa_bssid_ignore_get(NULL, NULL) != NULL ||
+ wpa_bssid_ignore_get(NULL, (u8 *) "123456") != NULL ||
+ wpa_bssid_ignore_get(&wpa_s, NULL) != NULL ||
+ wpa_bssid_ignore_get(&wpa_s, (u8 *) "123456") != NULL)
goto fail;
- if (wpa_blacklist_add(NULL, NULL) == 0 ||
- wpa_blacklist_add(NULL, (u8 *) "123456") == 0 ||
- wpa_blacklist_add(&wpa_s, NULL) == 0)
+ if (wpa_bssid_ignore_add(NULL, NULL) == 0 ||
+ wpa_bssid_ignore_add(NULL, (u8 *) "123456") == 0 ||
+ wpa_bssid_ignore_add(&wpa_s, NULL) == 0)
goto fail;
- if (wpa_blacklist_del(NULL, NULL) == 0 ||
- wpa_blacklist_del(NULL, (u8 *) "123456") == 0 ||
- wpa_blacklist_del(&wpa_s, NULL) == 0 ||
- wpa_blacklist_del(&wpa_s, (u8 *) "123456") == 0)
+ if (wpa_bssid_ignore_del(NULL, NULL) == 0 ||
+ wpa_bssid_ignore_del(NULL, (u8 *) "123456") == 0 ||
+ wpa_bssid_ignore_del(&wpa_s, NULL) == 0 ||
+ wpa_bssid_ignore_del(&wpa_s, (u8 *) "123456") == 0)
goto fail;
- if (wpa_blacklist_add(&wpa_s, (u8 *) "111111") < 0 ||
- wpa_blacklist_add(&wpa_s, (u8 *) "111111") < 0 ||
- wpa_blacklist_add(&wpa_s, (u8 *) "222222") < 0 ||
- wpa_blacklist_add(&wpa_s, (u8 *) "333333") < 0 ||
- wpa_blacklist_add(&wpa_s, (u8 *) "444444") < 0 ||
- wpa_blacklist_del(&wpa_s, (u8 *) "333333") < 0 ||
- wpa_blacklist_del(&wpa_s, (u8 *) "xxxxxx") == 0 ||
- wpa_blacklist_get(&wpa_s, (u8 *) "xxxxxx") != NULL ||
- wpa_blacklist_get(&wpa_s, (u8 *) "111111") == NULL ||
- wpa_blacklist_get(&wpa_s, (u8 *) "222222") == NULL ||
- wpa_blacklist_get(&wpa_s, (u8 *) "444444") == NULL ||
- wpa_blacklist_del(&wpa_s, (u8 *) "111111") < 0 ||
- wpa_blacklist_del(&wpa_s, (u8 *) "222222") < 0 ||
- wpa_blacklist_del(&wpa_s, (u8 *) "444444") < 0 ||
- wpa_blacklist_add(&wpa_s, (u8 *) "111111") < 0 ||
- wpa_blacklist_add(&wpa_s, (u8 *) "222222") < 0 ||
- wpa_blacklist_add(&wpa_s, (u8 *) "333333") < 0)
+ if (wpa_bssid_ignore_add(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "222222") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "333333") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "444444") < 0 ||
+ wpa_bssid_ignore_del(&wpa_s, (u8 *) "333333") < 0 ||
+ wpa_bssid_ignore_del(&wpa_s, (u8 *) "xxxxxx") == 0 ||
+ wpa_bssid_ignore_get(&wpa_s, (u8 *) "xxxxxx") != NULL ||
+ wpa_bssid_ignore_get(&wpa_s, (u8 *) "111111") == NULL ||
+ wpa_bssid_ignore_get(&wpa_s, (u8 *) "222222") == NULL ||
+ wpa_bssid_ignore_get(&wpa_s, (u8 *) "444444") == NULL ||
+ wpa_bssid_ignore_del(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_bssid_ignore_del(&wpa_s, (u8 *) "222222") < 0 ||
+ wpa_bssid_ignore_del(&wpa_s, (u8 *) "444444") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "222222") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "333333") < 0)
+ goto fail;
+
+ wpa_bssid_ignore_clear(&wpa_s);
+
+ if (wpa_bssid_ignore_add(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "222222") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "333333") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "444444") < 0 ||
+ !wpa_bssid_ignore_is_listed(&wpa_s, (u8 *) "111111") ||
+ wpa_bssid_ignore_del(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_bssid_ignore_is_listed(&wpa_s, (u8 *) "111111") ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "111111") < 0)
+ goto fail;
+
+ wpa_bssid_ignore_update(&wpa_s);
+
+ if (!wpa_bssid_ignore_is_listed(&wpa_s, (u8 *) "111111"))
goto fail;
ret = 0;
fail:
- wpa_blacklist_clear(&wpa_s);
+ wpa_bssid_ignore_clear(&wpa_s);
if (ret)
- wpa_printf(MSG_ERROR, "blacklist module test failure");
+ wpa_printf(MSG_ERROR, "bssid_ignore module test failure");
return ret;
}
@@ -76,7 +93,7 @@ int wpas_module_tests(void)
wpa_printf(MSG_INFO, "wpa_supplicant module tests");
- if (wpas_blacklist_module_tests() < 0)
+ if (wpas_bssid_ignore_module_tests() < 0)
ret = -1;
#ifdef CONFIG_WPS
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 9f68b22d..1dd3d82f 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -26,7 +26,7 @@
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "notify.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
#include "bss.h"
#include "scan.h"
#include "ap.h"
@@ -94,14 +94,14 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "WPS: PIN registration with " MACSTR
" did not succeed - continue trying to find "
"suitable AP", MAC2STR(bssid));
- wpa_blacklist_add(wpa_s, bssid);
+ wpa_bssid_ignore_add(wpa_s, bssid);
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s,
- wpa_s->blacklist_cleared ? 5 : 0, 0);
- wpa_s->blacklist_cleared = 0;
+ wpa_s->bssid_ignore_cleared ? 5 : 0, 0);
+ wpa_s->bssid_ignore_cleared = false;
return 1;
}
@@ -720,7 +720,7 @@ static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
wpas_notify_wps_event_success(wpa_s);
if (wpa_s->current_ssid)
wpas_clear_temp_disabled(wpa_s, wpa_s->current_ssid, 1);
- wpa_s->extra_blacklist_count = 0;
+ wpa_s->consecutive_conn_failures = 0;
/*
* Enable the networks disabled during wpas_wps_reassoc after 10
@@ -1139,7 +1139,7 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
wpa_s->scan_runs = 0;
wpa_s->normal_scans = 0;
wpa_s->wps_success = 0;
- wpa_s->blacklist_cleared = 0;
+ wpa_s->bssid_ignore_cleared = false;
wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -2883,10 +2883,11 @@ static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s)
for (i = 0; i < wpa_s->num_wps_ap; i++) {
struct wps_ap_info *ap = &wpa_s->wps_ap[i];
- struct wpa_blacklist *e = wpa_blacklist_get(wpa_s, ap->bssid);
+ struct wpa_bssid_ignore *e = wpa_bssid_ignore_get(wpa_s,
+ ap->bssid);
wpa_printf(MSG_DEBUG, "WPS: AP[%d] " MACSTR " type=%d "
- "tries=%d last_attempt=%d sec ago blacklist=%d",
+ "tries=%d last_attempt=%d sec ago bssid_ignore=%d",
(int) i, MAC2STR(ap->bssid), ap->type, ap->tries,
ap->last_attempt.sec > 0 ?
(int) now.sec - (int) ap->last_attempt.sec : -1,
@@ -2948,7 +2949,7 @@ static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
MAC2STR(res->bssid), ap->type, type);
ap->type = type;
if (type != WPS_AP_NOT_SEL_REG)
- wpa_blacklist_del(wpa_s, ap->bssid);
+ wpa_bssid_ignore_del(wpa_s, ap->bssid);
}
ap->pbc_active = pbc_active;
if (uuid)